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(double size) {
26 9072 : return size == 1 || size == 2 || size == 4;
27 : }
28 :
29 : // ES #sec-atomics.islockfree
30 45360 : 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 18144 : return *isolate->factory()->ToBoolean(AtomicIsLockFree(size->Number()));
36 : }
37 :
38 : // ES #sec-validatesharedintegertypedarray
39 1164 : V8_WARN_UNUSED_RESULT MaybeHandle<JSTypedArray> ValidateSharedIntegerTypedArray(
40 : Isolate* isolate, Handle<Object> object, bool only_int32 = false) {
41 1164 : if (object->IsJSTypedArray()) {
42 : Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object);
43 2328 : if (typed_array->GetBuffer()->is_shared()) {
44 1001 : if (only_int32) {
45 1001 : 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 613 : 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 858 : 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 1716 : 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 1644 : if (!TryNumberToSize(*access_index_obj, &access_index) ||
77 1644 : typed_array->WasDetached() || access_index >= typed_array->length()) {
78 216 : isolate->Throw(*isolate->factory()->NewRangeError(
79 216 : MessageTemplate::kInvalidAtomicAccessIndex));
80 : return Nothing<size_t>();
81 : }
82 : return Just<size_t>(access_index);
83 : }
84 :
85 : namespace {
86 524 : MaybeHandle<Object> AtomicsWake(Isolate* isolate, Handle<Object> array,
87 : Handle<Object> index, Handle<Object> count) {
88 : Handle<JSTypedArray> sta;
89 1048 : ASSIGN_RETURN_ON_EXCEPTION(
90 : isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true),
91 : Object);
92 :
93 371 : Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
94 371 : MAYBE_RETURN_NULL(maybe_index);
95 : size_t i = maybe_index.FromJust();
96 :
97 : uint32_t c;
98 299 : if (count->IsUndefined(isolate)) {
99 : c = kMaxUInt32;
100 : } else {
101 289 : ASSIGN_RETURN_ON_EXCEPTION(isolate, count,
102 : Object::ToInteger(isolate, count), Object);
103 : double count_double = count->Number();
104 289 : if (count_double < 0)
105 : count_double = 0;
106 289 : else if (count_double > kMaxUInt32)
107 : count_double = kMaxUInt32;
108 289 : c = static_cast<uint32_t>(count_double);
109 : }
110 :
111 299 : Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
112 598 : size_t addr = (i << 2) + sta->byte_offset();
113 :
114 598 : return Handle<Object>(FutexEmulation::Wake(array_buffer, addr, c), isolate);
115 : }
116 :
117 : } // namespace
118 :
119 : // ES #sec-atomics.wake
120 : // Atomics.wake( typedArray, index, count )
121 2145 : BUILTIN(AtomicsWake) {
122 : HandleScope scope(isolate);
123 429 : Handle<Object> array = args.atOrUndefined(isolate, 1);
124 429 : Handle<Object> index = args.atOrUndefined(isolate, 2);
125 429 : Handle<Object> count = args.atOrUndefined(isolate, 3);
126 :
127 429 : isolate->CountUsage(v8::Isolate::UseCounterFeature::kAtomicsWake);
128 1083 : RETURN_RESULT_OR_FAILURE(isolate, AtomicsWake(isolate, array, index, count));
129 : }
130 :
131 : // ES #sec-atomics.notify
132 : // Atomics.notify( typedArray, index, count )
133 475 : BUILTIN(AtomicsNotify) {
134 : HandleScope scope(isolate);
135 95 : Handle<Object> array = args.atOrUndefined(isolate, 1);
136 95 : Handle<Object> index = args.atOrUndefined(isolate, 2);
137 95 : Handle<Object> count = args.atOrUndefined(isolate, 3);
138 :
139 95 : isolate->CountUsage(v8::Isolate::UseCounterFeature::kAtomicsNotify);
140 190 : RETURN_RESULT_OR_FAILURE(isolate, AtomicsWake(isolate, array, index, count));
141 : }
142 :
143 : // ES #sec-atomics.wait
144 : // Atomics.wait( typedArray, index, value, timeout )
145 3200 : BUILTIN(AtomicsWait) {
146 : HandleScope scope(isolate);
147 640 : Handle<Object> array = args.atOrUndefined(isolate, 1);
148 640 : Handle<Object> index = args.atOrUndefined(isolate, 2);
149 : Handle<Object> value = args.atOrUndefined(isolate, 3);
150 : Handle<Object> timeout = args.atOrUndefined(isolate, 4);
151 :
152 : Handle<JSTypedArray> sta;
153 1433 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
154 : isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true));
155 :
156 487 : Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
157 559 : if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
158 : size_t i = maybe_index.FromJust();
159 :
160 415 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
161 : Object::ToInt32(isolate, value));
162 415 : int32_t value_int32 = NumberToInt32(*value);
163 :
164 : double timeout_number;
165 415 : if (timeout->IsUndefined(isolate)) {
166 : timeout_number = ReadOnlyRoots(isolate).infinity_value()->Number();
167 : } else {
168 316 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, timeout,
169 : Object::ToNumber(isolate, timeout));
170 : timeout_number = timeout->Number();
171 158 : if (std::isnan(timeout_number))
172 : timeout_number = ReadOnlyRoots(isolate).infinity_value()->Number();
173 104 : else if (timeout_number < 0)
174 : timeout_number = 0;
175 : }
176 :
177 415 : if (!isolate->allow_atomics_wait()) {
178 18 : THROW_NEW_ERROR_RETURN_FAILURE(
179 : isolate, NewTypeError(MessageTemplate::kAtomicsWaitNotAllowed));
180 : }
181 :
182 406 : Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
183 810 : size_t addr = (i << 2) + sta->byte_offset();
184 :
185 : return FutexEmulation::WaitJs(isolate, array_buffer, addr, value_int32,
186 405 : timeout_number);
187 : }
188 :
189 : } // namespace internal
190 122004 : } // namespace v8
|