| /* |
| * Copyright (C) 2016-2021 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 "FrameTracers.h" |
| #include "JSCInlines.h" |
| #include "JSTypedArrays.h" |
| #include "ReleaseHeapAccessScope.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(notify, Notify, 3) \ |
| macro(or, Or, 3) \ |
| macro(store, Store, 3) \ |
| macro(sub, Sub, 3) \ |
| macro(wait, Wait, 4) \ |
| macro(xor, Xor, 3) |
| |
| #define DECLARE_FUNC_PROTO(lowerName, upperName, count) \ |
| static JSC_DECLARE_HOST_FUNCTION(atomicsFunc ## upperName); |
| FOR_EACH_ATOMICS_FUNC(DECLARE_FUNC_PROTO) |
| #undef DECLARE_FUNC_PROTO |
| |
| const ClassInfo AtomicsObject::s_info = { "Atomics"_s, &Base::s_info, nullptr, nullptr, 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)) 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 ""_s), count, atomicsFunc ## upperName, Atomics ## upperName ## Intrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum)); |
| FOR_EACH_ATOMICS_FUNC(PUT_DIRECT_NATIVE_FUNC) |
| #undef PUT_DIRECT_NATIVE_FUNC |
| |
| JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); |
| } |
| |
| namespace { |
| |
| template<typename Adaptor, typename Func> |
| EncodedJSValue atomicReadModifyWriteCase(JSGlobalObject* globalObject, VM& vm, const JSValue* args, JSArrayBufferView* typedArrayView, unsigned accessIndex, const Func& func) |
| { |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| |
| JSGenericTypedArrayView<Adaptor>* typedArray = jsCast<JSGenericTypedArrayView<Adaptor>*>(typedArrayView); |
| |
| typename Adaptor::Type extraArgs[Func::numExtraArgs + 1]; // Add 1 to avoid 0 size array error in VS. |
| for (unsigned i = 0; i < Func::numExtraArgs; ++i) { |
| auto value = toNativeFromValue<Adaptor>(globalObject, args[2 + i]); |
| RETURN_IF_EXCEPTION(scope, { }); |
| extraArgs[i] = value; |
| } |
| |
| if (typedArray->isDetached()) |
| return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage); |
| |
| auto result = func(typedArray->typedVector() + accessIndex, extraArgs); |
| RELEASE_AND_RETURN(scope, JSValue::encode(Adaptor::toJSValue(globalObject, result))); |
| } |
| |
| static unsigned validateAtomicAccess(JSGlobalObject* globalObject, VM& vm, JSArrayBufferView* typedArrayView, JSValue accessIndexValue) |
| { |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| unsigned accessIndex = 0; |
| if (LIKELY(accessIndexValue.isUInt32())) |
| accessIndex = accessIndexValue.asUInt32(); |
| else { |
| accessIndex = accessIndexValue.toIndex(globalObject, "accessIndex"); |
| RETURN_IF_EXCEPTION(scope, 0); |
| } |
| |
| if (accessIndex >= typedArrayView->length()) { |
| throwRangeError(globalObject, scope, "Access index out of bounds for atomic access."_s); |
| return 0; |
| } |
| |
| return accessIndex; |
| } |
| |
| enum class TypedArrayOperationMode { ReadWrite, Wait }; |
| template<TypedArrayOperationMode mode> |
| inline JSArrayBufferView* validateIntegerTypedArray(JSGlobalObject* globalObject, JSValue typedArrayValue) |
| { |
| VM& vm = globalObject->vm(); |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| |
| JSArrayBufferView* typedArray = validateTypedArray(globalObject, typedArrayValue); |
| RETURN_IF_EXCEPTION(scope, { }); |
| |
| if constexpr (mode == TypedArrayOperationMode::Wait) { |
| switch (typedArray->type()) { |
| case Int32ArrayType: |
| case BigInt64ArrayType: |
| break; |
| default: |
| throwTypeError(globalObject, scope, "Typed array argument must be an Int32Array or BigInt64Array."_s); |
| return { }; |
| } |
| } else { |
| switch (typedArray->type()) { |
| case Int8ArrayType: |
| case Int16ArrayType: |
| case Int32ArrayType: |
| case Uint8ArrayType: |
| case Uint16ArrayType: |
| case Uint32ArrayType: |
| case BigInt64ArrayType: |
| case BigUint64ArrayType: |
| break; |
| default: |
| throwTypeError(globalObject, scope, "Typed array argument must be an Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, Uint32Array, BigInt64Array, or BigUint64Array."_s); |
| return { }; |
| } |
| } |
| return typedArray; |
| } |
| |
| template<typename Func> |
| EncodedJSValue atomicReadModifyWrite(JSGlobalObject* globalObject, VM& vm, const JSValue* args, const Func& func) |
| { |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| |
| JSArrayBufferView* typedArrayView = validateIntegerTypedArray<TypedArrayOperationMode::ReadWrite>(globalObject, args[0]); |
| RETURN_IF_EXCEPTION(scope, { }); |
| |
| unsigned accessIndex = validateAtomicAccess(globalObject, vm, typedArrayView, args[1]); |
| RETURN_IF_EXCEPTION(scope, { }); |
| |
| scope.release(); |
| switch (typedArrayView->type()) { |
| case Int8ArrayType: |
| return atomicReadModifyWriteCase<Int8Adaptor>(globalObject, vm, args, typedArrayView, accessIndex, func); |
| case Int16ArrayType: |
| return atomicReadModifyWriteCase<Int16Adaptor>(globalObject, vm, args, typedArrayView, accessIndex, func); |
| case Int32ArrayType: |
| return atomicReadModifyWriteCase<Int32Adaptor>(globalObject, vm, args, typedArrayView, accessIndex, func); |
| case Uint8ArrayType: |
| return atomicReadModifyWriteCase<Uint8Adaptor>(globalObject, vm, args, typedArrayView, accessIndex, func); |
| case Uint16ArrayType: |
| return atomicReadModifyWriteCase<Uint16Adaptor>(globalObject, vm, args, typedArrayView, accessIndex, func); |
| case Uint32ArrayType: |
| return atomicReadModifyWriteCase<Uint32Adaptor>(globalObject, vm, args, typedArrayView, accessIndex, func); |
| case BigInt64ArrayType: |
| return atomicReadModifyWriteCase<BigInt64Adaptor>(globalObject, vm, args, typedArrayView, accessIndex, func); |
| case BigUint64ArrayType: |
| return atomicReadModifyWriteCase<BigUint64Adaptor>(globalObject, vm, args, typedArrayView, accessIndex, func); |
| default: |
| RELEASE_ASSERT_NOT_REACHED(); |
| return JSValue::encode(jsUndefined()); |
| } |
| } |
| |
| template<typename Func> |
| EncodedJSValue atomicReadModifyWrite(JSGlobalObject* globalObject, CallFrame* callFrame, const Func& func) |
| { |
| JSValue args[2 + Func::numExtraArgs]; |
| for (unsigned i = 2 + Func::numExtraArgs; i--;) |
| args[i] = callFrame->argument(i); |
| return atomicReadModifyWrite(globalObject, globalObject->vm(), args, func); |
| } |
| |
| struct AddFunc { |
| static constexpr unsigned numExtraArgs = 1; |
| |
| template<typename T> |
| T operator()(T* ptr, const T* args) const |
| { |
| return WTF::atomicExchangeAdd(ptr, args[0]); |
| } |
| }; |
| |
| struct AndFunc { |
| static constexpr unsigned numExtraArgs = 1; |
| |
| template<typename T> |
| T operator()(T* ptr, const T* args) const |
| { |
| return WTF::atomicExchangeAnd(ptr, args[0]); |
| } |
| }; |
| |
| struct CompareExchangeFunc { |
| static constexpr unsigned numExtraArgs = 2; |
| |
| template<typename T> |
| T operator()(T* ptr, const T* args) const |
| { |
| T expected = args[0]; |
| T newValue = args[1]; |
| return WTF::atomicCompareExchangeStrong(ptr, expected, newValue); |
| } |
| }; |
| |
| struct ExchangeFunc { |
| static constexpr unsigned numExtraArgs = 1; |
| |
| template<typename T> |
| T operator()(T* ptr, const T* args) const |
| { |
| return WTF::atomicExchange(ptr, args[0]); |
| } |
| }; |
| |
| struct LoadFunc { |
| static constexpr unsigned numExtraArgs = 0; |
| |
| template<typename T> |
| T operator()(T* ptr, const T*) const |
| { |
| return WTF::atomicLoadFullyFenced(ptr); |
| } |
| }; |
| |
| struct OrFunc { |
| static constexpr unsigned numExtraArgs = 1; |
| |
| template<typename T> |
| T operator()(T* ptr, const T* args) const |
| { |
| return WTF::atomicExchangeOr(ptr, args[0]); |
| } |
| }; |
| |
| struct SubFunc { |
| static constexpr unsigned numExtraArgs = 1; |
| |
| template<typename T> |
| T operator()(T* ptr, const T* args) const |
| { |
| return WTF::atomicExchangeSub(ptr, args[0]); |
| } |
| }; |
| |
| struct XorFunc { |
| static constexpr unsigned numExtraArgs = 1; |
| |
| template<typename T> |
| T operator()(T* ptr, const T* args) const |
| { |
| return WTF::atomicExchangeXor(ptr, args[0]); |
| } |
| }; |
| |
| EncodedJSValue isLockFree(JSGlobalObject* globalObject, JSValue arg) |
| { |
| VM& vm = globalObject->vm(); |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| |
| int32_t size = arg.toInt32(globalObject); |
| RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); |
| |
| bool result; |
| switch (size) { |
| case 1: |
| case 2: |
| case 4: |
| case 8: |
| result = true; |
| break; |
| default: |
| result = false; |
| break; |
| } |
| return JSValue::encode(jsBoolean(result)); |
| } |
| |
| template<typename Adaptor> |
| EncodedJSValue atomicStoreCase(JSGlobalObject* globalObject, VM& vm, JSValue operand, JSArrayBufferView* typedArrayView, unsigned accessIndex) |
| { |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| |
| JSGenericTypedArrayView<Adaptor>* typedArray = jsCast<JSGenericTypedArrayView<Adaptor>*>(typedArrayView); |
| |
| typename Adaptor::Type extraArg; |
| JSValue value; |
| if constexpr (std::is_same_v<Adaptor, BigInt64Adaptor> || std::is_same_v<Adaptor, BigUint64Adaptor>) { |
| value = operand.toBigInt(globalObject); |
| RETURN_IF_EXCEPTION(scope, { }); |
| extraArg = toNativeFromValue<Adaptor>(globalObject, value); |
| RETURN_IF_EXCEPTION(scope, { }); |
| } else { |
| value = jsNumber(operand.toIntegerOrInfinity(globalObject)); |
| RETURN_IF_EXCEPTION(scope, { }); |
| extraArg = toNativeFromValue<Adaptor>(globalObject, value); |
| RETURN_IF_EXCEPTION(scope, { }); |
| } |
| |
| if (typedArray->isDetached()) |
| return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage); |
| |
| WTF::atomicStoreFullyFenced(typedArray->typedVector() + accessIndex, extraArg); |
| RELEASE_AND_RETURN(scope, JSValue::encode(value)); |
| } |
| |
| EncodedJSValue atomicStore(JSGlobalObject* globalObject, VM& vm, JSValue base, JSValue index, JSValue operand) |
| { |
| // https://tc39.es/ecma262/#sec-atomics.store |
| |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| |
| JSArrayBufferView* typedArrayView = validateIntegerTypedArray<TypedArrayOperationMode::ReadWrite>(globalObject, base); |
| RETURN_IF_EXCEPTION(scope, { }); |
| |
| unsigned accessIndex = validateAtomicAccess(globalObject, vm, typedArrayView, index); |
| RETURN_IF_EXCEPTION(scope, { }); |
| |
| scope.release(); |
| switch (typedArrayView->type()) { |
| case Int8ArrayType: |
| return atomicStoreCase<Int8Adaptor>(globalObject, vm, operand, typedArrayView, accessIndex); |
| case Int16ArrayType: |
| return atomicStoreCase<Int16Adaptor>(globalObject, vm, operand, typedArrayView, accessIndex); |
| case Int32ArrayType: |
| return atomicStoreCase<Int32Adaptor>(globalObject, vm, operand, typedArrayView, accessIndex); |
| case Uint8ArrayType: |
| return atomicStoreCase<Uint8Adaptor>(globalObject, vm, operand, typedArrayView, accessIndex); |
| case Uint16ArrayType: |
| return atomicStoreCase<Uint16Adaptor>(globalObject, vm, operand, typedArrayView, accessIndex); |
| case Uint32ArrayType: |
| return atomicStoreCase<Uint32Adaptor>(globalObject, vm, operand, typedArrayView, accessIndex); |
| case BigInt64ArrayType: |
| return atomicStoreCase<BigInt64Adaptor>(globalObject, vm, operand, typedArrayView, accessIndex); |
| case BigUint64ArrayType: |
| return atomicStoreCase<BigUint64Adaptor>(globalObject, vm, operand, typedArrayView, accessIndex); |
| default: |
| RELEASE_ASSERT_NOT_REACHED(); |
| return { }; |
| } |
| } |
| |
| } // anonymous namespace |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncAdd, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| return atomicReadModifyWrite(globalObject, callFrame, AddFunc()); |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncAnd, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| return atomicReadModifyWrite(globalObject, callFrame, AndFunc()); |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncCompareExchange, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| return atomicReadModifyWrite(globalObject, callFrame, CompareExchangeFunc()); |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncExchange, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| return atomicReadModifyWrite(globalObject, callFrame, ExchangeFunc()); |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncIsLockFree, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| return isLockFree(globalObject, callFrame->argument(0)); |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncLoad, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| return atomicReadModifyWrite(globalObject, callFrame, LoadFunc()); |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncOr, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| return atomicReadModifyWrite(globalObject, callFrame, OrFunc()); |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncStore, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| return atomicStore(globalObject, globalObject->vm(), callFrame->argument(0), callFrame->argument(1), callFrame->argument(2)); |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncSub, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| return atomicReadModifyWrite(globalObject, callFrame, SubFunc()); |
| } |
| |
| template<typename ValueType, typename JSArrayType> |
| JSValue atomicsWaitImpl(JSGlobalObject* globalObject, JSArrayType* typedArray, unsigned accessIndex, ValueType expectedValue, JSValue timeoutValue) |
| { |
| VM& vm = globalObject->vm(); |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| |
| ValueType* ptr = typedArray->typedVector() + accessIndex; |
| |
| double timeoutInMilliseconds = timeoutValue.toNumber(globalObject); |
| RETURN_IF_EXCEPTION(scope, { }); |
| Seconds timeout = Seconds::infinity(); |
| if (!std::isnan(timeoutInMilliseconds)) |
| timeout = std::max(Seconds::fromMilliseconds(timeoutInMilliseconds), 0_s); |
| |
| if (!vm.m_typedArrayController->isAtomicsWaitAllowedOnCurrentThread()) { |
| throwTypeError(globalObject, scope, "Atomics.wait cannot be called from the current thread."_s); |
| return { }; |
| } |
| |
| bool didPassValidation = false; |
| ParkingLot::ParkResult result; |
| { |
| ReleaseHeapAccessScope releaseHeapAccessScope(vm.heap); |
| result = ParkingLot::parkConditionally( |
| ptr, |
| [&] () -> bool { |
| didPassValidation = WTF::atomicLoad(ptr) == expectedValue; |
| return didPassValidation; |
| }, |
| [] () { }, |
| MonotonicTime::now() + timeout); |
| } |
| if (!didPassValidation) |
| return vm.smallStrings.notEqualString(); |
| if (!result.wasUnparked) |
| return vm.smallStrings.timedOutString(); |
| return vm.smallStrings.okString(); |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncWait, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| VM& vm = globalObject->vm(); |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| |
| auto* typedArrayView = validateIntegerTypedArray<TypedArrayOperationMode::Wait>(globalObject, callFrame->argument(0)); |
| RETURN_IF_EXCEPTION(scope, { }); |
| |
| if (!typedArrayView->isShared()) |
| return throwVMTypeError(globalObject, scope, "Typed array for wait/notify must wrap a SharedArrayBuffer."_s); |
| |
| unsigned accessIndex = validateAtomicAccess(globalObject, vm, typedArrayView, callFrame->argument(1)); |
| RETURN_IF_EXCEPTION(scope, { }); |
| |
| switch (typedArrayView->type()) { |
| case Int32ArrayType: { |
| int32_t expectedValue = callFrame->argument(2).toInt32(globalObject); |
| RETURN_IF_EXCEPTION(scope, { }); |
| RELEASE_AND_RETURN(scope, JSValue::encode(atomicsWaitImpl<int32_t>(globalObject, jsCast<JSInt32Array*>(typedArrayView), accessIndex, expectedValue, callFrame->argument(3)))); |
| } |
| case BigInt64ArrayType: { |
| int64_t expectedValue = callFrame->argument(2).toBigInt64(globalObject); |
| RETURN_IF_EXCEPTION(scope, { }); |
| RELEASE_AND_RETURN(scope, JSValue::encode(atomicsWaitImpl<int64_t>(globalObject, jsCast<JSBigInt64Array*>(typedArrayView), accessIndex, expectedValue, callFrame->argument(3)))); |
| } |
| default: |
| RELEASE_ASSERT_NOT_REACHED(); |
| break; |
| } |
| return { }; |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncNotify, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| VM& vm = globalObject->vm(); |
| auto scope = DECLARE_THROW_SCOPE(vm); |
| |
| auto* typedArrayView = validateIntegerTypedArray<TypedArrayOperationMode::Wait>(globalObject, callFrame->argument(0)); |
| RETURN_IF_EXCEPTION(scope, { }); |
| |
| unsigned accessIndex = validateAtomicAccess(globalObject, vm, typedArrayView, callFrame->argument(1)); |
| RETURN_IF_EXCEPTION(scope, { }); |
| |
| JSValue countValue = callFrame->argument(2); |
| unsigned count = UINT_MAX; |
| if (!countValue.isUndefined()) { |
| double countInt = countValue.toIntegerOrInfinity(globalObject); |
| RETURN_IF_EXCEPTION(scope, { }); |
| double countDouble = std::max(0.0, countInt); |
| if (countDouble < UINT_MAX) |
| count = static_cast<unsigned>(countDouble); |
| } |
| |
| if (!typedArrayView->isShared()) |
| return JSValue::encode(jsNumber(0)); |
| |
| switch (typedArrayView->type()) { |
| case Int32ArrayType: { |
| int32_t* ptr = jsCast<JSInt32Array*>(typedArrayView)->typedVector() + accessIndex; |
| return JSValue::encode(jsNumber(ParkingLot::unparkCount(ptr, count))); |
| } |
| case BigInt64ArrayType: { |
| int64_t* ptr = jsCast<JSBigInt64Array*>(typedArrayView)->typedVector() + accessIndex; |
| return JSValue::encode(jsNumber(ParkingLot::unparkCount(ptr, count))); |
| } |
| default: |
| RELEASE_ASSERT_NOT_REACHED(); |
| break; |
| } |
| return { }; |
| } |
| |
| JSC_DEFINE_HOST_FUNCTION(atomicsFuncXor, (JSGlobalObject* globalObject, CallFrame* callFrame)) |
| { |
| return atomicReadModifyWrite(globalObject, callFrame, XorFunc()); |
| } |
| |
| IGNORE_WARNINGS_BEGIN("frame-address") |
| |
| JSC_DEFINE_JIT_OPERATION(operationAtomicsAdd, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) |
| { |
| VM& vm = globalObject->vm(); |
| CallFrame* callFrame = DECLARE_CALL_FRAME(vm); |
| JITOperationPrologueCallFrameTracer tracer(vm, callFrame); |
| JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; |
| return atomicReadModifyWrite(globalObject, vm, args, AddFunc()); |
| } |
| |
| JSC_DEFINE_JIT_OPERATION(operationAtomicsAnd, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) |
| { |
| VM& vm = globalObject->vm(); |
| CallFrame* callFrame = DECLARE_CALL_FRAME(vm); |
| JITOperationPrologueCallFrameTracer tracer(vm, callFrame); |
| JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; |
| return atomicReadModifyWrite(globalObject, vm, args, AndFunc()); |
| } |
| |
| JSC_DEFINE_JIT_OPERATION(operationAtomicsCompareExchange, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue expected, EncodedJSValue newValue)) |
| { |
| VM& vm = globalObject->vm(); |
| CallFrame* callFrame = DECLARE_CALL_FRAME(vm); |
| JITOperationPrologueCallFrameTracer tracer(vm, callFrame); |
| JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(expected), JSValue::decode(newValue)}; |
| return atomicReadModifyWrite(globalObject, vm, args, CompareExchangeFunc()); |
| } |
| |
| JSC_DEFINE_JIT_OPERATION(operationAtomicsExchange, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) |
| { |
| VM& vm = globalObject->vm(); |
| CallFrame* callFrame = DECLARE_CALL_FRAME(vm); |
| JITOperationPrologueCallFrameTracer tracer(vm, callFrame); |
| JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; |
| return atomicReadModifyWrite(globalObject, vm, args, ExchangeFunc()); |
| } |
| |
| JSC_DEFINE_JIT_OPERATION(operationAtomicsIsLockFree, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue size)) |
| { |
| VM& vm = globalObject->vm(); |
| CallFrame* callFrame = DECLARE_CALL_FRAME(vm); |
| JITOperationPrologueCallFrameTracer tracer(vm, callFrame); |
| return isLockFree(globalObject, JSValue::decode(size)); |
| } |
| |
| JSC_DEFINE_JIT_OPERATION(operationAtomicsLoad, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index)) |
| { |
| VM& vm = globalObject->vm(); |
| CallFrame* callFrame = DECLARE_CALL_FRAME(vm); |
| JITOperationPrologueCallFrameTracer tracer(vm, callFrame); |
| JSValue args[] = {JSValue::decode(base), JSValue::decode(index)}; |
| return atomicReadModifyWrite(globalObject, vm, args, LoadFunc()); |
| } |
| |
| JSC_DEFINE_JIT_OPERATION(operationAtomicsOr, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) |
| { |
| VM& vm = globalObject->vm(); |
| CallFrame* callFrame = DECLARE_CALL_FRAME(vm); |
| JITOperationPrologueCallFrameTracer tracer(vm, callFrame); |
| JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; |
| return atomicReadModifyWrite(globalObject, vm, args, OrFunc()); |
| } |
| |
| JSC_DEFINE_JIT_OPERATION(operationAtomicsStore, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) |
| { |
| VM& vm = globalObject->vm(); |
| CallFrame* callFrame = DECLARE_CALL_FRAME(vm); |
| JITOperationPrologueCallFrameTracer tracer(vm, callFrame); |
| return atomicStore(globalObject, vm, JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)); |
| } |
| |
| JSC_DEFINE_JIT_OPERATION(operationAtomicsSub, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) |
| { |
| VM& vm = globalObject->vm(); |
| CallFrame* callFrame = DECLARE_CALL_FRAME(vm); |
| JITOperationPrologueCallFrameTracer tracer(vm, callFrame); |
| JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; |
| return atomicReadModifyWrite(globalObject, vm, args, SubFunc()); |
| } |
| |
| JSC_DEFINE_JIT_OPERATION(operationAtomicsXor, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) |
| { |
| VM& vm = globalObject->vm(); |
| CallFrame* callFrame = DECLARE_CALL_FRAME(vm); |
| JITOperationPrologueCallFrameTracer tracer(vm, callFrame); |
| JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; |
| return atomicReadModifyWrite(globalObject, vm, args, XorFunc()); |
| } |
| |
| IGNORE_WARNINGS_END |
| |
| } // namespace JSC |
| |