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