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