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/runtime/runtime-utils.h"
6 :
7 : #include "src/arguments.h"
8 : #include "src/elements.h"
9 : #include "src/factory.h"
10 : #include "src/messages.h"
11 : #include "src/objects-inl.h"
12 : #include "src/runtime/runtime.h"
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 0 : RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
18 : SealHandleScope shs(isolate);
19 : DCHECK_EQ(1, args.length());
20 0 : CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
21 0 : return holder->byte_length();
22 : }
23 :
24 :
25 5858 : RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
26 1956 : HandleScope scope(isolate);
27 : DCHECK_EQ(1, args.length());
28 1956 : Handle<Object> argument = args.at(0);
29 : // This runtime function is exposed in ClusterFuzz and as such has to
30 : // support arbitrary arguments.
31 1956 : if (!argument->IsJSArrayBuffer()) {
32 0 : THROW_NEW_ERROR_RETURN_FAILURE(
33 : isolate, NewTypeError(MessageTemplate::kNotTypedArray));
34 : }
35 1956 : Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(argument);
36 1956 : if (!array_buffer->is_neuterable()) {
37 0 : return isolate->heap()->undefined_value();
38 : }
39 1956 : if (array_buffer->backing_store() == nullptr) {
40 10 : CHECK_EQ(Smi::kZero, array_buffer->byte_length());
41 10 : return isolate->heap()->undefined_value();
42 : }
43 : // Shared array buffers should never be neutered.
44 1946 : CHECK(!array_buffer->is_shared());
45 : DCHECK(!array_buffer->is_external());
46 : void* backing_store = array_buffer->backing_store();
47 1946 : size_t byte_length = NumberToSize(array_buffer->byte_length());
48 1946 : array_buffer->set_is_external(true);
49 1946 : isolate->heap()->UnregisterArrayBuffer(*array_buffer);
50 1946 : array_buffer->Neuter();
51 1946 : isolate->array_buffer_allocator()->Free(backing_store, byte_length);
52 1946 : return isolate->heap()->undefined_value();
53 : }
54 :
55 50726 : RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) {
56 25363 : HandleScope scope(isolate);
57 : DCHECK_EQ(3, args.length());
58 50726 : CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target, 0);
59 50726 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, source, 1);
60 50726 : CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 2);
61 :
62 : size_t length;
63 25363 : CHECK(TryNumberToSize(*length_obj, &length));
64 :
65 25363 : ElementsAccessor* accessor = target->GetElementsAccessor();
66 50726 : return accessor->CopyElements(source, target, length);
67 : }
68 :
69 : #define BUFFER_VIEW_GETTER(Type, getter, accessor) \
70 : RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \
71 : HandleScope scope(isolate); \
72 : DCHECK_EQ(1, args.length()); \
73 : CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \
74 : return holder->accessor(); \
75 : }
76 :
77 6056 : BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
78 33796 : BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
79 72156 : BUFFER_VIEW_GETTER(TypedArray, Length, length)
80 :
81 : #undef BUFFER_VIEW_GETTER
82 :
83 35336 : RUNTIME_FUNCTION(Runtime_ArrayBufferViewWasNeutered) {
84 17668 : HandleScope scope(isolate);
85 : DCHECK_EQ(1, args.length());
86 17668 : return isolate->heap()->ToBoolean(JSTypedArray::cast(args[0])->WasNeutered());
87 : }
88 :
89 22200 : RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
90 11100 : HandleScope scope(isolate);
91 : DCHECK_EQ(1, args.length());
92 22200 : CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
93 22200 : return *holder->GetBuffer();
94 : }
95 :
96 :
97 : namespace {
98 :
99 : template <typename T>
100 360 : bool CompareNum(T x, T y) {
101 360 : if (x < y) {
102 : return true;
103 270 : } else if (x > y) {
104 : return false;
105 : } else if (!std::is_integral<T>::value) {
106 117 : double _x = x, _y = y;
107 234 : if (x == 0 && x == y) {
108 : /* -0.0 is less than +0.0 */
109 180 : return std::signbit(_x) && !std::signbit(_y);
110 126 : } else if (!std::isnan(_x) && std::isnan(_y)) {
111 : /* number is less than NaN */
112 : return true;
113 : }
114 : }
115 72 : return false;
116 : }
117 :
118 : } // namespace
119 :
120 866 : RUNTIME_FUNCTION(Runtime_TypedArraySortFast) {
121 433 : HandleScope scope(isolate);
122 : DCHECK_EQ(1, args.length());
123 :
124 433 : CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0);
125 :
126 : Handle<JSTypedArray> array;
127 : const char* method = "%TypedArray%.prototype.sort";
128 866 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
129 : isolate, array, JSTypedArray::Validate(isolate, target_obj, method));
130 :
131 : // This line can be removed when JSTypedArray::Validate throws
132 : // if array.[[ViewedArrayBuffer]] is neutered(v8:4648)
133 433 : if (V8_UNLIKELY(array->WasNeutered())) return *array;
134 :
135 433 : size_t length = array->length_value();
136 433 : if (length <= 1) return *array;
137 :
138 : Handle<FixedTypedArrayBase> elements(
139 271 : FixedTypedArrayBase::cast(array->elements()));
140 271 : switch (array->type()) {
141 : #define TYPED_ARRAY_SORT(Type, type, TYPE, ctype, size) \
142 : case kExternal##Type##Array: { \
143 : ctype* data = static_cast<ctype*>(elements->DataPtr()); \
144 : if (kExternal##Type##Array == kExternalFloat64Array || \
145 : kExternal##Type##Array == kExternalFloat32Array) \
146 : std::sort(data, data + length, CompareNum<ctype>); \
147 : else \
148 : std::sort(data, data + length); \
149 : break; \
150 : }
151 :
152 271 : TYPED_ARRAYS(TYPED_ARRAY_SORT)
153 : #undef TYPED_ARRAY_SORT
154 : }
155 :
156 433 : return *array;
157 : }
158 :
159 0 : RUNTIME_FUNCTION(Runtime_IsTypedArray) {
160 0 : HandleScope scope(isolate);
161 : DCHECK_EQ(1, args.length());
162 0 : return isolate->heap()->ToBoolean(args[0]->IsJSTypedArray());
163 : }
164 :
165 0 : RUNTIME_FUNCTION(Runtime_IsSharedTypedArray) {
166 0 : HandleScope scope(isolate);
167 : DCHECK_EQ(1, args.length());
168 : return isolate->heap()->ToBoolean(
169 0 : args[0]->IsJSTypedArray() &&
170 0 : JSTypedArray::cast(args[0])->GetBuffer()->is_shared());
171 : }
172 :
173 :
174 0 : RUNTIME_FUNCTION(Runtime_IsSharedIntegerTypedArray) {
175 0 : HandleScope scope(isolate);
176 : DCHECK_EQ(1, args.length());
177 0 : if (!args[0]->IsJSTypedArray()) {
178 0 : return isolate->heap()->false_value();
179 : }
180 :
181 0 : Handle<JSTypedArray> obj(JSTypedArray::cast(args[0]));
182 0 : return isolate->heap()->ToBoolean(obj->GetBuffer()->is_shared() &&
183 0 : obj->type() != kExternalFloat32Array &&
184 0 : obj->type() != kExternalFloat64Array &&
185 0 : obj->type() != kExternalUint8ClampedArray);
186 : }
187 :
188 :
189 0 : RUNTIME_FUNCTION(Runtime_IsSharedInteger32TypedArray) {
190 0 : HandleScope scope(isolate);
191 : DCHECK_EQ(1, args.length());
192 0 : if (!args[0]->IsJSTypedArray()) {
193 0 : return isolate->heap()->false_value();
194 : }
195 :
196 0 : Handle<JSTypedArray> obj(JSTypedArray::cast(args[0]));
197 0 : return isolate->heap()->ToBoolean(obj->GetBuffer()->is_shared() &&
198 0 : obj->type() == kExternalInt32Array);
199 : }
200 :
201 2920 : RUNTIME_FUNCTION(Runtime_TypedArraySpeciesCreateByLength) {
202 1460 : HandleScope scope(isolate);
203 : DCHECK_EQ(args.length(), 2);
204 1460 : Handle<JSTypedArray> exemplar = args.at<JSTypedArray>(0);
205 1460 : Handle<Object> length = args.at(1);
206 : int argc = 1;
207 2920 : ScopedVector<Handle<Object>> argv(argc);
208 1460 : argv[0] = length;
209 : Handle<JSTypedArray> result_array;
210 : // TODO(tebbi): Pass correct method name.
211 2920 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
212 : isolate, result_array,
213 : JSTypedArray::SpeciesCreate(isolate, exemplar, argc, argv.start(), ""));
214 1460 : return *result_array;
215 : }
216 :
217 : } // namespace internal
218 : } // namespace v8
|