JSC should support SharedArrayBuffer
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Nov 2016 03:10:00 +0000 (03:10 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 1 Nov 2016 03:10:00 +0000 (03:10 +0000)
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.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208209 268f45cc-cd09-0410-ab3c-d52691b4dbfc

108 files changed:
JSTests/ChangeLog
JSTests/stress/SharedArrayBuffer.js [new file with mode: 0644]
LayoutTests/ChangeLog
LayoutTests/js/dom/global-constructors-attributes-dedicated-worker-expected.txt
LayoutTests/platform/mac-wk1/js/dom/global-constructors-attributes-expected.txt
LayoutTests/platform/mac-yosemite/js/dom/global-constructors-attributes-expected.txt
LayoutTests/platform/mac/js/dom/global-constructors-attributes-expected.txt
LayoutTests/workers/sab/simple-expected.txt [new file with mode: 0644]
LayoutTests/workers/sab/simple-worker-1.js [new file with mode: 0644]
LayoutTests/workers/sab/simple-worker-2.js [new file with mode: 0644]
LayoutTests/workers/sab/simple.html [new file with mode: 0644]
LayoutTests/workers/sab/worker-resources.js [new file with mode: 0644]
Source/JavaScriptCore/API/JSTypedArray.cpp
Source/JavaScriptCore/API/tests/CompareAndSwapTest.cpp
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/LargeAllocation.h
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/runtime/ArrayBuffer.cpp
Source/JavaScriptCore/runtime/ArrayBuffer.h
Source/JavaScriptCore/runtime/ArrayBufferSharingMode.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/ArrayBufferView.h
Source/JavaScriptCore/runtime/AtomicsObject.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/AtomicsObject.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/DataView.cpp
Source/JavaScriptCore/runtime/GenericTypedArrayViewInlines.h
Source/JavaScriptCore/runtime/Intrinsic.h
Source/JavaScriptCore/runtime/JSArrayBuffer.cpp
Source/JavaScriptCore/runtime/JSArrayBuffer.h
Source/JavaScriptCore/runtime/JSArrayBufferConstructor.cpp
Source/JavaScriptCore/runtime/JSArrayBufferConstructor.h
Source/JavaScriptCore/runtime/JSArrayBufferPrototype.cpp
Source/JavaScriptCore/runtime/JSArrayBufferPrototype.h
Source/JavaScriptCore/runtime/JSArrayBufferView.cpp
Source/JavaScriptCore/runtime/JSArrayBufferView.h
Source/JavaScriptCore/runtime/JSArrayBufferViewInlines.h
Source/JavaScriptCore/runtime/JSDataView.cpp
Source/JavaScriptCore/runtime/JSDataView.h
Source/JavaScriptCore/runtime/JSDataViewPrototype.cpp
Source/JavaScriptCore/runtime/JSGenericTypedArrayView.h
Source/JavaScriptCore/runtime/JSGenericTypedArrayViewInlines.h
Source/JavaScriptCore/runtime/JSGenericTypedArrayViewPrototypeFunctions.h
Source/JavaScriptCore/runtime/JSGlobalObject.cpp
Source/JavaScriptCore/runtime/JSGlobalObject.h
Source/JavaScriptCore/runtime/MathObject.cpp
Source/JavaScriptCore/runtime/RuntimeFlags.h
Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp
Source/JavaScriptCore/runtime/SimpleTypedArrayController.h
Source/JavaScriptCore/runtime/TypedArrayController.h
Source/JavaScriptCore/runtime/TypedArrayType.h
Source/JavaScriptCore/runtime/VM.h
Source/WTF/ChangeLog
Source/WTF/wtf/Atomics.h
Source/WTF/wtf/Bitmap.h
Source/WTF/wtf/FastBitVector.h
Source/WTF/wtf/ParkingLot.cpp
Source/WTF/wtf/ParkingLot.h
Source/WebCore/ChangeLog
Source/WebCore/Modules/encryptedmedia/CDMSessionClearKey.cpp
Source/WebCore/Modules/fetch/FetchBody.cpp
Source/WebCore/Modules/mediastream/RTCDataChannel.cpp
Source/WebCore/Modules/webaudio/AudioBuffer.cpp
Source/WebCore/Modules/websockets/WebSocket.cpp
Source/WebCore/bindings/js/JSBlobCustom.cpp
Source/WebCore/bindings/js/JSCryptoAlgorithmDictionary.cpp
Source/WebCore/bindings/js/JSCryptoCustom.cpp
Source/WebCore/bindings/js/JSCryptoOperationData.cpp
Source/WebCore/bindings/js/JSDOMBinding.h
Source/WebCore/bindings/js/JSDataCueCustom.cpp
Source/WebCore/bindings/js/JSDictionary.cpp
Source/WebCore/bindings/js/JSFileCustom.cpp
Source/WebCore/bindings/js/JSMessagePortCustom.cpp
Source/WebCore/bindings/js/JSWebGLRenderingContextBaseCustom.cpp
Source/WebCore/bindings/js/JSWorkerCustom.cpp
Source/WebCore/bindings/js/JSWorkerGlobalScopeBase.cpp
Source/WebCore/bindings/js/JSXMLHttpRequestCustom.cpp
Source/WebCore/bindings/js/SerializedScriptValue.cpp
Source/WebCore/bindings/js/StructuredClone.cpp
Source/WebCore/bindings/js/WebCoreTypedArrayController.cpp
Source/WebCore/bindings/js/WebCoreTypedArrayController.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/css/FontFace.cpp
Source/WebCore/html/canvas/WebGL2RenderingContext.cpp
Source/WebCore/platform/graphics/avfoundation/MediaPlayerPrivateAVFoundation.cpp
Source/WebCore/workers/DedicatedWorkerThread.cpp
Source/WebCore/workers/DedicatedWorkerThread.h
Source/WebCore/workers/Worker.cpp
Source/WebCore/workers/Worker.h
Source/WebCore/workers/WorkerGlobalScopeProxy.h
Source/WebCore/workers/WorkerMessagingProxy.cpp
Source/WebCore/workers/WorkerMessagingProxy.h
Source/WebCore/workers/WorkerThread.cpp
Source/WebCore/workers/WorkerThread.h
Source/WebKit/mac/ChangeLog
Source/WebKit/mac/WebView/WebPreferencesPrivate.h
Source/WebKit/win/ChangeLog
Source/WebKit/win/Interfaces/IWebPreferencesPrivate.idl
Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/C/WKPreferencesRefPrivate.h
Source/WebKit2/UIProcess/API/Cocoa/WKPreferencesPrivate.h
Source/WebKit2/WebProcess/InjectedBundle/InjectedBundle.cpp
Tools/ChangeLog
Tools/DumpRenderTree/TestRunner.cpp

index 5f891a7..d966130 100644 (file)
@@ -1,3 +1,19 @@
+2016-10-31  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should support SharedArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=163986
+
+        Reviewed by Keith Miller.
+        
+        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):
+
 2016-10-31  Saam Barati  <sbarati@apple.com>
 
         We should be able to eliminate rest parameter allocations
diff --git a/JSTests/stress/SharedArrayBuffer.js b/JSTests/stress/SharedArrayBuffer.js
new file mode 100644 (file)
index 0000000..27ba2fb
--- /dev/null
@@ -0,0 +1,133 @@
+// This is a basic test of SharedArrayBuffer API as we understand it.
+
+if (SharedArrayBuffer == ArrayBuffer)
+    throw new Error("SharedArrayBuffer and ArrayBuffer should be distinct");
+
+if (SharedArrayBuffer.prototype == ArrayBuffer.prototype)
+    throw new Error("SharedArrayBuffer.prototype and ArrayBuffer.prototype should be distinct");
+
+if (SharedArrayBuffer.prototype.__proto__ != Object.prototype)
+    throw new Error("SharedArrayBuffer.prototype.__proto__ should be Object.prototype");
+
+if (!(new SharedArrayBuffer(100) instanceof SharedArrayBuffer))
+    throw new Error("SharedArrayBuffer should be an instance of SharedArrayBuffer");
+
+if (!(new ArrayBuffer(100) instanceof ArrayBuffer))
+    throw new Error("ArrayBuffer should be an instance of ArrayBuffer");
+
+if (new SharedArrayBuffer(100) instanceof ArrayBuffer)
+    throw new Error("SharedArrayBuffer should not be an instance of ArrayBuffer");
+
+if (new ArrayBuffer(100) instanceof SharedArrayBuffer)
+    throw new Error("ArrayBuffer should not be an instance of SharedArrayBuffer");
+
+function checkAtomics(name, count)
+{
+    if (!Atomics[name])
+        throw new Error("Missing Atomics." + name);
+    if (Atomics[name].length != count)
+        throw new Error("Atomics." + name + " should have length " + count + " but has length " + Atomics[name].length);
+}
+checkAtomics("add", 3);
+checkAtomics("and", 3);
+checkAtomics("compareExchange", 4);
+checkAtomics("exchange", 3);
+checkAtomics("isLockFree", 1);
+checkAtomics("load", 2);
+checkAtomics("or", 3);
+checkAtomics("store", 3);
+checkAtomics("sub", 3);
+checkAtomics("wait", 4);
+checkAtomics("wake", 3);
+checkAtomics("xor", 3);
+
+// These should all succeed.
+var dv = new DataView(new SharedArrayBuffer(128));
+var i8a = new Int8Array(new SharedArrayBuffer(128));
+var i16a = new Int16Array(new SharedArrayBuffer(128));
+var i32a = new Int32Array(new SharedArrayBuffer(128));
+var u8a = new Uint8Array(new SharedArrayBuffer(128));
+var u8ca = new Uint8ClampedArray(new SharedArrayBuffer(128));
+var u16a = new Uint16Array(new SharedArrayBuffer(128));
+var u32a = new Uint32Array(new SharedArrayBuffer(128));
+var f32a = new Float32Array(new SharedArrayBuffer(128));
+var f64a = new Float64Array(new SharedArrayBuffer(128));
+
+function shouldFail(f, name)
+{
+    try {
+        f();
+    } catch (e) {
+        if (e.name == name.name)
+            return;
+        throw new Error(f + " threw the wrong error: " + e);
+    }
+    throw new Error(f + " succeeded!");
+}
+
+for (bad of [void 0, null, false, true, 1, 0.5, Symbol(), {}, "hello", dv, u8ca, f32a, f64a]) {
+    shouldFail(() => Atomics.add(bad, 0, 0), TypeError);
+    shouldFail(() => Atomics.and(bad, 0, 0), TypeError);
+    shouldFail(() => Atomics.compareExchange(bad, 0, 0, 0), TypeError);
+    shouldFail(() => Atomics.exchange(bad, 0, 0), TypeError);
+    shouldFail(() => Atomics.load(bad, 0), TypeError);
+    shouldFail(() => Atomics.or(bad, 0, 0), TypeError);
+    shouldFail(() => Atomics.store(bad, 0, 0), TypeError);
+    shouldFail(() => Atomics.sub(bad, 0, 0), TypeError);
+    shouldFail(() => Atomics.xor(bad, 0, 0), TypeError);
+}
+
+for (bad of [void 0, null, false, true, 1, 0.5, Symbol(), {}, "hello", dv, i8a, i16a, u8a, u8ca, u16a, u32a, f32a, f64a]) {
+    shouldFail(() => Atomics.wait(bad, 0, 0), TypeError);
+    shouldFail(() => Atomics.wake(bad, 0, 0), TypeError);
+}
+
+for (idx of [-1, -1000000000000, 10000, 10000000000000, "hello"]) {
+    for (a of [i8a, i16a, i32a, u8a, u16a, u32a]) {
+        shouldFail(() => Atomics.add(a, idx, 0), RangeError);
+        shouldFail(() => Atomics.add(a, idx, 0), RangeError);
+        shouldFail(() => Atomics.compareExchange(a, idx, 0, 0), RangeError);
+        shouldFail(() => Atomics.exchange(a, idx, 0), RangeError);
+        shouldFail(() => Atomics.load(a, idx), RangeError);
+        shouldFail(() => Atomics.or(a, idx, 0), RangeError);
+        shouldFail(() => Atomics.store(a, idx, 0), RangeError);
+        shouldFail(() => Atomics.sub(a, idx, 0), RangeError);
+        shouldFail(() => Atomics.xor(a, idx, 0), RangeError);
+    }
+    shouldFail(() => Atomics.wait(i32a, idx, 0), RangeError);
+    shouldFail(() => Atomics.wake(i32a, idx, 0), RangeError);
+}
+
+function runAtomic(array, index, init, name, args, expectedResult, expectedOutcome)
+{
+    array[index] = init;
+    var result = Atomics[name](array, index, ...args);
+    if (result != expectedResult)
+        throw new Error("Expected Atomics." + name + "(array, " + index + ", " + args.join(", ") + ") to return " + expectedResult + " but returned " + result + " for " + Object.prototype.toString.apply(array));
+    if (array[index] !== expectedOutcome)
+        throw new Error("Expected Atomics." + name + "(array, " + index + ", " + args.join(", ") + ") to result in array[" + index + "] = " + expectedOutcome + " but got " + array[index] + " for " + Object.prototype.toString.apply(array));
+}
+
+for (a of [i8a, i16a, i32a, u8a, u16a, u32a]) {
+    runAtomic(a, 0, 13, "add", [42], 13, 55);
+    runAtomic(a, 0, 13, "and", [42], 13, 8);
+    runAtomic(a, 0, 13, "compareExchange", [25, 42], 13, 13);
+    runAtomic(a, 0, 13, "compareExchange", [13, 42], 13, 42);
+    runAtomic(a, 0, 13, "exchange", [42], 13, 42);
+    runAtomic(a, 0, 13, "load", [], 13, 13);
+    runAtomic(a, 0, 13, "or", [42], 13, 47);
+    runAtomic(a, 0, 13, "store", [42], 42, 42);
+    runAtomic(a, 0, 42, "sub", [13], 42, 29);
+    runAtomic(a, 0, 13, "xor", [42], 13, 39);
+}
+
+i32a[0] = 0;
+var result = Atomics.wait(i32a, 0, 1);
+if (result != "not-equal")
+    throw "Error: bad result from Atomics.wait: " + result;
+for (timeout of [0, 1, 10]) {
+    var result = Atomics.wait(i32a, 0, 0, timeout);
+    if (result != "timed-out")
+        throw "Error: bad result from Atomics.wait: " + result;
+}
+
index aa98b96..af90838 100644 (file)
@@ -1,3 +1,19 @@
+2016-10-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should support SharedArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=163986
+
+        Reviewed by Keith Miller.
+        
+        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.
+
 2016-10-31  Simon Fraser  <simon.fraser@apple.com>
 
         Make UIScriptController::zoomToScale() work on Mac WK1 and WK2
index ef5873d..5e61d1a 100644 (file)
@@ -239,6 +239,11 @@ PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Set').hasOwnProperty('get
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Set').hasOwnProperty('set') is false
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Set').enumerable is false
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'Set').configurable is true
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').value is SharedArrayBuffer
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').hasOwnProperty('get') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').hasOwnProperty('set') is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').enumerable is false
+PASS [Worker] Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').configurable is true
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'String').value is String
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'String').hasOwnProperty('get') is false
 PASS [Worker] Object.getOwnPropertyDescriptor(global, 'String').hasOwnProperty('set') is false
index 184b170..03e2324 100644 (file)
@@ -2038,6 +2038,11 @@ PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').hasOwnProperty('get')
 PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').enumerable is false
 PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').value is SharedArrayBuffer
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').configurable is true
 PASS Object.getOwnPropertyDescriptor(global, 'SourceBuffer').value is SourceBuffer
 PASS Object.getOwnPropertyDescriptor(global, 'SourceBuffer').hasOwnProperty('get') is false
 PASS Object.getOwnPropertyDescriptor(global, 'SourceBuffer').hasOwnProperty('set') is false
index ca4dba4..a6be6f1 100644 (file)
@@ -2058,6 +2058,11 @@ PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').hasOwnProperty('get')
 PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').enumerable is false
 PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').value is SharedArrayBuffer
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').configurable is true
 PASS Object.getOwnPropertyDescriptor(global, 'SourceBuffer').value is SourceBuffer
 PASS Object.getOwnPropertyDescriptor(global, 'SourceBuffer').hasOwnProperty('get') is false
 PASS Object.getOwnPropertyDescriptor(global, 'SourceBuffer').hasOwnProperty('set') is false
index f30365a..5f77888 100644 (file)
@@ -2058,6 +2058,11 @@ PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').hasOwnProperty('get')
 PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').hasOwnProperty('set') is false
 PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').enumerable is false
 PASS Object.getOwnPropertyDescriptor(global, 'ShadowRoot').configurable is true
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').value is SharedArrayBuffer
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').hasOwnProperty('get') is false
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').hasOwnProperty('set') is false
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').enumerable is false
+PASS Object.getOwnPropertyDescriptor(global, 'SharedArrayBuffer').configurable is true
 PASS Object.getOwnPropertyDescriptor(global, 'SourceBuffer').value is SourceBuffer
 PASS Object.getOwnPropertyDescriptor(global, 'SourceBuffer').hasOwnProperty('get') is false
 PASS Object.getOwnPropertyDescriptor(global, 'SourceBuffer').hasOwnProperty('set') is false
diff --git a/LayoutTests/workers/sab/simple-expected.txt b/LayoutTests/workers/sab/simple-expected.txt
new file mode 100644 (file)
index 0000000..3c4b8c6
--- /dev/null
@@ -0,0 +1,3 @@
+All workers done!
+Test passed!
+
diff --git a/LayoutTests/workers/sab/simple-worker-1.js b/LayoutTests/workers/sab/simple-worker-1.js
new file mode 100644 (file)
index 0000000..341d5e1
--- /dev/null
@@ -0,0 +1,24 @@
+importScripts("worker-resources.js");
+
+onmessage = function (event) {
+    var memory = event.data;
+    var didStartIdx = 0;
+    var shouldGoIdx = 1;
+    var didEndIdx = 2;
+    
+    postMessage("Started!");
+    postMessage("Memory: " + memory);
+    
+    wait(memory, didStartIdx, 0, 1);
+    
+    postMessage("It started!");
+    
+    memory[shouldGoIdx] = 1;
+    wake(memory, shouldGoIdx);
+    
+    wait(memory, didEndIdx, 0, 1);
+    
+    postMessage("All done!");
+    postMessage("Memory: " + memory);
+    postMessage("done");
+}
diff --git a/LayoutTests/workers/sab/simple-worker-2.js b/LayoutTests/workers/sab/simple-worker-2.js
new file mode 100644 (file)
index 0000000..056ba95
--- /dev/null
@@ -0,0 +1,22 @@
+importScripts("worker-resources.js");
+
+onmessage = function(event) {
+    var memory = event.data;
+    var didStartIdx = 0;
+    var shouldGoIdx = 1;
+    var didEndIdx = 2;
+    
+    postMessage("Started!");
+    postMessage("Memory: " + memory);
+    
+    Atomics.store(memory, didStartIdx, 1);
+    wake(memory, didStartIdx);
+
+    wait(memory, shouldGoIdx, 0, 1);
+    
+    Atomics.store(memory, didEndIdx, 1);
+    wake(memory, didEndIdx, 1);
+
+    postMessage("Memory: " + memory);
+    postMessage("done");
+}
diff --git a/LayoutTests/workers/sab/simple.html b/LayoutTests/workers/sab/simple.html
new file mode 100644 (file)
index 0000000..1daa5f7
--- /dev/null
@@ -0,0 +1,90 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+</head>
+<body>
+<script>
+function getOrCreate(id, tagName)
+{
+    var element = document.getElementById(id);
+    if (element)
+        return element;
+    
+    element = document.createElement(tagName);
+    element.id = id;
+    var parent = document.body || document.documentElement;
+    var refNode = parent.firstChild;
+    
+    parent.insertBefore(element, refNode);
+    return element;
+}
+
+function debug(msg)
+{
+    var span = document.createElement("span");
+    getOrCreate("console", "div").appendChild(span); // insert it first so XHTML knows the namespace
+    span.innerHTML = msg + '<br />';
+}
+
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+var verbose = false;
+
+var sab = new SharedArrayBuffer(100 * 4);
+
+var memory = new Int32Array(sab);
+
+var numWorkers = 0;
+function startWorker(file)
+{
+    if (verbose)
+        debug("Starting worker: " + file);
+    numWorkers++;
+    var worker = new Worker(file);
+    worker.onmessage = function(event) {
+        if (event.data == "done") {
+            if (verbose)
+                debug("Finished worker: " + file);
+            if (--numWorkers)
+                return;
+            debug("All workers done!");
+            done();
+            return;
+        }
+        if (event.data.indexOf("Error") == 0) {
+            debug("Test failed: "+ event.data);
+            if (window.testRunner)
+                testRunner.notifyDone();
+        }
+        
+        if (verbose)
+            debug("Event from " + file + ": " + event.data);
+    };
+    worker.postMessage(memory, [sab]);
+}
+
+function done()
+{
+    for (var i = 0; i < 3; ++i) {
+        if (memory[i] != 1)
+            throw "Error: Bad value at memory[" + i + "]: " + memory[i];
+    }
+    for (var i = 3; i < memory.length; ++i) {
+        if (memory[i] != 0)
+            throw "Error: Bad value at memory[" + i + "]: " + memory[i];
+    }
+    debug("Test passed!");
+
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+startWorker("simple-worker-1.js");
+startWorker("simple-worker-2.js");
+
+</script>
+</body>
+</html>
diff --git a/LayoutTests/workers/sab/worker-resources.js b/LayoutTests/workers/sab/worker-resources.js
new file mode 100644 (file)
index 0000000..941e87f
--- /dev/null
@@ -0,0 +1,35 @@
+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");
+    }
+}
+
index d488cc8..14883da 100644 (file)
@@ -36,6 +36,7 @@
 #include "JSDataView.h"
 #include "JSGenericTypedArrayViewInlines.h"
 #include "JSTypedArrays.h"
+#include "TypedArrayController.h"
 #include <wtf/RefPtr.h>
 
 using namespace JSC;
@@ -239,7 +240,7 @@ void* JSObjectGetTypedArrayBytesPtr(JSContextRef ctx, JSObjectRef objectRef, JSV
     JSObject* object = toJS(objectRef);
 
     if (JSArrayBufferView* typedArray = jsDynamicCast<JSArrayBufferView*>(object)) {
-        ArrayBuffer* buffer = typedArray->buffer();
+        ArrayBuffer* buffer = typedArray->possiblySharedBuffer();
         buffer->pinAndLock();
         return buffer->data();
     }
@@ -283,7 +284,7 @@ JSObjectRef JSObjectGetTypedArrayBuffer(JSContextRef ctx, JSObjectRef objectRef,
     JSObject* object = toJS(objectRef);
 
     if (JSArrayBufferView* typedArray = jsDynamicCast<JSArrayBufferView*>(object))
-        return toRef(exec->vm().m_typedArrayController->toJS(exec, typedArray->globalObject(), typedArray->buffer()));
+        return toRef(exec->vm().m_typedArrayController->toJS(exec, typedArray->globalObject(), typedArray->possiblySharedBuffer()));
 
     return nullptr;
 }
@@ -298,7 +299,7 @@ JSObjectRef JSObjectMakeArrayBufferWithBytesNoCopy(JSContextRef ctx, void* bytes
             bytesDeallocator(p, deallocatorContext);
     });
 
-    JSArrayBuffer* jsBuffer = JSArrayBuffer::create(exec->vm(), exec->lexicalGlobalObject()->arrayBufferStructure(), WTFMove(buffer));
+    JSArrayBuffer* jsBuffer = JSArrayBuffer::create(exec->vm(), exec->lexicalGlobalObject()->arrayBufferStructure(ArrayBufferSharingMode::Default), WTFMove(buffer));
     if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow)
         return nullptr;
 
index 525ebc9..e78086c 100644 (file)
@@ -63,7 +63,7 @@ inline bool Bitmap::concurrentTestAndSet(size_t n)
         oldValue = *wordPtr;
         if (oldValue & mask)
             return true;
-    } while (!WTF::weakCompareAndSwap(wordPtr, oldValue, static_cast<uint8_t>(oldValue | mask)));
+    } while (!WTF::atomicCompareExchangeWeakRelaxed(wordPtr, oldValue, static_cast<uint8_t>(oldValue | mask)));
     return false;
 }
 
index 2608f2c..d3f8f07 100644 (file)
@@ -639,6 +639,7 @@ set(JavaScriptCore_SOURCES
     runtime/ArrayConventions.cpp
     runtime/ArrayIteratorPrototype.cpp
     runtime/ArrayPrototype.cpp
+    runtime/AtomicsObject.cpp
     runtime/AsyncFunctionConstructor.cpp
     runtime/AsyncFunctionPrototype.cpp
     runtime/BasicBlockLocation.cpp
index 68393b0..de215f3 100644 (file)
@@ -1,3 +1,236 @@
+2016-10-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should support SharedArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=163986
+
+        Reviewed by Keith Miller.
+        
+        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):
+
 2016-10-31  Saam Barati  <sbarati@apple.com>
 
         We should be able to eliminate rest parameter allocations
index 4355bdb..95ef32b 100644 (file)
                0F300B7B18AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F300B7918AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.cpp */; };
                0F300B7C18AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F300B7A18AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.h */; };
                0F30D7C01D95D6320053089D /* CPU.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F30D7BF1D95D62F0053089D /* CPU.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               0F30FB611DC2DE99003124F2 /* ArrayBufferSharingMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F30FB601DC2DE96003124F2 /* ArrayBufferSharingMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F32BD101BB34F190093A57F /* HeapHelperPool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F32BD0E1BB34F190093A57F /* HeapHelperPool.cpp */; };
                0F32BD111BB34F190093A57F /* HeapHelperPool.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F32BD0F1BB34F190093A57F /* HeapHelperPool.h */; };
                0F338DF11BE93AD10013C88F /* B3StackmapValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F338DEF1BE93AD10013C88F /* B3StackmapValue.cpp */; };
                0F7C39FF1C90C55B00480151 /* DFGOpInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7C39FE1C90C55B00480151 /* DFGOpInfo.h */; };
                0F7C5FB81D888A0C0044F5E2 /* MarkedBlockInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7C5FB71D888A010044F5E2 /* MarkedBlockInlines.h */; };
                0F7C5FBA1D8895070044F5E2 /* MarkedSpaceInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7C5FB91D8895050044F5E2 /* MarkedSpaceInlines.h */; };
+               0F7CF9561DC1258D0098CC12 /* AtomicsObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7CF9541DC1258B0098CC12 /* AtomicsObject.cpp */; };
+               0F7CF9571DC125900098CC12 /* AtomicsObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7CF9551DC1258B0098CC12 /* AtomicsObject.h */; };
                0F7F988B1D9596C500F4F12E /* DFGStoreBarrierClusteringPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7F98891D9596C300F4F12E /* DFGStoreBarrierClusteringPhase.cpp */; };
                0F7F988C1D9596C800F4F12E /* DFGStoreBarrierClusteringPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7F988A1D9596C300F4F12E /* DFGStoreBarrierClusteringPhase.h */; };
                0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8023E91613832300A0BA45 /* ByValInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0F300B7918AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGIntegerCheckCombiningPhase.cpp; path = dfg/DFGIntegerCheckCombiningPhase.cpp; sourceTree = "<group>"; };
                0F300B7A18AB1B1400A6D72E /* DFGIntegerCheckCombiningPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGIntegerCheckCombiningPhase.h; path = dfg/DFGIntegerCheckCombiningPhase.h; sourceTree = "<group>"; };
                0F30D7BF1D95D62F0053089D /* CPU.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CPU.h; sourceTree = "<group>"; };
+               0F30FB601DC2DE96003124F2 /* ArrayBufferSharingMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayBufferSharingMode.h; sourceTree = "<group>"; };
                0F32BD0E1BB34F190093A57F /* HeapHelperPool.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapHelperPool.cpp; sourceTree = "<group>"; };
                0F32BD0F1BB34F190093A57F /* HeapHelperPool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapHelperPool.h; sourceTree = "<group>"; };
                0F338DEF1BE93AD10013C88F /* B3StackmapValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = B3StackmapValue.cpp; path = b3/B3StackmapValue.cpp; sourceTree = "<group>"; };
                0F7C39FE1C90C55B00480151 /* DFGOpInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOpInfo.h; path = dfg/DFGOpInfo.h; sourceTree = "<group>"; };
                0F7C5FB71D888A010044F5E2 /* MarkedBlockInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkedBlockInlines.h; sourceTree = "<group>"; };
                0F7C5FB91D8895050044F5E2 /* MarkedSpaceInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkedSpaceInlines.h; sourceTree = "<group>"; };
+               0F7CF9541DC1258B0098CC12 /* AtomicsObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AtomicsObject.cpp; sourceTree = "<group>"; };
+               0F7CF9551DC1258B0098CC12 /* AtomicsObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AtomicsObject.h; sourceTree = "<group>"; };
                0F7F98891D9596C300F4F12E /* DFGStoreBarrierClusteringPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGStoreBarrierClusteringPhase.cpp; path = dfg/DFGStoreBarrierClusteringPhase.cpp; sourceTree = "<group>"; };
                0F7F988A1D9596C300F4F12E /* DFGStoreBarrierClusteringPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGStoreBarrierClusteringPhase.h; path = dfg/DFGStoreBarrierClusteringPhase.h; sourceTree = "<group>"; };
                0F8023E91613832300A0BA45 /* ByValInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByValInfo.h; sourceTree = "<group>"; };
                                A7A8AF2617ADB5F3005AB174 /* ArrayBuffer.h */,
                                0FFC99D2184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp */,
                                0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h */,
+                               0F30FB601DC2DE96003124F2 /* ArrayBufferSharingMode.h */,
                                A7A8AF2717ADB5F3005AB174 /* ArrayBufferView.cpp */,
                                A7A8AF2817ADB5F3005AB174 /* ArrayBufferView.h */,
                                BC7952060E15E8A800A898AB /* ArrayConstructor.cpp */,
                                F692A84D0255597D01FF60F7 /* ArrayPrototype.cpp */,
                                F692A84E0255597D01FF60F7 /* ArrayPrototype.h */,
                                0FB7F38A15ED8E3800F167B2 /* ArrayStorage.h */,
+                               0F7CF9541DC1258B0098CC12 /* AtomicsObject.cpp */,
+                               0F7CF9551DC1258B0098CC12 /* AtomicsObject.h */,
                                5B70CFDD1DB69E5C00EC23F9 /* AsyncFunctionConstructor.cpp */,
                                5B70CFDC1DB69E5C00EC23F9 /* AsyncFunctionConstructor.h */,
                                5B70CFDB1DB69E5C00EC23F9 /* AsyncFunctionPrototype.cpp */,
                                0F7C39FC1C8F659500480151 /* RegExpObjectInlines.h */,
                                BCD202BF0E1706A7002C7E82 /* RegExpPrototype.cpp */,
                                BCD202C00E1706A7002C7E82 /* RegExpPrototype.h */,
-                               0FB7F39115ED8E3800F167B2 /* TypeError.h */,
                                70B0A9D01A9B66200001306A /* RuntimeFlags.h */,
                                527773DD1AAF83AC00BDE7E8 /* RuntimeType.cpp */,
                                52C0611D1AA51E1B00B4ADBA /* RuntimeType.h */,
                                0F2B66DB17B6B5AB00A7AE3F /* TypedArrays.h */,
                                0F2B66DC17B6B5AB00A7AE3F /* TypedArrayType.cpp */,
                                0F2B66DD17B6B5AB00A7AE3F /* TypedArrayType.h */,
+                               0FB7F39115ED8E3800F167B2 /* TypeError.h */,
                                52B310FE1975B4240080857C /* TypeLocationCache.cpp */,
                                52B311001975B4670080857C /* TypeLocationCache.h */,
                                0FFB6C361AF48DDC00DB1BF7 /* TypeofType.cpp */,
                                0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */,
                                A5311C361C77CEC500E6B1B6 /* HeapSnapshotBuilder.h in Headers */,
                                A7BDAEC917F4EA1400F6140C /* ArrayIteratorPrototype.h in Headers */,
+                               0F7CF9571DC125900098CC12 /* AtomicsObject.h in Headers */,
                                996B73181BDA068000331B84 /* ArrayIteratorPrototype.lut.h in Headers */,
                                0F63945515D07057006A597C /* ArrayProfile.h in Headers */,
                                BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */,
                                A5FD0068189AFE9C00633231 /* ScriptArguments.h in Headers */,
                                A503FA21188EFF6800110F14 /* ScriptBreakpoint.h in Headers */,
                                A5FD006E189B00AA00633231 /* ScriptCallFrame.h in Headers */,
+                               0F30FB611DC2DE99003124F2 /* ArrayBufferSharingMode.h in Headers */,
                                A5FD0070189B00AA00633231 /* ScriptCallStack.h in Headers */,
                                A5FD007E189B0B4C00633231 /* ScriptCallStackFactory.h in Headers */,
                                A503FA22188EFF6800110F14 /* ScriptDebugListener.h in Headers */,
                                147341E71DC2CE9600AA29BA /* ScriptExecutable.cpp in Sources */,
                                0F2B670717B6B5AB00A7AE3F /* TypedArrayController.cpp in Sources */,
                                0F2B670A17B6B5AB00A7AE3F /* TypedArrayType.cpp in Sources */,
+                               0F7CF9561DC1258D0098CC12 /* AtomicsObject.cpp in Sources */,
                                52B310FF1975B4240080857C /* TypeLocationCache.cpp in Sources */,
                                0FFB6C381AF48DDC00DB1BF7 /* TypeofType.cpp in Sources */,
                                52C952B919A28A1C0069B386 /* TypeProfiler.cpp in Sources */,
index a653ae8..1067b22 100644 (file)
@@ -2529,7 +2529,7 @@ CodeBlock* CodeBlock::specialOSREntryBlockOrNull()
 
 void CodeBlock::visitWeakly(SlotVisitor& visitor)
 {
-    bool setByMe = m_visitWeaklyHasBeenCalled.compareExchangeStrong(false, true);
+    bool setByMe = !m_visitWeaklyHasBeenCalled.compareExchangeStrong(false, true);
     if (!setByMe)
         return;
 
index 8761d9b..3cdc9bc 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -42,7 +42,9 @@ void ArrayBufferViewWatchpointAdaptor::add(
         ArrayBufferNeuteringWatchpoint::create(*codeBlock->vm());
     neuteringWatchpoint->set()->add(watchpoint);
     codeBlock->addConstant(neuteringWatchpoint);
-    codeBlock->vm()->heap.addReference(neuteringWatchpoint, view->buffer());
+    // FIXME: We don't need to set this watchpoint at all for shared buffers.
+    // https://bugs.webkit.org/show_bug.cgi?id=164108
+    codeBlock->vm()->heap.addReference(neuteringWatchpoint, view->possiblySharedBuffer());
 }
 
 void InferredValueAdaptor::add(
index 29389a5..46fc411 100644 (file)
@@ -1574,7 +1574,7 @@ void Heap::reportExtraMemoryVisited(CellState oldState, size_t size)
     
     for (;;) {
         size_t oldSize = *counter;
-        if (WTF::weakCompareAndSwap(counter, oldSize, oldSize + size))
+        if (WTF::atomicCompareExchangeWeakRelaxed(counter, oldSize, oldSize + size))
             return;
     }
 }
@@ -1590,7 +1590,7 @@ void Heap::reportExternalMemoryVisited(CellState oldState, size_t size)
 
     for (;;) {
         size_t oldSize = *counter;
-        if (WTF::weakCompareAndSwap(counter, oldSize, oldSize + size))
+        if (WTF::atomicCompareExchangeWeakRelaxed(counter, oldSize, oldSize + size))
             return;
     }
 }
index 7f09e4c..a9f4500 100644 (file)
@@ -114,7 +114,7 @@ public:
         // traffic.
         if (isMarked())
             return true;
-        return !m_isMarked.compareExchangeStrong(false, true);
+        return m_isMarked.compareExchangeStrong(false, true);
     }
     ALWAYS_INLINE bool testAndSetMarked(HeapCell*) { return testAndSetMarked(); }
     void clearMarked() { m_isMarked.store(false); }
index 7480363..2b53ca1 100644 (file)
@@ -2056,7 +2056,7 @@ EncodedJSValue JSC_HOST_CALL functionTransferArrayBuffer(ExecState* exec)
         return JSValue::encode(throwException(exec, scope, createError(exec, ASCIILiteral("Expected an array buffer"))));
     
     ArrayBufferContents dummyContents;
-    buffer->impl()->transfer(dummyContents);
+    buffer->impl()->transferTo(dummyContents);
     
     return JSValue::encode(jsUndefined());
 }
index 163f14f..9716fdd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 namespace JSC {
 
-bool ArrayBuffer::transfer(ArrayBufferContents& result)
+SharedArrayBufferContents::SharedArrayBufferContents(void* data, ArrayBufferDestructorFunction&& destructor)
+    : m_data(data)
+    , m_destructor(WTFMove(destructor))
+{
+}
+
+SharedArrayBufferContents::~SharedArrayBufferContents()
+{
+    m_destructor(m_data);
+}
+
+ArrayBufferContents::ArrayBufferContents()
+{
+    reset();
+}
+
+ArrayBufferContents::ArrayBufferContents(ArrayBufferContents&& other)
+{
+    reset();
+    other.transferTo(*this);
+}
+
+ArrayBufferContents::ArrayBufferContents(void* data, unsigned sizeInBytes, ArrayBufferDestructorFunction&& destructor)
+    : m_data(data)
+    , m_sizeInBytes(sizeInBytes)
+{
+    m_destructor = WTFMove(destructor);
+}
+
+ArrayBufferContents& ArrayBufferContents::operator=(ArrayBufferContents&& other)
+{
+    other.transferTo(*this);
+    return *this;
+}
+
+ArrayBufferContents::~ArrayBufferContents()
+{
+    destroy();
+}
+
+void ArrayBufferContents::clear()
+{
+    destroy();
+    reset();
+}
+
+void ArrayBufferContents::destroy()
+{
+    m_destructor(m_data);
+}
+
+void ArrayBufferContents::reset()
+{
+    m_destructor = [] (void*) { };
+    m_shared = nullptr;
+    m_data = nullptr;
+    m_sizeInBytes = 0;
+}
+
+void ArrayBufferContents::tryAllocate(unsigned numElements, unsigned elementByteSize, InitializationPolicy policy)
+{
+    // Do not allow 31-bit overflow of the total size.
+    if (numElements) {
+        unsigned totalSize = numElements * elementByteSize;
+        if (totalSize / numElements != elementByteSize
+            || totalSize > static_cast<unsigned>(std::numeric_limits<int32_t>::max())) {
+            reset();
+            return;
+        }
+    }
+    bool allocationSucceeded = false;
+    if (policy == ZeroInitialize)
+        allocationSucceeded = WTF::tryFastCalloc(numElements, elementByteSize).getValue(m_data);
+    else {
+        ASSERT(policy == DontInitialize);
+        allocationSucceeded = WTF::tryFastMalloc(numElements * elementByteSize).getValue(m_data);
+    }
+
+    if (allocationSucceeded) {
+        m_sizeInBytes = numElements * elementByteSize;
+        m_destructor = [] (void* p) { fastFree(p); };
+        return;
+    }
+    reset();
+}
+
+void ArrayBufferContents::makeShared()
+{
+    m_shared = adoptRef(new SharedArrayBufferContents(m_data, WTFMove(m_destructor)));
+    m_destructor = [] (void*) { };
+}
+
+void ArrayBufferContents::transferTo(ArrayBufferContents& other)
+{
+    other.clear();
+    other.m_data = m_data;
+    other.m_sizeInBytes = m_sizeInBytes;
+    other.m_destructor = WTFMove(m_destructor);
+    other.m_shared = m_shared;
+    clear();
+}
+
+void ArrayBufferContents::copyTo(ArrayBufferContents& other)
+{
+    ASSERT(!other.m_data);
+    other.tryAllocate(m_sizeInBytes, sizeof(char), ArrayBufferContents::DontInitialize);
+    if (!other.m_data)
+        return;
+    memcpy(other.m_data, m_data, m_sizeInBytes);
+    other.m_sizeInBytes = m_sizeInBytes;
+}
+
+void ArrayBufferContents::shareWith(ArrayBufferContents& other)
+{
+    ASSERT(!other.m_data);
+    ASSERT(m_shared);
+    other.m_destructor = [] (void*) { };
+    other.m_shared = m_shared;
+    other.m_data = m_data;
+    other.m_sizeInBytes = m_sizeInBytes;
+}
+
+Ref<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize)
+{
+    auto buffer = tryCreate(numElements, elementByteSize);
+    if (!buffer)
+        CRASH();
+    return buffer.releaseNonNull();
+}
+
+Ref<ArrayBuffer> ArrayBuffer::create(ArrayBuffer& other)
+{
+    return ArrayBuffer::create(other.data(), other.byteLength());
+}
+
+Ref<ArrayBuffer> ArrayBuffer::create(const void* source, unsigned byteLength)
+{
+    auto buffer = tryCreate(source, byteLength);
+    if (!buffer)
+        CRASH();
+    return buffer.releaseNonNull();
+}
+
+Ref<ArrayBuffer> ArrayBuffer::create(ArrayBufferContents&& contents)
+{
+    return adoptRef(*new ArrayBuffer(WTFMove(contents)));
+}
+
+Ref<ArrayBuffer> ArrayBuffer::createAdopted(const void* data, unsigned byteLength)
+{
+    return createFromBytes(data, byteLength, [] (void* p) { fastFree(p); });
+}
+
+Ref<ArrayBuffer> ArrayBuffer::createFromBytes(const void* data, unsigned byteLength, ArrayBufferDestructorFunction&& destructor)
+{
+    ArrayBufferContents contents(const_cast<void*>(data), byteLength, WTFMove(destructor));
+    return create(WTFMove(contents));
+}
+
+RefPtr<ArrayBuffer> ArrayBuffer::tryCreate(unsigned numElements, unsigned elementByteSize)
+{
+    return tryCreate(numElements, elementByteSize, ArrayBufferContents::ZeroInitialize);
+}
+
+RefPtr<ArrayBuffer> ArrayBuffer::tryCreate(ArrayBuffer& other)
+{
+    return tryCreate(other.data(), other.byteLength());
+}
+
+RefPtr<ArrayBuffer> ArrayBuffer::tryCreate(const void* source, unsigned byteLength)
+{
+    ArrayBufferContents contents;
+    contents.tryAllocate(byteLength, 1, ArrayBufferContents::ZeroInitialize);
+    if (!contents.m_data)
+        return nullptr;
+    return createInternal(WTFMove(contents), source, byteLength);
+}
+
+Ref<ArrayBuffer> ArrayBuffer::createUninitialized(unsigned numElements, unsigned elementByteSize)
+{
+    return create(numElements, elementByteSize, ArrayBufferContents::DontInitialize);
+}
+
+RefPtr<ArrayBuffer> ArrayBuffer::tryCreateUninitialized(unsigned numElements, unsigned elementByteSize)
+{
+    return tryCreate(numElements, elementByteSize, ArrayBufferContents::DontInitialize);
+}
+
+Ref<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy)
+{
+    auto buffer = tryCreate(numElements, elementByteSize, policy);
+    if (!buffer)
+        CRASH();
+    return buffer.releaseNonNull();
+}
+
+Ref<ArrayBuffer> ArrayBuffer::createInternal(ArrayBufferContents&& contents, const void* source, unsigned byteLength)
+{
+    ASSERT(!byteLength || source);
+    auto buffer = adoptRef(*new ArrayBuffer(WTFMove(contents)));
+    memcpy(buffer->data(), source, byteLength);
+    return buffer;
+}
+
+RefPtr<ArrayBuffer> ArrayBuffer::tryCreate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy)
+{
+    ArrayBufferContents contents;
+    contents.tryAllocate(numElements, elementByteSize, policy);
+    if (!contents.m_data)
+        return nullptr;
+    return adoptRef(*new ArrayBuffer(WTFMove(contents)));
+}
+
+ArrayBuffer::ArrayBuffer(ArrayBufferContents&& contents)
+    : m_contents(WTFMove(contents))
+    , m_pinCount(0)
+    , m_locked(false)
+{
+}
+
+RefPtr<ArrayBuffer> ArrayBuffer::slice(int begin, int end) const
+{
+    return sliceImpl(clampIndex(begin), clampIndex(end));
+}
+
+RefPtr<ArrayBuffer> ArrayBuffer::slice(int begin) const
+{
+    return sliceImpl(clampIndex(begin), byteLength());
+}
+
+RefPtr<ArrayBuffer> ArrayBuffer::sliceImpl(unsigned begin, unsigned end) const
+{
+    unsigned size = begin <= end ? end - begin : 0;
+    RefPtr<ArrayBuffer> result = ArrayBuffer::create(static_cast<const char*>(data()) + begin, size);
+    result->setSharingMode(sharingMode());
+    return result;
+}
+
+void ArrayBuffer::makeShared()
+{
+    m_contents.makeShared();
+}
+
+void ArrayBuffer::setSharingMode(ArrayBufferSharingMode newSharingMode)
+{
+    if (newSharingMode == sharingMode())
+        return;
+    RELEASE_ASSERT(!isShared()); // Cannot revert sharing.
+    RELEASE_ASSERT(newSharingMode == ArrayBufferSharingMode::Shared);
+    makeShared();
+}
+
+bool ArrayBuffer::transferTo(ArrayBufferContents& result)
 {
     Ref<ArrayBuffer> protect(*this);
 
@@ -40,6 +292,11 @@ bool ArrayBuffer::transfer(ArrayBufferContents& result)
         result.m_data = 0;
         return false;
     }
+    
+    if (isShared()) {
+        m_contents.shareWith(result);
+        return true;
+    }
 
     bool isNeuterable = !m_pinCount && !m_locked;
 
@@ -50,7 +307,7 @@ bool ArrayBuffer::transfer(ArrayBufferContents& result)
         return true;
     }
 
-    m_contents.transfer(result);
+    m_contents.transferTo(result);
     for (size_t i = numberOfIncomingReferences(); i--;) {
         JSCell* cell = incomingReferenceAt(i);
         if (JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(cell))
index b4d889a..b263b7a 100644 (file)
 
 #pragma once
 
+#include "ArrayBufferSharingMode.h"
 #include "GCIncomingRefCounted.h"
 #include "Weak.h"
-#include <functional>
+#include <wtf/Function.h>
 #include <wtf/StdLibExtras.h>
+#include <wtf/ThreadSafeRefCounted.h>
 
 namespace JSC {
 
@@ -36,31 +38,42 @@ class ArrayBuffer;
 class ArrayBufferView;
 class JSArrayBuffer;
 
-typedef std::function<void(void*)> ArrayBufferDestructorFunction;
-static void arrayBufferDestructorNull(void*) { }
-static void arrayBufferDestructorDefault(void* p) { fastFree(p); }
+typedef Function<void(void*)> ArrayBufferDestructorFunction;
+
+class SharedArrayBufferContents : public ThreadSafeRefCounted<SharedArrayBufferContents> {
+public:
+    SharedArrayBufferContents(void* data, ArrayBufferDestructorFunction&&);
+    ~SharedArrayBufferContents();
+    
+    void* data() const { return m_data; }
+    
+private:
+    void* m_data;
+    ArrayBufferDestructorFunction m_destructor;
+};
 
 class ArrayBufferContents {
     WTF_MAKE_NONCOPYABLE(ArrayBufferContents);
 public:
-    ArrayBufferContents() 
-        : m_destructor(arrayBufferDestructorNull)
-        , m_data(nullptr)
-        , m_sizeInBytes(0)
-    { }
+    JS_EXPORT_PRIVATE ArrayBufferContents();
+    
+    JS_EXPORT_PRIVATE ArrayBufferContents(ArrayBufferContents&&);
+    JS_EXPORT_PRIVATE ArrayBufferContents& operator=(ArrayBufferContents&&);
 
-    inline ~ArrayBufferContents();
+    JS_EXPORT_PRIVATE ~ArrayBufferContents();
+    
+    JS_EXPORT_PRIVATE void clear();
     
-    void* data() { return m_data; }
-    unsigned sizeInBytes() { return m_sizeInBytes; }
+    void* data() const { return m_data; }
+    unsigned sizeInBytes() const { return m_sizeInBytes; }
+    
+    bool isShared() const { return m_shared; }
 
 private:
-    ArrayBufferContents(void* data, unsigned sizeInBytes, ArrayBufferDestructorFunction&& destructor)
-        : m_data(data)
-        , m_sizeInBytes(sizeInBytes)
-    {
-        m_destructor = WTFMove(destructor);
-    }
+    ArrayBufferContents(void* data, unsigned sizeInBytes, ArrayBufferDestructorFunction&&);
+    
+    void destroy();
+    void reset();
 
     friend class ArrayBuffer;
 
@@ -69,60 +82,54 @@ private:
         DontInitialize
     };
 
-    static inline void tryAllocate(unsigned numElements, unsigned elementByteSize, InitializationPolicy, ArrayBufferContents&);
-    void transfer(ArrayBufferContents& other)
-    {
-        ASSERT(!other.m_data);
-        std::swap(m_data, other.m_data);
-        std::swap(m_sizeInBytes, other.m_sizeInBytes);
-        std::swap(m_destructor, other.m_destructor);
-    }
-
-    void copyTo(ArrayBufferContents& other)
-    {
-        ASSERT(!other.m_data);
-        ArrayBufferContents::tryAllocate(m_sizeInBytes, sizeof(char), ArrayBufferContents::DontInitialize, other);
-        if (!other.m_data)
-            return;
-        memcpy(other.m_data, m_data, m_sizeInBytes);
-        other.m_sizeInBytes = m_sizeInBytes;
-    }
+    void tryAllocate(unsigned numElements, unsigned elementByteSize, InitializationPolicy);
+    
+    void makeShared();
+    void transferTo(ArrayBufferContents&);
+    void copyTo(ArrayBufferContents&);
+    void shareWith(ArrayBufferContents&);
 
     ArrayBufferDestructorFunction m_destructor;
+    RefPtr<SharedArrayBufferContents> m_shared;
     void* m_data;
     unsigned m_sizeInBytes;
 };
 
 class ArrayBuffer : public GCIncomingRefCounted<ArrayBuffer> {
 public:
-    static inline Ref<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize);
-    static inline Ref<ArrayBuffer> create(ArrayBuffer&);
-    static inline Ref<ArrayBuffer> create(const void* source, unsigned byteLength);
-    static inline Ref<ArrayBuffer> create(ArrayBufferContents&);
-    static inline Ref<ArrayBuffer> createAdopted(const void* data, unsigned byteLength);
-    static inline Ref<ArrayBuffer> createFromBytes(const void* data, unsigned byteLength, ArrayBufferDestructorFunction&&);
-    static inline RefPtr<ArrayBuffer> tryCreate(unsigned numElements, unsigned elementByteSize);
-    static inline RefPtr<ArrayBuffer> tryCreate(ArrayBuffer&);
-    static inline RefPtr<ArrayBuffer> tryCreate(const void* source, unsigned byteLength);
+    JS_EXPORT_PRIVATE static Ref<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize);
+    JS_EXPORT_PRIVATE static Ref<ArrayBuffer> create(ArrayBuffer&);
+    JS_EXPORT_PRIVATE static Ref<ArrayBuffer> create(const void* source, unsigned byteLength);
+    JS_EXPORT_PRIVATE static Ref<ArrayBuffer> create(ArrayBufferContents&&);
+    JS_EXPORT_PRIVATE static Ref<ArrayBuffer> createAdopted(const void* data, unsigned byteLength);
+    JS_EXPORT_PRIVATE static Ref<ArrayBuffer> createFromBytes(const void* data, unsigned byteLength, ArrayBufferDestructorFunction&&);
+    JS_EXPORT_PRIVATE static RefPtr<ArrayBuffer> tryCreate(unsigned numElements, unsigned elementByteSize);
+    JS_EXPORT_PRIVATE static RefPtr<ArrayBuffer> tryCreate(ArrayBuffer&);
+    JS_EXPORT_PRIVATE static RefPtr<ArrayBuffer> tryCreate(const void* source, unsigned byteLength);
 
     // Only for use by Uint8ClampedArray::createUninitialized and SharedBuffer::createArrayBuffer.
-    static inline Ref<ArrayBuffer> createUninitialized(unsigned numElements, unsigned elementByteSize);
-    static inline RefPtr<ArrayBuffer> tryCreateUninitialized(unsigned numElements, unsigned elementByteSize);
+    JS_EXPORT_PRIVATE static Ref<ArrayBuffer> createUninitialized(unsigned numElements, unsigned elementByteSize);
+    JS_EXPORT_PRIVATE static RefPtr<ArrayBuffer> tryCreateUninitialized(unsigned numElements, unsigned elementByteSize);
 
     inline void* data();
     inline const void* data() const;
     inline unsigned byteLength() const;
     
+    void makeShared();
+    void setSharingMode(ArrayBufferSharingMode);
+    inline bool isShared() const;
+    inline ArrayBufferSharingMode sharingMode() const { return isShared() ? ArrayBufferSharingMode::Shared : ArrayBufferSharingMode::Default; }
+    
     inline size_t gcSizeEstimateInBytes() const;
 
-    inline RefPtr<ArrayBuffer> slice(int begin, int end) const;
-    inline RefPtr<ArrayBuffer> slice(int begin) const;
+    JS_EXPORT_PRIVATE RefPtr<ArrayBuffer> slice(int begin, int end) const;
+    JS_EXPORT_PRIVATE RefPtr<ArrayBuffer> slice(int begin) const;
     
     inline void pin();
     inline void unpin();
     inline void pinAndLock();
 
-    JS_EXPORT_PRIVATE bool transfer(ArrayBufferContents&);
+    JS_EXPORT_PRIVATE bool transferTo(ArrayBufferContents&);
     bool isNeutered() { return !m_contents.m_data; }
     
     static ptrdiff_t offsetOfData() { return OBJECT_OFFSETOF(ArrayBuffer, m_contents) + OBJECT_OFFSETOF(ArrayBufferContents, m_data); }
@@ -130,11 +137,11 @@ public:
     ~ArrayBuffer() { }
 
 private:
-    static inline Ref<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
-    static inline Ref<ArrayBuffer> createInternal(ArrayBufferContents&, const void*, unsigned);
-    static inline RefPtr<ArrayBuffer> tryCreate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
-    inline ArrayBuffer(ArrayBufferContents&);
-    inline RefPtr<ArrayBuffer> sliceImpl(unsigned begin, unsigned end) const;
+    static Ref<ArrayBuffer> create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
+    static Ref<ArrayBuffer> createInternal(ArrayBufferContents&&, const void*, unsigned);
+    static RefPtr<ArrayBuffer> tryCreate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy);
+    ArrayBuffer(ArrayBufferContents&&);
+    RefPtr<ArrayBuffer> sliceImpl(unsigned begin, unsigned end) const;
     inline unsigned clampIndex(int index) const;
     static inline int clampValue(int x, int left, int right);
 
@@ -156,104 +163,6 @@ int ArrayBuffer::clampValue(int x, int left, int right)
     return x;
 }
 
-Ref<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize)
-{
-    auto buffer = tryCreate(numElements, elementByteSize);
-    if (!buffer)
-        CRASH();
-    return buffer.releaseNonNull();
-}
-
-Ref<ArrayBuffer> ArrayBuffer::create(ArrayBuffer& other)
-{
-    return ArrayBuffer::create(other.data(), other.byteLength());
-}
-
-Ref<ArrayBuffer> ArrayBuffer::create(const void* source, unsigned byteLength)
-{
-    auto buffer = tryCreate(source, byteLength);
-    if (!buffer)
-        CRASH();
-    return buffer.releaseNonNull();
-}
-
-Ref<ArrayBuffer> ArrayBuffer::create(ArrayBufferContents& contents)
-{
-    return adoptRef(*new ArrayBuffer(contents));
-}
-
-Ref<ArrayBuffer> ArrayBuffer::createAdopted(const void* data, unsigned byteLength)
-{
-    return createFromBytes(data, byteLength, WTFMove(arrayBufferDestructorDefault));
-}
-
-Ref<ArrayBuffer> ArrayBuffer::createFromBytes(const void* data, unsigned byteLength, ArrayBufferDestructorFunction&& destructor)
-{
-    ArrayBufferContents contents(const_cast<void*>(data), byteLength, WTFMove(destructor));
-    return create(contents);
-}
-
-RefPtr<ArrayBuffer> ArrayBuffer::tryCreate(unsigned numElements, unsigned elementByteSize)
-{
-    return tryCreate(numElements, elementByteSize, ArrayBufferContents::ZeroInitialize);
-}
-
-RefPtr<ArrayBuffer> ArrayBuffer::tryCreate(ArrayBuffer& other)
-{
-    return tryCreate(other.data(), other.byteLength());
-}
-
-RefPtr<ArrayBuffer> ArrayBuffer::tryCreate(const void* source, unsigned byteLength)
-{
-    ArrayBufferContents contents;
-    ArrayBufferContents::tryAllocate(byteLength, 1, ArrayBufferContents::ZeroInitialize, contents);
-    if (!contents.m_data)
-        return nullptr;
-    return createInternal(contents, source, byteLength);
-}
-
-Ref<ArrayBuffer> ArrayBuffer::createUninitialized(unsigned numElements, unsigned elementByteSize)
-{
-    return create(numElements, elementByteSize, ArrayBufferContents::DontInitialize);
-}
-
-RefPtr<ArrayBuffer> ArrayBuffer::tryCreateUninitialized(unsigned numElements, unsigned elementByteSize)
-{
-    return tryCreate(numElements, elementByteSize, ArrayBufferContents::DontInitialize);
-}
-
-Ref<ArrayBuffer> ArrayBuffer::create(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy)
-{
-    auto buffer = tryCreate(numElements, elementByteSize, policy);
-    if (!buffer)
-        CRASH();
-    return buffer.releaseNonNull();
-}
-
-Ref<ArrayBuffer> ArrayBuffer::createInternal(ArrayBufferContents& contents, const void* source, unsigned byteLength)
-{
-    ASSERT(!byteLength || source);
-    auto buffer = adoptRef(*new ArrayBuffer(contents));
-    memcpy(buffer->data(), source, byteLength);
-    return buffer;
-}
-
-RefPtr<ArrayBuffer> ArrayBuffer::tryCreate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy)
-{
-    ArrayBufferContents contents;
-    ArrayBufferContents::tryAllocate(numElements, elementByteSize, policy, contents);
-    if (!contents.m_data)
-        return nullptr;
-    return adoptRef(*new ArrayBuffer(contents));
-}
-
-ArrayBuffer::ArrayBuffer(ArrayBufferContents& contents)
-    : m_pinCount(0)
-    , m_locked(false)
-{
-    contents.transfer(m_contents);
-}
-
 void* ArrayBuffer::data()
 {
     return m_contents.m_data;
@@ -269,25 +178,15 @@ unsigned ArrayBuffer::byteLength() const
     return m_contents.m_sizeInBytes;
 }
 
-size_t ArrayBuffer::gcSizeEstimateInBytes() const
-{
-    return sizeof(ArrayBuffer) + static_cast<size_t>(byteLength());
-}
-
-RefPtr<ArrayBuffer> ArrayBuffer::slice(int begin, int end) const
-{
-    return sliceImpl(clampIndex(begin), clampIndex(end));
-}
-
-RefPtr<ArrayBuffer> ArrayBuffer::slice(int begin) const
+bool ArrayBuffer::isShared() const
 {
-    return sliceImpl(clampIndex(begin), byteLength());
+    return m_contents.isShared();
 }
 
-RefPtr<ArrayBuffer> ArrayBuffer::sliceImpl(unsigned begin, unsigned end) const
+size_t ArrayBuffer::gcSizeEstimateInBytes() const
 {
-    unsigned size = begin <= end ? end - begin : 0;
-    return ArrayBuffer::create(static_cast<const char*>(data()) + begin, size);
+    // FIXME: We probably want to scale this by the shared ref count or something.
+    return sizeof(ArrayBuffer) + static_cast<size_t>(byteLength());
 }
 
 unsigned ArrayBuffer::clampIndex(int index) const
@@ -313,38 +212,6 @@ void ArrayBuffer::pinAndLock()
     m_locked = true;
 }
 
-void ArrayBufferContents::tryAllocate(unsigned numElements, unsigned elementByteSize, ArrayBufferContents::InitializationPolicy policy, ArrayBufferContents& result)
-{
-    // Do not allow 31-bit overflow of the total size.
-    if (numElements) {
-        unsigned totalSize = numElements * elementByteSize;
-        if (totalSize / numElements != elementByteSize
-            || totalSize > static_cast<unsigned>(std::numeric_limits<int32_t>::max())) {
-            result.m_data = 0;
-            return;
-        }
-    }
-    bool allocationSucceeded = false;
-    if (policy == ZeroInitialize)
-        allocationSucceeded = WTF::tryFastCalloc(numElements, elementByteSize).getValue(result.m_data);
-    else {
-        ASSERT(policy == DontInitialize);
-        allocationSucceeded = WTF::tryFastMalloc(numElements * elementByteSize).getValue(result.m_data);
-    }
-
-    if (allocationSucceeded) {
-        result.m_sizeInBytes = numElements * elementByteSize;
-        result.m_destructor = arrayBufferDestructorDefault;
-        return;
-    }
-    result.m_data = 0;
-}
-
-ArrayBufferContents::~ArrayBufferContents()
-{
-    m_destructor(m_data);
-}
-
 } // namespace JSC
 
 using JSC::ArrayBuffer;
diff --git a/Source/JavaScriptCore/runtime/ArrayBufferSharingMode.h b/Source/JavaScriptCore/runtime/ArrayBufferSharingMode.h
new file mode 100644 (file)
index 0000000..0dd14c2
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#pragma once
+
+#include <wtf/PrintStream.h>
+
+namespace JSC {
+
+enum class ArrayBufferSharingMode {
+    Default,
+    Shared
+};
+
+inline const char* arrayBufferSharingModeName(ArrayBufferSharingMode sharingMode)
+{
+    switch (sharingMode) {
+    case ArrayBufferSharingMode::Default:
+        return "ArrayBuffer";
+    case ArrayBufferSharingMode::Shared:
+        return "SharedArrayBuffer";
+    }
+    RELEASE_ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
+} // namespace JSC
+
+namespace WTF {
+
+inline void printInternal(PrintStream& out, JSC::ArrayBufferSharingMode mode)
+{
+    out.print(JSC::arrayBufferSharingModeName(mode));
+}
+
+} // namespace WTF
+
index befd94f..55f346e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2009, 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -48,12 +48,26 @@ public:
         return !m_buffer || m_buffer->isNeutered();
     }
     
-    PassRefPtr<ArrayBuffer> buffer() const
+    PassRefPtr<ArrayBuffer> possiblySharedBuffer() const
     {
         if (isNeutered())
             return 0;
         return m_buffer;
     }
+    
+    PassRefPtr<ArrayBuffer> unsharedBuffer() const
+    {
+        PassRefPtr<ArrayBuffer> result = possiblySharedBuffer();
+        RELEASE_ASSERT(!result->isShared());
+        return result;
+    }
+    
+    bool isShared() const
+    {
+        if (isNeutered())
+            return false;
+        return m_buffer->isShared();
+    }
 
     void* baseAddress() const
     {
diff --git a/Source/JavaScriptCore/runtime/AtomicsObject.cpp b/Source/JavaScriptCore/runtime/AtomicsObject.cpp
new file mode 100644 (file)
index 0000000..ca7ed73
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include "config.h"
+#include "AtomicsObject.h"
+
+#include "JSCInlines.h"
+#include "JSTypedArrays.h"
+#include "ObjectPrototype.h"
+#include "TypedArrayController.h"
+
+namespace JSC {
+
+STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(AtomicsObject);
+
+#define FOR_EACH_ATOMICS_FUNC(macro)                                    \
+    macro(add, Add, 3)                                                  \
+    macro(and, And, 3)                                                  \
+    macro(compareExchange, CompareExchange, 4)                          \
+    macro(exchange, Exchange, 3)                                        \
+    macro(isLockFree, IsLockFree, 1)                                    \
+    macro(load, Load, 2)                                                \
+    macro(or, Or, 3)                                                    \
+    macro(store, Store, 3)                                              \
+    macro(sub, Sub, 3)                                                  \
+    macro(wait, Wait, 4)                                                \
+    macro(wake, Wake, 3)                                                \
+    macro(xor, Xor, 3)
+
+#define DECLARE_FUNC_PROTO(lowerName, upperName, count)                 \
+    EncodedJSValue JSC_HOST_CALL atomicsFunc ## upperName(ExecState*);
+FOR_EACH_ATOMICS_FUNC(DECLARE_FUNC_PROTO)
+#undef DECLARE_FUNC_PROTO
+
+const ClassInfo AtomicsObject::s_info = { "Atomics", &Base::s_info, 0, CREATE_METHOD_TABLE(AtomicsObject) };
+
+AtomicsObject::AtomicsObject(VM& vm, Structure* structure)
+    : JSNonFinalObject(vm, structure)
+{
+}
+
+AtomicsObject* AtomicsObject::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+{
+    AtomicsObject* object = new (NotNull, allocateCell<AtomicsObject>(vm.heap)) AtomicsObject(vm, structure);
+    object->finishCreation(vm, globalObject);
+    return object;
+}
+
+Structure* AtomicsObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
+{
+    return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
+}
+
+void AtomicsObject::finishCreation(VM& vm, JSGlobalObject* globalObject)
+{
+    Base::finishCreation(vm);
+    ASSERT(inherits(info()));
+    
+#define PUT_DIRECT_NATIVE_FUNC(lowerName, upperName, count) \
+    putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(&vm, #lowerName), count, atomicsFunc ## upperName, Atomics ## upperName ## Intrinsic, DontEnum);
+    FOR_EACH_ATOMICS_FUNC(PUT_DIRECT_NATIVE_FUNC)
+#undef PUT_DIRECT_NATIVE_FUNC
+}
+
+namespace {
+
+template<unsigned numExtraArgs, typename Adaptor, typename Func>
+EncodedJSValue atomicOperationWithArgsCase(ExecState* exec, ThrowScope& scope, JSArrayBufferView* typedArrayView, unsigned accessIndex, const Func& func)
+{
+    JSGenericTypedArrayView<Adaptor>* typedArray = jsCast<JSGenericTypedArrayView<Adaptor>*>(typedArrayView);
+    
+    typename Adaptor::Type extraArgs[numExtraArgs + 1]; // Add 1 to avoid 0 size array error in VS.
+    for (unsigned i = 0; i < numExtraArgs; ++i) {
+        int32_t value = exec->argument(2 + i).toInt32(exec);
+        RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined()));
+        extraArgs[i] = Adaptor::toNativeFromInt32(value);
+    }
+
+    typename Adaptor::Type result = func(typedArray->typedVector() + accessIndex, extraArgs);
+    return JSValue::encode(Adaptor::toJSValue(result));
+}
+
+unsigned validatedAccessIndex(VM& vm, ExecState* exec, JSArrayBufferView* typedArrayView)
+{
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue accessIndexValue = exec->argument(1);
+    if (UNLIKELY(!accessIndexValue.isInt32())) {
+        accessIndexValue = jsNumber(accessIndexValue.toNumber(exec));
+        RETURN_IF_EXCEPTION(scope, 0);
+        if (!accessIndexValue.isInt32()) {
+            throwRangeError(exec, scope, ASCIILiteral("Access index is not an integer."));
+            return 0;
+        }
+    }
+    int32_t accessIndex = accessIndexValue.asInt32();
+    
+    ASSERT(typedArrayView->length() <= static_cast<unsigned>(INT_MAX));
+    if (static_cast<unsigned>(accessIndex) >= typedArrayView->length()) {
+        throwRangeError(exec, scope, ASCIILiteral("Access index out of bounds for atomic access."));
+        return 0;
+    }
+    
+    return accessIndex;
+}
+
+template<unsigned numExtraArgs, typename Func>
+EncodedJSValue atomicOperationWithArgs(ExecState* exec, const Func& func)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    JSValue typedArrayValue = exec->argument(0);
+    if (!typedArrayValue.isCell()) {
+        throwTypeError(exec, scope, ASCIILiteral("Typed array argument must be a cell."));
+        return JSValue::encode(jsUndefined());
+    }
+    
+    JSCell* typedArrayCell = typedArrayValue.asCell();
+    
+    JSType type = typedArrayCell->type();
+    switch (type) {
+    case Int8ArrayType:
+    case Int16ArrayType:
+    case Int32ArrayType:
+    case Uint8ArrayType:
+    case Uint16ArrayType:
+    case Uint32ArrayType:
+        break;
+    default:
+        throwTypeError(exec, scope, ASCIILiteral("Typed array argument must be an Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, or Uint32Array."));
+        return JSValue::encode(jsUndefined());
+    }
+    
+    JSArrayBufferView* typedArrayView = jsCast<JSArrayBufferView*>(typedArrayCell);
+    if (!typedArrayView->isShared()) {
+        throwTypeError(exec, scope, ASCIILiteral("Typed array argument must wrap a SharedArrayBuffer."));
+        return JSValue::encode(jsUndefined());
+    }
+    
+    unsigned accessIndex = validatedAccessIndex(vm, exec, typedArrayView);
+    RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined()));
+    
+    switch (type) {
+    case Int8ArrayType:
+        return atomicOperationWithArgsCase<numExtraArgs, Int8Adaptor>(exec, scope, typedArrayView, accessIndex, func);
+    case Int16ArrayType:
+        return atomicOperationWithArgsCase<numExtraArgs, Int16Adaptor>(exec, scope, typedArrayView, accessIndex, func);
+    case Int32ArrayType:
+        return atomicOperationWithArgsCase<numExtraArgs, Int32Adaptor>(exec, scope, typedArrayView, accessIndex, func);
+    case Uint8ArrayType:
+        return atomicOperationWithArgsCase<numExtraArgs, Uint8Adaptor>(exec, scope, typedArrayView, accessIndex, func);
+    case Uint16ArrayType:
+        return atomicOperationWithArgsCase<numExtraArgs, Uint16Adaptor>(exec, scope, typedArrayView, accessIndex, func);
+    case Uint32ArrayType:
+        return atomicOperationWithArgsCase<numExtraArgs, Uint32Adaptor>(exec, scope, typedArrayView, accessIndex, func);
+    default:
+        RELEASE_ASSERT_NOT_REACHED();
+        return JSValue::encode(jsUndefined());
+    }
+}
+
+} // anonymous namespace
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncAdd(ExecState* exec)
+{
+    return atomicOperationWithArgs<1>(
+        exec, [&] (auto* ptr, const auto* args) {
+            return WTF::atomicExchangeAdd(ptr, args[0]);
+        });
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncAnd(ExecState* exec)
+{
+    return atomicOperationWithArgs<1>(
+        exec, [&] (auto* ptr, const auto* args) {
+            return WTF::atomicExchangeAnd(ptr, args[0]);
+        });
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncCompareExchange(ExecState* exec)
+{
+    return atomicOperationWithArgs<2>(
+        exec, [&] (auto* ptr, const auto* args) {
+            return WTF::atomicCompareExchangeStrong(ptr, args[0], args[1]);
+        });
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncExchange(ExecState* exec)
+{
+    return atomicOperationWithArgs<1>(
+        exec, [&] (auto* ptr, const auto* args) {
+            return WTF::atomicExchange(ptr, args[0]);
+        });
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncIsLockFree(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    int32_t size = exec->argument(0).toInt32(exec);
+    RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined()));
+    
+    bool result;
+    switch (size) {
+    case 1:
+    case 2:
+    case 4:
+        result = true;
+        break;
+    default:
+        result = false;
+        break;
+    }
+    return JSValue::encode(jsBoolean(result));
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncLoad(ExecState* exec)
+{
+    return atomicOperationWithArgs<0>(
+        exec, [&] (auto* ptr, const auto*) {
+            return WTF::atomicLoad(ptr);
+        });
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncOr(ExecState* exec)
+{
+    return atomicOperationWithArgs<1>(
+        exec, [&] (auto* ptr, const auto* args) {
+            return WTF::atomicExchangeOr(ptr, args[0]);
+        });
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncStore(ExecState* exec)
+{
+    return atomicOperationWithArgs<1>(
+        exec, [&] (auto* ptr, const auto* args) {
+            auto value = args[0];
+            WTF::atomicStore(ptr, value);
+            return value;
+        });
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncSub(ExecState* exec)
+{
+    return atomicOperationWithArgs<1>(
+        exec, [&] (auto* ptr, const auto* args) {
+            return WTF::atomicExchangeSub(ptr, args[0]);
+        });
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncWait(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    
+    JSInt32Array* typedArray = jsDynamicCast<JSInt32Array*>(exec->argument(0));
+    if (!typedArray) {
+        throwTypeError(exec, scope, ASCIILiteral("Typed array for wait/wake must be an Int32Array."));
+        return JSValue::encode(jsUndefined());
+    }
+    
+    if (!typedArray->isShared()) {
+        throwTypeError(exec, scope, ASCIILiteral("Typed array for wait/wake must wrap a SharedArrayBuffer."));
+        return JSValue::encode(jsUndefined());
+    }
+
+    unsigned accessIndex = validatedAccessIndex(vm, exec, typedArray);
+    RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined()));
+    
+    int32_t* ptr = typedArray->typedVector() + accessIndex;
+    
+    int32_t expectedValue = exec->argument(2).toInt32(exec);
+    RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined()));
+    
+    double timeoutInMilliseconds = exec->argument(3).toNumber(exec);
+    RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined()));
+    
+    if (!vm.m_typedArrayController->isAtomicsWaitAllowedOnCurrentThread()) {
+        throwTypeError(exec, scope, ASCIILiteral("Atomics.wait cannot be called from the current thread."));
+        return JSValue::encode(jsUndefined());
+    }
+    
+    double timeoutInNanoseconds = timeoutInMilliseconds * 1000 * 1000;
+
+    // This covers the proposed rule:
+    //
+    // 4. If timeout is not provided or is undefined then let t be +inf. Otherwise:
+    //     a. Let q be ? ToNumber(timeout).
+    //     b. If q is NaN then let t be +inf, otherwise let t be max(0, q).
+    //
+    // exec->argument(3) returns undefined if it's not provided and ToNumber(undefined) returns NaN,
+    // so NaN is the only special case.
+    if (timeoutInNanoseconds == timeoutInNanoseconds)
+        timeoutInNanoseconds = std::max(0., timeoutInNanoseconds);
+    else
+        timeoutInNanoseconds = std::numeric_limits<double>::infinity();
+    
+    // What happens next is a pile of nonsense, but it's all needed because of corner cases
+    // inside std::chrono.
+    // FIXME: Stop using std::chrono.
+    
+    ParkingLot::Clock::time_point timeout;
+    if (timeoutInNanoseconds > static_cast<double>(std::numeric_limits<int64_t>::max()))
+        timeout = ParkingLot::Clock::time_point::max();
+    else {
+        std::chrono::nanoseconds relativeTimeout =
+            std::chrono::nanoseconds(static_cast<int64_t>(timeoutInNanoseconds));
+        if (relativeTimeout < std::chrono::nanoseconds::zero())
+            timeout = ParkingLot::Clock::now();
+        else if (relativeTimeout > ParkingLot::Clock::duration::max())
+            timeout = ParkingLot::Clock::time_point::max();
+        else {
+            ParkingLot::Clock::duration myRelativeTimeout =
+                std::chrono::duration_cast<ParkingLot::Clock::duration>(relativeTimeout);
+            timeout = ParkingLot::Clock::now() + myRelativeTimeout;
+        }
+    }
+    
+    bool didPassValidation = false;
+    ParkingLot::ParkResult result = ParkingLot::parkConditionally(
+        ptr,
+        [&] () -> bool {
+            didPassValidation = WTF::atomicLoad(ptr) == expectedValue;
+            return didPassValidation;
+        },
+        [] () { },
+        timeout);
+    const char* resultString;
+    if (!didPassValidation)
+        resultString = "not-equal";
+    else if (!result.wasUnparked)
+        resultString = "timed-out";
+    else
+        resultString = "ok";
+    return JSValue::encode(jsString(exec, ASCIILiteral(resultString)));
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncWake(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    
+    JSInt32Array* typedArray = jsDynamicCast<JSInt32Array*>(exec->argument(0));
+    if (!typedArray) {
+        throwTypeError(exec, scope, ASCIILiteral("Typed array for wait/wake must be an Int32Array."));
+        return JSValue::encode(jsUndefined());
+    }
+    
+    if (!typedArray->isShared()) {
+        throwTypeError(exec, scope, ASCIILiteral("Typed array for wait/wake must wrap a SharedArrayBuffer."));
+        return JSValue::encode(jsUndefined());
+    }
+
+    unsigned accessIndex = validatedAccessIndex(vm, exec, typedArray);
+    RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined()));
+    
+    int32_t* ptr = typedArray->typedVector() + accessIndex;
+    
+    JSValue countValue = exec->argument(2);
+    unsigned count = UINT_MAX;
+    if (!countValue.isUndefined()) {
+        int32_t countInt = countValue.toInt32(exec);
+        RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined()));
+        count = std::max(0, countInt);
+    }
+
+    return JSValue::encode(jsNumber(ParkingLot::unparkCount(ptr, count)));
+}
+
+EncodedJSValue JSC_HOST_CALL atomicsFuncXor(ExecState* exec)
+{
+    return atomicOperationWithArgs<1>(
+        exec, [&] (auto* ptr, const auto* args) {
+            return WTF::atomicExchangeXor(ptr, args[0]);
+        });
+}
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/AtomicsObject.h b/Source/JavaScriptCore/runtime/AtomicsObject.h
new file mode 100644 (file)
index 0000000..e8144ce
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#pragma once
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class AtomicsObject : public JSNonFinalObject {
+private:
+    AtomicsObject(VM&, Structure*);
+
+public:
+    typedef JSNonFinalObject Base;
+    
+    static AtomicsObject* create(VM&, JSGlobalObject*, Structure*);
+    
+    DECLARE_INFO;
+    
+    static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
+
+protected:
+    void finishCreation(VM&, JSGlobalObject*);
+};
+
+} // namespace JSC
+
index 5c8c76f..d51361b 100644 (file)
@@ -89,6 +89,7 @@
     macro(Set)\
     macro(SetIterator)\
     macro(ShadowRoot) \
+    macro(SharedArrayBuffer) \
     macro(StaticRange) \
     macro(String) \
     macro(Symbol) \
index 4fc73bf..b10ca40 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -53,7 +53,7 @@ Ref<DataView> DataView::create(PassRefPtr<ArrayBuffer> passedBuffer)
 JSArrayBufferView* DataView::wrap(ExecState* exec, JSGlobalObject* globalObject)
 {
     return JSDataView::create(
-        exec, globalObject->typedArrayStructure(TypeDataView), buffer(), byteOffset(),
+        exec, globalObject->typedArrayStructure(TypeDataView), possiblySharedBuffer(), byteOffset(),
         byteLength());
 }
 
index 5dcd0af..da7a453 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -93,8 +93,9 @@ GenericTypedArrayView<Adaptor>::subarray(int start, int end) const
 {
     unsigned offset, length;
     calculateOffsetAndLength(start, end, this->length(), &offset, &length);
-    clampOffsetAndNumElements<Adaptor::Type>(buffer(), byteOffset(), &offset, &length);
-    return create(buffer(), offset, length);
+    ArrayBuffer* buffer = possiblySharedBuffer();
+    clampOffsetAndNumElements<Adaptor::Type>(buffer, byteOffset(), &offset, &length);
+    return create(buffer, offset, length);
 }
 
 template<typename Adaptor>
index 62133f8..e4f216a 100644 (file)
@@ -65,6 +65,18 @@ enum JS_EXPORT_PRIVATE Intrinsic {
     JSMapHasIntrinsic,
     JSSetHasIntrinsic,
     HasOwnPropertyIntrinsic,
+    AtomicsAddIntrinsic,
+    AtomicsAndIntrinsic,
+    AtomicsCompareExchangeIntrinsic,
+    AtomicsExchangeIntrinsic,
+    AtomicsIsLockFreeIntrinsic,
+    AtomicsLoadIntrinsic,
+    AtomicsOrIntrinsic,
+    AtomicsStoreIntrinsic,
+    AtomicsSubIntrinsic,
+    AtomicsWaitIntrinsic,
+    AtomicsWakeIntrinsic,
+    AtomicsXorIntrinsic,
     ToLowerCaseIntrinsic,
 
     // Getter intrinsics.
index bcb9f94..38c0d06 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "JSCInlines.h"
 #include "TypeError.h"
+#include "TypedArrayController.h"
 
 namespace JSC {
 
@@ -43,6 +44,7 @@ JSArrayBuffer::JSArrayBuffer(VM& vm, Structure* structure, PassRefPtr<ArrayBuffe
 void JSArrayBuffer::finishCreation(VM& vm, JSGlobalObject* globalObject)
 {
     Base::finishCreation(vm);
+    // This probably causes GCs in the various VMs to overcount the impact of the array buffer.
     vm.heap.addReference(this, m_impl);
     vm.m_typedArrayController->registerWrapper(globalObject, m_impl, this);
 }
@@ -66,6 +68,16 @@ Structure* JSArrayBuffer::createStructure(
         NonArray);
 }
 
+bool JSArrayBuffer::isShared() const
+{
+    return m_impl->isShared();
+}
+
+ArrayBufferSharingMode JSArrayBuffer::sharingMode() const
+{
+    return m_impl->sharingMode();
+}
+
 size_t JSArrayBuffer::estimatedSize(JSCell* cell)
 {
     JSArrayBuffer* thisObject = jsCast<JSArrayBuffer*>(cell);
index ab8ad38..310204f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -47,10 +47,14 @@ public:
     
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
 
-    static ArrayBuffer* toWrapped(JSValue);
+    bool isShared() const;
+    ArrayBufferSharingMode sharingMode() const;
     
     DECLARE_EXPORT_INFO;
     
+    // This is the default DOM unwrapping. It calls toUnsharedArrayBuffer().
+    static RefPtr<ArrayBuffer> toWrapped(JSValue);
+    
 protected:
 
     static size_t estimatedSize(JSCell*);
@@ -65,7 +69,7 @@ private:
     ArrayBuffer* m_impl;
 };
 
-inline ArrayBuffer* toArrayBuffer(JSValue value)
+inline ArrayBuffer* toPossiblySharedArrayBuffer(JSValue value)
 {
     JSArrayBuffer* wrapper = jsDynamicCast<JSArrayBuffer*>(value);
     if (!wrapper)
@@ -73,9 +77,17 @@ inline ArrayBuffer* toArrayBuffer(JSValue value)
     return wrapper->impl();
 }
 
-inline ArrayBuffer* JSArrayBuffer::toWrapped(JSValue value)
+inline ArrayBuffer* toUnsharedArrayBuffer(JSValue value)
+{
+    ArrayBuffer* result = toPossiblySharedArrayBuffer(value);
+    if (!result || result->isShared())
+        return nullptr;
+    return result;
+}
+
+inline RefPtr<ArrayBuffer> JSArrayBuffer::toWrapped(JSValue value)
 {
-    return toArrayBuffer(value);
+    return toUnsharedArrayBuffer(value);
 }
 
 } // namespace JSC
index 18ce88c..8d30160 100644 (file)
@@ -44,28 +44,31 @@ const ClassInfo JSArrayBufferConstructor::s_info = {
     CREATE_METHOD_TABLE(JSArrayBufferConstructor)
 };
 
-JSArrayBufferConstructor::JSArrayBufferConstructor(VM& vm, Structure* structure)
+JSArrayBufferConstructor::JSArrayBufferConstructor(VM& vm, Structure* structure, ArrayBufferSharingMode sharingMode)
     : Base(vm, structure)
+    , m_sharingMode(sharingMode)
 {
 }
 
 void JSArrayBufferConstructor::finishCreation(VM& vm, JSArrayBufferPrototype* prototype, GetterSetter* speciesSymbol)
 {
-    Base::finishCreation(vm, ASCIILiteral("ArrayBuffer"));
+    Base::finishCreation(vm, ASCIILiteral(arrayBufferSharingModeName(m_sharingMode)));
     putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, DontEnum | DontDelete | ReadOnly);
     putDirectWithoutTransition(vm, vm.propertyNames->length, jsNumber(1), DontEnum | DontDelete | ReadOnly);
     putDirectNonIndexAccessor(vm, vm.propertyNames->speciesSymbol, speciesSymbol, Accessor | ReadOnly | DontEnum);
 
-    JSGlobalObject* globalObject = this->globalObject();
-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->isView, arrayBufferFuncIsView, DontEnum, 1);
-    JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().isViewPrivateName(), arrayBufferFuncIsView, DontEnum, 1);
+    if (m_sharingMode == ArrayBufferSharingMode::Default) {
+        JSGlobalObject* globalObject = this->globalObject();
+        JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->isView, arrayBufferFuncIsView, DontEnum, 1);
+        JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->builtinNames().isViewPrivateName(), arrayBufferFuncIsView, DontEnum, 1);
+    }
 }
 
-JSArrayBufferConstructor* JSArrayBufferConstructor::create(VM& vm, Structure* structure, JSArrayBufferPrototype* prototype, GetterSetter* speciesSymbol)
+JSArrayBufferConstructor* JSArrayBufferConstructor::create(VM& vm, Structure* structure, JSArrayBufferPrototype* prototype, GetterSetter* speciesSymbol, ArrayBufferSharingMode sharingMode)
 {
     JSArrayBufferConstructor* result =
         new (NotNull, allocateCell<JSArrayBufferConstructor>(vm.heap))
-        JSArrayBufferConstructor(vm, structure);
+        JSArrayBufferConstructor(vm, structure, sharingMode);
     result->finishCreation(vm, prototype, speciesSymbol);
     return result;
 }
@@ -99,8 +102,13 @@ static EncodedJSValue JSC_HOST_CALL constructArrayBuffer(ExecState* exec)
     auto buffer = ArrayBuffer::tryCreate(length, 1);
     if (!buffer)
         return JSValue::encode(throwOutOfMemoryError(exec, scope));
-
-    Structure* arrayBufferStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), constructor->globalObject()->arrayBufferStructure());
+    
+    if (constructor->sharingMode() == ArrayBufferSharingMode::Shared)
+        buffer->makeShared();
+    
+    ASSERT(constructor->sharingMode() == buffer->sharingMode());
+    
+    Structure* arrayBufferStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), constructor->globalObject()->arrayBufferStructure(constructor->sharingMode()));
     RETURN_IF_EXCEPTION(scope, encodedJSValue());
     JSArrayBuffer* result = JSArrayBuffer::create(vm, arrayBufferStructure, WTFMove(buffer));
     
index c4be777..9c75324 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "ArrayBuffer.h"
 #include "InternalFunction.h"
 
 namespace JSC {
@@ -37,19 +38,24 @@ public:
     typedef InternalFunction Base;
 
 protected:
-    JSArrayBufferConstructor(VM&, Structure*);
+    JSArrayBufferConstructor(VM&, Structure*, ArrayBufferSharingMode);
     void finishCreation(VM&, JSArrayBufferPrototype*, GetterSetter* speciesSymbol);
 
 public:
-    static JSArrayBufferConstructor* create(VM&, Structure*, JSArrayBufferPrototype*, GetterSetter* speciesSymbol);
+    static JSArrayBufferConstructor* create(VM&, Structure*, JSArrayBufferPrototype*, GetterSetter* speciesSymbol, ArrayBufferSharingMode);
     
     DECLARE_INFO;
     
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+    
+    ArrayBufferSharingMode sharingMode() const { return m_sharingMode; }
 
 protected:
     static ConstructType getConstructData(JSCell*, ConstructData&);
     static CallType getCallData(JSCell*, CallData&);
+
+private:
+    ArrayBufferSharingMode m_sharingMode;
 };
 
 } // namespace JSC
index 7cb52b6..14db596 100644 (file)
@@ -63,7 +63,7 @@ static EncodedJSValue JSC_HOST_CALL arrayBufferProtoFuncSlice(ExecState* exec)
     if (!newBuffer)
         return JSValue::encode(throwOutOfMemoryError(exec, scope));
     
-    Structure* structure = callee->globalObject()->arrayBufferStructure();
+    Structure* structure = callee->globalObject()->arrayBufferStructure(newBuffer->sharingMode());
     
     JSArrayBuffer* result = JSArrayBuffer::create(vm, structure, newBuffer);
     
@@ -74,8 +74,9 @@ const ClassInfo JSArrayBufferPrototype::s_info = {
     "ArrayBufferPrototype", &Base::s_info, 0, CREATE_METHOD_TABLE(JSArrayBufferPrototype)
 };
 
-JSArrayBufferPrototype::JSArrayBufferPrototype(VM& vm, Structure* structure)
+JSArrayBufferPrototype::JSArrayBufferPrototype(VM& vm, Structure* structure, ArrayBufferSharingMode sharingMode)
     : Base(vm, structure)
+    , m_sharingMode(sharingMode)
 {
 }
 
@@ -84,14 +85,14 @@ void JSArrayBufferPrototype::finishCreation(VM& vm, JSGlobalObject* globalObject
     Base::finishCreation(vm);
     
     JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION(vm.propertyNames->slice, arrayBufferProtoFuncSlice, DontEnum, 2);
-    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "ArrayBuffer"), DontEnum | ReadOnly);
+    putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, arrayBufferSharingModeName(m_sharingMode)), DontEnum | ReadOnly);
 }
 
-JSArrayBufferPrototype* JSArrayBufferPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+JSArrayBufferPrototype* JSArrayBufferPrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure, ArrayBufferSharingMode sharingMode)
 {
     JSArrayBufferPrototype* prototype =
         new (NotNull, allocateCell<JSArrayBufferPrototype>(vm.heap))
-        JSArrayBufferPrototype(vm, structure);
+        JSArrayBufferPrototype(vm, structure, sharingMode);
     prototype->finishCreation(vm, globalObject);
     return prototype;
 }
index fe5d505..e5e1f69 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "ArrayBuffer.h"
 #include "JSObject.h"
 
 namespace JSC {
@@ -34,15 +35,18 @@ public:
     typedef JSNonFinalObject Base;
 
 protected:
-    JSArrayBufferPrototype(VM&, Structure*);
+    JSArrayBufferPrototype(VM&, Structure*, ArrayBufferSharingMode);
     void finishCreation(VM&, JSGlobalObject*);
 
 public:
-    static JSArrayBufferPrototype* create(VM&, JSGlobalObject*, Structure*);
+    static JSArrayBufferPrototype* create(VM&, JSGlobalObject*, Structure*, ArrayBufferSharingMode);
     
     DECLARE_INFO;
     
     static Structure* createStructure(VM&, JSGlobalObject*, JSValue prototype);
+
+private:
+    ArrayBufferSharingMode m_sharingMode;
 };
 
 } // namespace JSC
index 5ba90ab..2fd5e4b 100644 (file)
@@ -29,6 +29,7 @@
 #include "JSArrayBuffer.h"
 #include "JSCInlines.h"
 #include "TypeError.h"
+#include "TypedArrayController.h"
 
 namespace JSC {
 
@@ -147,7 +148,7 @@ void JSArrayBufferView::finishCreation(VM& vm)
         return;
     case DataViewMode:
         ASSERT(!butterfly());
-        vm.heap.addReference(this, jsCast<JSDataView*>(this)->buffer());
+        vm.heap.addReference(this, jsCast<JSDataView*>(this)->possiblySharedBuffer());
         return;
     }
     RELEASE_ASSERT_NOT_REACHED();
@@ -158,7 +159,7 @@ void JSArrayBufferView::visitChildren(JSCell* cell, SlotVisitor& visitor)
     JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(cell);
 
     if (thisObject->hasArrayBuffer()) {
-        ArrayBuffer* buffer = thisObject->buffer();
+        ArrayBuffer* buffer = thisObject->possiblySharedBuffer();
         RELEASE_ASSERT(buffer);
         visitor.addOpaqueRoot(buffer);
     }
@@ -177,6 +178,13 @@ bool JSArrayBufferView::put(
     
     return Base::put(thisObject, exec, propertyName, value, slot);
 }
+
+ArrayBuffer* JSArrayBufferView::unsharedBuffer()
+{
+    ArrayBuffer* result = possiblySharedBuffer();
+    RELEASE_ASSERT(!result->isShared());
+    return result;
+}
     
 void JSArrayBufferView::finalize(JSCell* cell)
 {
@@ -186,12 +194,22 @@ void JSArrayBufferView::finalize(JSCell* cell)
         fastFree(thisObject->m_vector.get());
 }
 
-RefPtr<ArrayBufferView> JSArrayBufferView::toWrapped(JSValue value)
+JSArrayBuffer* JSArrayBufferView::unsharedJSBuffer(ExecState* exec)
+{
+    return exec->vm().m_typedArrayController->toJS(exec, globalObject(), unsharedBuffer());
+}
+
+JSArrayBuffer* JSArrayBufferView::possiblySharedJSBuffer(ExecState* exec)
+{
+    return exec->vm().m_typedArrayController->toJS(exec, globalObject(), possiblySharedBuffer());
+}
+
+void JSArrayBufferView::neuter()
 {
-    auto* wrapper = jsDynamicCast<JSArrayBufferView*>(value);
-    if (!wrapper)
-        return nullptr;
-    return wrapper->impl();
+    RELEASE_ASSERT(hasArrayBuffer());
+    RELEASE_ASSERT(!isShared());
+    m_length = 0;
+    m_vector.clear();
 }
 
 } // namespace JSC
index b866636..76a2f75 100644 (file)
@@ -157,9 +157,13 @@ public:
     TypedArrayMode mode() const { return m_mode; }
     bool hasArrayBuffer() const { return JSC::hasArrayBuffer(mode()); }
     
-    ArrayBuffer* buffer();
-    JSArrayBuffer* jsBuffer(ExecState* exec) { return exec->vm().m_typedArrayController->toJS(exec, globalObject(), buffer()); }
-    PassRefPtr<ArrayBufferView> impl();
+    bool isShared();
+    JS_EXPORT_PRIVATE ArrayBuffer* unsharedBuffer();
+    ArrayBuffer* possiblySharedBuffer();
+    JSArrayBuffer* unsharedJSBuffer(ExecState* exec);
+    JSArrayBuffer* possiblySharedJSBuffer(ExecState* exec);
+    PassRefPtr<ArrayBufferView> unsharedImpl();
+    PassRefPtr<ArrayBufferView> possiblySharedImpl();
     bool isNeutered() { return hasArrayBuffer() && !vector(); }
     void neuter();
     
@@ -173,8 +177,8 @@ public:
     static ptrdiff_t offsetOfVector() { return OBJECT_OFFSETOF(JSArrayBufferView, m_vector); }
     static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(JSArrayBufferView, m_length); }
     static ptrdiff_t offsetOfMode() { return OBJECT_OFFSETOF(JSArrayBufferView, m_mode); }
-
-    JS_EXPORT_PRIVATE static RefPtr<ArrayBufferView> toWrapped(JSValue);
+    
+    static RefPtr<ArrayBufferView> toWrapped(JSValue);
 
 private:
     static void finalize(JSCell*);
@@ -195,6 +199,6 @@ protected:
 
 namespace WTF {
 
-void printInternal(PrintStream&, JSC::TypedArrayMode);
+JS_EXPORT_PRIVATE void printInternal(PrintStream&, JSC::TypedArrayMode);
 
 } // namespace WTF
index b4dca89..a0656ca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 namespace JSC {
 
-inline ArrayBuffer* JSArrayBufferView::buffer()
+inline bool JSArrayBufferView::isShared()
+{
+    switch (m_mode) {
+    case WastefulTypedArray:
+        return existingBufferInButterfly()->isShared();
+    case DataViewMode:
+        return jsCast<JSDataView*>(this)->possiblySharedBuffer()->isShared();
+    default:
+        return false;
+    }
+}
+
+inline ArrayBuffer* JSArrayBufferView::possiblySharedBuffer()
 {
     switch (m_mode) {
     case WastefulTypedArray:
         return existingBufferInButterfly();
     case DataViewMode:
-        return jsCast<JSDataView*>(this)->buffer();
+        return jsCast<JSDataView*>(this)->possiblySharedBuffer();
     default:
         return methodTable()->slowDownAndWasteMemory(this);
     }
@@ -49,31 +61,39 @@ inline ArrayBuffer* JSArrayBufferView::existingBufferInButterfly()
     return butterfly()->indexingHeader()->arrayBuffer();
 }
 
-inline PassRefPtr<ArrayBufferView> JSArrayBufferView::impl()
+inline PassRefPtr<ArrayBufferView> JSArrayBufferView::possiblySharedImpl()
 {
     return methodTable()->getTypedArrayImpl(this);
 }
 
-inline void JSArrayBufferView::neuter()
+inline PassRefPtr<ArrayBufferView> JSArrayBufferView::unsharedImpl()
 {
-    ASSERT(hasArrayBuffer());
-    m_length = 0;
-    m_vector.clear();
+    PassRefPtr<ArrayBufferView> result = possiblySharedImpl();
+    RELEASE_ASSERT(!result->isShared());
+    return result;
 }
 
 inline unsigned JSArrayBufferView::byteOffset()
 {
     if (!hasArrayBuffer())
         return 0;
-
-    ASSERT(!vector() == !buffer()->data());
-
+    
+    ArrayBuffer* buffer = possiblySharedBuffer();
+    ASSERT(!vector() == !buffer->data());
+    
     ptrdiff_t delta =
-        bitwise_cast<uint8_t*>(vector()) - static_cast<uint8_t*>(buffer()->data());
+        bitwise_cast<uint8_t*>(vector()) - static_cast<uint8_t*>(buffer->data());
     
     unsigned result = static_cast<unsigned>(delta);
     ASSERT(static_cast<ptrdiff_t>(result) == delta);
     return result;
 }
 
+inline RefPtr<ArrayBufferView> JSArrayBufferView::toWrapped(JSValue value)
+{
+    if (JSArrayBufferView* view = jsDynamicCast<JSArrayBufferView*>(value))
+        return view->unsharedImpl();
+    return nullptr;
+}
+
 } // namespace JSC
index d7506f6..d161b89 100644 (file)
@@ -92,9 +92,14 @@ bool JSDataView::setIndex(ExecState*, unsigned, JSValue)
     return false;
 }
 
-PassRefPtr<DataView> JSDataView::typedImpl()
+PassRefPtr<DataView> JSDataView::possiblySharedTypedImpl()
 {
-    return DataView::create(buffer(), byteOffset(), length());
+    return DataView::create(possiblySharedBuffer(), byteOffset(), length());
+}
+
+PassRefPtr<DataView> JSDataView::unsharedTypedImpl()
+{
+    return DataView::create(unsharedBuffer(), byteOffset(), length());
 }
 
 bool JSDataView::getOwnPropertySlot(
@@ -178,7 +183,7 @@ ArrayBuffer* JSDataView::slowDownAndWasteMemory(JSArrayBufferView*)
 PassRefPtr<ArrayBufferView> JSDataView::getTypedArrayImpl(JSArrayBufferView* object)
 {
     JSDataView* thisObject = jsCast<JSDataView*>(object);
-    return thisObject->typedImpl();
+    return thisObject->possiblySharedTypedImpl();
 }
 
 Structure* JSDataView::createStructure(
index 8c49e2d..cae3a92 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -50,9 +50,15 @@ public:
     bool set(ExecState*, unsigned, JSObject*, unsigned, unsigned length);
     bool setIndex(ExecState*, unsigned, JSValue);
     
-    ArrayBuffer* buffer() const { return m_buffer; }
+    ArrayBuffer* possiblySharedBuffer() const { return m_buffer; }
+    ArrayBuffer* unsharedBuffer() const
+    {
+        RELEASE_ASSERT(!m_buffer->isShared());
+        return m_buffer;
+    }
     
-    PassRefPtr<DataView> typedImpl();
+    PassRefPtr<DataView> possiblySharedTypedImpl();
+    PassRefPtr<DataView> unsharedTypedImpl();
     
     static const TypedArrayType TypedArrayStorageType = TypeDataView;
 
index 1f8e0c2..6855a5c 100644 (file)
@@ -228,7 +228,7 @@ EncodedJSValue JSC_HOST_CALL dataViewProtoGetterBuffer(ExecState* exec)
     if (!view)
         return throwVMTypeError(exec, scope, "DataView.prototype.buffer expects |this| to be a DataView object");
 
-    return JSValue::encode(view->jsBuffer(exec));
+    return JSValue::encode(view->possiblySharedJSBuffer(exec));
 }
 
 EncodedJSValue JSC_HOST_CALL dataViewProtoGetterByteLength(ExecState* exec)
index aab5f10..355390d 100644 (file)
@@ -225,13 +225,9 @@ public:
     // then it will have thrown an exception.
     bool set(ExecState*, unsigned offset, JSObject*, unsigned objectOffset, unsigned length, CopyType type = CopyType::Unobservable);
     
-    RefPtr<typename Adaptor::ViewType> typedImpl()
-    {
-        return Adaptor::ViewType::create(buffer(), byteOffset(), length());
-    }
+    PassRefPtr<typename Adaptor::ViewType> possiblySharedTypedImpl();
+    PassRefPtr<typename Adaptor::ViewType> unsharedTypedImpl();
 
-    static RefPtr<typename Adaptor::ViewType> toWrapped(JSValue);
-    
     static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype)
     {
         return Structure::create(vm, globalObject, prototype, TypeInfo(typeForTypedArrayType(Adaptor::typeValue), StructureFlags), info(), NonArray);
@@ -270,6 +266,9 @@ public:
 
     static const TypedArrayType TypedArrayStorageType = Adaptor::typeValue;
 
+    // This is the default DOM unwrapping. It calls toUnsharedNativeTypedView().
+    static RefPtr<typename Adaptor::ViewType> toWrapped(JSValue);
+    
 protected:
     friend struct TypedArrayClassInfos;
 
@@ -361,18 +360,27 @@ private:
 };
 
 template<typename Adaptor>
-inline RefPtr<typename Adaptor::ViewType> toNativeTypedView(JSValue value)
+inline RefPtr<typename Adaptor::ViewType> toPossiblySharedNativeTypedView(JSValue value)
 {
     typename Adaptor::JSViewType* wrapper = jsDynamicCast<typename Adaptor::JSViewType*>(value);
     if (!wrapper)
         return nullptr;
-    return wrapper->typedImpl();
+    return wrapper->possiblySharedTypedImpl();
+}
+
+template<typename Adaptor>
+inline RefPtr<typename Adaptor::ViewType> toUnsharedNativeTypedView(JSValue value)
+{
+    RefPtr<typename Adaptor::ViewType> result = toPossiblySharedNativeTypedView<Adaptor>(value);
+    if (!result || result->isShared())
+        return nullptr;
+    return result;
 }
 
 template<typename Adaptor>
 RefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::toWrapped(JSValue value)
 {
-    return JSC::toNativeTypedView<Adaptor>(value);
+    return JSC::toUnsharedNativeTypedView<Adaptor>(value);
 }
 
 } // namespace JSC
index b565572..367b135 100644 (file)
@@ -125,7 +125,7 @@ template<typename Adaptor>
 JSGenericTypedArrayView<Adaptor>* JSGenericTypedArrayView<Adaptor>::create(
     VM& vm, Structure* structure, PassRefPtr<typename Adaptor::ViewType> impl)
 {
-    RefPtr<ArrayBuffer> buffer = impl->buffer();
+    RefPtr<ArrayBuffer> buffer = impl->possiblySharedBuffer();
     ConstructionContext context(vm, structure, buffer, impl->byteOffset(), impl->length());
     ASSERT(context);
     JSGenericTypedArrayView* result =
@@ -313,6 +313,18 @@ bool JSGenericTypedArrayView<Adaptor>::set(
 }
 
 template<typename Adaptor>
+PassRefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::possiblySharedTypedImpl()
+{
+    return Adaptor::ViewType::create(possiblySharedBuffer(), byteOffset(), length());
+}
+
+template<typename Adaptor>
+PassRefPtr<typename Adaptor::ViewType> JSGenericTypedArrayView<Adaptor>::unsharedTypedImpl()
+{
+    return Adaptor::ViewType::create(unsharedBuffer(), byteOffset(), length());
+}
+
+template<typename Adaptor>
 ArrayBuffer* JSGenericTypedArrayView<Adaptor>::existingBuffer()
 {
     return existingBufferInButterfly();
@@ -532,7 +544,7 @@ ArrayBuffer* JSGenericTypedArrayView<Adaptor>::slowDownAndWasteMemory(JSArrayBuf
     DeferGCForAWhile deferGC(*heap);
     
     ASSERT(!thisObject->hasIndexingHeader());
-
+    
     RELEASE_ASSERT(!thisObject->hasIndexingHeader());
     thisObject->m_butterfly.set(vm, thisObject, Butterfly::createOrGrowArrayRight(
         thisObject->butterfly(), vm, thisObject, thisObject->structure(),
@@ -570,7 +582,7 @@ PassRefPtr<ArrayBufferView>
 JSGenericTypedArrayView<Adaptor>::getTypedArrayImpl(JSArrayBufferView* object)
 {
     JSGenericTypedArrayView* thisObject = jsCast<JSGenericTypedArrayView*>(object);
-    return thisObject->typedImpl();
+    return thisObject->possiblySharedTypedImpl();
 }
 
 } // namespace JSC
index 1d5b412..ed32568 100644 (file)
@@ -37,6 +37,7 @@
 #include "JSStringJoiner.h"
 #include "StructureInlines.h"
 #include "TypedArrayAdaptors.h"
+#include "TypedArrayController.h"
 #include <wtf/StdLibExtras.h>
 
 namespace JSC {
@@ -346,7 +347,7 @@ EncodedJSValue JSC_HOST_CALL genericTypedArrayViewProtoGetterFuncBuffer(VM&, Exe
     // 22.2.3.3
     ViewClass* thisObject = jsCast<ViewClass*>(exec->thisValue());
 
-    return JSValue::encode(thisObject->jsBuffer(exec));
+    return JSValue::encode(thisObject->possiblySharedJSBuffer(exec));
 }
 
 template<typename ViewClass>
@@ -525,7 +526,7 @@ EncodedJSValue JSC_HOST_CALL genericTypedArrayViewPrivateFuncSubarrayCreate(VM&v
     unsigned offset = begin;
     unsigned length = end - begin;
 
-    RefPtr<ArrayBuffer> arrayBuffer = thisObject->buffer();
+    RefPtr<ArrayBuffer> arrayBuffer = thisObject->possiblySharedBuffer();
     RELEASE_ASSERT(thisLength == thisObject->length());
 
     unsigned newByteOffset = thisObject->byteOffset() + offset * ViewClass::elementSize;
@@ -542,7 +543,7 @@ EncodedJSValue JSC_HOST_CALL genericTypedArrayViewPrivateFuncSubarrayCreate(VM&v
     }
 
     MarkedArgumentBuffer args;
-    args.append(vm.m_typedArrayController->toJS(exec, thisObject->globalObject(), thisObject->buffer()));
+    args.append(vm.m_typedArrayController->toJS(exec, thisObject->globalObject(), arrayBuffer.get()));
     args.append(jsNumber(newByteOffset));
     args.append(jsNumber(length));
 
index cb3b300..4c5cbbb 100644 (file)
@@ -33,6 +33,7 @@
 #include "ArrayConstructor.h"
 #include "ArrayIteratorPrototype.h"
 #include "ArrayPrototype.h"
+#include "AtomicsObject.h"
 #include "AsyncFunctionConstructor.h"
 #include "AsyncFunctionPrototype.h"
 #include "BooleanConstructor.h"
@@ -203,6 +204,12 @@ static JSValue createConsoleProperty(VM& vm, JSObject* object)
     return ConsoleObject::create(vm, global, ConsoleObject::createStructure(vm, global, constructEmptyObject(global->globalExec())));
 }
 
+static JSValue createAtomicsProperty(VM& vm, JSObject* object)
+{
+    JSGlobalObject* global = jsCast<JSGlobalObject*>(object);
+    return AtomicsObject::create(vm, global, AtomicsObject::createStructure(vm, global, global->objectPrototype()));
+}
+
 static EncodedJSValue JSC_HOST_CALL makeBoundFunction(ExecState* exec)
 {
     VM& vm = exec->vm();
@@ -253,6 +260,7 @@ const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &sup
   Proxy                 createProxyProperty                          DontEnum|PropertyCallback
   JSON                  createJSONProperty                           DontEnum|PropertyCallback
   Math                  createMathProperty                           DontEnum|PropertyCallback
+  Atomics               createAtomicsProperty                        DontEnum|PropertyCallback
   console               createConsoleProperty                        DontEnum|PropertyCallback
   Int8Array             JSGlobalObject::m_typedArrayInt8             DontEnum|ClassStructure
   Int16Array            JSGlobalObject::m_typedArrayInt16            DontEnum|ClassStructure
@@ -543,6 +551,13 @@ void JSGlobalObject::init(VM& vm)
 
     m_parseIntFunction.set(vm, this, JSFunction::create(vm, this, 2, vm.propertyNames->parseInt.string(), globalFuncParseInt, NoIntrinsic));
     putDirectWithoutTransition(vm, vm.propertyNames->parseInt, m_parseIntFunction.get(), DontEnum);
+    
+    m_arrayBufferPrototype.set(vm, this, JSArrayBufferPrototype::create(vm, this, JSArrayBufferPrototype::createStructure(vm, this, m_objectPrototype.get()), ArrayBufferSharingMode::Default));
+    m_arrayBufferStructure.set(vm, this, JSArrayBuffer::createStructure(vm, this, m_arrayBufferPrototype.get()));
+    if (m_runtimeFlags.isSharedArrayBufferEnabled()) {
+        m_sharedArrayBufferPrototype.set(vm, this, JSArrayBufferPrototype::create(vm, this, JSArrayBufferPrototype::createStructure(vm, this, m_objectPrototype.get()), ArrayBufferSharingMode::Shared));
+        m_sharedArrayBufferStructure.set(vm, this, JSArrayBuffer::createStructure(vm, this, m_sharedArrayBufferPrototype.get()));
+    }
 
 #define CREATE_PROTOTYPE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName, prototypeBase) \
 m_ ## lowerName ## Prototype.set(vm, this, capitalName##Prototype::create(vm, this, capitalName##Prototype::createStructure(vm, this, m_ ## prototypeBase ## Prototype.get()))); \
@@ -595,6 +610,14 @@ m_ ## properName ## Structure.set(vm, this, instanceType::createStructure(vm, th
     
     m_regExpConstructor.set(vm, this, RegExpConstructor::create(vm, RegExpConstructor::createStructure(vm, this, m_functionPrototype.get()), m_regExpPrototype.get(), m_speciesGetterSetter.get()));
     
+    JSArrayBufferConstructor* arrayBufferConstructor = JSArrayBufferConstructor::create(vm, JSArrayBufferConstructor::createStructure(vm, this, m_functionPrototype.get()), m_arrayBufferPrototype.get(), m_speciesGetterSetter.get(), ArrayBufferSharingMode::Default);
+    m_arrayBufferPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, arrayBufferConstructor, DontEnum);
+    JSArrayBufferConstructor* sharedArrayBufferConstructor = nullptr;
+    if (m_runtimeFlags.isSharedArrayBufferEnabled()) {
+        sharedArrayBufferConstructor = JSArrayBufferConstructor::create(vm, JSArrayBufferConstructor::createStructure(vm, this, m_functionPrototype.get()), m_sharedArrayBufferPrototype.get(), m_speciesGetterSetter.get(), ArrayBufferSharingMode::Shared);
+        m_sharedArrayBufferPrototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, sharedArrayBufferConstructor, DontEnum);
+    }
+    
 #define CREATE_CONSTRUCTOR_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName, prototypeBase) \
 capitalName ## Constructor* lowerName ## Constructor = capitalName ## Constructor::create(vm, capitalName ## Constructor::createStructure(vm, this, m_functionPrototype.get()), m_ ## lowerName ## Prototype.get(), m_speciesGetterSetter.get()); \
 m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->constructor, lowerName ## Constructor, DontEnum); \
@@ -661,6 +684,10 @@ m_ ## lowerName ## Prototype->putDirectWithoutTransition(vm, vm.propertyNames->c
     putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().ObjectPrivateName(), objectConstructor, DontEnum | DontDelete | ReadOnly);
     putDirectWithoutTransition(vm, vm.propertyNames->builtinNames().ArrayPrivateName(), arrayConstructor, DontEnum | DontDelete | ReadOnly);
 
+    putDirectWithoutTransition(vm, vm.propertyNames->ArrayBuffer, arrayBufferConstructor, DontEnum);
+    if (m_runtimeFlags.isSharedArrayBufferEnabled())
+        putDirectWithoutTransition(vm, vm.propertyNames->SharedArrayBuffer, sharedArrayBufferConstructor, DontEnum);
+
 #define PUT_CONSTRUCTOR_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName, prototypeBase) \
 putDirectWithoutTransition(vm, vm.propertyNames-> jsName, lowerName ## Constructor, DontEnum); \
 
@@ -1172,6 +1199,11 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(&thisObject->m_callableProxyObjectStructure);
     visitor.append(&thisObject->m_proxyRevokeStructure);
     visitor.append(&thisObject->m_moduleLoaderStructure);
+    
+    visitor.append(&thisObject->m_arrayBufferPrototype);
+    visitor.append(&thisObject->m_arrayBufferStructure);
+    visitor.append(&thisObject->m_sharedArrayBufferPrototype);
+    visitor.append(&thisObject->m_sharedArrayBufferStructure);
 
 #define VISIT_SIMPLE_TYPE(CapitalName, lowerName, properName, instanceType, jsName, prototypeBase) \
     visitor.append(&thisObject->m_ ## lowerName ## Prototype); \
index ee79488..ea57506 100644 (file)
@@ -22,6 +22,7 @@
 #pragma once
 
 #include "ArrayAllocationProfile.h"
+#include "ArrayBufferSharingMode.h"
 #include "InternalFunction.h"
 #include "JSArray.h"
 #include "JSArrayBufferPrototype.h"
@@ -71,12 +72,18 @@ class GeneratorFunctionPrototype;
 class GetterSetter;
 class GlobalCodeBlock;
 class InputCursor;
+class JSArrayBuffer;
+class JSArrayBufferConstructor;
+class JSArrayBufferPrototype;
 class JSGlobalObjectDebuggable;
 class JSInternalPromise;
 class JSModuleLoader;
 class JSPromise;
 class JSPromiseConstructor;
 class JSPromisePrototype;
+class JSSharedArrayBuffer;
+class JSSharedArrayBufferConstructor;
+class JSSharedArrayBufferPrototype;
 class JSTypedArrayViewConstructor;
 class JSTypedArrayViewPrototype;
 class LLIntOffsetsExtractor;
@@ -105,8 +112,7 @@ struct HashTable;
     macro(Number, number, numberObject, NumberObject, Number, object) \
     macro(Error, error, error, ErrorInstance, Error, object) \
     macro(Map, map, map, JSMap, Map, object) \
-    macro(JSPromise, promise, promise, JSPromise, Promise, object) \
-    macro(JSArrayBuffer, arrayBuffer, arrayBuffer, JSArrayBuffer, ArrayBuffer, object) \
+    macro(JSPromise, promise, promise, JSPromise, Promise, object)
 
 #define FOR_EACH_BUILTIN_DERIVED_ITERATOR_TYPE(macro) \
     DEFINE_STANDARD_BUILTIN(macro, MapIterator, mapIterator) \
@@ -321,6 +327,10 @@ public:
     WriteBarrier<Structure> m_callableProxyObjectStructure;
     WriteBarrier<Structure> m_proxyRevokeStructure;
     WriteBarrier<Structure> m_moduleLoaderStructure;
+    WriteBarrier<JSArrayBufferPrototype> m_arrayBufferPrototype;
+    WriteBarrier<Structure> m_arrayBufferStructure;
+    WriteBarrier<JSArrayBufferPrototype> m_sharedArrayBufferPrototype;
+    WriteBarrier<Structure> m_sharedArrayBufferStructure;
 
 #define DEFINE_STORAGE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName, prototypeBase) \
     WriteBarrier<capitalName ## Prototype> m_ ## lowerName ## Prototype; \
@@ -640,7 +650,26 @@ public:
     void setName(const String&);
     const String& name() const { return m_name; }
 
-    JSArrayBufferPrototype* arrayBufferPrototype() const { return m_arrayBufferPrototype.get(); }
+    JSArrayBufferPrototype* arrayBufferPrototype(ArrayBufferSharingMode sharingMode) const
+    {
+        switch (sharingMode) {
+        case ArrayBufferSharingMode::Default:
+            return m_arrayBufferPrototype.get();
+        case ArrayBufferSharingMode::Shared:
+            return m_sharedArrayBufferPrototype.get();
+        }
+    }
+    Structure* arrayBufferStructure(ArrayBufferSharingMode sharingMode) const
+    {
+        switch (sharingMode) {
+        case ArrayBufferSharingMode::Default:
+            return m_arrayBufferStructure.get();
+        case ArrayBufferSharingMode::Shared:
+            return m_sharedArrayBufferStructure.get();
+        }
+        RELEASE_ASSERT_NOT_REACHED();
+        return nullptr;
+    }
 
 #define DEFINE_ACCESSORS_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName, prototypeBase) \
     Structure* properName ## Structure() { return m_ ## properName ## Structure.get(); }
index a5cbb9b..d9052f0 100644 (file)
 #include "config.h"
 #include "MathObject.h"
 
-#include "Lookup.h"
+#include "JSCInlines.h"
 #include "MathCommon.h"
 #include "ObjectPrototype.h"
-#include "JSCInlines.h"
 #include <time.h>
 #include <wtf/Assertions.h>
 #include <wtf/MathExtras.h>
index 11a3d4c..3874bde 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2015 Yusuke Suzuki <utatane.tea@gmail.com>.
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -30,7 +31,8 @@
 namespace JSC {
 
 // macro(name, isEnabledFlag)
-#define JSC_RUNTIME_FLAG(macro)
+#define JSC_RUNTIME_FLAG(macro) \
+    macro(SharedArrayBufferEnabled, true)
 
 class RuntimeFlags {
 private:
index cd82668..a25028c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -43,7 +43,7 @@ JSArrayBuffer* SimpleTypedArrayController::toJS(
 
     // The JSArrayBuffer::create function will register the wrapper in finishCreation.
     JSArrayBuffer* result = JSArrayBuffer::create(
-        exec->vm(), globalObject->arrayBufferStructure(), native);
+        exec->vm(), globalObject->arrayBufferStructure(native->sharingMode()), native);
     return result;
 }
 
@@ -53,6 +53,11 @@ void SimpleTypedArrayController::registerWrapper(JSGlobalObject*, ArrayBuffer* n
     native->m_wrapper = Weak<JSArrayBuffer>(wrapper, &m_owner);
 }
 
+bool SimpleTypedArrayController::isAtomicsWaitAllowedOnCurrentThread()
+{
+    return true;
+}
+
 bool SimpleTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor)
 {
     auto& wrapper = *JSC::jsCast<JSC::JSArrayBuffer*>(handle.slot()->asCell());
index df31f04..d2b03c2 100644 (file)
@@ -53,6 +53,7 @@ public:
     
     JSArrayBuffer* toJS(ExecState*, JSGlobalObject*, ArrayBuffer*) override;
     void registerWrapper(JSGlobalObject*, ArrayBuffer*, JSArrayBuffer*) override;
+    bool isAtomicsWaitAllowedOnCurrentThread() override;
 
 private:
     class JSArrayBufferOwner : public WeakHandleOwner {
index e725d35..64d3f55 100644 (file)
@@ -41,6 +41,7 @@ public:
     
     virtual JSArrayBuffer* toJS(ExecState*, JSGlobalObject*, ArrayBuffer*) = 0;
     virtual void registerWrapper(JSGlobalObject*, ArrayBuffer*, JSArrayBuffer*) = 0;
+    virtual bool isAtomicsWaitAllowedOnCurrentThread() = 0;
 };
 
 } // namespace JSC
index 7c752b1..eab7c21 100644 (file)
@@ -26,6 +26,7 @@
 #pragma once
 
 #include "JSType.h"
+#include <wtf/Optional.h>
 #include <wtf/PrintStream.h>
 
 namespace JSC {
@@ -119,6 +120,32 @@ inline size_t elementSize(TypedArrayType type)
 const ClassInfo* constructorClassInfoForType(TypedArrayType);
 JSType typeForTypedArrayType(TypedArrayType);
 
+inline TypedArrayType typedArrayTypeForType(JSType type)
+{
+    switch (type) {
+    case Int8ArrayType:
+        return TypeInt8;
+    case Int16ArrayType:
+        return TypeInt16;
+    case Int32ArrayType:
+        return TypeInt32;
+    case Uint8ArrayType:
+        return TypeUint8;
+    case Uint8ClampedArrayType:
+        return TypeUint8Clamped;
+    case Uint16ArrayType:
+        return TypeUint16;
+    case Uint32ArrayType:
+        return TypeUint32;
+    case Float32ArrayType:
+        return TypeFloat32;
+    case Float64ArrayType:
+        return TypeFloat64;
+    default:
+        return NotTypedArray;
+    }
+}
+
 inline bool isInt(TypedArrayType type)
 {
     switch (type) {
index a97f181..4fd7ec4 100644 (file)
@@ -49,7 +49,6 @@
 #include "SourceCode.h"
 #include "Strong.h"
 #include "ThunkGenerators.h"
-#include "TypedArrayController.h"
 #include "VMEntryRecord.h"
 #include "Watchpoint.h"
 #include <wtf/Bag.h>
@@ -114,6 +113,7 @@ class Structure;
 class RegExp;
 #endif
 class Symbol;
+class TypedArrayController;
 class UnlinkedCodeBlock;
 class UnlinkedEvalCodeBlock;
 class UnlinkedFunctionExecutable;
index 0484c06..736c751 100644 (file)
@@ -1,3 +1,50 @@
+2016-10-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should support SharedArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=163986
+
+        Reviewed by Keith Miller.
+        
+        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).
+
 2016-10-30  Frederic Wang  <fwang@igalia.com>
 
         Use HarfBuzz ot-math API to parse the OpenType MATH table
index a434bc2..4a88ea4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2008, 2010, 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2007-2008, 2010, 2012-2016 Apple Inc. All rights reserved.
  * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
  *
  * Redistribution and use in source and binary forms, with or without
@@ -62,39 +62,115 @@ struct Atomic {
         return value.compare_exchange_weak(expectedOrActual, desired, order);
     }
 
+    ALWAYS_INLINE bool compareExchangeWeakRelaxed(T expected, T desired)
+    {
+        return compareExchangeWeak(expected, desired, std::memory_order_relaxed);
+    }
+
     ALWAYS_INLINE bool compareExchangeWeak(T expected, T desired, std::memory_order order_success, std::memory_order order_failure)
     {
         T expectedOrActual = expected;
         return value.compare_exchange_weak(expectedOrActual, desired, order_success, order_failure);
     }
 
-    ALWAYS_INLINE bool compareExchangeStrong(T expected, T desired, std::memory_order order = std::memory_order_seq_cst)
+    ALWAYS_INLINE T compareExchangeStrong(T expected, T desired, std::memory_order order = std::memory_order_seq_cst)
     {
         T expectedOrActual = expected;
-        return value.compare_exchange_strong(expectedOrActual, desired, order);
+        value.compare_exchange_strong(expectedOrActual, desired, order);
+        return expectedOrActual;
     }
 
-    ALWAYS_INLINE bool compareExchangeStrong(T expected, T desired, std::memory_order order_success, std::memory_order order_failure)
+    ALWAYS_INLINE T compareExchangeStrong(T expected, T desired, std::memory_order order_success, std::memory_order order_failure)
     {
         T expectedOrActual = expected;
-        return value.compare_exchange_strong(expectedOrActual, desired, order_success, order_failure);
+        value.compare_exchange_strong(expectedOrActual, desired, order_success, order_failure);
+        return expectedOrActual;
     }
 
     template<typename U>
-    ALWAYS_INLINE T exchangeAndAdd(U addend, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_add(addend, order); }
+    ALWAYS_INLINE T exchangeAdd(U operand, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_add(operand, order); }
+    
+    template<typename U>
+    ALWAYS_INLINE T exchangeAnd(U operand, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_and(operand, order); }
+    
+    template<typename U>
+    ALWAYS_INLINE T exchangeOr(U operand, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_or(operand, order); }
+    
+    template<typename U>
+    ALWAYS_INLINE T exchangeSub(U operand, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_sub(operand, order); }
+    
+    template<typename U>
+    ALWAYS_INLINE T exchangeXor(U operand, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_xor(operand, order); }
     
     ALWAYS_INLINE T exchange(T newValue, std::memory_order order = std::memory_order_seq_cst) { return value.exchange(newValue, order); }
 
     std::atomic<T> value;
 };
 
-// This is a weak CAS function that takes a direct pointer and has no portable fencing guarantees.
 template<typename T>
-inline bool weakCompareAndSwap(volatile T* location, T expected, T newValue)
+inline T atomicLoad(T* location, std::memory_order order = std::memory_order_seq_cst)
+{
+    return bitwise_cast<Atomic<T>*>(location)->load(order);
+}
+
+template<typename T>
+inline void atomicStore(T* location, T newValue, std::memory_order order = std::memory_order_seq_cst)
+{
+    bitwise_cast<Atomic<T>*>(location)->store(newValue, order);
+}
+
+template<typename T>
+inline bool atomicCompareExchangeWeak(T* location, T expected, T newValue, std::memory_order order = std::memory_order_seq_cst)
+{
+    return bitwise_cast<Atomic<T>*>(location)->compareExchangeWeak(expected, newValue, order);
+}
+
+template<typename T>
+inline bool atomicCompareExchangeWeakRelaxed(T* location, T expected, T newValue)
+{
+    return bitwise_cast<Atomic<T>*>(location)->compareExchangeWeakRelaxed(expected, newValue);
+}
+
+template<typename T>
+inline T atomicCompareExchangeStrong(T* location, T expected, T newValue, std::memory_order order = std::memory_order_seq_cst)
+{
+    return bitwise_cast<Atomic<T>*>(location)->compareExchangeStrong(expected, newValue, order);
+}
+
+template<typename T, typename U>
+inline T atomicExchangeAdd(T* location, U operand, std::memory_order order = std::memory_order_seq_cst)
+{
+    return bitwise_cast<Atomic<T>*>(location)->exchangeAdd(operand, order);
+}
+
+template<typename T, typename U>
+inline T atomicExchangeAnd(T* location, U operand, std::memory_order order = std::memory_order_seq_cst)
+{
+    return bitwise_cast<Atomic<T>*>(location)->exchangeAnd(operand, order);
+}
+
+template<typename T, typename U>
+inline T atomicExchangeOr(T* location, U operand, std::memory_order order = std::memory_order_seq_cst)
+{
+    return bitwise_cast<Atomic<T>*>(location)->exchangeOr(operand, order);
+}
+
+template<typename T, typename U>
+inline T atomicExchangeSub(T* location, U operand, std::memory_order order = std::memory_order_seq_cst)
+{
+    return bitwise_cast<Atomic<T>*>(location)->exchangeSub(operand, order);
+}
+
+template<typename T, typename U>
+inline T atomicExchangeXor(T* location, U operand, std::memory_order order = std::memory_order_seq_cst)
+{
+    return bitwise_cast<Atomic<T>*>(location)->exchangeXor(operand, order);
+}
+
+template<typename T>
+inline T atomicExchange(T* location, T newValue, std::memory_order order = std::memory_order_seq_cst)
 {
-    ASSERT(isPointerTypeAlignmentOkay(location) && "natural alignment required");
-    ASSERT(bitwise_cast<std::atomic<T>*>(location)->is_lock_free() && "expected lock-free type");
-    return bitwise_cast<Atomic<T>*>(location)->compareExchangeWeak(expected, newValue, std::memory_order_relaxed);
+    return bitwise_cast<Atomic<T>*>(location)->exchange(newValue, order);
 }
 
 // Just a compiler fence. Has no effect on the hardware, but tells the compiler
index 2041c65..89b2c9d 100644 (file)
@@ -142,7 +142,7 @@ inline bool Bitmap<bitmapSize, WordType>::concurrentTestAndSet(size_t n)
         oldValue = *wordPtr;
         if (oldValue & mask)
             return true;
-    } while (!weakCompareAndSwap(wordPtr, oldValue, static_cast<WordType>(oldValue | mask)));
+    } while (!atomicCompareExchangeWeakRelaxed(wordPtr, oldValue, static_cast<WordType>(oldValue | mask)));
     return false;
 }
 
@@ -157,7 +157,7 @@ inline bool Bitmap<bitmapSize, WordType>::concurrentTestAndClear(size_t n)
         oldValue = *wordPtr;
         if (!(oldValue & mask))
             return false;
-    } while (!weakCompareAndSwap(wordPtr, oldValue, static_cast<WordType>(oldValue & ~mask)));
+    } while (!atomicCompareExchangeWeakRelaxed(wordPtr, oldValue, static_cast<WordType>(oldValue & ~mask)));
     return true;
 }
 
index ba25e72..9119a1d 100644 (file)
@@ -569,7 +569,7 @@ public:
                     return false;
                 newValue = oldValue & ~mask;
             }
-            if (weakCompareAndSwap(pointer, oldValue, newValue))
+            if (atomicCompareExchangeWeakRelaxed(pointer, oldValue, newValue))
                 return true;
         }
     }
index c5b9fcb..ef626e7 100644 (file)
@@ -416,7 +416,7 @@ void ensureHashtableSize(unsigned numThreads)
     // OK, right now the old hashtable is locked up and the new hashtable is ready to rock and
     // roll. After we install the new hashtable, we can release all bucket locks.
     
-    bool result = hashtable.compareExchangeStrong(oldHashtable, newHashtable);
+    bool result = hashtable.compareExchangeStrong(oldHashtable, newHashtable) == oldHashtable;
     RELEASE_ASSERT(result);
 
     unlockHashtable(bucketsToUnlock);
@@ -671,6 +671,11 @@ NEVER_INLINE ParkingLot::UnparkResult ParkingLot::unparkOne(const void* address)
     RefPtr<ThreadData> threadData;
     result.mayHaveMoreThreads = dequeue(
         address,
+        // Why is this here?
+        // FIXME: It seems like this could be IgnoreEmpty, but I switched this to EnsureNonEmpty
+        // without explanation in r199760. We need it to use EnsureNonEmpty if we need to perform
+        // some operation while holding the bucket lock, which usually goes into the finish func.
+        // But if that operation is a no-op, then it's not clear why we need this.
         BucketMode::EnsureNonEmpty,
         [&] (ThreadData* element, bool) {
             if (element->address != address)
@@ -743,14 +748,19 @@ NEVER_INLINE void ParkingLot::unparkOneImpl(
     threadData->parkingCondition.notify_one();
 }
 
-NEVER_INLINE void ParkingLot::unparkAll(const void* address)
+NEVER_INLINE unsigned ParkingLot::unparkCount(const void* address, unsigned count)
 {
+    if (!count)
+        return 0;
+    
     if (verbose)
-        dataLog(toString(currentThread(), ": unparking all from ", RawPointer(address), ".\n"));
+        dataLog(toString(currentThread(), ": unparking count = ", count, " from ", RawPointer(address), ".\n"));
     
     Vector<RefPtr<ThreadData>, 8> threadDatas;
     dequeue(
         address,
+        // FIXME: It seems like this ought to be EnsureNonEmpty if we follow what unparkOne() does,
+        // but that seems wrong.
         BucketMode::IgnoreEmpty,
         [&] (ThreadData* element, bool) {
             if (verbose)
@@ -758,6 +768,8 @@ NEVER_INLINE void ParkingLot::unparkAll(const void* address)
             if (element->address != address)
                 return DequeueResult::Ignore;
             threadDatas.append(element);
+            if (threadDatas.size() == count)
+                return DequeueResult::RemoveAndStop;
             return DequeueResult::RemoveAndContinue;
         },
         [] (bool) { });
@@ -775,6 +787,13 @@ NEVER_INLINE void ParkingLot::unparkAll(const void* address)
 
     if (verbose)
         dataLog(toString(currentThread(), ": done unparking.\n"));
+    
+    return threadDatas.size();
+}
+
+NEVER_INLINE void ParkingLot::unparkAll(const void* address)
+{
+    unparkCount(address, UINT_MAX);
 }
 
 NEVER_INLINE void ParkingLot::forEachImpl(const ScopedLambda<void(ThreadIdentifier, const void*)>& callback)
index 421d507..c0e1158 100644 (file)
@@ -128,6 +128,8 @@ public:
     {
         unparkOneImpl(address, scopedLambdaRef<intptr_t(UnparkResult)>(callback));
     }
+    
+    WTF_EXPORT_PRIVATE static unsigned unparkCount(const void* address, unsigned count);
 
     // Unparks every thread from the queue associated with the given address, which cannot be null.
     WTF_EXPORT_PRIVATE static void unparkAll(const void* address);
index 16eb737..edde74c 100644 (file)
@@ -1,3 +1,102 @@
+2016-10-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should support SharedArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=163986
+
+        Reviewed by Keith Miller.
+
+        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):
+
 2016-10-31  Simon Fraser  <simon.fraser@apple.com>
 
         Make UIScriptController::zoomToScale() work on Mac WK1 and WK2
index ed70c85..0096a4a 100644 (file)
@@ -183,7 +183,7 @@ RefPtr<ArrayBuffer> CDMSessionClearKey::cachedKeyForKeyID(const String& keyId) c
 
     auto keyData = m_cachedKeys.get(keyId);
     RefPtr<Uint8Array> keyDataArray = Uint8Array::create(keyData.data(), keyData.size());
-    return keyDataArray->buffer();
+    return keyDataArray->unsharedBuffer();
 }
 
 }
index 4fd4a07..8d02b12 100644 (file)
@@ -73,12 +73,12 @@ Optional<FetchBody> FetchBody::extract(ScriptExecutionContext& context, JSC::Exe
     if (value.inherits(JSReadableStream::info()))
         return FetchBody();
     if (value.inherits(JSC::JSArrayBuffer::info())) {
-        ArrayBuffer* data = toArrayBuffer(value);
+        ArrayBuffer* data = toUnsharedArrayBuffer(value);
         ASSERT(data);
         return FetchBody(*data);
     }
     if (value.inherits(JSC::JSArrayBufferView::info()))
-        return FetchBody(toArrayBufferView(value).releaseConstNonNull());
+        return FetchBody(toUnsharedArrayBufferView(value).releaseConstNonNull());
 
     return Nullopt;
 }
index 104c1cc..b720c2c 100644 (file)
@@ -219,7 +219,7 @@ ExceptionOr<void> RTCDataChannel::send(ArrayBuffer& data)
 
 ExceptionOr<void> RTCDataChannel::send(ArrayBufferView& data)
 {
-    return send(*data.buffer());
+    return send(*data.unsharedBuffer());
 }
 
 ExceptionOr<void> RTCDataChannel::send(Blob&)
index 3038ac0..43d760f 100644 (file)
@@ -92,7 +92,7 @@ ExceptionOr<Ref<Float32Array>> AudioBuffer::getChannelData(unsigned channelIndex
     if (channelIndex >= m_channels.size())
         return Exception { SYNTAX_ERR };
     auto& channelData = *m_channels[channelIndex];
-    auto array = Float32Array::create(channelData.buffer(), channelData.byteOffset(), channelData.length());
+    auto array = Float32Array::create(channelData.unsharedBuffer(), channelData.byteOffset(), channelData.length());
     RELEASE_ASSERT(array);
     return array.releaseNonNull();
 }
index 7b2f894..6432165 100644 (file)
@@ -358,7 +358,7 @@ ExceptionOr<void> WebSocket::send(ArrayBufferView& arrayBufferView)
         return { };
     }
     ASSERT(m_channel);
-    m_channel->send(*arrayBufferView.buffer(), arrayBufferView.byteOffset(), arrayBufferView.byteLength());
+    m_channel->send(*arrayBufferView.unsharedBuffer(), arrayBufferView.byteOffset(), arrayBufferView.byteLength());
     return { };
 }
 
index d47c9e8..130f987 100644 (file)
@@ -120,9 +120,9 @@ EncodedJSValue JSC_HOST_CALL constructJSBlob(ExecState& exec)
         JSValue item = blobParts->get(&exec, i);
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
-        if (ArrayBuffer* arrayBuffer = toArrayBuffer(item))
+        if (ArrayBuffer* arrayBuffer = toUnsharedArrayBuffer(item))
             blobBuilder.append(arrayBuffer);
-        else if (auto arrayBufferView = toArrayBufferView(item))
+        else if (auto arrayBufferView = toUnsharedArrayBufferView(item))
             blobBuilder.append(WTFMove(arrayBufferView));
         else if (Blob* blob = JSBlob::toWrapped(item))
             blobBuilder.append(blob);
index 3d7a049..8845b33 100644 (file)
@@ -242,7 +242,7 @@ static RefPtr<CryptoAlgorithmParametersDeprecated> createRsaKeyGenParams(ExecSta
     JSValue publicExponentValue = getProperty(&state, value.getObject(), "publicExponent");
     RETURN_IF_EXCEPTION(scope, nullptr);
 
-    RefPtr<Uint8Array> publicExponentArray = toUint8Array(publicExponentValue);
+    RefPtr<Uint8Array> publicExponentArray = toUnsharedUint8Array(publicExponentValue);
     if (!publicExponentArray) {
         throwTypeError(&state, scope, ASCIILiteral("Expected a Uint8Array in publicExponent"));
         return nullptr;
index f2b1c71..fae8870 100644 (file)
@@ -45,7 +45,7 @@ JSValue JSCrypto::getRandomValues(ExecState& state)
         return throwException(&state, scope, createNotEnoughArgumentsError(&state));
 
     JSValue buffer = state.argument(0);
-    auto arrayBufferView = toArrayBufferView(buffer);
+    auto arrayBufferView = toUnsharedArrayBufferView(buffer);
     if (!arrayBufferView)
         return throwTypeError(&state, scope);
 
index 1896157..c6faf72 100644 (file)
@@ -39,9 +39,9 @@ bool cryptoOperationDataFromJSValue(ExecState* exec, JSValue value, CryptoOperat
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
 
-    if (ArrayBuffer* buffer = toArrayBuffer(value))
+    if (ArrayBuffer* buffer = toUnsharedArrayBuffer(value))
         result = std::make_pair(static_cast<uint8_t*>(buffer->data()), buffer->byteLength());
-    else if (RefPtr<ArrayBufferView> bufferView = toArrayBufferView(value))
+    else if (RefPtr<ArrayBufferView> bufferView = toUnsharedArrayBufferView(value))
         result = std::make_pair(static_cast<uint8_t*>(bufferView->baseAddress()), bufferView->byteLength());
     else {
         throwTypeError(exec, scope, ASCIILiteral("Only ArrayBuffer and ArrayBufferView objects can be passed as CryptoOperationData"));
index 18ab3c1..9a4e036 100644 (file)
@@ -269,16 +269,27 @@ JSC::JSValue toJSIterator(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSValue);
 template<typename T> JSC::JSValue toJSIterator(JSC::ExecState&, JSDOMGlobalObject&, const T&);
 JSC::JSValue toJSIteratorEnd(JSC::ExecState&);
 
-RefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue);
-RefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue);
-RefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue);
-RefPtr<JSC::Int32Array> toInt32Array(JSC::JSValue);
-RefPtr<JSC::Uint8Array> toUint8Array(JSC::JSValue);
-RefPtr<JSC::Uint8ClampedArray> toUint8ClampedArray(JSC::JSValue);
-RefPtr<JSC::Uint16Array> toUint16Array(JSC::JSValue);
-RefPtr<JSC::Uint32Array> toUint32Array(JSC::JSValue);
-RefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue);
-RefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue);
+RefPtr<JSC::ArrayBufferView> toPossiblySharedArrayBufferView(JSC::JSValue);
+RefPtr<JSC::Int8Array> toPossiblySharedInt8Array(JSC::JSValue);
+RefPtr<JSC::Int16Array> toPossiblySharedInt16Array(JSC::JSValue);
+RefPtr<JSC::Int32Array> toPossiblySharedInt32Array(JSC::JSValue);
+RefPtr<JSC::Uint8Array> toPossiblySharedUint8Array(JSC::JSValue);
+RefPtr<JSC::Uint8ClampedArray> toPossiblySharedUint8ClampedArray(JSC::JSValue);
+RefPtr<JSC::Uint16Array> toPossiblySharedUint16Array(JSC::JSValue);
+RefPtr<JSC::Uint32Array> toPossiblySharedUint32Array(JSC::JSValue);
+RefPtr<JSC::Float32Array> toPossiblySharedFloat32Array(JSC::JSValue);
+RefPtr<JSC::Float64Array> toPossiblySharedFloat64Array(JSC::JSValue);
+
+RefPtr<JSC::ArrayBufferView> toUnsharedArrayBufferView(JSC::JSValue);
+RefPtr<JSC::Int8Array> toUnsharedInt8Array(JSC::JSValue);
+RefPtr<JSC::Int16Array> toUnsharedInt16Array(JSC::JSValue);
+RefPtr<JSC::Int32Array> toUnsharedInt32Array(JSC::JSValue);
+RefPtr<JSC::Uint8Array> toUnsharedUint8Array(JSC::JSValue);
+RefPtr<JSC::Uint8ClampedArray> toUnsharedUint8ClampedArray(JSC::JSValue);
+RefPtr<JSC::Uint16Array> toUnsharedUint16Array(JSC::JSValue);
+RefPtr<JSC::Uint32Array> toUnsharedUint32Array(JSC::JSValue);
+RefPtr<JSC::Float32Array> toUnsharedFloat32Array(JSC::JSValue);
+RefPtr<JSC::Float64Array> toUnsharedFloat64Array(JSC::JSValue);
 
 template<typename T, typename JSType> Vector<Ref<T>> toRefNativeArray(JSC::ExecState&, JSC::JSValue);
 WEBCORE_EXPORT bool hasIteratorMethod(JSC::ExecState&, JSC::JSValue);
@@ -604,7 +615,7 @@ inline JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject,
         return result;
 
     // The JSArrayBuffer::create function will register the wrapper in finishCreation.
-    return JSC::JSArrayBuffer::create(state->vm(), globalObject->arrayBufferStructure(), &buffer);
+    return JSC::JSArrayBuffer::create(state->vm(), globalObject->arrayBufferStructure(buffer.sharingMode()), &buffer);
 }
 
 inline JSC::JSValue toJS(JSC::ExecState* state, JSC::JSGlobalObject* globalObject, JSC::ArrayBufferView& view)
@@ -680,23 +691,41 @@ inline JSC::JSValue toJSIteratorEnd(JSC::ExecState& state)
     return createIteratorResultObject(&state, JSC::jsUndefined(), true);
 }
 
-inline RefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue value)
+inline RefPtr<JSC::ArrayBufferView> toPossiblySharedArrayBufferView(JSC::JSValue value)
 {
     auto* wrapper = jsDynamicDowncast<JSC::JSArrayBufferView*>(value);
     if (!wrapper)
         return nullptr;
-    return wrapper->impl();
-}
-
-inline RefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int8Adaptor>(value); }
-inline RefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int16Adaptor>(value); }
-inline RefPtr<JSC::Int32Array> toInt32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int32Adaptor>(value); }
-inline RefPtr<JSC::Uint8Array> toUint8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8Adaptor>(value); }
-inline RefPtr<JSC::Uint8ClampedArray> toUint8ClampedArray(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8ClampedAdaptor>(value); }
-inline RefPtr<JSC::Uint16Array> toUint16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint16Adaptor>(value); }
-inline RefPtr<JSC::Uint32Array> toUint32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint32Adaptor>(value); }
-inline RefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float32Adaptor>(value); }
-inline RefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float64Adaptor>(value); }
+    return wrapper->possiblySharedImpl();
+}
+
+inline RefPtr<JSC::ArrayBufferView> toUnsharedArrayBufferView(JSC::JSValue value)
+{
+    auto result = toPossiblySharedArrayBufferView(value);
+    if (!result || result->isShared())
+        return nullptr;
+    return result;
+}
+
+inline RefPtr<JSC::Int8Array> toPossiblySharedInt8Array(JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Int8Adaptor>(value); }
+inline RefPtr<JSC::Int16Array> toPossiblySharedInt16Array(JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Int16Adaptor>(value); }
+inline RefPtr<JSC::Int32Array> toPossiblySharedInt32Array(JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Int32Adaptor>(value); }
+inline RefPtr<JSC::Uint8Array> toPossiblySharedUint8Array(JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Uint8Adaptor>(value); }
+inline RefPtr<JSC::Uint8ClampedArray> toPossiblySharedUint8ClampedArray(JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Uint8ClampedAdaptor>(value); }
+inline RefPtr<JSC::Uint16Array> toPossiblySharedUint16Array(JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Uint16Adaptor>(value); }
+inline RefPtr<JSC::Uint32Array> toPossiblySharedUint32Array(JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Uint32Adaptor>(value); }
+inline RefPtr<JSC::Float32Array> toPossiblySharedFloat32Array(JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Float32Adaptor>(value); }
+inline RefPtr<JSC::Float64Array> toPossiblySharedFloat64Array(JSC::JSValue value) { return JSC::toPossiblySharedNativeTypedView<JSC::Float64Adaptor>(value); }
+
+inline RefPtr<JSC::Int8Array> toUnsharedInt8Array(JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Int8Adaptor>(value); }
+inline RefPtr<JSC::Int16Array> toUnsharedInt16Array(JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Int16Adaptor>(value); }
+inline RefPtr<JSC::Int32Array> toUnsharedInt32Array(JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Int32Adaptor>(value); }
+inline RefPtr<JSC::Uint8Array> toUnsharedUint8Array(JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Uint8Adaptor>(value); }
+inline RefPtr<JSC::Uint8ClampedArray> toUnsharedUint8ClampedArray(JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Uint8ClampedAdaptor>(value); }
+inline RefPtr<JSC::Uint16Array> toUnsharedUint16Array(JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Uint16Adaptor>(value); }
+inline RefPtr<JSC::Uint32Array> toUnsharedUint32Array(JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Uint32Adaptor>(value); }
+inline RefPtr<JSC::Float32Array> toUnsharedFloat32Array(JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Float32Adaptor>(value); }
+inline RefPtr<JSC::Float64Array> toUnsharedFloat64Array(JSC::JSValue value) { return JSC::toUnsharedNativeTypedView<JSC::Float64Adaptor>(value); }
 
 template<typename T, typename JST> inline Vector<Ref<T>> toRefNativeArray(JSC::ExecState& state, JSC::JSValue value)
 {
index 3217eeb..4fe35f5 100644 (file)
@@ -84,7 +84,7 @@ EncodedJSValue JSC_HOST_CALL constructJSDataCue(ExecState& exec)
 
     if (valueArgument.isCell() && valueArgument.asCell()->inherits(std::remove_pointer<JSArrayBuffer*>::type::info())) {
 
-        ArrayBuffer* data = toArrayBuffer(valueArgument);
+        ArrayBuffer* data = toUnsharedArrayBuffer(valueArgument);
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
         if (UNLIKELY(!data)) {
index 1fdfd2f..447e7c2 100644 (file)
@@ -253,7 +253,7 @@ void JSDictionary::convertValue(ExecState* exec, JSValue value, ArrayValue& resu
 
 void JSDictionary::convertValue(JSC::ExecState*, JSC::JSValue value, RefPtr<Uint8Array>& result)
 {
-    result = toUint8Array(value);
+    result = toUnsharedUint8Array(value);
 }
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
index 8578d5e..43ff82e 100644 (file)
@@ -105,9 +105,9 @@ EncodedJSValue JSC_HOST_CALL constructJSFile(ExecState& exec)
         JSValue item = blobParts->get(&exec, i);
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
-        if (ArrayBuffer* arrayBuffer = toArrayBuffer(item))
+        if (ArrayBuffer* arrayBuffer = toUnsharedArrayBuffer(item))
             blobBuilder.append(arrayBuffer);
-        else if (RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(item))
+        else if (RefPtr<ArrayBufferView> arrayBufferView = toUnsharedArrayBufferView(item))
             blobBuilder.append(WTFMove(arrayBufferView));
         else if (Blob* blob = JSBlob::toWrapped(item))
             blobBuilder.append(blob);
index f135a4b..17387e3 100644 (file)
@@ -91,7 +91,7 @@ void extractTransferables(JSC::ExecState& state, JSC::JSValue value, Vector<RefP
             }
             portArray.append(WTFMove(port));
         } else {
-            if (RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(value))
+            if (RefPtr<ArrayBuffer> arrayBuffer = toPossiblySharedArrayBuffer(value))
                 arrayBuffers.append(WTFMove(arrayBuffer));
             else {
                 throwTypeError(&state, scope);
index f6eee7a..68a6e1e 100644 (file)
@@ -513,7 +513,7 @@ static JSC::JSValue dataFunctionf(DataFunctionToCall f, JSC::ExecState& state, W
     
     RETURN_IF_EXCEPTION(scope, JSValue());
     
-    RefPtr<Float32Array> webGLArray = toFloat32Array(state.uncheckedArgument(1));
+    RefPtr<Float32Array> webGLArray = toUnsharedFloat32Array(state.uncheckedArgument(1));
     RETURN_IF_EXCEPTION(scope, JSValue());
     
     ExceptionCode ec = 0;
@@ -596,7 +596,7 @@ static JSC::JSValue dataFunctioni(DataFunctionToCall f, JSC::ExecState& state, W
     if (!location && !state.uncheckedArgument(0).isUndefinedOrNull())
         return throwTypeError(&state, scope);
     
-    RefPtr<Int32Array> webGLArray = toInt32Array(state.uncheckedArgument(1));
+    RefPtr<Int32Array> webGLArray = toUnsharedInt32Array(state.uncheckedArgument(1));
     
     ExceptionCode ec = 0;
     if (webGLArray) {
@@ -662,7 +662,7 @@ static JSC::JSValue dataFunctionMatrix(DataFunctionMatrixToCall f, JSC::ExecStat
     bool transpose = state.uncheckedArgument(1).toBoolean(&state);
     RETURN_IF_EXCEPTION(scope, JSValue());
     
-    RefPtr<Float32Array> webGLArray = toFloat32Array(state.uncheckedArgument(2));
+    RefPtr<Float32Array> webGLArray = toUnsharedFloat32Array(state.uncheckedArgument(2));
 
     if (webGLArray) {
         switch (f) {
index 7e125d7..bffb041 100644 (file)
@@ -63,7 +63,7 @@ EncodedJSValue JSC_HOST_CALL constructJSWorker(ExecState& state)
     auto& window = asJSDOMWindow(state.lexicalGlobalObject())->wrapped();
 
     ASSERT(window.document());
-    return JSValue::encode(toJSNewlyCreated(state, globalObject, scope, Worker::create(*window.document(), scriptURL)));
+    return JSValue::encode(toJSNewlyCreated(state, globalObject, scope, Worker::create(*window.document(), scriptURL, globalObject.runtimeFlags())));
 }
 
 } // namespace WebCore
index a617709..3277c69 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009, 2016 Apple Inc. All rights reserved.
  * Copyright (C) 2009 Google Inc. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,6 +36,7 @@
 #include "JSWorkerGlobalScope.h"
 #include "Language.h"
 #include "WorkerGlobalScope.h"
+#include "WorkerThread.h"
 #include <runtime/JSCInlines.h>
 #include <runtime/JSCJSValueInlines.h>
 #include <runtime/Microtask.h>
@@ -97,7 +98,8 @@ bool JSWorkerGlobalScopeBase::shouldInterruptScriptBeforeTimeout(const JSGlobalO
 
 RuntimeFlags JSWorkerGlobalScopeBase::javaScriptRuntimeFlags(const JSGlobalObject* object)
 {
-    return JSGlobalObject::javaScriptRuntimeFlags(object);
+    const JSWorkerGlobalScopeBase *thisObject = jsCast<const JSWorkerGlobalScopeBase*>(object);
+    return thisObject->m_wrapped->thread().runtimeFlags();
 }
 
 void JSWorkerGlobalScopeBase::queueTaskToEventLoop(const JSGlobalObject* object, Ref<JSC::Microtask>&& task)
index 3e58e92..3362f44 100644 (file)
@@ -115,10 +115,10 @@ JSValue JSXMLHttpRequest::send(ExecState& state)
         result = wrapped().send(*JSBlob::toWrapped(value));
     else if (value.inherits(JSDOMFormData::info()))
         result = wrapped().send(*JSDOMFormData::toWrapped(value));
-    else if (value.inherits(JSArrayBuffer::info()))
-        result = wrapped().send(*toArrayBuffer(value));
-    else if (value.inherits(JSArrayBufferView::info()))
-        result = wrapped().send(*toArrayBufferView(value).get());
+    else if (RefPtr<ArrayBuffer> arrayBuffer = toUnsharedArrayBuffer(value))
+        result = wrapped().send(*arrayBuffer);
+    else if (RefPtr<ArrayBufferView> arrayBufferView = toUnsharedArrayBufferView(value))
+        result = wrapped().send(*arrayBufferView);
     else {
         // FIXME: If toString raises an exception, should we exit before calling willSendXMLHttpRequest?
         // FIXME: If toString raises an exception, should we exit before calling send?
index f264173..5973ca1 100644 (file)
@@ -727,10 +727,10 @@ private:
         else
             return false;
 
-        RefPtr<ArrayBufferView> arrayBufferView = toArrayBufferView(obj);
+        RefPtr<ArrayBufferView> arrayBufferView = toPossiblySharedArrayBufferView(obj);
         write(static_cast<uint32_t>(arrayBufferView->byteOffset()));
         write(static_cast<uint32_t>(arrayBufferView->byteLength()));
-        RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->buffer();
+        RefPtr<ArrayBuffer> arrayBuffer = arrayBufferView->possiblySharedBuffer();
         if (!arrayBuffer) {
             code = ValidationError;
             return true;
@@ -845,7 +845,7 @@ private:
                 code = ValidationError;
                 return true;
             }
-            if (ArrayBuffer* arrayBuffer = toArrayBuffer(obj)) {
+            if (ArrayBuffer* arrayBuffer = toPossiblySharedArrayBuffer(obj)) {
                 if (arrayBuffer->isNeutered()) {
                     code = ValidationError;
                     return true;
@@ -1838,7 +1838,7 @@ private:
         if (length * elementSize != byteLength)
             return false;
 
-        RefPtr<ArrayBuffer> arrayBuffer = toArrayBuffer(arrayBufferObj);
+        RefPtr<ArrayBuffer> arrayBuffer = toPossiblySharedArrayBuffer(arrayBufferObj);
         switch (arrayBufferViewSubtag) {
         case DataViewTag:
             arrayBufferView = getJSValue(DataView::create(arrayBuffer, byteOffset, length).get());
@@ -2359,7 +2359,14 @@ private:
                 fail();
                 return JSValue();
             }
-            JSValue result = JSArrayBuffer::create(m_exec->vm(), m_globalObject->arrayBufferStructure(), WTFMove(arrayBuffer));
+            Structure* structure = m_globalObject->arrayBufferStructure(arrayBuffer->sharingMode());
+            // A crazy RuntimeFlags mismatch could mean that we are not equipped to handle shared
+            // array buffers while the sender is. In that case, we would see a null structure here.
+            if (!structure) {
+                fail();
+                return JSValue();
+            }
+            JSValue result = JSArrayBuffer::create(m_exec->vm(), structure, WTFMove(arrayBuffer));
             m_gcBuffer.append(result);
             return result;
         }
@@ -2372,7 +2379,7 @@ private:
             }
 
             if (!m_arrayBuffers[index])
-                m_arrayBuffers[index] = ArrayBuffer::create(m_arrayBufferContents->at(index));
+                m_arrayBuffers[index] = ArrayBuffer::create(WTFMove(m_arrayBufferContents->at(index)));
 
             return getJSValue(m_arrayBuffers[index].get());
         }
@@ -2674,7 +2681,7 @@ std::unique_ptr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScrip
             continue;
         visited.add(arrayBuffers[arrayBufferIndex].get());
 
-        bool result = arrayBuffers[arrayBufferIndex]->transfer(contents->at(arrayBufferIndex));
+        bool result = arrayBuffers[arrayBufferIndex]->transferTo(contents->at(arrayBufferIndex));
         if (!result) {
             code = ValidationError;
             return nullptr;
index fd8c6ff..01662c6 100644 (file)
@@ -41,13 +41,13 @@ EncodedJSValue JSC_HOST_CALL structuredCloneArrayBuffer(ExecState* execState)
     ASSERT(execState->argumentCount());
     ASSERT(execState->lexicalGlobalObject());
 
-    ArrayBuffer* buffer = toArrayBuffer(execState->uncheckedArgument(0));
+    ArrayBuffer* buffer = toUnsharedArrayBuffer(execState->uncheckedArgument(0));
     if (!buffer) {
         setDOMException(execState, DATA_CLONE_ERR);
         return JSValue::encode(jsUndefined());
     }
 
-    return JSValue::encode(JSArrayBuffer::create(execState->vm(), execState->lexicalGlobalObject()->arrayBufferStructure(), ArrayBuffer::tryCreate(buffer->data(), buffer->byteLength())));
+    return JSValue::encode(JSArrayBuffer::create(execState->vm(), execState->lexicalGlobalObject()->arrayBufferStructure(ArrayBufferSharingMode::Default), ArrayBuffer::tryCreate(buffer->data(), buffer->byteLength())));
 }
 
 EncodedJSValue JSC_HOST_CALL structuredCloneArrayBufferView(ExecState* execState)
@@ -59,7 +59,7 @@ EncodedJSValue JSC_HOST_CALL structuredCloneArrayBufferView(ExecState* execState
     auto* bufferView = jsDynamicDowncast<JSArrayBufferView*>(value);
     ASSERT(bufferView);
 
-    auto* buffer = bufferView->buffer();
+    auto* buffer = bufferView->unsharedBuffer();
     if (!buffer) {
         setDOMException(execState, DATA_CLONE_ERR);
         return JSValue::encode(jsUndefined());
index 838e4bf..dd09c43 100644 (file)
@@ -52,6 +52,11 @@ void WebCoreTypedArrayController::registerWrapper(JSC::JSGlobalObject* globalObj
     cacheWrapper(JSC::jsCast<JSDOMGlobalObject*>(globalObject)->world(), native, wrapper);
 }
 
+bool WebCoreTypedArrayController::isAtomicsWaitAllowedOnCurrentThread()
+{
+    return !isMainThread();
+}
+
 bool WebCoreTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor)
 {
     auto& wrapper = *JSC::jsCast<JSC::JSArrayBuffer*>(handle.slot()->asCell());
index 529a1fb..3bb94bc 100644 (file)
@@ -41,6 +41,7 @@ public:
     
     JSC::JSArrayBuffer* toJS(JSC::ExecState*, JSC::JSGlobalObject*, JSC::ArrayBuffer*) override;
     void registerWrapper(JSC::JSGlobalObject*, ArrayBuffer*, JSC::JSArrayBuffer*) override;
+    bool isAtomicsWaitAllowedOnCurrentThread() override;
 
     JSC::WeakHandleOwner* wrapperOwner() { return &m_owner; }
 
index d6c0e57..bee5e0c 100644 (file)
@@ -5314,7 +5314,7 @@ sub JSValueToNative
 
     AddToImplIncludesForIDLType($type, $conditional);
 
-    return ("to@{[$type->name]}($value)", 1) if $codeGenerator->IsTypedArrayType($type);
+    return ("toUnshared@{[$type->name]}($value)", 1) if $codeGenerator->IsTypedArrayType($type);
     return ("parseEnumeration<" . GetEnumerationClassName($type, $interface) . ">($stateReference, $value)", 1) if $codeGenerator->IsEnumType($type);
 
     # FIXME: EventListener should be a callback interface.
index f91639a..17d355a 100644 (file)
@@ -60,9 +60,9 @@ ExceptionOr<Ref<FontFace>> FontFace::create(JSC::ExecState& state, Document& doc
         if (!is<CSSValueList>(value.get()))
             return Exception { SYNTAX_ERR };
         CSSFontFace::appendSources(result->backing(), downcast<CSSValueList>(*value), &document, false);
-    } else if (auto arrayBufferView = toArrayBufferView(source))
+    } else if (auto arrayBufferView = toUnsharedArrayBufferView(source))
         dataRequiresAsynchronousLoading = populateFontFaceWithArrayBuffer(result->backing(), arrayBufferView.releaseNonNull());
-    else if (auto arrayBuffer = toArrayBuffer(source)) {
+    else if (auto arrayBuffer = toUnsharedArrayBuffer(source)) {
         auto arrayBufferView = JSC::Uint8Array::create(arrayBuffer, 0, arrayBuffer->byteLength());
         dataRequiresAsynchronousLoading = populateFontFaceWithArrayBuffer(result->backing(), arrayBufferView.releaseNonNull());
     }
index 91bbdec..c1cf186 100644 (file)
@@ -94,7 +94,7 @@ void WebGL2RenderingContext::bufferData(GC3Denum target, ArrayBufferView& data,
         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "srcOffset or length is out of bounds");
         return;
     }
-    auto slice = Uint8Array::create(data.buffer(), data.byteOffset() + srcOffset, length);
+    auto slice = Uint8Array::create(data.unsharedBuffer(), data.byteOffset() + srcOffset, length);
     if (!slice) {
         synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, "bufferData", "Could not create intermediate ArrayBufferView");
         return;
@@ -108,7 +108,7 @@ void WebGL2RenderingContext::bufferSubData(GC3Denum target, long long offset, Ar
         synthesizeGLError(GraphicsContext3D::INVALID_VALUE, "bufferData", "srcOffset or length is out of bounds");
         return;
     }
-    auto slice = Uint8Array::create(data.buffer(), data.byteOffset() + srcOffset, length);
+    auto slice = Uint8Array::create(data.unsharedBuffer(), data.byteOffset() + srcOffset, length);
     if (!slice) {
         synthesizeGLError(GraphicsContext3D::OUT_OF_MEMORY, "bufferData", "Could not create intermediate ArrayBufferView");
         return;
index 58f4e48..7ab7ecb 100644 (file)
@@ -1025,7 +1025,7 @@ bool MediaPlayerPrivateAVFoundation::extractKeyURIKeyIDAndCertificateFromInitDat
     if (initData->byteLength() < 4)
         return false;
 
-    RefPtr<ArrayBuffer> initDataBuffer = initData->buffer();
+    RefPtr<ArrayBuffer> initDataBuffer = initData->unsharedBuffer();
 
     // Use a DataView to read uint32 values from the buffer, as Uint32Array requires the reads be aligned on 4-byte boundaries. 
     RefPtr<JSC::DataView> initDataView = JSC::DataView::create(initDataBuffer, 0, initDataBuffer->byteLength());
index a750abe..790f4be 100644 (file)
@@ -38,8 +38,8 @@
 
 namespace WebCore {
 
-DedicatedWorkerThread::DedicatedWorkerThread(const URL& url, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerObjectProxy& workerObjectProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
-    : WorkerThread(url, userAgent, sourceCode, workerLoaderProxy, workerObjectProxy, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, topOrigin, connectionProxy, socketProvider)
+DedicatedWorkerThread::DedicatedWorkerThread(const URL& url, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerObjectProxy& workerObjectProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, JSC::RuntimeFlags runtimeFlags)
+    : WorkerThread(url, userAgent, sourceCode, workerLoaderProxy, workerObjectProxy, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, topOrigin, connectionProxy, socketProvider, runtimeFlags)
     , m_workerObjectProxy(workerObjectProxy)
 {
 }
index 80a4a63..c503cdb 100644 (file)
@@ -53,7 +53,7 @@ protected:
     void runEventLoop() override;
 
 private:
-    DedicatedWorkerThread(const URL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerObjectProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*);
+    DedicatedWorkerThread(const URL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerObjectProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*, JSC::RuntimeFlags);
 
     WorkerObjectProxy& m_workerObjectProxy;
 };
index 19d93bd..1dc998b 100644 (file)
@@ -51,9 +51,10 @@ void networkStateChanged(bool isOnLine)
         worker->notifyNetworkStateChange(isOnLine);
 }
 
-inline Worker::Worker(ScriptExecutionContext& context)
+inline Worker::Worker(ScriptExecutionContext& context, JSC::RuntimeFlags runtimeFlags)
     : ActiveDOMObject(&context)
     , m_contextProxy(WorkerGlobalScopeProxy::create(this))
+    , m_runtimeFlags(runtimeFlags)
 {
     if (!allWorkers) {
         allWorkers = new HashSet<Worker*>;
@@ -64,14 +65,14 @@ inline Worker::Worker(ScriptExecutionContext& context)
     ASSERT_UNUSED(addResult, addResult.isNewEntry);
 }
 
-ExceptionOr<Ref<Worker>> Worker::create(ScriptExecutionContext& context, const String& url)
+ExceptionOr<Ref<Worker>> Worker::create(ScriptExecutionContext& context, const String& url, JSC::RuntimeFlags runtimeFlags)
 {
     ASSERT(isMainThread());
 
     // We don't currently support nested workers, so workers can only be created from documents.
     ASSERT_WITH_SECURITY_IMPLICATION(context.isDocument());
 
-    auto worker = adoptRef(*new Worker(context));
+    auto worker = adoptRef(*new Worker(context, runtimeFlags));
 
     worker->suspendIfNeeded();
 
@@ -154,7 +155,7 @@ void Worker::notifyFinished()
         dispatchEvent(Event::create(eventNames().errorEvent, false, true));
     else {
         const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders = m_contentSecurityPolicyResponseHeaders ? m_contentSecurityPolicyResponseHeaders.value() : scriptExecutionContext()->contentSecurityPolicy()->responseHeaders();
-        m_contextProxy->startWorkerGlobalScope(m_scriptLoader->url(), scriptExecutionContext()->userAgent(m_scriptLoader->url()), m_scriptLoader->script(), contentSecurityPolicyResponseHeaders, m_shouldBypassMainWorldContentSecurityPolicy);
+        m_contextProxy->startWorkerGlobalScope(m_scriptLoader->url(), scriptExecutionContext()->userAgent(m_scriptLoader->url()), m_scriptLoader->script(), contentSecurityPolicyResponseHeaders, m_shouldBypassMainWorldContentSecurityPolicy, m_runtimeFlags);
         InspectorInstrumentation::scriptImported(scriptExecutionContext(), m_scriptLoader->identifier(), m_scriptLoader->script());
     }
     m_scriptLoader = nullptr;
index 0840696..3bf31e8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008, 2010, 2016 Apple Inc. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,6 +31,7 @@
 #include "EventTarget.h"
 #include "MessagePort.h"
 #include "WorkerScriptLoaderClient.h"
+#include <runtime/RuntimeFlags.h>
 #include <wtf/Optional.h>
 #include <wtf/text/AtomicStringHash.h>
 
@@ -42,7 +43,7 @@ class WorkerScriptLoader;
 
 class Worker final : public AbstractWorker, public ActiveDOMObject, private WorkerScriptLoaderClient {
 public:
-    static ExceptionOr<Ref<Worker>> create(ScriptExecutionContext&, const String& url);
+    static ExceptionOr<Ref<Worker>> create(ScriptExecutionContext&, const String& url, JSC::RuntimeFlags);
     virtual ~Worker();
 
     ExceptionOr<void> postMessage(RefPtr<SerializedScriptValue>&& message, Vector<RefPtr<MessagePort>>&&);
@@ -54,7 +55,7 @@ public:
     ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
 
 private:
-    explicit Worker(ScriptExecutionContext&);
+    explicit Worker(ScriptExecutionContext&, JSC::RuntimeFlags);
 
     EventTargetInterface eventTargetInterface() const final { return WorkerEventTargetInterfaceType; }
 
@@ -73,6 +74,7 @@ private:
     WorkerGlobalScopeProxy* m_contextProxy; // The proxy outlives the worker to perform thread shutdown.
     Optional<ContentSecurityPolicyResponseHeaders> m_contentSecurityPolicyResponseHeaders;
     bool m_shouldBypassMainWorldContentSecurityPolicy { false };
+    JSC::RuntimeFlags m_runtimeFlags;
 };
 
 } // namespace WebCore
index dd7d00f..16f9723 100644 (file)
@@ -48,7 +48,7 @@ namespace WebCore {
 
         virtual ~WorkerGlobalScopeProxy() { }
 
-        virtual void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy) = 0;
+        virtual void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, JSC::RuntimeFlags) = 0;
 
         virtual void terminateWorkerGlobalScope() = 0;
 
index aa14b7f..9bd2ed8 100644 (file)
@@ -74,7 +74,7 @@ WorkerMessagingProxy::~WorkerMessagingProxy()
         || (is<WorkerGlobalScope>(*m_scriptExecutionContext) && currentThread() == downcast<WorkerGlobalScope>(*m_scriptExecutionContext).thread().threadID()));
 }
 
-void WorkerMessagingProxy::startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy)
+void WorkerMessagingProxy::startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, JSC::RuntimeFlags runtimeFlags)
 {
     // FIXME: This need to be revisited when we support nested worker one day
     ASSERT(m_scriptExecutionContext);
@@ -93,7 +93,7 @@ void WorkerMessagingProxy::startWorkerGlobalScope(const URL& scriptURL, const St
     SocketProvider* socketProvider = nullptr;
 #endif
 
-    RefPtr<DedicatedWorkerThread> thread = DedicatedWorkerThread::create(scriptURL, userAgent, sourceCode, *this, *this, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, document.topOrigin(), proxy, socketProvider);
+    RefPtr<DedicatedWorkerThread> thread = DedicatedWorkerThread::create(scriptURL, userAgent, sourceCode, *this, *this, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, document.topOrigin(), proxy, socketProvider, runtimeFlags);
 
     workerThreadCreated(thread);
     thread->start();
index b0d43cb..a2ec4ac 100644 (file)
@@ -50,7 +50,7 @@ namespace WebCore {
 
         // Implementations of WorkerGlobalScopeProxy.
         // (Only use these methods in the worker object thread.)
-        void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy) override;
+        void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, JSC::RuntimeFlags) override;
         void terminateWorkerGlobalScope() override;
         void postMessageToWorkerGlobalScope(RefPtr<SerializedScriptValue>&&, std::unique_ptr<MessagePortChannelArray>) override;
         bool hasPendingActivity() const override;
index 0fb4c87..573894c 100644 (file)
@@ -94,10 +94,11 @@ WorkerThreadStartupData::WorkerThreadStartupData(const URL& scriptURL, const Str
 {
 }
 
-WorkerThread::WorkerThread(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider)
+WorkerThread::WorkerThread(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin, IDBClient::IDBConnectionProxy* connectionProxy, SocketProvider* socketProvider, JSC::RuntimeFlags runtimeFlags)
     : m_threadID(0)
     , m_workerLoaderProxy(workerLoaderProxy)
     , m_workerReportingProxy(workerReportingProxy)
+    , m_runtimeFlags(runtimeFlags)
     , m_startupData(std::make_unique<WorkerThreadStartupData>(scriptURL, userAgent, sourceCode, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, topOrigin))
 #if ENABLE(INDEXED_DATABASE)
     , m_idbConnectionProxy(connectionProxy)
index c711afe..27f3385 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "WorkerRunLoop.h"
 #include <memory>
+#include <runtime/RuntimeFlags.h>
 #include <wtf/Forward.h>
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
@@ -76,9 +77,11 @@ public:
 
     void startRunningDebuggerTasks();
     void stopRunningDebuggerTasks();
+    
+    JSC::RuntimeFlags runtimeFlags() const { return m_runtimeFlags; }
 
 protected:
-    WorkerThread(const URL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerReportingProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*);
+    WorkerThread(const URL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerReportingProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin, IDBClient::IDBConnectionProxy*, SocketProvider*, JSC::RuntimeFlags);
 
     // Factory method for creating a new worker context for the thread.
     virtual Ref<WorkerGlobalScope> createWorkerGlobalScope(const URL&, const String& userAgent, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, PassRefPtr<SecurityOrigin> topOrigin) = 0;
@@ -100,6 +103,7 @@ private:
     WorkerRunLoop m_runLoop;
     WorkerLoaderProxy& m_workerLoaderProxy;
     WorkerReportingProxy& m_workerReportingProxy;
+    JSC::RuntimeFlags m_runtimeFlags;
     bool m_pausedForDebugger { false };
 
     RefPtr<WorkerGlobalScope> m_workerGlobalScope;
index cd7dd5a..59a3fc2 100644 (file)
@@ -1,3 +1,14 @@
+2016-10-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should support SharedArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=163986
+
+        Reviewed by Keith Miller.
+        
+        Support the RuntimeFlag.
+
+        * WebView/WebPreferencesPrivate.h:
+
 2016-10-31  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [WK1] Candidate visibility should not update as a result of selection during a dictionary lookup
index 1e83056..ce3edf0 100644 (file)
@@ -53,7 +53,8 @@ typedef enum {
 } WebStorageBlockingPolicy;
 
 typedef enum {
-    WebKitJavaScriptRuntimeFlagsAllEnabled = 0
+    WebKitJavaScriptRuntimeFlagsSharedArrayBufferEnabled = 1u << 0,
+    WebKitJavaScriptRuntimeFlagsAllEnabled = WebKitJavaScriptRuntimeFlagsSharedArrayBufferEnabled
 } WebKitJavaScriptRuntimeFlags;
 
 extern NSString *WebPreferencesChangedNotification;
index 551eb1f..013c56e 100644 (file)
@@ -1,3 +1,14 @@
+2016-10-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should support SharedArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=163986
+
+        Reviewed by Keith Miller.
+
+        Support the RuntimeFlag.
+
+        * Interfaces/IWebPreferencesPrivate.idl:
+
 2016-10-31  Joseph Pecoraro  <pecoraro@apple.com>
 
         Use #pragma once in WebCore
index d65d587..bfa698c 100644 (file)
@@ -32,7 +32,8 @@ import "ocidl.idl";
 #endif
 
 typedef enum WebKitJavaScriptRuntimeFlags {
-    WebKitJavaScriptRuntimeFlagsAllEnabled = 0
+    WebKitJavaScriptRuntimeFlagsSharedArrayBufferEnabled = 1,
+    WebKitJavaScriptRuntimeFlagsAllEnabled = 1
 } WebKitJavaScriptRuntimeFlags;
 
 [
@@ -191,4 +192,4 @@ interface IWebPreferencesPrivate3 : IWebPreferencesPrivate2
 interface IWebPreferencesPrivate4 : IWebPreferencesPrivate3
 {
     HRESULT setApplicationId([in] BSTR applicationId);
-}
\ No newline at end of file
+}
index a76d730..59e41fa 100644 (file)
@@ -1,3 +1,17 @@
+2016-10-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should support SharedArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=163986
+
+        Reviewed by Keith Miller.
+        
+        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):
+
 2016-10-31  Brady Eidson  <beidson@apple.com>
 
         IndexedDB 2.0: Support IDBObjectStore getAll/getAllKeys.
index 070037d..a9aa063 100644 (file)
@@ -50,7 +50,8 @@ enum WKEditableLinkBehavior {
 typedef enum WKEditableLinkBehavior WKEditableLinkBehavior;
 
 enum WKJavaScriptRuntimeFlags {
-    kWKJavaScriptRuntimeFlagsAllEnabled = 0
+    kWKJavaScriptRuntimeFlagsSharedArrayBufferEnabled = 1 << 0,
+    kWKJavaScriptRuntimeFlagsAllEnabled = kWKJavaScriptRuntimeFlagsSharedArrayBufferEnabled
 };
 typedef unsigned WKJavaScriptRuntimeFlagSet;
 
index e141bfb..7b956f2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -43,7 +43,8 @@ typedef NS_OPTIONS(NSUInteger, _WKDebugOverlayRegions) {
 } WK_API_AVAILABLE(macosx(10.11), ios(9.0));
 
 typedef NS_OPTIONS(NSUInteger, _WKJavaScriptRuntimeFlags) {
-    _WKJavaScriptRuntimeFlagsAllEnabled = 0
+    _WKJavaScriptRuntimeFlagsSharedArrayBufferEnabled = 1 << 0,
+    _WKJavaScriptRuntimeFlagsAllEnabled = _WKJavaScriptRuntimeFlagsSharedArrayBufferEnabled
 } WK_API_AVAILABLE(macosx(10.11), ios(9.0));
 
 @class _WKExperimentalFeature;
index 8154cc5..295ec6f 100644 (file)
@@ -572,7 +572,7 @@ uint64_t InjectedBundle::webNotificationID(JSContextRef jsContext, JSValueRef js
 PassRefPtr<API::Data> InjectedBundle::createWebDataFromUint8Array(JSContextRef context, JSValueRef data)
 {
     JSC::ExecState* execState = toJS(context);
-    RefPtr<Uint8Array> arrayData = WebCore::toUint8Array(toJS(execState, data));
+    RefPtr<Uint8Array> arrayData = WebCore::toUnsharedUint8Array(toJS(execState, data));
     return API::Data::create(static_cast<unsigned char*>(arrayData->baseAddress()), arrayData->byteLength());
 }
 
index 6d5627b..8263405 100644 (file)
@@ -1,3 +1,15 @@
+2016-10-29  Filip Pizlo  <fpizlo@apple.com>
+
+        JSC should support SharedArrayBuffer
+        https://bugs.webkit.org/show_bug.cgi?id=163986
+
+        Reviewed by Keith Miller.
+        
+        Use the right kind of typed array API.
+
+        * DumpRenderTree/TestRunner.cpp:
+        (setAudioResultCallback):
+
 2016-10-31  Simon Fraser  <simon.fraser@apple.com>
 
         Make UIScriptController::zoomToScale() work on Mac WK1 and WK2
index ef2d158..10ee02b 100644 (file)
@@ -340,7 +340,7 @@ static JSValueRef setAudioResultCallback(JSContextRef context, JSObjectRef funct
     // FIXME (123058): Use a JSC API to get buffer contents once such is exposed.
     JSC::JSArrayBufferView* jsBufferView = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(toJS(toJS(context), arguments[0]));
     ASSERT(jsBufferView);
-    RefPtr<JSC::ArrayBufferView> bufferView = jsBufferView->impl();
+    RefPtr<JSC::ArrayBufferView> bufferView = jsBufferView->unsharedImpl();
     const char* buffer = static_cast<const char*>(bufferView->baseAddress());
     std::vector<char> audioData(buffer, buffer + bufferView->byteLength());