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