Home | History | Annotate | Download | only in builtins
      1 // Copyright 2016 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/base/macros.h"
      6 #include "src/base/platform/mutex.h"
      7 #include "src/base/platform/time.h"
      8 #include "src/builtins/builtins-utils-inl.h"
      9 #include "src/builtins/builtins.h"
     10 #include "src/code-factory.h"
     11 #include "src/conversions-inl.h"
     12 #include "src/counters.h"
     13 #include "src/futex-emulation.h"
     14 #include "src/globals.h"
     15 #include "src/heap/factory.h"
     16 #include "src/objects-inl.h"
     17 #include "src/objects/js-array-buffer-inl.h"
     18 
     19 namespace v8 {
     20 namespace internal {
     21 
     22 // See builtins-arraybuffer.cc for implementations of
     23 // SharedArrayBuffer.prototye.byteLength and SharedArrayBuffer.prototype.slice
     24 
     25 inline bool AtomicIsLockFree(uint32_t size) {
     26   return size == 1 || size == 2 || size == 4;
     27 }
     28 
     29 // ES #sec-atomics.islockfree
     30 BUILTIN(AtomicsIsLockFree) {
     31   HandleScope scope(isolate);
     32   Handle<Object> size = args.atOrUndefined(isolate, 1);
     33   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, size,
     34                                      Object::ToNumber(isolate, size));
     35   return *isolate->factory()->ToBoolean(AtomicIsLockFree(size->Number()));
     36 }
     37 
     38 // ES #sec-validatesharedintegertypedarray
     39 V8_WARN_UNUSED_RESULT MaybeHandle<JSTypedArray> ValidateSharedIntegerTypedArray(
     40     Isolate* isolate, Handle<Object> object, bool only_int32 = false) {
     41   if (object->IsJSTypedArray()) {
     42     Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object);
     43     if (typed_array->GetBuffer()->is_shared()) {
     44       if (only_int32) {
     45         if (typed_array->type() == kExternalInt32Array) return typed_array;
     46       } else {
     47         if (typed_array->type() != kExternalFloat32Array &&
     48             typed_array->type() != kExternalFloat64Array &&
     49             typed_array->type() != kExternalUint8ClampedArray)
     50           return typed_array;
     51       }
     52     }
     53   }
     54 
     55   THROW_NEW_ERROR(
     56       isolate,
     57       NewTypeError(only_int32 ? MessageTemplate::kNotInt32SharedTypedArray
     58                               : MessageTemplate::kNotIntegerSharedTypedArray,
     59                    object),
     60       JSTypedArray);
     61 }
     62 
     63 // ES #sec-validateatomicaccess
     64 // ValidateAtomicAccess( typedArray, requestIndex )
     65 V8_WARN_UNUSED_RESULT Maybe<size_t> ValidateAtomicAccess(
     66     Isolate* isolate, Handle<JSTypedArray> typed_array,
     67     Handle<Object> request_index) {
     68   Handle<Object> access_index_obj;
     69   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     70       isolate, access_index_obj,
     71       Object::ToIndex(isolate, request_index,
     72                       MessageTemplate::kInvalidAtomicAccessIndex),
     73       Nothing<size_t>());
     74 
     75   size_t access_index;
     76   if (!TryNumberToSize(*access_index_obj, &access_index) ||
     77       access_index >= typed_array->length_value()) {
     78     isolate->Throw(*isolate->factory()->NewRangeError(
     79         MessageTemplate::kInvalidAtomicAccessIndex));
     80     return Nothing<size_t>();
     81   }
     82   return Just<size_t>(access_index);
     83 }
     84 
     85 // ES #sec-atomics.wake
     86 // Atomics.wake( typedArray, index, count )
     87 BUILTIN(AtomicsWake) {
     88   HandleScope scope(isolate);
     89   Handle<Object> array = args.atOrUndefined(isolate, 1);
     90   Handle<Object> index = args.atOrUndefined(isolate, 2);
     91   Handle<Object> count = args.atOrUndefined(isolate, 3);
     92 
     93   Handle<JSTypedArray> sta;
     94   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     95       isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true));
     96 
     97   Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
     98   if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
     99   size_t i = maybe_index.FromJust();
    100 
    101   uint32_t c;
    102   if (count->IsUndefined(isolate)) {
    103     c = kMaxUInt32;
    104   } else {
    105     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, count,
    106                                        Object::ToInteger(isolate, count));
    107     double count_double = count->Number();
    108     if (count_double < 0)
    109       count_double = 0;
    110     else if (count_double > kMaxUInt32)
    111       count_double = kMaxUInt32;
    112     c = static_cast<uint32_t>(count_double);
    113   }
    114 
    115   Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
    116   size_t addr = (i << 2) + NumberToSize(sta->byte_offset());
    117 
    118   return FutexEmulation::Wake(array_buffer, addr, c);
    119 }
    120 
    121 // ES #sec-atomics.wait
    122 // Atomics.wait( typedArray, index, value, timeout )
    123 BUILTIN(AtomicsWait) {
    124   HandleScope scope(isolate);
    125   Handle<Object> array = args.atOrUndefined(isolate, 1);
    126   Handle<Object> index = args.atOrUndefined(isolate, 2);
    127   Handle<Object> value = args.atOrUndefined(isolate, 3);
    128   Handle<Object> timeout = args.atOrUndefined(isolate, 4);
    129 
    130   Handle<JSTypedArray> sta;
    131   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
    132       isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true));
    133 
    134   Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
    135   if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
    136   size_t i = maybe_index.FromJust();
    137 
    138   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
    139                                      Object::ToInt32(isolate, value));
    140   int32_t value_int32 = NumberToInt32(*value);
    141 
    142   double timeout_number;
    143   if (timeout->IsUndefined(isolate)) {
    144     timeout_number = ReadOnlyRoots(isolate).infinity_value()->Number();
    145   } else {
    146     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, timeout,
    147                                        Object::ToNumber(isolate, timeout));
    148     timeout_number = timeout->Number();
    149     if (std::isnan(timeout_number))
    150       timeout_number = ReadOnlyRoots(isolate).infinity_value()->Number();
    151     else if (timeout_number < 0)
    152       timeout_number = 0;
    153   }
    154 
    155   if (!isolate->allow_atomics_wait()) {
    156     THROW_NEW_ERROR_RETURN_FAILURE(
    157         isolate, NewTypeError(MessageTemplate::kAtomicsWaitNotAllowed));
    158   }
    159 
    160   Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
    161   size_t addr = (i << 2) + NumberToSize(sta->byte_offset());
    162 
    163   return FutexEmulation::Wait(isolate, array_buffer, addr, value_int32,
    164                               timeout_number);
    165 }
    166 
    167 }  // namespace internal
    168 }  // namespace v8
    169