Line data Source code
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/arguments-inl.h"
6 : #include "src/counters.h"
7 : #include "src/elements.h"
8 : #include "src/heap/factory.h"
9 : #include "src/heap/heap-inl.h"
10 : #include "src/message-template.h"
11 : #include "src/objects-inl.h"
12 : #include "src/objects/js-array-buffer-inl.h"
13 : #include "src/runtime/runtime-utils.h"
14 : #include "src/runtime/runtime.h"
15 :
16 : namespace v8 {
17 : namespace internal {
18 :
19 5968 : 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 2984 : if (!argument->IsJSArrayBuffer()) {
26 0 : THROW_NEW_ERROR_RETURN_FAILURE(
27 : isolate, NewTypeError(MessageTemplate::kNotTypedArray));
28 : }
29 2984 : Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(argument);
30 2984 : if (!array_buffer->is_detachable()) {
31 : return ReadOnlyRoots(isolate).undefined_value();
32 : }
33 2957 : if (array_buffer->backing_store() == nullptr) {
34 0 : CHECK_EQ(0, array_buffer->byte_length());
35 : return ReadOnlyRoots(isolate).undefined_value();
36 : }
37 : // Shared array buffers should never be detached.
38 2957 : CHECK(!array_buffer->is_shared());
39 : DCHECK(!array_buffer->is_external());
40 : void* backing_store = array_buffer->backing_store();
41 : size_t byte_length = array_buffer->byte_length();
42 : array_buffer->set_is_external(true);
43 2957 : isolate->heap()->UnregisterArrayBuffer(*array_buffer);
44 2957 : array_buffer->Detach();
45 2957 : isolate->array_buffer_allocator()->Free(backing_store, byte_length);
46 : return ReadOnlyRoots(isolate).undefined_value();
47 : }
48 :
49 58620 : RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) {
50 : HandleScope scope(isolate);
51 : DCHECK_EQ(3, args.length());
52 29310 : CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target, 0);
53 : CONVERT_ARG_HANDLE_CHECKED(Object, source, 1);
54 29310 : CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 2);
55 :
56 : size_t length;
57 29310 : CHECK(TryNumberToSize(*length_obj, &length));
58 :
59 29310 : ElementsAccessor* accessor = target->GetElementsAccessor();
60 58620 : return accessor->CopyElements(source, target, length);
61 : }
62 :
63 0 : RUNTIME_FUNCTION(Runtime_TypedArrayGetLength) {
64 : HandleScope scope(isolate);
65 : DCHECK_EQ(1, args.length());
66 0 : CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
67 : return holder->length();
68 : }
69 :
70 0 : RUNTIME_FUNCTION(Runtime_ArrayBufferViewWasDetached) {
71 : HandleScope scope(isolate);
72 : DCHECK_EQ(1, args.length());
73 : return isolate->heap()->ToBoolean(JSTypedArray::cast(args[0])->WasDetached());
74 : }
75 :
76 1306 : RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
77 : HandleScope scope(isolate);
78 : DCHECK_EQ(1, args.length());
79 653 : CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
80 1306 : return *holder->GetBuffer();
81 : }
82 :
83 :
84 : namespace {
85 :
86 : template <typename T>
87 360 : bool CompareNum(T x, T y) {
88 360 : if (x < y) {
89 : return true;
90 270 : } else if (x > y) {
91 : return false;
92 : } else if (!std::is_integral<T>::value) {
93 117 : double _x = x, _y = y;
94 234 : if (x == 0 && x == y) {
95 : /* -0.0 is less than +0.0 */
96 180 : return std::signbit(_x) && !std::signbit(_y);
97 126 : } else if (!std::isnan(_x) && std::isnan(_y)) {
98 : /* number is less than NaN */
99 : return true;
100 : }
101 : }
102 72 : return false;
103 : }
104 :
105 : } // namespace
106 :
107 1008 : RUNTIME_FUNCTION(Runtime_TypedArraySortFast) {
108 : HandleScope scope(isolate);
109 : DCHECK_EQ(1, args.length());
110 :
111 : CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0);
112 :
113 : Handle<JSTypedArray> array;
114 : const char* method = "%TypedArray%.prototype.sort";
115 1008 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
116 : isolate, array, JSTypedArray::Validate(isolate, target_obj, method));
117 :
118 : // This line can be removed when JSTypedArray::Validate throws
119 : // if array.[[ViewedArrayBuffer]] is detached(v8:4648)
120 504 : if (V8_UNLIKELY(array->WasDetached())) return *array;
121 :
122 : size_t length = array->length_value();
123 504 : if (length <= 1) return *array;
124 :
125 : Handle<FixedTypedArrayBase> elements(
126 : FixedTypedArrayBase::cast(array->elements()), isolate);
127 342 : switch (array->type()) {
128 : #define TYPED_ARRAY_SORT(Type, type, TYPE, ctype) \
129 : case kExternal##Type##Array: { \
130 : ctype* data = static_cast<ctype*>(elements->DataPtr()); \
131 : if (kExternal##Type##Array == kExternalFloat64Array || \
132 : kExternal##Type##Array == kExternalFloat32Array) { \
133 : if (COMPRESS_POINTERS_BOOL && alignof(ctype) > kTaggedSize) { \
134 : /* TODO(ishell, v8:8875): See UnalignedSlot<T> for details. */ \
135 : std::sort(UnalignedSlot<ctype>(data), \
136 : UnalignedSlot<ctype>(data + length), CompareNum<ctype>); \
137 : } else { \
138 : std::sort(data, data + length, CompareNum<ctype>); \
139 : } \
140 : } else { \
141 : if (COMPRESS_POINTERS_BOOL && alignof(ctype) > kTaggedSize) { \
142 : /* TODO(ishell, v8:8875): See UnalignedSlot<T> for details. */ \
143 : std::sort(UnalignedSlot<ctype>(data), \
144 : UnalignedSlot<ctype>(data + length)); \
145 : } else { \
146 : std::sort(data, data + length); \
147 : } \
148 : } \
149 : break; \
150 : }
151 :
152 342 : TYPED_ARRAYS(TYPED_ARRAY_SORT)
153 : #undef TYPED_ARRAY_SORT
154 : }
155 :
156 : return *array;
157 : }
158 :
159 0 : RUNTIME_FUNCTION(Runtime_IsTypedArray) {
160 : HandleScope scope(isolate);
161 : DCHECK_EQ(1, args.length());
162 : return isolate->heap()->ToBoolean(args[0]->IsJSTypedArray());
163 : }
164 :
165 : // 22.2.3.23 %TypedArray%.prototype.set ( overloaded [ , offset ] )
166 2754 : RUNTIME_FUNCTION(Runtime_TypedArraySet) {
167 : HandleScope scope(isolate);
168 : Handle<JSTypedArray> target = args.at<JSTypedArray>(0);
169 : Handle<Object> obj = args.at(1);
170 : Handle<Smi> offset = args.at<Smi>(2);
171 :
172 : DCHECK(!target->WasDetached()); // Checked in TypedArrayPrototypeSet.
173 : DCHECK(!obj->IsJSTypedArray()); // Should be handled by CSA.
174 : DCHECK_LE(0, offset->value());
175 :
176 1377 : const uint32_t uint_offset = static_cast<uint32_t>(offset->value());
177 :
178 1377 : if (obj->IsNumber()) {
179 : // For number as a first argument, throw TypeError
180 : // instead of silently ignoring the call, so that
181 : // users know they did something wrong.
182 : // (Consistent with Firefox and Blink/WebKit)
183 126 : THROW_NEW_ERROR_RETURN_FAILURE(
184 : isolate, NewTypeError(MessageTemplate::kInvalidArgument));
185 : }
186 :
187 2628 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, obj,
188 : Object::ToObject(isolate, obj));
189 :
190 : Handle<Object> len;
191 2628 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
192 : isolate, len,
193 : Object::GetProperty(isolate, obj, isolate->factory()->length_string()));
194 2628 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, len,
195 : Object::ToLength(isolate, len));
196 :
197 3699 : if (uint_offset + len->Number() > target->length_value()) {
198 36 : THROW_NEW_ERROR_RETURN_FAILURE(
199 : isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
200 : }
201 :
202 : uint32_t int_l;
203 1215 : CHECK(DoubleToUint32IfEqualToSelf(len->Number(), &int_l));
204 :
205 : Handle<JSReceiver> source = Handle<JSReceiver>::cast(obj);
206 1215 : ElementsAccessor* accessor = target->GetElementsAccessor();
207 2430 : return accessor->CopyElements(source, target, int_l, uint_offset);
208 : }
209 :
210 : } // namespace internal
211 120216 : } // namespace v8
|