v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
runtime-typedarray.cc
Go to the documentation of this file.
1// Copyright 2014 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
8#include "src/heap/factory.h"
13#include "src/runtime/runtime.h"
14#include "third_party/fp16/src/include/fp16.h"
15
16namespace v8 {
17namespace internal {
18
19RUNTIME_FUNCTION(Runtime_ArrayBufferDetach) {
20 HandleScope scope(isolate);
21 // This runtime function is exposed in ClusterFuzz and as such has to
22 // support arbitrary arguments.
23 if (args.length() < 1 || !IsJSArrayBuffer(*args.at(0))) {
25 isolate, NewTypeError(MessageTemplate::kNotTypedArray));
26 }
27 auto array_buffer = Cast<JSArrayBuffer>(args.at(0));
28 constexpr bool kForceForWasmMemory = false;
29 MAYBE_RETURN(JSArrayBuffer::Detach(array_buffer, kForceForWasmMemory,
30 args.atOrUndefined(isolate, 1)),
31 ReadOnlyRoots(isolate).exception());
32 return ReadOnlyRoots(isolate).undefined_value();
33}
34
35RUNTIME_FUNCTION(Runtime_ArrayBufferSetDetachKey) {
36 HandleScope scope(isolate);
37 DCHECK_EQ(2, args.length());
38 Handle<Object> argument = args.at(0);
40 // This runtime function is exposed in ClusterFuzz and as such has to
41 // support arbitrary arguments.
42 if (!IsJSArrayBuffer(*argument)) {
44 isolate, NewTypeError(MessageTemplate::kNotTypedArray));
45 }
46 auto array_buffer = Cast<JSArrayBuffer>(argument);
47 array_buffer->set_detach_key(*key);
48 return ReadOnlyRoots(isolate).undefined_value();
49}
50
51RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) {
52 HandleScope scope(isolate);
53 DCHECK_EQ(3, args.length());
55 DirectHandle<JSAny> source = args.at<JSAny>(1);
56 size_t length;
57 CHECK(TryNumberToSize(args[2], &length));
58 ElementsAccessor* accessor = target->GetElementsAccessor();
59 return accessor->CopyElements(source, target, length, 0);
60}
61
62RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
63 HandleScope scope(isolate);
64 DCHECK_EQ(1, args.length());
66 return *holder->GetBuffer();
67}
68
69RUNTIME_FUNCTION(Runtime_GrowableSharedArrayBufferByteLength) {
70 HandleScope scope(isolate);
71 DCHECK_EQ(1, args.length());
73
74 // When this is called from Wasm code (which can happen by recognizing the
75 // special `DataView.prototype.byteLength` import), clear the "thread in wasm"
76 // flag, which is important in case any GC needs to happen when allocating the
77 // number below.
78 // TODO(40192807): Find a better fix, either by replacing the global flag, or
79 // by implementing this via a Wasm-specific external reference callback which
80 // returns a uintptr_t directly (without allocating on the heap).
81 SaveAndClearThreadInWasmFlag clear_wasm_flag(isolate);
82
83 CHECK_EQ(0, array_buffer->byte_length_unchecked());
84 size_t byte_length = array_buffer->GetBackingStore()->byte_length();
85 return *isolate->factory()->NewNumberFromSize(byte_length);
86}
87
88namespace {
89
90template <typename T>
91bool CompareNum(T x, T y) {
92 if (x < y) {
93 return true;
94 } else if (x > y) {
95 return false;
96 } else if (!std::is_integral_v<T>) {
97 double _x = x, _y = y;
98 if (x == 0 && x == y) {
99 /* -0.0 is less than +0.0 */
100 return std::signbit(_x) && !std::signbit(_y);
101 } else if (!std::isnan(_x) && std::isnan(_y)) {
102 /* number is less than NaN */
103 return true;
104 }
105 }
106 return false;
107}
108
109bool LessThanFloat16RawBits(uint16_t x, uint16_t y) {
110 return CompareNum(fp16_ieee_to_fp32_value(x), fp16_ieee_to_fp32_value(y));
111}
112
113} // namespace
114
115RUNTIME_FUNCTION(Runtime_TypedArraySortFast) {
116 HandleScope scope(isolate);
117 DCHECK_EQ(1, args.length());
118
119 // Validation is handled in the Torque builtin.
121 DCHECK(!array->WasDetached());
122 DCHECK(!array->IsOutOfBounds());
123
124#ifdef V8_OS_LINUX
125 if (v8_flags.multi_mapped_mock_allocator) {
126 // Sorting is meaningless with the mock allocator, and std::sort
127 // might crash (because aliasing elements violate its assumptions).
128 return *array;
129 }
130#endif
131
132 const size_t byte_length = array->GetByteLength();
133
134 // In case of a SAB, the data is copied into temporary memory, as
135 // std::sort might crash in case the underlying data is concurrently
136 // modified while sorting.
137 CHECK(IsJSArrayBuffer(array->buffer()));
138 DirectHandle<JSArrayBuffer> buffer(Cast<JSArrayBuffer>(array->buffer()),
139 isolate);
140 const bool copy_data = buffer->is_shared();
141
142 DirectHandle<ByteArray> array_copy;
143 std::vector<uint8_t> offheap_copy;
144 void* data_copy_ptr = nullptr;
145 if (copy_data) {
146 if (byte_length <= static_cast<unsigned>(
148 array_copy =
149 isolate->factory()->NewByteArray(static_cast<int>(byte_length));
150 data_copy_ptr = array_copy->begin();
151 } else {
152 // Allocate copy in C++ heap.
153 offheap_copy.resize(byte_length);
154 data_copy_ptr = &offheap_copy[0];
155 }
156 base::Relaxed_Memcpy(static_cast<base::Atomic8*>(data_copy_ptr),
157 static_cast<base::Atomic8*>(array->DataPtr()),
158 byte_length);
159 }
160
162
163 size_t length = array->GetLength();
164 DCHECK_LT(1, length);
165
166 switch (array->type()) {
167#define TYPED_ARRAY_SORT(Type, type, TYPE, ctype) \
168 case kExternal##Type##Array: { \
169 ctype* data = copy_data ? reinterpret_cast<ctype*>(data_copy_ptr) \
170 : static_cast<ctype*>(array->DataPtr()); \
171 SBXCHECK(length * sizeof(ctype) == byte_length); \
172 if (kExternal##Type##Array == kExternalFloat64Array || \
173 kExternal##Type##Array == kExternalFloat32Array) { \
174 if (COMPRESS_POINTERS_BOOL && alignof(ctype) > kTaggedSize) { \
175 /* TODO(ishell, v8:8875): See UnalignedSlot<T> for details. */ \
176 std::sort(UnalignedSlot<ctype>(data), \
177 UnalignedSlot<ctype>(data + length), CompareNum<ctype>); \
178 } else { \
179 std::sort(data, data + length, CompareNum<ctype>); \
180 } \
181 } else if (kExternal##Type##Array == kExternalFloat16Array) { \
182 DCHECK_IMPLIES(COMPRESS_POINTERS_BOOL, alignof(ctype) <= kTaggedSize); \
183 std::sort(data, data + length, LessThanFloat16RawBits); \
184 } else { \
185 if (COMPRESS_POINTERS_BOOL && alignof(ctype) > kTaggedSize) { \
186 /* TODO(ishell, v8:8875): See UnalignedSlot<T> for details. */ \
187 std::sort(UnalignedSlot<ctype>(data), \
188 UnalignedSlot<ctype>(data + length)); \
189 } else { \
190 std::sort(data, data + length); \
191 } \
192 } \
193 break; \
194 }
196#undef TYPED_ARRAY_SORT
197 }
198
199 if (copy_data) {
200 DCHECK_NOT_NULL(data_copy_ptr);
201 DCHECK_NE(array_copy.is_null(), offheap_copy.empty());
202 base::Relaxed_Memcpy(static_cast<base::Atomic8*>(array->DataPtr()),
203 static_cast<base::Atomic8*>(data_copy_ptr),
204 byte_length);
205 }
206
207 return *array;
208}
209
210RUNTIME_FUNCTION(Runtime_TypedArraySet) {
211 HandleScope scope(isolate);
212 DCHECK_EQ(4, args.length());
214 DirectHandle<JSAny> source = args.at<JSAny>(1);
215 size_t length;
216 CHECK(TryNumberToSize(args[2], &length));
217 size_t offset;
219 ElementsAccessor* accessor = target->GetElementsAccessor();
220 return accessor->CopyElements(source, target, length, offset);
221}
222
223RUNTIME_FUNCTION(Runtime_ArrayBufferMaxByteLength) {
224 HandleScope shs(isolate);
225 size_t heap_max = isolate->array_buffer_allocator()->MaxAllocationSize();
226 return *isolate->factory()->NewNumber(heap_max);
227}
228
229} // namespace internal
230} // namespace v8
static constexpr int LengthFor(int size_in_bytes)
V8_INLINE bool is_null() const
Definition handles.h:693
virtual void CopyElements(Isolate *isolate, DirectHandle< FixedArrayBase > source, ElementsKind source_kind, DirectHandle< FixedArrayBase > destination, int size)=0
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > Detach(DirectHandle< JSArrayBuffer > buffer, bool force_for_wasm_memory=false, DirectHandle< Object > key={})
#define TYPED_ARRAYS(V)
#define RUNTIME_FUNCTION(Name)
Definition arguments.h:162
#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)
Definition isolate.h:294
#define MAYBE_RETURN(call, value)
Definition isolate.h:408
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
int32_t offset
int x
void Relaxed_Memcpy(volatile Atomic8 *dst, volatile const Atomic8 *src, size_t bytes)
Definition atomicops.h:363
char Atomic8
Definition atomicops.h:57
constexpr int kMaxRegularHeapObjectSize
Definition globals.h:680
V8_EXPORT_PRIVATE FlagValues v8_flags
bool TryNumberToSize(Tagged< Object > number, size_t *result)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
#define TYPED_ARRAY_SORT(Type, type, TYPE, ctype)
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485