AtomicsObject.cpp
1 /* 2 * Copyright (C) 2016-2019 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "AtomicsObject.h" 28 29 #include "FrameTracers.h" 30 #include "JSCInlines.h" 31 #include "JSTypedArrays.h" 32 #include "ReleaseHeapAccessScope.h" 33 #include "TypedArrayController.h" 34 35 namespace JSC { 36 37 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(AtomicsObject); 38 39 #define FOR_EACH_ATOMICS_FUNC(macro) \ 40 macro(add, Add, 3) \ 41 macro(and, And, 3) \ 42 macro(compareExchange, CompareExchange, 4) \ 43 macro(exchange, Exchange, 3) \ 44 macro(isLockFree, IsLockFree, 1) \ 45 macro(load, Load, 2) \ 46 macro(notify, Notify, 3) \ 47 macro(or, Or, 3) \ 48 macro(store, Store, 3) \ 49 macro(sub, Sub, 3) \ 50 macro(wait, Wait, 4) \ 51 macro(xor, Xor, 3) 52 53 #define DECLARE_FUNC_PROTO(lowerName, upperName, count) \ 54 static JSC_DECLARE_HOST_FUNCTION(atomicsFunc ## upperName); 55 FOR_EACH_ATOMICS_FUNC(DECLARE_FUNC_PROTO) 56 #undef DECLARE_FUNC_PROTO 57 58 const ClassInfo AtomicsObject::s_info = { "Atomics", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(AtomicsObject) }; 59 60 AtomicsObject::AtomicsObject(VM& vm, Structure* structure) 61 : JSNonFinalObject(vm, structure) 62 { 63 } 64 65 AtomicsObject* AtomicsObject::create(VM& vm, JSGlobalObject* globalObject, Structure* structure) 66 { 67 AtomicsObject* object = new (NotNull, allocateCell<AtomicsObject>(vm.heap)) AtomicsObject(vm, structure); 68 object->finishCreation(vm, globalObject); 69 return object; 70 } 71 72 Structure* AtomicsObject::createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) 73 { 74 return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info()); 75 } 76 77 void AtomicsObject::finishCreation(VM& vm, JSGlobalObject* globalObject) 78 { 79 Base::finishCreation(vm); 80 ASSERT(inherits(vm, info())); 81 82 #define PUT_DIRECT_NATIVE_FUNC(lowerName, upperName, count) \ 83 putDirectNativeFunctionWithoutTransition(vm, globalObject, Identifier::fromString(vm, #lowerName), count, atomicsFunc ## upperName, Atomics ## upperName ## Intrinsic, static_cast<unsigned>(PropertyAttribute::DontEnum)); 84 FOR_EACH_ATOMICS_FUNC(PUT_DIRECT_NATIVE_FUNC) 85 #undef PUT_DIRECT_NATIVE_FUNC 86 87 JSC_TO_STRING_TAG_WITHOUT_TRANSITION(); 88 } 89 90 namespace { 91 92 template<typename Adaptor, typename Func> 93 EncodedJSValue atomicReadModifyWriteCase(JSGlobalObject* globalObject, const JSValue* args, ThrowScope& scope, JSArrayBufferView* typedArrayView, unsigned accessIndex, const Func& func) 94 { 95 JSGenericTypedArrayView<Adaptor>* typedArray = jsCast<JSGenericTypedArrayView<Adaptor>*>(typedArrayView); 96 97 double extraArgs[Func::numExtraArgs + 1]; // Add 1 to avoid 0 size array error in VS. 98 for (unsigned i = 0; i < Func::numExtraArgs; ++i) { 99 double value = args[2 + i].toIntegerOrInfinity(globalObject); 100 RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); 101 extraArgs[i] = value; 102 } 103 104 if (typedArray->isDetached()) 105 return throwVMTypeError(globalObject, scope, typedArrayBufferHasBeenDetachedErrorMessage); 106 107 return JSValue::encode(func(typedArray->typedVector() + accessIndex, extraArgs)); 108 } 109 110 static unsigned validateAtomicAccess(VM& vm, JSGlobalObject* globalObject, JSArrayBufferView* typedArrayView, JSValue accessIndexValue) 111 { 112 auto scope = DECLARE_THROW_SCOPE(vm); 113 unsigned accessIndex = 0; 114 if (LIKELY(accessIndexValue.isUInt32())) 115 accessIndex = accessIndexValue.asUInt32(); 116 else { 117 accessIndex = accessIndexValue.toIndex(globalObject, "accessIndex"); 118 RETURN_IF_EXCEPTION(scope, 0); 119 } 120 121 ASSERT(typedArrayView->length() <= static_cast<unsigned>(INT_MAX)); 122 if (accessIndex >= typedArrayView->length()) { 123 throwRangeError(globalObject, scope, "Access index out of bounds for atomic access."_s); 124 return 0; 125 } 126 127 return accessIndex; 128 } 129 130 static JSArrayBufferView* validateTypedArray(JSGlobalObject* globalObject, JSValue typedArrayValue) 131 { 132 VM& vm = globalObject->vm(); 133 auto scope = DECLARE_THROW_SCOPE(vm); 134 135 if (!typedArrayValue.isCell()) { 136 throwTypeError(globalObject, scope, "Argument needs to be a typed array."_s); 137 return nullptr; 138 } 139 140 JSCell* typedArrayCell = typedArrayValue.asCell(); 141 if (!isTypedView(typedArrayCell->classInfo(vm)->typedArrayStorageType)) { 142 throwTypeError(globalObject, scope, "Argument needs to be a typed array."_s); 143 return nullptr; 144 } 145 146 JSArrayBufferView* typedArray = jsCast<JSArrayBufferView*>(typedArrayCell); 147 if (typedArray->isDetached()) { 148 throwTypeError(globalObject, scope, "Argument typed array is detached."_s); 149 return nullptr; 150 } 151 return typedArray; 152 } 153 154 enum class TypedArrayOperationMode { Read, Write }; 155 template<TypedArrayOperationMode mode> 156 inline JSArrayBufferView* validateIntegerTypedArray(JSGlobalObject* globalObject, JSValue typedArrayValue) 157 { 158 VM& vm = globalObject->vm(); 159 auto scope = DECLARE_THROW_SCOPE(vm); 160 161 JSArrayBufferView* typedArray = validateTypedArray(globalObject, typedArrayValue); 162 RETURN_IF_EXCEPTION(scope, { }); 163 164 if constexpr (mode == TypedArrayOperationMode::Write) { 165 switch (typedArray->type()) { 166 case Int32ArrayType: 167 break; 168 default: 169 throwTypeError(globalObject, scope, "Typed array argument must be an Int32Array."_s); 170 return { }; 171 } 172 } else { 173 switch (typedArray->type()) { 174 case Int8ArrayType: 175 case Int16ArrayType: 176 case Int32ArrayType: 177 case Uint8ArrayType: 178 case Uint16ArrayType: 179 case Uint32ArrayType: 180 break; 181 default: 182 throwTypeError(globalObject, scope, "Typed array argument must be an Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, or Uint32Array."_s); 183 return { }; 184 } 185 } 186 return typedArray; 187 } 188 189 template<typename Func> 190 EncodedJSValue atomicReadModifyWrite(VM& vm, JSGlobalObject* globalObject, const JSValue* args, const Func& func) 191 { 192 auto scope = DECLARE_THROW_SCOPE(vm); 193 194 JSArrayBufferView* typedArrayView = validateIntegerTypedArray<TypedArrayOperationMode::Read>(globalObject, args[0]); 195 RETURN_IF_EXCEPTION(scope, { }); 196 197 unsigned accessIndex = validateAtomicAccess(vm, globalObject, typedArrayView, args[1]); 198 RETURN_IF_EXCEPTION(scope, { }); 199 200 switch (typedArrayView->type()) { 201 case Int8ArrayType: 202 return atomicReadModifyWriteCase<Int8Adaptor>(globalObject, args, scope, typedArrayView, accessIndex, func); 203 case Int16ArrayType: 204 return atomicReadModifyWriteCase<Int16Adaptor>(globalObject, args, scope, typedArrayView, accessIndex, func); 205 case Int32ArrayType: 206 return atomicReadModifyWriteCase<Int32Adaptor>(globalObject, args, scope, typedArrayView, accessIndex, func); 207 case Uint8ArrayType: 208 return atomicReadModifyWriteCase<Uint8Adaptor>(globalObject, args, scope, typedArrayView, accessIndex, func); 209 case Uint16ArrayType: 210 return atomicReadModifyWriteCase<Uint16Adaptor>(globalObject, args, scope, typedArrayView, accessIndex, func); 211 case Uint32ArrayType: 212 return atomicReadModifyWriteCase<Uint32Adaptor>(globalObject, args, scope, typedArrayView, accessIndex, func); 213 default: 214 RELEASE_ASSERT_NOT_REACHED(); 215 return JSValue::encode(jsUndefined()); 216 } 217 } 218 219 template<typename Func> 220 EncodedJSValue atomicReadModifyWrite(JSGlobalObject* globalObject, CallFrame* callFrame, const Func& func) 221 { 222 JSValue args[2 + Func::numExtraArgs]; 223 for (unsigned i = 2 + Func::numExtraArgs; i--;) 224 args[i] = callFrame->argument(i); 225 return atomicReadModifyWrite(globalObject->vm(), globalObject, args, func); 226 } 227 228 struct AddFunc { 229 static constexpr unsigned numExtraArgs = 1; 230 231 template<typename T> 232 JSValue operator()(T* ptr, const double* args) const 233 { 234 return jsNumber(WTF::atomicExchangeAdd(ptr, toInt32(args[0]))); 235 } 236 }; 237 238 struct AndFunc { 239 static constexpr unsigned numExtraArgs = 1; 240 241 template<typename T> 242 JSValue operator()(T* ptr, const double* args) const 243 { 244 return jsNumber(WTF::atomicExchangeAnd(ptr, toInt32(args[0]))); 245 } 246 }; 247 248 struct CompareExchangeFunc { 249 static constexpr unsigned numExtraArgs = 2; 250 251 template<typename T> 252 JSValue operator()(T* ptr, const double* args) const 253 { 254 T expected = static_cast<T>(toInt32(args[0])); 255 T newValue = static_cast<T>(toInt32(args[1])); 256 return jsNumber(WTF::atomicCompareExchangeStrong(ptr, expected, newValue)); 257 } 258 }; 259 260 struct ExchangeFunc { 261 static constexpr unsigned numExtraArgs = 1; 262 263 template<typename T> 264 JSValue operator()(T* ptr, const double* args) const 265 { 266 return jsNumber(WTF::atomicExchange(ptr, static_cast<T>(toInt32(args[0])))); 267 } 268 }; 269 270 struct LoadFunc { 271 static constexpr unsigned numExtraArgs = 0; 272 273 template<typename T> 274 JSValue operator()(T* ptr, const double*) const 275 { 276 return jsNumber(WTF::atomicLoadFullyFenced(ptr)); 277 } 278 }; 279 280 struct OrFunc { 281 static constexpr unsigned numExtraArgs = 1; 282 283 template<typename T> 284 JSValue operator()(T* ptr, const double* args) const 285 { 286 return jsNumber(WTF::atomicExchangeOr(ptr, toInt32(args[0]))); 287 } 288 }; 289 290 struct StoreFunc { 291 static constexpr unsigned numExtraArgs = 1; 292 293 template<typename T> 294 JSValue operator()(T* ptr, const double* args) const 295 { 296 double valueAsInt = args[0]; 297 T valueAsT = static_cast<T>(toInt32(valueAsInt)); 298 WTF::atomicStoreFullyFenced(ptr, valueAsT); 299 return jsNumber(valueAsInt); 300 } 301 }; 302 303 struct SubFunc { 304 static constexpr unsigned numExtraArgs = 1; 305 306 template<typename T> 307 JSValue operator()(T* ptr, const double* args) const 308 { 309 return jsNumber(WTF::atomicExchangeSub(ptr, toInt32(args[0]))); 310 } 311 }; 312 313 struct XorFunc { 314 static constexpr unsigned numExtraArgs = 1; 315 316 template<typename T> 317 JSValue operator()(T* ptr, const double* args) const 318 { 319 return jsNumber(WTF::atomicExchangeXor(ptr, toInt32(args[0]))); 320 } 321 }; 322 323 EncodedJSValue isLockFree(JSGlobalObject* globalObject, JSValue arg) 324 { 325 VM& vm = globalObject->vm(); 326 auto scope = DECLARE_THROW_SCOPE(vm); 327 328 int32_t size = arg.toInt32(globalObject); 329 RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); 330 331 bool result; 332 switch (size) { 333 case 1: 334 case 2: 335 case 4: 336 result = true; 337 break; 338 default: 339 result = false; 340 break; 341 } 342 return JSValue::encode(jsBoolean(result)); 343 } 344 345 } // anonymous namespace 346 347 JSC_DEFINE_HOST_FUNCTION(atomicsFuncAdd, (JSGlobalObject* globalObject, CallFrame* callFrame)) 348 { 349 return atomicReadModifyWrite(globalObject, callFrame, AddFunc()); 350 } 351 352 JSC_DEFINE_HOST_FUNCTION(atomicsFuncAnd, (JSGlobalObject* globalObject, CallFrame* callFrame)) 353 { 354 return atomicReadModifyWrite(globalObject, callFrame, AndFunc()); 355 } 356 357 JSC_DEFINE_HOST_FUNCTION(atomicsFuncCompareExchange, (JSGlobalObject* globalObject, CallFrame* callFrame)) 358 { 359 return atomicReadModifyWrite(globalObject, callFrame, CompareExchangeFunc()); 360 } 361 362 JSC_DEFINE_HOST_FUNCTION(atomicsFuncExchange, (JSGlobalObject* globalObject, CallFrame* callFrame)) 363 { 364 return atomicReadModifyWrite(globalObject, callFrame, ExchangeFunc()); 365 } 366 367 JSC_DEFINE_HOST_FUNCTION(atomicsFuncIsLockFree, (JSGlobalObject* globalObject, CallFrame* callFrame)) 368 { 369 return isLockFree(globalObject, callFrame->argument(0)); 370 } 371 372 JSC_DEFINE_HOST_FUNCTION(atomicsFuncLoad, (JSGlobalObject* globalObject, CallFrame* callFrame)) 373 { 374 return atomicReadModifyWrite(globalObject, callFrame, LoadFunc()); 375 } 376 377 JSC_DEFINE_HOST_FUNCTION(atomicsFuncOr, (JSGlobalObject* globalObject, CallFrame* callFrame)) 378 { 379 return atomicReadModifyWrite(globalObject, callFrame, OrFunc()); 380 } 381 382 JSC_DEFINE_HOST_FUNCTION(atomicsFuncStore, (JSGlobalObject* globalObject, CallFrame* callFrame)) 383 { 384 return atomicReadModifyWrite(globalObject, callFrame, StoreFunc()); 385 } 386 387 JSC_DEFINE_HOST_FUNCTION(atomicsFuncSub, (JSGlobalObject* globalObject, CallFrame* callFrame)) 388 { 389 return atomicReadModifyWrite(globalObject, callFrame, SubFunc()); 390 } 391 392 JSC_DEFINE_HOST_FUNCTION(atomicsFuncWait, (JSGlobalObject* globalObject, CallFrame* callFrame)) 393 { 394 VM& vm = globalObject->vm(); 395 auto scope = DECLARE_THROW_SCOPE(vm); 396 397 auto* typedArrayBuffer = validateIntegerTypedArray<TypedArrayOperationMode::Write>(globalObject, callFrame->argument(0)); 398 RETURN_IF_EXCEPTION(scope, { }); 399 auto* typedArray = jsCast<JSInt32Array*>(typedArrayBuffer); 400 401 if (!typedArray->isShared()) { 402 throwTypeError(globalObject, scope, "Typed array for wait/notify must wrap a SharedArrayBuffer."_s); 403 return JSValue::encode(jsUndefined()); 404 } 405 406 unsigned accessIndex = validateAtomicAccess(vm, globalObject, typedArray, callFrame->argument(1)); 407 RETURN_IF_EXCEPTION(scope, { }); 408 409 int32_t* ptr = typedArray->typedVector() + accessIndex; 410 411 int32_t expectedValue = callFrame->argument(2).toInt32(globalObject); 412 RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); 413 414 double timeoutInMilliseconds = callFrame->argument(3).toNumber(globalObject); 415 RETURN_IF_EXCEPTION(scope, JSValue::encode(jsUndefined())); 416 Seconds timeout = Seconds::infinity(); 417 if (!std::isnan(timeoutInMilliseconds)) 418 timeout = std::max(Seconds::fromMilliseconds(timeoutInMilliseconds), 0_s); 419 420 if (!vm.m_typedArrayController->isAtomicsWaitAllowedOnCurrentThread()) { 421 throwTypeError(globalObject, scope, "Atomics.wait cannot be called from the current thread."_s); 422 return JSValue::encode(jsUndefined()); 423 } 424 425 bool didPassValidation = false; 426 ParkingLot::ParkResult result; 427 { 428 ReleaseHeapAccessScope releaseHeapAccessScope(vm.heap); 429 result = ParkingLot::parkConditionally( 430 ptr, 431 [&] () -> bool { 432 didPassValidation = WTF::atomicLoad(ptr) == expectedValue; 433 return didPassValidation; 434 }, 435 [] () { }, 436 MonotonicTime::now() + timeout); 437 } 438 if (!didPassValidation) 439 return JSValue::encode(vm.smallStrings.notEqualString()); 440 if (!result.wasUnparked) 441 return JSValue::encode(vm.smallStrings.timedOutString()); 442 return JSValue::encode(vm.smallStrings.okString()); 443 } 444 445 JSC_DEFINE_HOST_FUNCTION(atomicsFuncNotify, (JSGlobalObject* globalObject, CallFrame* callFrame)) 446 { 447 VM& vm = globalObject->vm(); 448 auto scope = DECLARE_THROW_SCOPE(vm); 449 450 auto* typedArrayBuffer = validateIntegerTypedArray<TypedArrayOperationMode::Write>(globalObject, callFrame->argument(0)); 451 RETURN_IF_EXCEPTION(scope, { }); 452 auto* typedArray = jsCast<JSInt32Array*>(typedArrayBuffer); 453 454 unsigned accessIndex = validateAtomicAccess(vm, globalObject, typedArray, callFrame->argument(1)); 455 RETURN_IF_EXCEPTION(scope, { }); 456 457 JSValue countValue = callFrame->argument(2); 458 unsigned count = UINT_MAX; 459 if (!countValue.isUndefined()) { 460 double countInt = countValue.toIntegerOrInfinity(globalObject); 461 RETURN_IF_EXCEPTION(scope, { }); 462 double countDouble = std::max(0.0, countInt); 463 if (countDouble < UINT_MAX) 464 count = static_cast<unsigned>(countDouble); 465 } 466 467 if (!typedArray->isShared()) 468 return JSValue::encode(jsNumber(0)); 469 470 int32_t* ptr = typedArray->typedVector() + accessIndex; 471 return JSValue::encode(jsNumber(ParkingLot::unparkCount(ptr, count))); 472 } 473 474 JSC_DEFINE_HOST_FUNCTION(atomicsFuncXor, (JSGlobalObject* globalObject, CallFrame* callFrame)) 475 { 476 return atomicReadModifyWrite(globalObject, callFrame, XorFunc()); 477 } 478 479 IGNORE_WARNINGS_BEGIN("frame-address") 480 481 JSC_DEFINE_JIT_OPERATION(operationAtomicsAdd, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) 482 { 483 VM& vm = globalObject->vm(); 484 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 485 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 486 JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; 487 return atomicReadModifyWrite(vm, globalObject, args, AddFunc()); 488 } 489 490 JSC_DEFINE_JIT_OPERATION(operationAtomicsAnd, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) 491 { 492 VM& vm = globalObject->vm(); 493 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 494 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 495 JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; 496 return atomicReadModifyWrite(vm, globalObject, args, AndFunc()); 497 } 498 499 JSC_DEFINE_JIT_OPERATION(operationAtomicsCompareExchange, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue expected, EncodedJSValue newValue)) 500 { 501 VM& vm = globalObject->vm(); 502 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 503 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 504 JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(expected), JSValue::decode(newValue)}; 505 return atomicReadModifyWrite(vm, globalObject, args, CompareExchangeFunc()); 506 } 507 508 JSC_DEFINE_JIT_OPERATION(operationAtomicsExchange, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) 509 { 510 VM& vm = globalObject->vm(); 511 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 512 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 513 JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; 514 return atomicReadModifyWrite(vm, globalObject, args, ExchangeFunc()); 515 } 516 517 JSC_DEFINE_JIT_OPERATION(operationAtomicsIsLockFree, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue size)) 518 { 519 VM& vm = globalObject->vm(); 520 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 521 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 522 return isLockFree(globalObject, JSValue::decode(size)); 523 } 524 525 JSC_DEFINE_JIT_OPERATION(operationAtomicsLoad, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index)) 526 { 527 VM& vm = globalObject->vm(); 528 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 529 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 530 JSValue args[] = {JSValue::decode(base), JSValue::decode(index)}; 531 return atomicReadModifyWrite(vm, globalObject, args, LoadFunc()); 532 } 533 534 JSC_DEFINE_JIT_OPERATION(operationAtomicsOr, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) 535 { 536 VM& vm = globalObject->vm(); 537 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 538 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 539 JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; 540 return atomicReadModifyWrite(vm, globalObject, args, OrFunc()); 541 } 542 543 JSC_DEFINE_JIT_OPERATION(operationAtomicsStore, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) 544 { 545 VM& vm = globalObject->vm(); 546 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 547 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 548 JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; 549 return atomicReadModifyWrite(vm, globalObject, args, StoreFunc()); 550 } 551 552 JSC_DEFINE_JIT_OPERATION(operationAtomicsSub, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) 553 { 554 VM& vm = globalObject->vm(); 555 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 556 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 557 JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; 558 return atomicReadModifyWrite(vm, globalObject, args, SubFunc()); 559 } 560 561 JSC_DEFINE_JIT_OPERATION(operationAtomicsXor, EncodedJSValue, (JSGlobalObject* globalObject, EncodedJSValue base, EncodedJSValue index, EncodedJSValue operand)) 562 { 563 VM& vm = globalObject->vm(); 564 CallFrame* callFrame = DECLARE_CALL_FRAME(vm); 565 JITOperationPrologueCallFrameTracer tracer(vm, callFrame); 566 JSValue args[] = {JSValue::decode(base), JSValue::decode(index), JSValue::decode(operand)}; 567 return atomicReadModifyWrite(vm, globalObject, args, XorFunc()); 568 } 569 570 IGNORE_WARNINGS_END 571 572 } // namespace JSC 573