LCOV - code coverage report
Current view: top level - src/runtime - runtime-atomics.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 9 144 6.2 %
Date: 2017-04-26 Functions: 2 62 3.2 %

          Line data    Source code
       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             : #if V8_CC_GNU
      23             : 
      24             : template <typename T>
      25             : inline T ExchangeSeqCst(T* p, T value) {
      26           0 :   return __atomic_exchange_n(p, value, __ATOMIC_SEQ_CST);
      27             : }
      28             : 
      29             : template <typename T>
      30             : inline T CompareExchangeSeqCst(T* p, T oldval, T newval) {
      31           0 :   (void)__atomic_compare_exchange_n(p, &oldval, newval, 0, __ATOMIC_SEQ_CST,
      32           0 :                                     __ATOMIC_SEQ_CST);
      33           0 :   return oldval;
      34             : }
      35             : 
      36             : template <typename T>
      37             : inline T AddSeqCst(T* p, T value) {
      38           0 :   return __atomic_fetch_add(p, value, __ATOMIC_SEQ_CST);
      39             : }
      40             : 
      41             : template <typename T>
      42             : inline T SubSeqCst(T* p, T value) {
      43           0 :   return __atomic_fetch_sub(p, value, __ATOMIC_SEQ_CST);
      44             : }
      45             : 
      46             : template <typename T>
      47             : inline T AndSeqCst(T* p, T value) {
      48           0 :   return __atomic_fetch_and(p, value, __ATOMIC_SEQ_CST);
      49             : }
      50             : 
      51             : template <typename T>
      52             : inline T OrSeqCst(T* p, T value) {
      53           0 :   return __atomic_fetch_or(p, value, __ATOMIC_SEQ_CST);
      54             : }
      55             : 
      56             : template <typename T>
      57             : inline T XorSeqCst(T* p, T value) {
      58           0 :   return __atomic_fetch_xor(p, value, __ATOMIC_SEQ_CST);
      59             : }
      60             : 
      61             : #elif V8_CC_MSVC
      62             : 
      63             : #define InterlockedExchange32 _InterlockedExchange
      64             : #define InterlockedCompareExchange32 _InterlockedCompareExchange
      65             : #define InterlockedCompareExchange8 _InterlockedCompareExchange8
      66             : #define InterlockedExchangeAdd32 _InterlockedExchangeAdd
      67             : #define InterlockedExchangeAdd16 _InterlockedExchangeAdd16
      68             : #define InterlockedExchangeAdd8 _InterlockedExchangeAdd8
      69             : #define InterlockedAnd32 _InterlockedAnd
      70             : #define InterlockedOr32 _InterlockedOr
      71             : #define InterlockedXor32 _InterlockedXor
      72             : 
      73             : #define ATOMIC_OPS(type, suffix, vctype)                                    \
      74             :   inline type ExchangeSeqCst(type* p, type value) {                         \
      75             :     return InterlockedExchange##suffix(reinterpret_cast<vctype*>(p),        \
      76             :                                        bit_cast<vctype>(value));            \
      77             :   }                                                                         \
      78             :   inline type CompareExchangeSeqCst(type* p, type oldval, type newval) {    \
      79             :     return InterlockedCompareExchange##suffix(reinterpret_cast<vctype*>(p), \
      80             :                                               bit_cast<vctype>(newval),     \
      81             :                                               bit_cast<vctype>(oldval));    \
      82             :   }                                                                         \
      83             :   inline type AddSeqCst(type* p, type value) {                              \
      84             :     return InterlockedExchangeAdd##suffix(reinterpret_cast<vctype*>(p),     \
      85             :                                           bit_cast<vctype>(value));         \
      86             :   }                                                                         \
      87             :   inline type SubSeqCst(type* p, type value) {                              \
      88             :     return InterlockedExchangeAdd##suffix(reinterpret_cast<vctype*>(p),     \
      89             :                                           -bit_cast<vctype>(value));        \
      90             :   }                                                                         \
      91             :   inline type AndSeqCst(type* p, type value) {                              \
      92             :     return InterlockedAnd##suffix(reinterpret_cast<vctype*>(p),             \
      93             :                                   bit_cast<vctype>(value));                 \
      94             :   }                                                                         \
      95             :   inline type OrSeqCst(type* p, type value) {                               \
      96             :     return InterlockedOr##suffix(reinterpret_cast<vctype*>(p),              \
      97             :                                  bit_cast<vctype>(value));                  \
      98             :   }                                                                         \
      99             :   inline type XorSeqCst(type* p, type value) {                              \
     100             :     return InterlockedXor##suffix(reinterpret_cast<vctype*>(p),             \
     101             :                                   bit_cast<vctype>(value));                 \
     102             :   }
     103             : 
     104             : ATOMIC_OPS(int8_t, 8, char)
     105             : ATOMIC_OPS(uint8_t, 8, char)
     106             : ATOMIC_OPS(int16_t, 16, short)  /* NOLINT(runtime/int) */
     107             : ATOMIC_OPS(uint16_t, 16, short) /* NOLINT(runtime/int) */
     108             : ATOMIC_OPS(int32_t, 32, long)   /* NOLINT(runtime/int) */
     109             : ATOMIC_OPS(uint32_t, 32, long)  /* NOLINT(runtime/int) */
     110             : 
     111             : #undef ATOMIC_OPS_INTEGER
     112             : #undef ATOMIC_OPS
     113             : 
     114             : #undef InterlockedExchange32
     115             : #undef InterlockedCompareExchange32
     116             : #undef InterlockedCompareExchange8
     117             : #undef InterlockedExchangeAdd32
     118             : #undef InterlockedExchangeAdd16
     119             : #undef InterlockedExchangeAdd8
     120             : #undef InterlockedAnd32
     121             : #undef InterlockedOr32
     122             : #undef InterlockedXor32
     123             : 
     124             : #else
     125             : 
     126             : #error Unsupported platform!
     127             : 
     128             : #endif
     129             : 
     130             : template <typename T>
     131             : T FromObject(Handle<Object> number);
     132             : 
     133             : template <>
     134             : inline uint8_t FromObject<uint8_t>(Handle<Object> number) {
     135           0 :   return NumberToUint32(*number);
     136             : }
     137             : 
     138             : template <>
     139             : inline int8_t FromObject<int8_t>(Handle<Object> number) {
     140           0 :   return NumberToInt32(*number);
     141             : }
     142             : 
     143             : template <>
     144             : inline uint16_t FromObject<uint16_t>(Handle<Object> number) {
     145           0 :   return NumberToUint32(*number);
     146             : }
     147             : 
     148             : template <>
     149             : inline int16_t FromObject<int16_t>(Handle<Object> number) {
     150           0 :   return NumberToInt32(*number);
     151             : }
     152             : 
     153             : template <>
     154             : inline uint32_t FromObject<uint32_t>(Handle<Object> number) {
     155           0 :   return NumberToUint32(*number);
     156             : }
     157             : 
     158             : template <>
     159             : inline int32_t FromObject<int32_t>(Handle<Object> number) {
     160           0 :   return NumberToInt32(*number);
     161             : }
     162             : 
     163             : 
     164             : inline Object* ToObject(Isolate* isolate, int8_t t) { return Smi::FromInt(t); }
     165             : 
     166             : inline Object* ToObject(Isolate* isolate, uint8_t t) { return Smi::FromInt(t); }
     167             : 
     168             : inline Object* ToObject(Isolate* isolate, int16_t t) { return Smi::FromInt(t); }
     169             : 
     170             : inline Object* ToObject(Isolate* isolate, uint16_t t) {
     171             :   return Smi::FromInt(t);
     172             : }
     173             : 
     174             : inline Object* ToObject(Isolate* isolate, int32_t t) {
     175           0 :   return *isolate->factory()->NewNumber(t);
     176             : }
     177             : 
     178             : inline Object* ToObject(Isolate* isolate, uint32_t t) {
     179           0 :   return *isolate->factory()->NewNumber(t);
     180             : }
     181             : 
     182             : template <typename T>
     183           0 : inline Object* DoExchange(Isolate* isolate, void* buffer, size_t index,
     184             :                           Handle<Object> obj) {
     185             :   T value = FromObject<T>(obj);
     186           0 :   T result = ExchangeSeqCst(static_cast<T*>(buffer) + index, value);
     187           0 :   return ToObject(isolate, result);
     188             : }
     189             : 
     190             : template <typename T>
     191           0 : 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           0 :       CompareExchangeSeqCst(static_cast<T*>(buffer) + index, oldval, newval);
     197           0 :   return ToObject(isolate, result);
     198             : }
     199             : 
     200             : template <typename T>
     201           0 : inline Object* DoAdd(Isolate* isolate, void* buffer, size_t index,
     202             :                      Handle<Object> obj) {
     203             :   T value = FromObject<T>(obj);
     204           0 :   T result = AddSeqCst(static_cast<T*>(buffer) + index, value);
     205           0 :   return ToObject(isolate, result);
     206             : }
     207             : 
     208             : template <typename T>
     209           0 : inline Object* DoSub(Isolate* isolate, void* buffer, size_t index,
     210             :                      Handle<Object> obj) {
     211             :   T value = FromObject<T>(obj);
     212           0 :   T result = SubSeqCst(static_cast<T*>(buffer) + index, value);
     213           0 :   return ToObject(isolate, result);
     214             : }
     215             : 
     216             : template <typename T>
     217           0 : inline Object* DoAnd(Isolate* isolate, void* buffer, size_t index,
     218             :                      Handle<Object> obj) {
     219             :   T value = FromObject<T>(obj);
     220           0 :   T result = AndSeqCst(static_cast<T*>(buffer) + index, value);
     221           0 :   return ToObject(isolate, result);
     222             : }
     223             : 
     224             : template <typename T>
     225           0 : inline Object* DoOr(Isolate* isolate, void* buffer, size_t index,
     226             :                     Handle<Object> obj) {
     227             :   T value = FromObject<T>(obj);
     228           0 :   T result = OrSeqCst(static_cast<T*>(buffer) + index, value);
     229           0 :   return ToObject(isolate, result);
     230             : }
     231             : 
     232             : template <typename T>
     233           0 : inline Object* DoXor(Isolate* isolate, void* buffer, size_t index,
     234             :                      Handle<Object> obj) {
     235             :   T value = FromObject<T>(obj);
     236           0 :   T result = XorSeqCst(static_cast<T*>(buffer) + index, value);
     237           0 :   return ToObject(isolate, result);
     238             : }
     239             : 
     240             : }  // anonymous namespace
     241             : 
     242             : // Duplicated from objects.h
     243             : // V has parameters (Type, type, TYPE, C type, element_size)
     244             : #define INTEGER_TYPED_ARRAYS(V)          \
     245             :   V(Uint8, uint8, UINT8, uint8_t, 1)     \
     246             :   V(Int8, int8, INT8, int8_t, 1)         \
     247             :   V(Uint16, uint16, UINT16, uint16_t, 2) \
     248             :   V(Int16, int16, INT16, int16_t, 2)     \
     249             :   V(Uint32, uint32, UINT32, uint32_t, 4) \
     250             :   V(Int32, int32, INT32, int32_t, 4)
     251             : 
     252        2520 : RUNTIME_FUNCTION(Runtime_ThrowNotIntegerSharedTypedArrayError) {
     253        1260 :   HandleScope scope(isolate);
     254             :   DCHECK_EQ(1, args.length());
     255        1260 :   CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
     256        2520 :   THROW_NEW_ERROR_RETURN_FAILURE(
     257             :       isolate,
     258        1260 :       NewTypeError(MessageTemplate::kNotIntegerSharedTypedArray, value));
     259             : }
     260             : 
     261           0 : RUNTIME_FUNCTION(Runtime_ThrowNotInt32SharedTypedArrayError) {
     262           0 :   HandleScope scope(isolate);
     263             :   DCHECK_EQ(1, args.length());
     264           0 :   CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
     265           0 :   THROW_NEW_ERROR_RETURN_FAILURE(
     266           0 :       isolate, NewTypeError(MessageTemplate::kNotInt32SharedTypedArray, value));
     267             : }
     268             : 
     269       10542 : RUNTIME_FUNCTION(Runtime_ThrowInvalidAtomicAccessIndexError) {
     270        5271 :   HandleScope scope(isolate);
     271             :   DCHECK_EQ(0, args.length());
     272       10542 :   THROW_NEW_ERROR_RETURN_FAILURE(
     273        5271 :       isolate, NewRangeError(MessageTemplate::kInvalidAtomicAccessIndex));
     274             : }
     275             : 
     276           0 : RUNTIME_FUNCTION(Runtime_AtomicsExchange) {
     277           0 :   HandleScope scope(isolate);
     278             :   DCHECK_EQ(3, args.length());
     279           0 :   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
     280           0 :   CONVERT_SIZE_ARG_CHECKED(index, 1);
     281           0 :   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
     282           0 :   CHECK(sta->GetBuffer()->is_shared());
     283           0 :   CHECK_LT(index, NumberToSize(sta->length()));
     284             : 
     285           0 :   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
     286           0 :                     NumberToSize(sta->byte_offset());
     287             : 
     288           0 :   switch (sta->type()) {
     289             : #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
     290             :   case kExternal##Type##Array:                              \
     291             :     return DoExchange<ctype>(isolate, source, index, value);
     292             : 
     293           0 :     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
     294             : #undef TYPED_ARRAY_CASE
     295             : 
     296             :     default:
     297             :       break;
     298             :   }
     299             : 
     300           0 :   UNREACHABLE();
     301           0 :   return isolate->heap()->undefined_value();
     302             : }
     303             : 
     304           0 : RUNTIME_FUNCTION(Runtime_AtomicsCompareExchange) {
     305           0 :   HandleScope scope(isolate);
     306             :   DCHECK_EQ(4, args.length());
     307           0 :   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
     308           0 :   CONVERT_SIZE_ARG_CHECKED(index, 1);
     309           0 :   CONVERT_NUMBER_ARG_HANDLE_CHECKED(oldobj, 2);
     310           0 :   CONVERT_NUMBER_ARG_HANDLE_CHECKED(newobj, 3);
     311           0 :   CHECK(sta->GetBuffer()->is_shared());
     312           0 :   CHECK_LT(index, NumberToSize(sta->length()));
     313             : 
     314           0 :   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
     315           0 :                     NumberToSize(sta->byte_offset());
     316             : 
     317           0 :   switch (sta->type()) {
     318             : #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
     319             :   case kExternal##Type##Array:                              \
     320             :     return DoCompareExchange<ctype>(isolate, source, index, oldobj, newobj);
     321             : 
     322           0 :     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
     323             : #undef TYPED_ARRAY_CASE
     324             : 
     325             :     default:
     326             :       break;
     327             :   }
     328             : 
     329           0 :   UNREACHABLE();
     330           0 :   return isolate->heap()->undefined_value();
     331             : }
     332             : 
     333             : // ES #sec-atomics.add
     334             : // Atomics.add( typedArray, index, value )
     335           0 : RUNTIME_FUNCTION(Runtime_AtomicsAdd) {
     336           0 :   HandleScope scope(isolate);
     337             :   DCHECK_EQ(3, args.length());
     338           0 :   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
     339           0 :   CONVERT_SIZE_ARG_CHECKED(index, 1);
     340           0 :   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
     341           0 :   CHECK(sta->GetBuffer()->is_shared());
     342           0 :   CHECK_LT(index, NumberToSize(sta->length()));
     343             : 
     344           0 :   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
     345           0 :                     NumberToSize(sta->byte_offset());
     346             : 
     347           0 :   switch (sta->type()) {
     348             : #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
     349             :   case kExternal##Type##Array:                              \
     350             :     return DoAdd<ctype>(isolate, source, index, value);
     351             : 
     352           0 :     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
     353             : #undef TYPED_ARRAY_CASE
     354             : 
     355             :     default:
     356             :       break;
     357             :   }
     358             : 
     359           0 :   UNREACHABLE();
     360           0 :   return isolate->heap()->undefined_value();
     361             : }
     362             : 
     363             : // ES #sec-atomics.sub
     364             : // Atomics.sub( typedArray, index, value )
     365           0 : RUNTIME_FUNCTION(Runtime_AtomicsSub) {
     366           0 :   HandleScope scope(isolate);
     367             :   DCHECK_EQ(3, args.length());
     368           0 :   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
     369           0 :   CONVERT_SIZE_ARG_CHECKED(index, 1);
     370           0 :   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
     371           0 :   CHECK(sta->GetBuffer()->is_shared());
     372           0 :   CHECK_LT(index, NumberToSize(sta->length()));
     373             : 
     374           0 :   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
     375           0 :                     NumberToSize(sta->byte_offset());
     376             : 
     377           0 :   switch (sta->type()) {
     378             : #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
     379             :   case kExternal##Type##Array:                              \
     380             :     return DoSub<ctype>(isolate, source, index, value);
     381             : 
     382           0 :     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
     383             : #undef TYPED_ARRAY_CASE
     384             : 
     385             :     default:
     386             :       break;
     387             :   }
     388             : 
     389           0 :   UNREACHABLE();
     390           0 :   return isolate->heap()->undefined_value();
     391             : }
     392             : 
     393             : // ES #sec-atomics.and
     394             : // Atomics.and( typedArray, index, value )
     395           0 : RUNTIME_FUNCTION(Runtime_AtomicsAnd) {
     396           0 :   HandleScope scope(isolate);
     397             :   DCHECK_EQ(3, args.length());
     398           0 :   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
     399           0 :   CONVERT_SIZE_ARG_CHECKED(index, 1);
     400           0 :   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
     401           0 :   CHECK(sta->GetBuffer()->is_shared());
     402           0 :   CHECK_LT(index, NumberToSize(sta->length()));
     403             : 
     404           0 :   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
     405           0 :                     NumberToSize(sta->byte_offset());
     406             : 
     407           0 :   switch (sta->type()) {
     408             : #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
     409             :   case kExternal##Type##Array:                              \
     410             :     return DoAnd<ctype>(isolate, source, index, value);
     411             : 
     412           0 :     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
     413             : #undef TYPED_ARRAY_CASE
     414             : 
     415             :     default:
     416             :       break;
     417             :   }
     418             : 
     419           0 :   UNREACHABLE();
     420           0 :   return isolate->heap()->undefined_value();
     421             : }
     422             : 
     423             : // ES #sec-atomics.or
     424             : // Atomics.or( typedArray, index, value )
     425           0 : RUNTIME_FUNCTION(Runtime_AtomicsOr) {
     426           0 :   HandleScope scope(isolate);
     427             :   DCHECK_EQ(3, args.length());
     428           0 :   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
     429           0 :   CONVERT_SIZE_ARG_CHECKED(index, 1);
     430           0 :   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
     431           0 :   CHECK(sta->GetBuffer()->is_shared());
     432           0 :   CHECK_LT(index, NumberToSize(sta->length()));
     433             : 
     434           0 :   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
     435           0 :                     NumberToSize(sta->byte_offset());
     436             : 
     437           0 :   switch (sta->type()) {
     438             : #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
     439             :   case kExternal##Type##Array:                              \
     440             :     return DoOr<ctype>(isolate, source, index, value);
     441             : 
     442           0 :     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
     443             : #undef TYPED_ARRAY_CASE
     444             : 
     445             :     default:
     446             :       break;
     447             :   }
     448             : 
     449           0 :   UNREACHABLE();
     450           0 :   return isolate->heap()->undefined_value();
     451             : }
     452             : 
     453             : // ES #sec-atomics.xor
     454             : // Atomics.xor( typedArray, index, value )
     455           0 : RUNTIME_FUNCTION(Runtime_AtomicsXor) {
     456           0 :   HandleScope scope(isolate);
     457             :   DCHECK_EQ(3, args.length());
     458           0 :   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, sta, 0);
     459           0 :   CONVERT_SIZE_ARG_CHECKED(index, 1);
     460           0 :   CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);
     461           0 :   CHECK(sta->GetBuffer()->is_shared());
     462           0 :   CHECK_LT(index, NumberToSize(sta->length()));
     463             : 
     464           0 :   uint8_t* source = static_cast<uint8_t*>(sta->GetBuffer()->backing_store()) +
     465           0 :                     NumberToSize(sta->byte_offset());
     466             : 
     467           0 :   switch (sta->type()) {
     468             : #define TYPED_ARRAY_CASE(Type, typeName, TYPE, ctype, size) \
     469             :   case kExternal##Type##Array:                              \
     470             :     return DoXor<ctype>(isolate, source, index, value);
     471             : 
     472           0 :     INTEGER_TYPED_ARRAYS(TYPED_ARRAY_CASE)
     473             : #undef TYPED_ARRAY_CASE
     474             : 
     475             :     default:
     476             :       break;
     477             :   }
     478             : 
     479           0 :   UNREACHABLE();
     480           0 :   return isolate->heap()->undefined_value();
     481             : }
     482             : 
     483             : }  // namespace internal
     484             : }  // namespace v8

Generated by: LCOV version 1.10