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
5 #include "src/base/atomicops.h"
6 #include "src/common/message-template.h"
7 #include "src/execution/arguments-inl.h"
8 #include "src/heap/factory.h"
9 #include "src/heap/heap-inl.h"
10 #include "src/logging/counters.h"
11 #include "src/objects/elements.h"
12 #include "src/objects/js-array-buffer-inl.h"
13 #include "src/objects/objects-inl.h"
14 #include "src/runtime/runtime-utils.h"
15 #include "src/runtime/runtime.h"
16
17 namespace v8 {
18 namespace internal {
19
RUNTIME_FUNCTION(Runtime_ArrayBufferDetach)20 RUNTIME_FUNCTION(Runtime_ArrayBufferDetach) {
21 HandleScope scope(isolate);
22 DCHECK_EQ(1, args.length());
23 Handle<Object> argument = args.at(0);
24 // This runtime function is exposed in ClusterFuzz and as such has to
25 // support arbitrary arguments.
26 if (!argument->IsJSArrayBuffer()) {
27 THROW_NEW_ERROR_RETURN_FAILURE(
28 isolate, NewTypeError(MessageTemplate::kNotTypedArray));
29 }
30 Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(argument);
31 array_buffer->Detach();
32 return ReadOnlyRoots(isolate).undefined_value();
33 }
34
RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements)35 RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) {
36 HandleScope scope(isolate);
37 DCHECK_EQ(3, args.length());
38 Handle<JSTypedArray> target = args.at<JSTypedArray>(0);
39 Handle<Object> source = args.at(1);
40 size_t length;
41 CHECK(TryNumberToSize(args[2], &length));
42 ElementsAccessor* accessor = target->GetElementsAccessor();
43 return accessor->CopyElements(source, target, length, 0);
44 }
45
RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer)46 RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
47 HandleScope scope(isolate);
48 DCHECK_EQ(1, args.length());
49 Handle<JSTypedArray> holder = args.at<JSTypedArray>(0);
50 return *holder->GetBuffer();
51 }
52
RUNTIME_FUNCTION(Runtime_GrowableSharedArrayBufferByteLength)53 RUNTIME_FUNCTION(Runtime_GrowableSharedArrayBufferByteLength) {
54 HandleScope scope(isolate);
55 DCHECK_EQ(1, args.length());
56 Handle<JSArrayBuffer> array_buffer = args.at<JSArrayBuffer>(0);
57
58 CHECK_EQ(0, array_buffer->byte_length());
59 size_t byte_length = array_buffer->GetBackingStore()->byte_length();
60 return *isolate->factory()->NewNumberFromSize(byte_length);
61 }
62
63 namespace {
64
65 template <typename T>
CompareNum(T x,T y)66 bool CompareNum(T x, T y) {
67 if (x < y) {
68 return true;
69 } else if (x > y) {
70 return false;
71 } else if (!std::is_integral<T>::value) {
72 double _x = x, _y = y;
73 if (x == 0 && x == y) {
74 /* -0.0 is less than +0.0 */
75 return std::signbit(_x) && !std::signbit(_y);
76 } else if (!std::isnan(_x) && std::isnan(_y)) {
77 /* number is less than NaN */
78 return true;
79 }
80 }
81 return false;
82 }
83
84 } // namespace
85
RUNTIME_FUNCTION(Runtime_TypedArraySortFast)86 RUNTIME_FUNCTION(Runtime_TypedArraySortFast) {
87 HandleScope scope(isolate);
88 DCHECK_EQ(1, args.length());
89
90 // Validation is handled in the Torque builtin.
91 Handle<JSTypedArray> array = args.at<JSTypedArray>(0);
92 DCHECK(!array->WasDetached());
93 DCHECK(!array->IsOutOfBounds());
94
95 #if MULTI_MAPPED_ALLOCATOR_AVAILABLE
96 if (FLAG_multi_mapped_mock_allocator) {
97 // Sorting is meaningless with the mock allocator, and std::sort
98 // might crash (because aliasing elements violate its assumptions).
99 return *array;
100 }
101 #endif
102
103 size_t length = array->GetLength();
104 DCHECK_LT(1, length);
105
106 // In case of a SAB, the data is copied into temporary memory, as
107 // std::sort might crash in case the underlying data is concurrently
108 // modified while sorting.
109 CHECK(array->buffer().IsJSArrayBuffer());
110 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(array->buffer()), isolate);
111 const bool copy_data = buffer->is_shared();
112
113 Handle<ByteArray> array_copy;
114 std::vector<uint8_t> offheap_copy;
115 void* data_copy_ptr = nullptr;
116 if (copy_data) {
117 const size_t bytes = array->GetByteLength();
118 if (bytes <= static_cast<unsigned>(
119 ByteArray::LengthFor(kMaxRegularHeapObjectSize))) {
120 array_copy = isolate->factory()->NewByteArray(static_cast<int>(bytes));
121 data_copy_ptr = array_copy->GetDataStartAddress();
122 } else {
123 // Allocate copy in C++ heap.
124 offheap_copy.resize(bytes);
125 data_copy_ptr = &offheap_copy[0];
126 }
127 base::Relaxed_Memcpy(static_cast<base::Atomic8*>(data_copy_ptr),
128 static_cast<base::Atomic8*>(array->DataPtr()), bytes);
129 }
130
131 DisallowGarbageCollection no_gc;
132
133 switch (array->type()) {
134 #define TYPED_ARRAY_SORT(Type, type, TYPE, ctype) \
135 case kExternal##Type##Array: { \
136 ctype* data = copy_data ? reinterpret_cast<ctype*>(data_copy_ptr) \
137 : static_cast<ctype*>(array->DataPtr()); \
138 if (kExternal##Type##Array == kExternalFloat64Array || \
139 kExternal##Type##Array == kExternalFloat32Array) { \
140 if (COMPRESS_POINTERS_BOOL && alignof(ctype) > kTaggedSize) { \
141 /* TODO(ishell, v8:8875): See UnalignedSlot<T> for details. */ \
142 std::sort(UnalignedSlot<ctype>(data), \
143 UnalignedSlot<ctype>(data + length), CompareNum<ctype>); \
144 } else { \
145 std::sort(data, data + length, CompareNum<ctype>); \
146 } \
147 } else { \
148 if (COMPRESS_POINTERS_BOOL && alignof(ctype) > kTaggedSize) { \
149 /* TODO(ishell, v8:8875): See UnalignedSlot<T> for details. */ \
150 std::sort(UnalignedSlot<ctype>(data), \
151 UnalignedSlot<ctype>(data + length)); \
152 } else { \
153 std::sort(data, data + length); \
154 } \
155 } \
156 break; \
157 }
158
159 TYPED_ARRAYS(TYPED_ARRAY_SORT)
160 #undef TYPED_ARRAY_SORT
161 }
162
163 if (copy_data) {
164 DCHECK_NOT_NULL(data_copy_ptr);
165 DCHECK_NE(array_copy.is_null(), offheap_copy.empty());
166 const size_t bytes = array->GetByteLength();
167 base::Relaxed_Memcpy(static_cast<base::Atomic8*>(array->DataPtr()),
168 static_cast<base::Atomic8*>(data_copy_ptr), bytes);
169 }
170
171 return *array;
172 }
173
RUNTIME_FUNCTION(Runtime_TypedArraySet)174 RUNTIME_FUNCTION(Runtime_TypedArraySet) {
175 HandleScope scope(isolate);
176 DCHECK_EQ(4, args.length());
177 Handle<JSTypedArray> target = args.at<JSTypedArray>(0);
178 Handle<Object> source = args.at(1);
179 size_t length;
180 CHECK(TryNumberToSize(args[2], &length));
181 size_t offset;
182 CHECK(TryNumberToSize(args[3], &offset));
183 ElementsAccessor* accessor = target->GetElementsAccessor();
184 return accessor->CopyElements(source, target, length, offset);
185 }
186
187 } // namespace internal
188 } // namespace v8
189