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