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