• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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