V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
builtins-sharedarraybuffer.cc
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  return size == 1 || size == 2 || size == 4;
27 }
28 
29 // ES #sec-atomics.islockfree
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
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 )
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  typed_array->WasNeutered() ||
78  access_index >= typed_array->length_value()) {
79  isolate->Throw(*isolate->factory()->NewRangeError(
80  MessageTemplate::kInvalidAtomicAccessIndex));
81  return Nothing<size_t>();
82  }
83  return Just<size_t>(access_index);
84 }
85 
86 namespace {
87 MaybeHandle<Object> AtomicsWake(Isolate* isolate, Handle<Object> array,
88  Handle<Object> index, Handle<Object> count) {
89  Handle<JSTypedArray> sta;
90  ASSIGN_RETURN_ON_EXCEPTION(
91  isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true),
92  Object);
93 
94  Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
95  MAYBE_RETURN_NULL(maybe_index);
96  size_t i = maybe_index.FromJust();
97 
98  uint32_t c;
99  if (count->IsUndefined(isolate)) {
100  c = kMaxUInt32;
101  } else {
102  ASSIGN_RETURN_ON_EXCEPTION(isolate, count,
103  Object::ToInteger(isolate, count), Object);
104  double count_double = count->Number();
105  if (count_double < 0)
106  count_double = 0;
107  else if (count_double > kMaxUInt32)
108  count_double = kMaxUInt32;
109  c = static_cast<uint32_t>(count_double);
110  }
111 
112  Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
113  size_t addr = (i << 2) + sta->byte_offset();
114 
115  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 BUILTIN(AtomicsWake) {
123  HandleScope scope(isolate);
124  Handle<Object> array = args.atOrUndefined(isolate, 1);
125  Handle<Object> index = args.atOrUndefined(isolate, 2);
126  Handle<Object> count = args.atOrUndefined(isolate, 3);
127 
128  isolate->CountUsage(v8::Isolate::UseCounterFeature::kAtomicsWake);
129  RETURN_RESULT_OR_FAILURE(isolate, AtomicsWake(isolate, array, index, count));
130 }
131 
132 // ES #sec-atomics.notify
133 // Atomics.notify( typedArray, index, count )
134 BUILTIN(AtomicsNotify) {
135  HandleScope scope(isolate);
136  Handle<Object> array = args.atOrUndefined(isolate, 1);
137  Handle<Object> index = args.atOrUndefined(isolate, 2);
138  Handle<Object> count = args.atOrUndefined(isolate, 3);
139 
140  isolate->CountUsage(v8::Isolate::UseCounterFeature::kAtomicsNotify);
141  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 BUILTIN(AtomicsWait) {
147  HandleScope scope(isolate);
148  Handle<Object> array = args.atOrUndefined(isolate, 1);
149  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  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
155  isolate, sta, ValidateSharedIntegerTypedArray(isolate, array, true));
156 
157  Maybe<size_t> maybe_index = ValidateAtomicAccess(isolate, sta, index);
158  if (maybe_index.IsNothing()) return ReadOnlyRoots(isolate).exception();
159  size_t i = maybe_index.FromJust();
160 
161  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
162  Object::ToInt32(isolate, value));
163  int32_t value_int32 = NumberToInt32(*value);
164 
165  double timeout_number;
166  if (timeout->IsUndefined(isolate)) {
167  timeout_number = ReadOnlyRoots(isolate).infinity_value()->Number();
168  } else {
169  ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, timeout,
170  Object::ToNumber(isolate, timeout));
171  timeout_number = timeout->Number();
172  if (std::isnan(timeout_number))
173  timeout_number = ReadOnlyRoots(isolate).infinity_value()->Number();
174  else if (timeout_number < 0)
175  timeout_number = 0;
176  }
177 
178  if (!isolate->allow_atomics_wait()) {
179  THROW_NEW_ERROR_RETURN_FAILURE(
180  isolate, NewTypeError(MessageTemplate::kAtomicsWaitNotAllowed));
181  }
182 
183  Handle<JSArrayBuffer> array_buffer = sta->GetBuffer();
184  size_t addr = (i << 2) + sta->byte_offset();
185 
186  return FutexEmulation::WaitJs(isolate, array_buffer, addr, value_int32,
187  timeout_number);
188 }
189 
190 } // namespace internal
191 } // namespace v8
Definition: libplatform.h:13