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 8460 : RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
26 2825 : HandleScope scope(isolate);
27 : DCHECK_EQ(1, args.length());
28 2825 : Handle<Object> argument = args.at(0);
29 : // This runtime function is exposed in ClusterFuzz and as such has to
30 : // support arbitrary arguments.
31 2825 : if (!argument->IsJSArrayBuffer()) {
32 0 : THROW_NEW_ERROR_RETURN_FAILURE(
33 : isolate, NewTypeError(MessageTemplate::kNotTypedArray));
34 : }
35 2825 : Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(argument);
36 :
37 2825 : if (array_buffer->backing_store() == NULL) {
38 15 : CHECK(Smi::kZero == array_buffer->byte_length());
39 15 : return isolate->heap()->undefined_value();
40 : }
41 : // Shared array buffers should never be neutered.
42 2810 : CHECK(!array_buffer->is_shared());
43 : DCHECK(!array_buffer->is_external());
44 : void* backing_store = array_buffer->backing_store();
45 2810 : size_t byte_length = NumberToSize(array_buffer->byte_length());
46 2810 : array_buffer->set_is_external(true);
47 2810 : isolate->heap()->UnregisterArrayBuffer(*array_buffer);
48 2810 : array_buffer->Neuter();
49 2810 : isolate->array_buffer_allocator()->Free(backing_store, byte_length);
50 2810 : return isolate->heap()->undefined_value();
51 : }
52 :
53 70196 : RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) {
54 35098 : HandleScope scope(isolate);
55 : DCHECK_EQ(3, args.length());
56 70196 : CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, destination, 0);
57 70196 : CONVERT_ARG_HANDLE_CHECKED(JSReceiver, source, 1);
58 70196 : CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 2);
59 :
60 : size_t length;
61 35098 : CHECK(TryNumberToSize(*length_obj, &length));
62 :
63 35098 : Handle<JSTypedArray> destination_ta = Handle<JSTypedArray>::cast(destination);
64 :
65 35098 : ElementsAccessor* accessor = destination_ta->GetElementsAccessor();
66 70196 : return accessor->CopyElements(source, destination, 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 10208 : BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
78 57604 : BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
79 206608 : BUFFER_VIEW_GETTER(TypedArray, Length, length)
80 :
81 : #undef BUFFER_VIEW_GETTER
82 :
83 82536 : RUNTIME_FUNCTION(Runtime_ArrayBufferViewWasNeutered) {
84 41268 : HandleScope scope(isolate);
85 : DCHECK_EQ(1, args.length());
86 41268 : return isolate->heap()->ToBoolean(JSTypedArray::cast(args[0])->WasNeutered());
87 : }
88 :
89 33438 : RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
90 16719 : HandleScope scope(isolate);
91 : DCHECK_EQ(1, args.length());
92 33438 : CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
93 33438 : return *holder->GetBuffer();
94 : }
95 :
96 :
97 : // Return codes for Runtime_TypedArraySetFastCases.
98 : // Should be synchronized with typedarray.js natives.
99 : enum TypedArraySetResultCodes {
100 : // Set from typed array of the same type.
101 : // This is processed by TypedArraySetFastCases
102 : TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
103 : // Set from typed array of the different type, overlapping in memory.
104 : TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
105 : // Set from typed array of the different type, non-overlapping.
106 : TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
107 : // Set from non-typed array.
108 : TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
109 : };
110 :
111 :
112 28156 : RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
113 14078 : HandleScope scope(isolate);
114 : DCHECK_EQ(3, args.length());
115 28156 : if (!args[0]->IsJSTypedArray()) {
116 168 : THROW_NEW_ERROR_RETURN_FAILURE(
117 : isolate, NewTypeError(MessageTemplate::kNotTypedArray));
118 : }
119 :
120 27988 : if (!args[1]->IsJSTypedArray()) {
121 7124 : return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
122 : }
123 :
124 13740 : CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0);
125 13740 : CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1);
126 13740 : CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
127 :
128 : Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
129 : Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
130 6870 : size_t offset = 0;
131 6870 : CHECK(TryNumberToSize(*offset_obj, &offset));
132 6870 : size_t target_length = target->length_value();
133 6870 : size_t source_length = source->length_value();
134 6870 : size_t target_byte_length = NumberToSize(target->byte_length());
135 6870 : size_t source_byte_length = NumberToSize(source->byte_length());
136 6870 : if (offset > target_length || offset + source_length > target_length ||
137 : offset + source_length < offset) { // overflow
138 114 : THROW_NEW_ERROR_RETURN_FAILURE(
139 : isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
140 : }
141 :
142 6813 : size_t target_offset = NumberToSize(target->byte_offset());
143 6813 : size_t source_offset = NumberToSize(source->byte_offset());
144 : uint8_t* target_base =
145 20439 : static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
146 6813 : target_offset;
147 : uint8_t* source_base =
148 20439 : static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
149 6813 : source_offset;
150 :
151 : // Typed arrays of the same type: use memmove.
152 13626 : if (target->type() == source->type()) {
153 12004 : memmove(target_base + offset * target->element_size(), source_base,
154 6002 : source_byte_length);
155 6002 : return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
156 : }
157 :
158 : // Typed arrays of different types over the same backing store
159 1352 : if ((source_base <= target_base &&
160 998 : source_base + source_byte_length > target_base) ||
161 270 : (target_base <= source_base &&
162 270 : target_base + target_byte_length > source_base)) {
163 : // We do not support overlapping ArrayBuffers
164 : DCHECK(target->GetBuffer()->backing_store() ==
165 : source->GetBuffer()->backing_store());
166 468 : return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
167 : } else { // Non-overlapping typed arrays
168 343 : return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
169 14078 : }
170 : }
171 :
172 : namespace {
173 :
174 : template <typename T>
175 560 : bool CompareNum(T x, T y) {
176 560 : if (x < y) {
177 : return true;
178 420 : } else if (x > y) {
179 : return false;
180 : } else if (!std::is_integral<T>::value) {
181 182 : double _x = x, _y = y;
182 364 : if (x == 0 && x == y) {
183 : /* -0.0 is less than +0.0 */
184 280 : return std::signbit(_x) && !std::signbit(_y);
185 196 : } else if (!std::isnan(_x) && std::isnan(_y)) {
186 : /* number is less than NaN */
187 : return true;
188 : }
189 : }
190 112 : return false;
191 : }
192 :
193 : } // namespace
194 :
195 842 : RUNTIME_FUNCTION(Runtime_TypedArraySortFast) {
196 421 : HandleScope scope(isolate);
197 : DCHECK_EQ(1, args.length());
198 :
199 421 : CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0);
200 :
201 : Handle<JSTypedArray> array;
202 : const char* method = "%TypedArray%.prototype.sort";
203 842 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
204 : isolate, array, JSTypedArray::Validate(isolate, target_obj, method));
205 :
206 : // This line can be removed when JSTypedArray::Validate throws
207 : // if array.[[ViewedArrayBuffer]] is neutered(v8:4648)
208 421 : if (V8_UNLIKELY(array->WasNeutered())) return *array;
209 :
210 421 : size_t length = array->length_value();
211 421 : if (length <= 1) return *array;
212 :
213 : Handle<FixedTypedArrayBase> elements(
214 421 : FixedTypedArrayBase::cast(array->elements()));
215 421 : switch (array->type()) {
216 : #define TYPED_ARRAY_SORT(Type, type, TYPE, ctype, size) \
217 : case kExternal##Type##Array: { \
218 : ctype* data = static_cast<ctype*>(elements->DataPtr()); \
219 : if (kExternal##Type##Array == kExternalFloat64Array || \
220 : kExternal##Type##Array == kExternalFloat32Array) \
221 : std::sort(data, data + length, CompareNum<ctype>); \
222 : else \
223 : std::sort(data, data + length); \
224 : break; \
225 : }
226 :
227 421 : TYPED_ARRAYS(TYPED_ARRAY_SORT)
228 : #undef TYPED_ARRAY_SORT
229 : }
230 :
231 421 : return *array;
232 : }
233 :
234 0 : RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
235 : DCHECK_EQ(0, args.length());
236 : DCHECK_OBJECT_SIZE(FLAG_typed_array_max_size_in_heap +
237 : FixedTypedArrayBase::kDataOffset);
238 0 : return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
239 : }
240 :
241 :
242 0 : RUNTIME_FUNCTION(Runtime_IsTypedArray) {
243 0 : HandleScope scope(isolate);
244 : DCHECK_EQ(1, args.length());
245 0 : return isolate->heap()->ToBoolean(args[0]->IsJSTypedArray());
246 : }
247 :
248 0 : RUNTIME_FUNCTION(Runtime_IsSharedTypedArray) {
249 0 : HandleScope scope(isolate);
250 : DCHECK_EQ(1, args.length());
251 : return isolate->heap()->ToBoolean(
252 0 : args[0]->IsJSTypedArray() &&
253 0 : JSTypedArray::cast(args[0])->GetBuffer()->is_shared());
254 : }
255 :
256 :
257 0 : RUNTIME_FUNCTION(Runtime_IsSharedIntegerTypedArray) {
258 0 : HandleScope scope(isolate);
259 : DCHECK_EQ(1, args.length());
260 0 : if (!args[0]->IsJSTypedArray()) {
261 0 : return isolate->heap()->false_value();
262 : }
263 :
264 0 : Handle<JSTypedArray> obj(JSTypedArray::cast(args[0]));
265 0 : return isolate->heap()->ToBoolean(obj->GetBuffer()->is_shared() &&
266 0 : obj->type() != kExternalFloat32Array &&
267 0 : obj->type() != kExternalFloat64Array &&
268 0 : obj->type() != kExternalUint8ClampedArray);
269 : }
270 :
271 :
272 0 : RUNTIME_FUNCTION(Runtime_IsSharedInteger32TypedArray) {
273 0 : HandleScope scope(isolate);
274 : DCHECK_EQ(1, args.length());
275 0 : if (!args[0]->IsJSTypedArray()) {
276 0 : return isolate->heap()->false_value();
277 : }
278 :
279 0 : Handle<JSTypedArray> obj(JSTypedArray::cast(args[0]));
280 0 : return isolate->heap()->ToBoolean(obj->GetBuffer()->is_shared() &&
281 0 : obj->type() == kExternalInt32Array);
282 : }
283 :
284 : } // namespace internal
285 : } // namespace v8
|