Line data Source code
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 9072 : return size == 1 || size == 2 || size == 4;
27 : }
28 :
29 : // ES #sec-atomics.islockfree
30 36288 : BUILTIN(AtomicsIsLockFree) {
31 : HandleScope scope(isolate);
32 : Handle<Object> size = args.atOrUndefined(isolate, 1);
33 18144 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, size,
34 : Object::ToNumber(isolate, size));
35 27216 : return *isolate->factory()->ToBoolean(AtomicIsLockFree(size->Number()));
36 : }
37 :
38 : // ES #sec-validatesharedintegertypedarray
39 1184 : V8_WARN_UNUSED_RESULT MaybeHandle<JSTypedArray> ValidateSharedIntegerTypedArray(
40 : Isolate* isolate, Handle<Object> object, bool only_int32 = false) {
41 2368 : if (object->IsJSTypedArray()) {
42 1184 : Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object);
43 2367 : if (typed_array->GetBuffer()->is_shared()) {
44 1021 : if (only_int32) {
45 1021 : if (typed_array->type() == kExternalInt32Array) return typed_array;
46 : } else {
47 0 : if (typed_array->type() != kExternalFloat32Array &&
48 0 : typed_array->type() != kExternalFloat64Array &&
49 0 : typed_array->type() != kExternalUint8ClampedArray)
50 0 : return typed_array;
51 : }
52 : }
53 : }
54 :
55 306 : 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 877 : 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 1754 : 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 2524 : if (!TryNumberToSize(*access_index_obj, &access_index) ||
77 3366 : typed_array->WasDetached() ||
78 842 : access_index >= typed_array->length_value()) {
79 : isolate->Throw(*isolate->factory()->NewRangeError(
80 216 : MessageTemplate::kInvalidAtomicAccessIndex));
81 : return Nothing<size_t>();
82 : }
83 : return Just<size_t>(access_index);
84 : }
85 :
86 : namespace {
87 532 : MaybeHandle<Object> AtomicsWake(Isolate* isolate, Handle<Object> array,
88 : Handle<Object> index, Handle<Object> count) {
89 : Handle<JSTypedArray> sta;
90 1064 : ASSIGN_RETURN_ON_EXCEPTION(
91 : isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true),
92 : Object);
93 :
94 379 : Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
95 379 : MAYBE_RETURN_NULL(maybe_index);
96 : size_t i = maybe_index.FromJust();
97 :
98 : uint32_t c;
99 614 : if (count->IsUndefined(isolate)) {
100 : c = kMaxUInt32;
101 : } else {
102 594 : ASSIGN_RETURN_ON_EXCEPTION(isolate, count,
103 : Object::ToInteger(isolate, count), Object);
104 297 : double count_double = count->Number();
105 297 : if (count_double < 0)
106 : count_double = 0;
107 297 : else if (count_double > kMaxUInt32)
108 : count_double = kMaxUInt32;
109 297 : c = static_cast<uint32_t>(count_double);
110 : }
111 :
112 307 : Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
113 614 : size_t addr = (i << 2) + sta->byte_offset();
114 :
115 614 : return Handle<Object>(FutexEmulation::Wake(array_buffer, addr, c), isolate);
116 : }
117 :
118 : } // namespace
119 :
120 : // ES #sec-atomics.wake
121 : // Atomics.wake( typedArray, index, count )
122 1748 : BUILTIN(AtomicsWake) {
123 : HandleScope scope(isolate);
124 437 : Handle<Object> array = args.atOrUndefined(isolate, 1);
125 437 : Handle<Object> index = args.atOrUndefined(isolate, 2);
126 437 : Handle<Object> count = args.atOrUndefined(isolate, 3);
127 :
128 437 : isolate->CountUsage(v8::Isolate::UseCounterFeature::kAtomicsWake);
129 1099 : RETURN_RESULT_OR_FAILURE(isolate, AtomicsWake(isolate, array, index, count));
130 : }
131 :
132 : // ES #sec-atomics.notify
133 : // Atomics.notify( typedArray, index, count )
134 380 : BUILTIN(AtomicsNotify) {
135 : HandleScope scope(isolate);
136 95 : Handle<Object> array = args.atOrUndefined(isolate, 1);
137 95 : Handle<Object> index = args.atOrUndefined(isolate, 2);
138 95 : Handle<Object> count = args.atOrUndefined(isolate, 3);
139 :
140 95 : isolate->CountUsage(v8::Isolate::UseCounterFeature::kAtomicsNotify);
141 190 : RETURN_RESULT_OR_FAILURE(isolate, AtomicsWake(isolate, array, index, count));
142 : }
143 :
144 : // ES #sec-atomics.wait
145 : // Atomics.wait( typedArray, index, value, timeout )
146 3034 : BUILTIN(AtomicsWait) {
147 : HandleScope scope(isolate);
148 652 : Handle<Object> array = args.atOrUndefined(isolate, 1);
149 652 : Handle<Object> index = args.atOrUndefined(isolate, 2);
150 : Handle<Object> value = args.atOrUndefined(isolate, 3);
151 : Handle<Object> timeout = args.atOrUndefined(isolate, 4);
152 :
153 : Handle<JSTypedArray> sta;
154 1456 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
155 : isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true));
156 :
157 498 : Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
158 571 : if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
159 : size_t i = maybe_index.FromJust();
160 :
161 853 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
162 : Object::ToInt32(isolate, value));
163 426 : int32_t value_int32 = NumberToInt32(*value);
164 :
165 : double timeout_number;
166 852 : if (timeout->IsUndefined(isolate)) {
167 269 : timeout_number = ReadOnlyRoots(isolate).infinity_value()->Number();
168 : } else {
169 316 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, timeout,
170 : Object::ToNumber(isolate, timeout));
171 158 : timeout_number = timeout->Number();
172 158 : if (std::isnan(timeout_number))
173 54 : timeout_number = ReadOnlyRoots(isolate).infinity_value()->Number();
174 104 : else if (timeout_number < 0)
175 : timeout_number = 0;
176 : }
177 :
178 427 : if (!isolate->allow_atomics_wait()) {
179 18 : THROW_NEW_ERROR_RETURN_FAILURE(
180 : isolate, NewTypeError(MessageTemplate::kAtomicsWaitNotAllowed));
181 : }
182 :
183 418 : Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
184 834 : size_t addr = (i << 2) + sta->byte_offset();
185 :
186 : return FutexEmulation::WaitJs(isolate, array_buffer, addr, value_int32,
187 417 : timeout_number);
188 : }
189 :
190 : } // namespace internal
191 183867 : } // namespace v8
|