Home | History | Annotate | Download | only in runtime
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/runtime/runtime-utils.h"
      6 
      7 #include "src/arguments.h"
      8 #include "src/base/macros.h"
      9 #include "src/base/platform/mutex.h"
     10 #include "src/conversions-inl.h"
     11 #include "src/factory.h"
     12 
     13 // Implement Atomic accesses to SharedArrayBuffers as defined in the
     14 // SharedArrayBuffer draft spec, found here
     15 // https://github.com/tc39/ecmascript_sharedmem
     16 
     17 namespace v8 {
     18 namespace internal {
     19 
     20 namespace {
     21 
     22 inline bool AtomicIsLockFree(uint32_t size) {
     23   return size == 1 || size == 2 || size == 4;
     24 }
     25 
     26 #if V8_CC_GNU
     27 
     28 template <typename T>
     29 inline T CompareExchangeSeqCst(T* p, T oldval, T newval) {
     30   (void)__atomic_compare_exchange_n(p, &oldval, newval, 0, __ATOMIC_SEQ_CST,
     31                                     __ATOMIC_SEQ_CST);
     32   return oldval;
     33 }
     34 
     35 template <typename T>
     36 inline T AddSeqCst(T* p, T value) {
     37   return __atomic_fetch_add(p, value, __ATOMIC_SEQ_CST);
     38 }
     39 
     40 template <typename T>
     41 inline T SubSeqCst(T* p, T value) {
     42   return __atomic_fetch_sub(p, value, __ATOMIC_SEQ_CST);
     43 }
     44 
     45 template <typename T>
     46 inline T AndSeqCst(T* p, T value) {
     47   return __atomic_fetch_and(p, value, __ATOMIC_SEQ_CST);
     48 }
     49 
     50 template <typename T>
     51 inline T OrSeqCst(T* p, T value) {
     52   return __atomic_fetch_or(p, value, __ATOMIC_SEQ_CST);
     53 }
     54 
     55 template <typename T>
     56 inline T XorSeqCst(T* p, T value) {
     57   return __atomic_fetch_xor(p, value, __ATOMIC_SEQ_CST);
     58 }
     59 
     60 template <typename T>
     61 inline T ExchangeSeqCst(T* p, T value) {
     62   return __atomic_exchange_n(p, value, __ATOMIC_SEQ_CST);
     63 }
     64 
     65 #elif V8_CC_MSVC
     66 
     67 #define InterlockedCompareExchange32 _InterlockedCompareExchange
     68 #define InterlockedExchange32 _InterlockedExchange
     69 #define InterlockedExchangeAdd32 _InterlockedExchangeAdd
     70 #define InterlockedAnd32 _InterlockedAnd
     71 #define InterlockedOr32 _InterlockedOr
     72 #define InterlockedXor32 _InterlockedXor
     73 #define InterlockedExchangeAdd16 _InterlockedExchangeAdd16
     74 #define InterlockedCompareExchange8 _InterlockedCompareExchange8
     75 #define InterlockedExchangeAdd8 _InterlockedExchangeAdd8
     76 
     77 #define ATOMIC_OPS(type, suffix, vctype)                                    \
     78   inline type AddSeqCst(type* p, type value) {                              \
     79     return InterlockedExchangeAdd##suffix(reinterpret_cast<vctype*>(p),     \
     80                                           bit_cast<vctype>(value));         \
     81   }                                                                         \
     82   inline type SubSeqCst(type* p, type value) {                              \
     83     return InterlockedExchangeAdd##suffix(reinterpret_cast<vctype*>(p),     \
     84                                           -bit_cast<vctype>(value));        \
     85   }                                                                         \
     86   inline type AndSeqCst(type* p, type value) {                              \
     87     return InterlockedAnd##suffix(reinterpret_cast<vctype*>(p),             \
     88                                   bit_cast<vctype>(value));                 \
     89   }                                                                         \
     90   inline type OrSeqCst(type* p, type value) {                               \
     91     return InterlockedOr##suffix(reinterpret_cast<vctype*>(p),              \
     92                                  bit_cast<vctype>(value));                  \
     93   }                                                                         \
     94   inline type XorSeqCst(type* p, type value) {                              \
     95     return InterlockedXor##suffix(reinterpret_cast<vctype*>(p),             \
     96                                   bit_cast<vctype>(value));                 \
     97   }                                                                         \
     98   inline type ExchangeSeqCst(type* p, type value) {                         \
     99     return InterlockedExchange##suffix(reinterpret_cast<vctype*>(p),        \
    100                                        bit_cast<vctype>(value));            \
    101   }                                                                         \
    102                                                                             \
    103   inline type CompareExchangeSeqCst(type* p, type oldval, type newval) {    \
    104     return InterlockedCompareExchange##suffix(reinterpret_cast<vctype*>(p), \
    105                                               bit_cast<vctype>(newval),     \
    106                                               bit_cast<vctype>(oldval));    \
    107   }
    108 
    109 ATOMIC_OPS(int8_t, 8, char)
    110 ATOMIC_OPS(uint8_t, 8, char)
    111 ATOMIC_OPS(int16_t, 16, short)  /* NOLINT(runtime/int) */
    112 ATOMIC_OPS(uint16_t, 16, short) /* NOLINT(runtime/int) */
    113 ATOMIC_OPS(int32_t, 32, long)   /* NOLINT(runtime/int) */
    114 ATOMIC_OPS(uint32_t, 32, long)  /* NOLINT(runtime/int) */
    115 
    116 #undef ATOMIC_OPS_INTEGER
    117 #undef ATOMIC_OPS
    118 
    119 #undef InterlockedCompareExchange32
    120 #undef InterlockedExchange32
    121 #undef InterlockedExchangeAdd32
    122 #undef InterlockedAnd32
    123 #undef InterlockedOr32
    124 #undef InterlockedXor32
    125 #undef InterlockedExchangeAdd16
    126 #undef InterlockedCompareExchange8
    127 #undef InterlockedExchangeAdd8
    128 
    129 #else
    130 
    131 #error Unsupported platform!
    132 
    133 #endif
    134 
    135 template <typename T>
    136 T FromObject(Handle<Object> number);
    137 
    138 template <>
    139 inline uint8_t FromObject<uint8_t>(Handle<Object> number) {
    140   return NumberToUint32(*number);
    141 }
    142 
    143 template <>
    144 inline int8_t FromObject<int8_t>(Handle<Object> number) {
    145   return NumberToInt32(*number);
    146 }
    147 
    148 template <>
    149 inline uint16_t FromObject<uint16_t>(Handle<Object> number) {
    150   return NumberToUint32(*number);
    151 }
    152 
    153 template <>
    154 inline int16_t FromObject<int16_t>(Handle<Object> number) {
    155   return NumberToInt32(*number);
    156 }
    157 
    158 template <>
    159 inline uint32_t FromObject<uint32_t>(Handle<Object> number) {
    160   return NumberToUint32(*number);
    161 }
    162 
    163 template <>
    164 inline int32_t FromObject<int32_t>(Handle<Object> number) {
    165   return NumberToInt32(*number);
    166 }
    167 
    168 
    169 inline Object* ToObject(Isolate* isolate, int8_t t) { return Smi::FromInt(t); }
    170 
    171 inline Object* ToObject(Isolate* isolate, uint8_t t) { return Smi::FromInt(t); }
    172 
    173 inline Object* ToObject(Isolate* isolate, int16_t t) { return Smi::FromInt(t); }
    174 
    175 inline Object* ToObject(Isolate* isolate, uint16_t t) {
    176   return Smi::FromInt(t);
    177 }
    178 
    179 
    180 inline Object* ToObject(Isolate* isolate, int32_t t) {
    181   return *isolate->factory()->NewNumber(t);
    182 }
    183 
    184 
    185 inline Object* ToObject(Isolate* isolate, uint32_t t) {
    186   return *isolate->factory()->NewNumber(t);
    187 }
    188 
    189 
    190 template <typename T>
    191 inline Object* DoCompareExchange(Isolate* isolate, void* buffer, size_t index,
    192                                  Handle<Object> oldobj, Handle<Object> newobj) {
    193   T oldval = FromObject<T>(oldobj);
    194   T newval = FromObject<T>(newobj);
    195   T result =
    196       CompareExchangeSeqCst(static_cast<T*>(buffer) + index, oldval, newval);
    197   return ToObject(isolate, result);
    198 }
    199 
    200 
    201 template <typename T>
    202 inline Object* DoAdd(Isolate* isolate, void* buffer, size_t index,
    203                      Handle<Object> obj) {
    204   T value = FromObject<T>(obj);
    205   T result = AddSeqCst(static_cast<T*>(buffer) + index, value);
    206   return ToObject(isolate, result);
    207 }
    208 
    209 
    210 template <typename T>
    211 inline Object* DoSub(Isolate* isolate, void* buffer, size_t index,
    212                      Handle<Object> obj) {
    213   T value = FromObject<T>(obj);
    214   T result = SubSeqCst(static_cast<T*>(buffer) + index, value);
    215   return ToObject(isolate, result);
    216 }
    217 
    218 
    219 template <typename T>
    220 inline Object* DoAnd(Isolate* isolate, void* buffer, size_t index,
    221                      Handle<Object> obj) {
    222   T value = FromObject<T>(obj);
    223   T result = AndSeqCst(static_cast<T*>(buffer) + index, value);
    224   return ToObject(isolate, result);
    225 }
    226 
    227 
    228 template <typename T>
    229 inline Object* DoOr(Isolate* isolate, void* buffer, size_t index,
    230                     Handle<Object> obj) {
    231   T value = FromObject<T>(obj);
    232   T result = OrSeqCst(static_cast<T*>(buffer) + index, value);
    233   return ToObject(isolate, result);
    234 }
    235 
    236 
    237 template <typename T>
    238 inline Object* DoXor(Isolate* isolate, void* buffer, size_t index,
    239                      Handle<Object> obj) {
    240   T value = FromObject<T>(obj);
    241   T result = XorSeqCst(static_cast<T*>(buffer) + index, value);
    242   return ToObject(isolate, result);
    243 }
    244 
    245 
    246 template <typename T>
    247 inline Object* DoExchange(Isolate* isolate, void* buffer, size_t index,
    248                           Handle<Object> obj) {
    249   T value = FromObject<T>(obj);
    250   T result = ExchangeSeqCst(static_cast<T*>(buffer) + index, value);
    251   return ToObject(isolate, result);
    252 }
    253 
    254 
    255 // Uint8Clamped functions
    256 
    257 uint8_t ClampToUint8(int32_t value) {
    258   if (value < 0) return 0;
    259   if (value > 255) return 255;
    260   return value;
    261 }
    262 
    263 
    264 inline Object* DoCompareExchangeUint8Clamped(Isolate* isolate, void* buffer,
    265                                              size_t index,
    266                                              Handle<Object> oldobj,
    267                                              Handle<Object> newobj) {
    268   typedef int32_t convert_type;
    269   uint8_t oldval = ClampToUint8(FromObject<convert_type>(oldobj));
    270   uint8_t newval = ClampToUint8(FromObject<convert_type>(newobj));
    271   uint8_t result = CompareExchangeSeqCst(static_cast<uint8_t*>(buffer) + index,
    272                                          oldval, newval);
    273   return ToObject(isolate, result);
    274 }
    275 
    276 
    277 #define DO_UINT8_CLAMPED_OP(name, op)                                        \
    278   inline Object* Do##name##Uint8Clamped(Isolate* isolate, void* buffer,      \
    279                                         size_t index, Handle<Object> obj) {  \
    280     typedef int32_t convert_type;                                            \
    281     uint8_t* p = static_cast<uint8_t*>(buffer) + index;                      \
    282     convert_type operand = FromObject<convert_type>(obj);                    \
    283     uint8_t expected;                                                        \
    284     uint8_t result;                                                          \
    285     do {                                                                     \
    286       expected = *p;                                                         \
    287       result = ClampToUint8(static_cast<convert_type>(expected) op operand); \
    288     } while (CompareExchangeSeqCst(p, expected, result) != expected);        \
    289     return ToObject(isolate, expected);                                      \
    290   }
    291 
    292 DO_UINT8_CLAMPED_OP(Add, +)
    293 DO_UINT8_CLAMPED_OP(Sub, -)
    294 DO_UINT8_CLAMPED_OP(And, &)
    295 DO_UINT8_CLAMPED_OP(Or, | )
    296 DO_UINT8_CLAMPED_OP(Xor, ^)
    297 
    298 #undef DO_UINT8_CLAMPED_OP
    299 
    300 
    301 inline Object* DoExchangeUint8Clamped(Isolate* isolate, void* buffer,
    302                                       size_t index, Handle<Object> obj) {
    303   typedef int32_t convert_type;
    304   uint8_t* p = static_cast<uint8_t*>(buffer) + index;
    305   uint8_t result = ClampToUint8(FromObject<convert_type>(obj));
    306   uint8_t expected;
    307   do {
    308     expected = *p;
    309   } while (CompareExchangeSeqCst(p, expected, result) != expected);
    310   return ToObject(isolate, expected);
    311 }
    312 
    313 
    314 }  // anonymous namespace
    315 
    316 // Duplicated from objects.h
    317 // V has parameters (Type, type, TYPE, C type, element_size)
    318 #define INTEGER_TYPED_ARRAYS(V)          \
    319   V(Uint8, uint8, UINT8, uint8_t, 1)     \
    320   V(Int8, int8, INT8, int8_t, 1)         \
    321   V(Uint16, uint16, UINT16, uint16_t, 2) \
    322   V(Int16, int16, INT16, int16_t, 2)     \
    323   V(Uint32, uint32, UINT32, uint32_t, 4) \
    324   V(Int32, int32, INT32, int32_t, 4)
    325 
    326 RUNTIME_FUNCTION(Runtime_ThrowNotIntegerSharedTypedArrayError) {
    327   HandleScope scope(isolate);
    328   DCHECK_EQ(1, args.length());
    329   CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
    330   THROW_NEW_ERROR_RETURN_FAILURE(
    331       isolate,
    332       NewTypeError(MessageTemplate::kNotIntegerSharedTypedArray, value));
    333 }
    334 
    335 RUNTIME_FUNCTION(Runtime_ThrowNotInt32SharedTypedArrayError) {
    336   HandleScope scope(isolate);
    337   DCHECK_EQ(1, args.length());
    338   CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
    339   THROW_NEW_ERROR_RETURN_FAILURE(
    340       isolate, NewTypeError(MessageTemplate::kNotInt32SharedTypedArray, value));
    341 }
    342 
    343 RUNTIME_FUNCTION(Runtime_ThrowInvalidAtomicAccessIndexError) {
    344   HandleScope scope(isolate);
    345   DCHECK_EQ(0, args.length());
    346   THROW_NEW_ERROR_RETURN_FAILURE(
    347       isolate, NewRangeError(MessageTemplate::kInvalidAtomicAccessIndex));
    348 }
    349 
    350 RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
    351   HandleScope scope(isolate);
    352   DCHECK_EQ(4, args.length());
    353   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
    354   CONVERT_SIZE_ARG_CHECKED(index, 1);
    355   CONVERT_NUMBER_ARG_HANDLE_CHECKED(oldobj, 2);
    356   CONVERT_NUMBER_ARG_HANDLE_CHECKED(newobj, 3);
    357   CHECK(sta->GetBuffer()->is_shared());
    358   CHECK_LT(index, NumberToSize(sta->length()));
    359 
    360   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
    361                     NumberToSize(sta->byte_offset());
    362 
    363   switch (sta->type()) {
    364 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
    365   case kExternal##Type##Array:                              \
    366     return DoCompareExchange<ctype>(isolate, source, index, oldobj, newobj);
    367 
    368     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
    369 #undef TYPED_ARRAY_CASE
    370 
    371     case kExternalUint8ClampedArray:
    372       return DoCompareExchangeUint8Clamped(isolate, source, index, oldobj,
    373                                            newobj);
    374 
    375     default:
    376       break;
    377   }
    378 
    379   UNREACHABLE();
    380   return isolate->heap()->undefined_value();
    381 }
    382 
    383 
    384 RUNTIME_FUNCTION(Runtime_AtomicsAdd) {
    385   HandleScope scope(isolate);
    386   DCHECK_EQ(3, args.length());
    387   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
    388   CONVERT_SIZE_ARG_CHECKED(index, 1);
    389   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
    390   CHECK(sta->GetBuffer()->is_shared());
    391   CHECK_LT(index, NumberToSize(sta->length()));
    392 
    393   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
    394                     NumberToSize(sta->byte_offset());
    395 
    396   switch (sta->type()) {
    397 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
    398   case kExternal##Type##Array:                              \
    399     return DoAdd<ctype>(isolate, source, index, value);
    400 
    401     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
    402 #undef TYPED_ARRAY_CASE
    403 
    404     case kExternalUint8ClampedArray:
    405       return DoAddUint8Clamped(isolate, source, index, value);
    406 
    407     default:
    408       break;
    409   }
    410 
    411   UNREACHABLE();
    412   return isolate->heap()->undefined_value();
    413 }
    414 
    415 
    416 RUNTIME_FUNCTION(Runtime_AtomicsSub) {
    417   HandleScope scope(isolate);
    418   DCHECK_EQ(3, args.length());
    419   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
    420   CONVERT_SIZE_ARG_CHECKED(index, 1);
    421   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
    422   CHECK(sta->GetBuffer()->is_shared());
    423   CHECK_LT(index, NumberToSize(sta->length()));
    424 
    425   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
    426                     NumberToSize(sta->byte_offset());
    427 
    428   switch (sta->type()) {
    429 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
    430   case kExternal##Type##Array:                              \
    431     return DoSub<ctype>(isolate, source, index, value);
    432 
    433     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
    434 #undef TYPED_ARRAY_CASE
    435 
    436     case kExternalUint8ClampedArray:
    437       return DoSubUint8Clamped(isolate, source, index, value);
    438 
    439     default:
    440       break;
    441   }
    442 
    443   UNREACHABLE();
    444   return isolate->heap()->undefined_value();
    445 }
    446 
    447 
    448 RUNTIME_FUNCTION(Runtime_AtomicsAnd) {
    449   HandleScope scope(isolate);
    450   DCHECK_EQ(3, args.length());
    451   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
    452   CONVERT_SIZE_ARG_CHECKED(index, 1);
    453   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
    454   CHECK(sta->GetBuffer()->is_shared());
    455   CHECK_LT(index, NumberToSize(sta->length()));
    456 
    457   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
    458                     NumberToSize(sta->byte_offset());
    459 
    460   switch (sta->type()) {
    461 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
    462   case kExternal##Type##Array:                              \
    463     return DoAnd<ctype>(isolate, source, index, value);
    464 
    465     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
    466 #undef TYPED_ARRAY_CASE
    467 
    468     case kExternalUint8ClampedArray:
    469       return DoAndUint8Clamped(isolate, source, index, value);
    470 
    471     default:
    472       break;
    473   }
    474 
    475   UNREACHABLE();
    476   return isolate->heap()->undefined_value();
    477 }
    478 
    479 
    480 RUNTIME_FUNCTION(Runtime_AtomicsOr) {
    481   HandleScope scope(isolate);
    482   DCHECK_EQ(3, args.length());
    483   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
    484   CONVERT_SIZE_ARG_CHECKED(index, 1);
    485   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
    486   CHECK(sta->GetBuffer()->is_shared());
    487   CHECK_LT(index, NumberToSize(sta->length()));
    488 
    489   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
    490                     NumberToSize(sta->byte_offset());
    491 
    492   switch (sta->type()) {
    493 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
    494   case kExternal##Type##Array:                              \
    495     return DoOr<ctype>(isolate, source, index, value);
    496 
    497     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
    498 #undef TYPED_ARRAY_CASE
    499 
    500     case kExternalUint8ClampedArray:
    501       return DoOrUint8Clamped(isolate, source, index, value);
    502 
    503     default:
    504       break;
    505   }
    506 
    507   UNREACHABLE();
    508   return isolate->heap()->undefined_value();
    509 }
    510 
    511 
    512 RUNTIME_FUNCTION(Runtime_AtomicsXor) {
    513   HandleScope scope(isolate);
    514   DCHECK_EQ(3, args.length());
    515   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
    516   CONVERT_SIZE_ARG_CHECKED(index, 1);
    517   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
    518   CHECK(sta->GetBuffer()->is_shared());
    519   CHECK_LT(index, NumberToSize(sta->length()));
    520 
    521   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
    522                     NumberToSize(sta->byte_offset());
    523 
    524   switch (sta->type()) {
    525 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
    526   case kExternal##Type##Array:                              \
    527     return DoXor<ctype>(isolate, source, index, value);
    528 
    529     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
    530 #undef TYPED_ARRAY_CASE
    531 
    532     case kExternalUint8ClampedArray:
    533       return DoXorUint8Clamped(isolate, source, index, value);
    534 
    535     default:
    536       break;
    537   }
    538 
    539   UNREACHABLE();
    540   return isolate->heap()->undefined_value();
    541 }
    542 
    543 
    544 RUNTIME_FUNCTION(Runtime_AtomicsExchange) {
    545   HandleScope scope(isolate);
    546   DCHECK_EQ(3, args.length());
    547   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
    548   CONVERT_SIZE_ARG_CHECKED(index, 1);
    549   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
    550   CHECK(sta->GetBuffer()->is_shared());
    551   CHECK_LT(index, NumberToSize(sta->length()));
    552 
    553   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
    554                     NumberToSize(sta->byte_offset());
    555 
    556   switch (sta->type()) {
    557 #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
    558   case kExternal##Type##Array:                              \
    559     return DoExchange<ctype>(isolate, source, index, value);
    560 
    561     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
    562 #undef TYPED_ARRAY_CASE
    563 
    564     case kExternalUint8ClampedArray:
    565       return DoExchangeUint8Clamped(isolate, source, index, value);
    566 
    567     default:
    568       break;
    569   }
    570 
    571   UNREACHABLE();
    572   return isolate->heap()->undefined_value();
    573 }
    574 
    575 
    576 RUNTIME_FUNCTION(Runtime_AtomicsIsLockFree) {
    577   HandleScope scope(isolate);
    578   DCHECK_EQ(1, args.length());
    579   CONVERT_NUMBER_ARG_HANDLE_CHECKED(size, 0);
    580   uint32_t usize = NumberToUint32(*size);
    581   return isolate->heap()->ToBoolean(AtomicIsLockFree(usize));
    582 }
    583 }  // namespace internal
    584 }  // namespace v8
    585