Line data Source code
1 : // Copyright 2016 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/builtins/builtins-utils-inl.h"
6 : #include "src/builtins/builtins.h"
7 : #include "src/counters.h"
8 : #include "src/elements.h"
9 : #include "src/objects-inl.h"
10 : #include "src/objects/heap-number-inl.h"
11 : #include "src/objects/js-array-buffer-inl.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 : // -----------------------------------------------------------------------------
17 : // ES6 section 22.2 TypedArray Objects
18 :
19 : // ES6 section 22.2.3.1 get %TypedArray%.prototype.buffer
20 898807 : BUILTIN(TypedArrayPrototypeBuffer) {
21 : HandleScope scope(isolate);
22 181959 : CHECK_RECEIVER(JSTypedArray, typed_array,
23 : "get %TypedArray%.prototype.buffer");
24 358082 : return *typed_array->GetBuffer();
25 : }
26 :
27 : namespace {
28 :
29 10260 : int64_t CapRelativeIndex(Handle<Object> num, int64_t minimum, int64_t maximum) {
30 10260 : if (V8_LIKELY(num->IsSmi())) {
31 9279 : int64_t relative = Smi::ToInt(*num);
32 2430 : return relative < 0 ? std::max<int64_t>(relative + maximum, minimum)
33 18558 : : std::min<int64_t>(relative, maximum);
34 : } else {
35 : DCHECK(num->IsHeapNumber());
36 981 : double relative = HeapNumber::cast(*num)->value();
37 : DCHECK(!std::isnan(relative));
38 : return static_cast<int64_t>(
39 990 : relative < 0 ? std::max<double>(relative + maximum, minimum)
40 1962 : : std::min<double>(relative, maximum));
41 : }
42 : }
43 :
44 : } // namespace
45 :
46 14580 : BUILTIN(TypedArrayPrototypeCopyWithin) {
47 : HandleScope scope(isolate);
48 :
49 : Handle<JSTypedArray> array;
50 : const char* method = "%TypedArray%.prototype.copyWithin";
51 6237 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
52 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
53 :
54 2511 : int64_t len = array->length();
55 : int64_t to = 0;
56 : int64_t from = 0;
57 : int64_t final = len;
58 :
59 2511 : if (V8_LIKELY(args.length() > 1)) {
60 : Handle<Object> num;
61 2511 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
62 : isolate, num, Object::ToInteger(isolate, args.at<Object>(1)));
63 2511 : to = CapRelativeIndex(num, 0, len);
64 :
65 2511 : if (args.length() > 2) {
66 2502 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
67 : isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
68 2502 : from = CapRelativeIndex(num, 0, len);
69 :
70 : Handle<Object> end = args.atOrUndefined(isolate, 3);
71 2502 : if (!end->IsUndefined(isolate)) {
72 882 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, num,
73 : Object::ToInteger(isolate, end));
74 882 : final = CapRelativeIndex(num, 0, len);
75 : }
76 : }
77 : }
78 :
79 5022 : int64_t count = std::min<int64_t>(final - from, len - to);
80 2997 : if (count <= 0) return *array;
81 :
82 : // TypedArray buffer may have been transferred/detached during parameter
83 : // processing above. Return early in this case, to prevent potential UAF error
84 : // TODO(caitp): throw here, as though the full algorithm were performed (the
85 : // throw would have come from ecma262/#sec-integerindexedelementget)
86 : // (see )
87 2025 : if (V8_UNLIKELY(array->WasDetached())) return *array;
88 :
89 : // Ensure processed indexes are within array bounds
90 : DCHECK_GE(from, 0);
91 : DCHECK_LT(from, len);
92 : DCHECK_GE(to, 0);
93 : DCHECK_LT(to, len);
94 : DCHECK_GE(len - count, 0);
95 :
96 : Handle<FixedTypedArrayBase> elements(
97 : FixedTypedArrayBase::cast(array->elements()), isolate);
98 2016 : size_t element_size = array->element_size();
99 2016 : to = to * element_size;
100 2016 : from = from * element_size;
101 2016 : count = count * element_size;
102 :
103 : uint8_t* data = static_cast<uint8_t*>(elements->DataPtr());
104 2016 : std::memmove(data + to, data + from, count);
105 :
106 2016 : return *array;
107 : }
108 :
109 23755 : BUILTIN(TypedArrayPrototypeFill) {
110 : HandleScope scope(isolate);
111 :
112 : Handle<JSTypedArray> array;
113 : const char* method = "%TypedArray%.prototype.fill";
114 9826 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
115 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
116 : ElementsKind kind = array->GetElementsKind();
117 :
118 4427 : Handle<Object> obj_value = args.atOrUndefined(isolate, 1);
119 4427 : if (kind == BIGINT64_ELEMENTS || kind == BIGUINT64_ELEMENTS) {
120 360 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, obj_value,
121 : BigInt::FromObject(isolate, obj_value));
122 : } else {
123 8566 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, obj_value,
124 : Object::ToNumber(isolate, obj_value));
125 : }
126 :
127 4355 : int64_t len = array->length();
128 : int64_t start = 0;
129 : int64_t end = len;
130 :
131 4355 : if (args.length() > 2) {
132 : Handle<Object> num = args.atOrUndefined(isolate, 2);
133 1296 : if (!num->IsUndefined(isolate)) {
134 1296 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
135 : isolate, num, Object::ToInteger(isolate, num));
136 1296 : start = CapRelativeIndex(num, 0, len);
137 :
138 : num = args.atOrUndefined(isolate, 3);
139 1296 : if (!num->IsUndefined(isolate)) {
140 882 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
141 : isolate, num, Object::ToInteger(isolate, num));
142 882 : end = CapRelativeIndex(num, 0, len);
143 : }
144 : }
145 : }
146 :
147 4355 : int64_t count = end - start;
148 4760 : if (count <= 0) return *array;
149 :
150 3950 : if (V8_UNLIKELY(array->WasDetached())) return *array;
151 :
152 : // Ensure processed indexes are within array bounds
153 : DCHECK_GE(start, 0);
154 : DCHECK_LT(start, len);
155 : DCHECK_GE(end, 0);
156 : DCHECK_LE(end, len);
157 : DCHECK_LE(count, len);
158 :
159 : return ElementsAccessor::ForKind(kind)->Fill(array, obj_value,
160 : static_cast<uint32_t>(start),
161 7900 : static_cast<uint32_t>(end));
162 : }
163 :
164 12195 : BUILTIN(TypedArrayPrototypeIncludes) {
165 : HandleScope scope(isolate);
166 :
167 : Handle<JSTypedArray> array;
168 : const char* method = "%TypedArray%.prototype.includes";
169 4914 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
170 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
171 :
172 2493 : if (args.length() < 2) return ReadOnlyRoots(isolate).false_value();
173 :
174 2313 : int64_t len = array->length();
175 2556 : if (len == 0) return ReadOnlyRoots(isolate).false_value();
176 :
177 : int64_t index = 0;
178 2070 : if (args.length() > 2) {
179 : Handle<Object> num;
180 1539 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
181 : isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
182 1215 : index = CapRelativeIndex(num, 0, len);
183 : }
184 :
185 : // TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
186 1908 : if (V8_UNLIKELY(array->WasDetached()))
187 0 : return ReadOnlyRoots(isolate).false_value();
188 :
189 1908 : Handle<Object> search_element = args.atOrUndefined(isolate, 1);
190 1908 : ElementsAccessor* elements = array->GetElementsAccessor();
191 : Maybe<bool> result = elements->IncludesValue(isolate, array, search_element,
192 : static_cast<uint32_t>(index),
193 3816 : static_cast<uint32_t>(len));
194 1908 : MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
195 3816 : return *isolate->factory()->ToBoolean(result.FromJust());
196 : }
197 :
198 7560 : BUILTIN(TypedArrayPrototypeIndexOf) {
199 : HandleScope scope(isolate);
200 :
201 : Handle<JSTypedArray> array;
202 : const char* method = "%TypedArray%.prototype.indexOf";
203 3186 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
204 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
205 :
206 1350 : int64_t len = array->length();
207 1350 : if (len == 0) return Smi::FromInt(-1);
208 :
209 : int64_t index = 0;
210 1269 : if (args.length() > 2) {
211 : Handle<Object> num;
212 486 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
213 : isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
214 486 : index = CapRelativeIndex(num, 0, len);
215 : }
216 :
217 : // TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
218 1269 : if (V8_UNLIKELY(array->WasDetached())) return Smi::FromInt(-1);
219 :
220 1269 : Handle<Object> search_element = args.atOrUndefined(isolate, 1);
221 1269 : ElementsAccessor* elements = array->GetElementsAccessor();
222 : Maybe<int64_t> result = elements->IndexOfValue(isolate, array, search_element,
223 : static_cast<uint32_t>(index),
224 2538 : static_cast<uint32_t>(len));
225 1269 : MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
226 2538 : return *isolate->factory()->NewNumberFromInt64(result.FromJust());
227 : }
228 :
229 7155 : BUILTIN(TypedArrayPrototypeLastIndexOf) {
230 : HandleScope scope(isolate);
231 :
232 : Handle<JSTypedArray> array;
233 : const char* method = "%TypedArray%.prototype.lastIndexOf";
234 3024 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
235 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
236 :
237 1269 : int64_t len = array->length();
238 1269 : if (len == 0) return Smi::FromInt(-1);
239 :
240 1188 : int64_t index = len - 1;
241 1188 : if (args.length() > 2) {
242 : Handle<Object> num;
243 486 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
244 : isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
245 : // Set a negative value (-1) for returning -1 if num is negative and
246 : // len + num is still negative. Upper bound is len - 1.
247 972 : index = std::min<int64_t>(CapRelativeIndex(num, -1, len), len - 1);
248 : }
249 :
250 1188 : if (index < 0) return Smi::FromInt(-1);
251 :
252 : // TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
253 1107 : if (V8_UNLIKELY(array->WasDetached())) return Smi::FromInt(-1);
254 :
255 1107 : Handle<Object> search_element = args.atOrUndefined(isolate, 1);
256 1107 : ElementsAccessor* elements = array->GetElementsAccessor();
257 : Maybe<int64_t> result = elements->LastIndexOfValue(
258 2214 : array, search_element, static_cast<uint32_t>(index));
259 1107 : MAYBE_RETURN(result, ReadOnlyRoots(isolate).exception());
260 2214 : return *isolate->factory()->NewNumberFromInt64(result.FromJust());
261 : }
262 :
263 1980 : BUILTIN(TypedArrayPrototypeReverse) {
264 : HandleScope scope(isolate);
265 :
266 : Handle<JSTypedArray> array;
267 : const char* method = "%TypedArray%.prototype.reverse";
268 954 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
269 : isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
270 :
271 234 : ElementsAccessor* elements = array->GetElementsAccessor();
272 468 : elements->Reverse(*array);
273 234 : return *array;
274 : }
275 :
276 : } // namespace internal
277 121996 : } // namespace v8
|