/ runtime / AtomicsObject.cpp
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