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 9072 : return size == 1 || size == 2 || size == 4;
26 : }
27 :
28 : // ES #sec-atomics.islockfree
29 27216 : BUILTIN(AtomicsIsLockFree) {
30 : HandleScope scope(isolate);
31 : Handle<Object> size = args.atOrUndefined(isolate, 1);
32 18144 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, size, Object::ToNumber(size));
33 27216 : return *isolate->factory()->ToBoolean(AtomicIsLockFree(size->Number()));
34 : }
35 :
36 : // ES #sec-validatesharedintegertypedarray
37 789 : MUST_USE_RESULT MaybeHandle<JSTypedArray> ValidateSharedIntegerTypedArray(
38 : Isolate* isolate, Handle<Object> object, bool only_int32 = false) {
39 789 : if (object->IsJSTypedArray()) {
40 : Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object);
41 1578 : if (typed_array->GetBuffer()->is_shared()) {
42 627 : if (only_int32) {
43 627 : 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 0 : return typed_array;
49 : }
50 : }
51 : }
52 :
53 612 : 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 483 : 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 966 : 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 : size_t access_index;
74 894 : if (!TryNumberToSize(*access_index_obj, &access_index) ||
75 447 : access_index >= typed_array->length_value()) {
76 : isolate->Throw(*isolate->factory()->NewRangeError(
77 216 : MessageTemplate::kInvalidAtomicAccessIndex));
78 : return Nothing<size_t>();
79 : }
80 : return Just<size_t>(access_index);
81 : }
82 :
83 : // ES #sec-atomics.wake
84 : // Atomics.wake( typedArray, index, count )
85 1089 : BUILTIN(AtomicsWake) {
86 : HandleScope scope(isolate);
87 363 : Handle<Object> array = args.atOrUndefined(isolate, 1);
88 363 : Handle<Object> index = args.atOrUndefined(isolate, 2);
89 : Handle<Object> count = args.atOrUndefined(isolate, 3);
90 :
91 : Handle<JSTypedArray> sta;
92 726 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
93 : isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true));
94 :
95 210 : Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
96 210 : if (maybe_index.IsNothing()) return isolate->heap()->exception();
97 : size_t i = maybe_index.FromJust();
98 :
99 : uint32_t c;
100 138 : if (count->IsUndefined(isolate)) {
101 : c = kMaxUInt32;
102 : } else {
103 138 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, count,
104 : Object::ToInteger(isolate, count));
105 : double count_double = count->Number();
106 138 : if (count_double < 0)
107 : count_double = 0;
108 138 : else if (count_double > kMaxUInt32)
109 : count_double = kMaxUInt32;
110 138 : c = static_cast<uint32_t>(count_double);
111 : }
112 :
113 138 : Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
114 276 : size_t addr = (i << 2) + NumberToSize(sta->byte_offset());
115 :
116 138 : return FutexEmulation::Wake(isolate, array_buffer, addr, c);
117 : }
118 :
119 : // ES #sec-atomics.wait
120 : // Atomics.wait( typedArray, index, value, timeout )
121 1479 : BUILTIN(AtomicsWait) {
122 : HandleScope scope(isolate);
123 426 : Handle<Object> array = args.atOrUndefined(isolate, 1);
124 426 : Handle<Object> index = args.atOrUndefined(isolate, 2);
125 : Handle<Object> value = args.atOrUndefined(isolate, 3);
126 : Handle<Object> timeout = args.atOrUndefined(isolate, 4);
127 :
128 : Handle<JSTypedArray> sta;
129 852 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
130 : isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true));
131 :
132 273 : Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
133 273 : if (maybe_index.IsNothing()) return isolate->heap()->exception();
134 : size_t i = maybe_index.FromJust();
135 :
136 201 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
137 : Object::ToInt32(isolate, value));
138 201 : int32_t value_int32 = NumberToInt32(*value);
139 :
140 : double timeout_number;
141 201 : if (timeout->IsUndefined(isolate)) {
142 102 : timeout_number = isolate->heap()->infinity_value()->Number();
143 : } else {
144 198 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, timeout,
145 : Object::ToNumber(timeout));
146 : timeout_number = timeout->Number();
147 99 : if (std::isnan(timeout_number))
148 27 : timeout_number = isolate->heap()->infinity_value()->Number();
149 72 : else if (timeout_number < 0)
150 : timeout_number = 0;
151 : }
152 :
153 201 : if (!isolate->allow_atomics_wait()) {
154 18 : THROW_NEW_ERROR_RETURN_FAILURE(
155 : isolate, NewTypeError(MessageTemplate::kAtomicsWaitNotAllowed));
156 : }
157 :
158 192 : Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
159 384 : size_t addr = (i << 2) + NumberToSize(sta->byte_offset());
160 :
161 : return FutexEmulation::Wait(isolate, array_buffer, addr, value_int32,
162 192 : timeout_number);
163 : }
164 :
165 : } // namespace internal
166 : } // namespace v8
|