• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
AtomicIsLockFree(uint32_t size)25 inline bool AtomicIsLockFree(uint32_t size) {
26   return size == 1 || size == 2 || size == 4;
27 }
28 
29 // ES #sec-atomics.islockfree
BUILTIN(AtomicsIsLockFree)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
ValidateSharedIntegerTypedArray(Isolate * isolate,Handle<Object> object,bool only_int32=false)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 )
ValidateAtomicAccess(Isolate * isolate,Handle<JSTypedArray> typed_array,Handle<Object> request_index)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 )
BUILTIN(AtomicsWake)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 )
BUILTIN(AtomicsWait)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