LCOV - code coverage report
Current view: top level - src/builtins - builtins-typedarray.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 126 127 99.2 %
Date: 2017-04-26 Functions: 20 28 71.4 %

          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.h"
       6             : #include "src/builtins/builtins.h"
       7             : #include "src/counters.h"
       8             : #include "src/elements.h"
       9             : #include "src/objects-inl.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : // -----------------------------------------------------------------------------
      15             : // ES6 section 22.2 TypedArray Objects
      16             : 
      17             : // ES6 section 22.2.3.1 get %TypedArray%.prototype.buffer
      18       61800 : BUILTIN(TypedArrayPrototypeBuffer) {
      19             :   HandleScope scope(isolate);
      20       23288 :   CHECK_RECEIVER(JSTypedArray, typed_array,
      21             :                  "get %TypedArray%.prototype.buffer");
      22       39408 :   return *typed_array->GetBuffer();
      23             : }
      24             : 
      25             : namespace {
      26             : 
      27       28694 : int64_t CapRelativeIndex(Handle<Object> num, int64_t minimum, int64_t maximum) {
      28             :   int64_t relative;
      29       28694 :   if (V8_LIKELY(num->IsSmi())) {
      30       27182 :     relative = Smi::cast(*num)->value();
      31             :   } else {
      32             :     DCHECK(num->IsHeapNumber());
      33             :     double fp = HeapNumber::cast(*num)->value();
      34        1512 :     if (V8_UNLIKELY(!std::isfinite(fp))) {
      35             :       // +Infinity / -Infinity
      36             :       DCHECK(!std::isnan(fp));
      37        1386 :       return fp < 0 ? minimum : maximum;
      38             :     }
      39         126 :     relative = static_cast<int64_t>(fp);
      40             :   }
      41       64948 :   return relative < 0 ? std::max<int64_t>(relative + maximum, minimum)
      42       76758 :                       : std::min<int64_t>(relative, maximum);
      43             : }
      44             : 
      45             : // ES7 section 22.2.4.6 TypedArrayCreate ( constructor, argumentList )
      46       13536 : MaybeHandle<JSTypedArray> TypedArrayCreate(Isolate* isolate,
      47             :                                            Handle<JSFunction> default_ctor,
      48             :                                            int argc, Handle<Object>* argv,
      49             :                                            const char* method_name) {
      50             :   // 1. Let newTypedArray be ? Construct(constructor, argumentList).
      51             :   Handle<Object> new_obj;
      52       27072 :   ASSIGN_RETURN_ON_EXCEPTION(
      53             :       isolate, new_obj, Execution::New(default_ctor, argc, argv), JSTypedArray);
      54             : 
      55             :   // 2. Perform ? ValidateTypedArray(newTypedArray).
      56             :   Handle<JSTypedArray> new_array;
      57       27072 :   ASSIGN_RETURN_ON_EXCEPTION(
      58             :       isolate, new_array, JSTypedArray::Validate(isolate, new_obj, method_name),
      59             :       JSTypedArray);
      60             : 
      61             :   // 3. If argumentList is a List of a single Number, then
      62             :   // If newTypedArray.[[ArrayLength]] < size, throw a TypeError exception.
      63             :   DCHECK_IMPLIES(argc == 1, argv[0]->IsSmi());
      64       39852 :   if (argc == 1 && new_array->length_value() < argv[0]->Number()) {
      65             :     const MessageTemplate::Template message =
      66             :         MessageTemplate::kTypedArrayTooShort;
      67         252 :     THROW_NEW_ERROR(isolate, NewTypeError(message), JSTypedArray);
      68             :   }
      69             : 
      70             :   // 4. Return newTypedArray.
      71             :   return new_array;
      72             : }
      73             : 
      74             : // ES7 section 22.2.4.7 TypedArraySpeciesCreate ( exemplar, argumentList )
      75       13536 : MaybeHandle<JSTypedArray> TypedArraySpeciesCreate(Isolate* isolate,
      76             :                                                   Handle<JSTypedArray> exemplar,
      77             :                                                   int argc,
      78             :                                                   Handle<Object>* argv,
      79             :                                                   const char* method_name) {
      80             :   // 1. Assert: exemplar is an Object that has a [[TypedArrayName]] internal
      81             :   // slot.
      82             :   DCHECK(exemplar->IsJSTypedArray());
      83             : 
      84             :   // 2. Let defaultConstructor be the intrinsic object listed in column one of
      85             :   // Table 51 for exemplar.[[TypedArrayName]].
      86       13536 :   Handle<JSFunction> default_ctor = isolate->uint8_array_fun();
      87       13536 :   switch (exemplar->type()) {
      88             : #define TYPED_ARRAY_CTOR(Type, type, TYPE, ctype, size) \
      89             :   case kExternal##Type##Array: {                        \
      90             :     default_ctor = isolate->type##_array_fun();         \
      91             :     break;                                              \
      92             :   }
      93             : 
      94        2209 :     TYPED_ARRAYS(TYPED_ARRAY_CTOR)
      95             : #undef TYPED_ARRAY_CTOR
      96             :     default:
      97           0 :       UNREACHABLE();
      98             :   }
      99             : 
     100             :   // 3. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
     101             :   Handle<Object> ctor;
     102       27072 :   ASSIGN_RETURN_ON_EXCEPTION(
     103             :       isolate, ctor,
     104             :       Object::SpeciesConstructor(isolate, exemplar, default_ctor),
     105             :       JSTypedArray);
     106             : 
     107             :   // 4. Return ? TypedArrayCreate(constructor, argumentList).
     108             :   return TypedArrayCreate(isolate, Handle<JSFunction>::cast(ctor), argc, argv,
     109       13536 :                           method_name);
     110             : }
     111             : 
     112       13536 : MaybeHandle<JSTypedArray> TypedArraySpeciesCreateByLength(
     113             :     Isolate* isolate, Handle<JSTypedArray> exemplar, const char* method_name,
     114             :     int64_t length) {
     115             :   const int argc = 1;
     116             :   ScopedVector<Handle<Object>> argv(argc);
     117       13536 :   argv[0] = isolate->factory()->NewNumberFromInt64(length);
     118             :   return TypedArraySpeciesCreate(isolate, exemplar, argc, argv.start(),
     119       27072 :                                  method_name);
     120             : }
     121             : 
     122             : }  // namespace
     123             : 
     124       13272 : BUILTIN(TypedArrayPrototypeCopyWithin) {
     125             :   HandleScope scope(isolate);
     126             : 
     127             :   Handle<JSTypedArray> array;
     128             :   const char* method = "%TypedArray%.prototype.copyWithin";
     129        8848 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     130             :       isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
     131             : 
     132        3794 :   int64_t len = array->length_value();
     133             :   int64_t to = 0;
     134             :   int64_t from = 0;
     135             :   int64_t final = len;
     136             : 
     137        3794 :   if (V8_LIKELY(args.length() > 1)) {
     138             :     Handle<Object> num;
     139        3794 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     140             :         isolate, num, Object::ToInteger(isolate, args.at<Object>(1)));
     141        3794 :     to = CapRelativeIndex(num, 0, len);
     142             : 
     143        3794 :     if (args.length() > 2) {
     144        3780 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     145             :           isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
     146        3780 :       from = CapRelativeIndex(num, 0, len);
     147             : 
     148             :       Handle<Object> end = args.atOrUndefined(isolate, 3);
     149        3780 :       if (!end->IsUndefined(isolate)) {
     150        1260 :         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, num,
     151             :                                            Object::ToInteger(isolate, end));
     152        1260 :         final = CapRelativeIndex(num, 0, len);
     153             :       }
     154             :     }
     155             :   }
     156             : 
     157        7588 :   int64_t count = std::min<int64_t>(final - from, len - to);
     158        4550 :   if (count <= 0) return *array;
     159             : 
     160             :   // TypedArray buffer may have been transferred/detached during parameter
     161             :   // processing above. Return early in this case, to prevent potential UAF error
     162             :   // TODO(caitp): throw here, as though the full algorithm were performed (the
     163             :   // throw would have come from ecma262/#sec-integerindexedelementget)
     164             :   // (see )
     165        3038 :   if (V8_UNLIKELY(array->WasNeutered())) return *array;
     166             : 
     167             :   // Ensure processed indexes are within array bounds
     168             :   DCHECK_GE(from, 0);
     169             :   DCHECK_LT(from, len);
     170             :   DCHECK_GE(to, 0);
     171             :   DCHECK_LT(to, len);
     172             :   DCHECK_GE(len - count, 0);
     173             : 
     174             :   Handle<FixedTypedArrayBase> elements(
     175             :       FixedTypedArrayBase::cast(array->elements()));
     176        3024 :   size_t element_size = array->element_size();
     177        3024 :   to = to * element_size;
     178        3024 :   from = from * element_size;
     179        3024 :   count = count * element_size;
     180             : 
     181             :   uint8_t* data = static_cast<uint8_t*>(elements->DataPtr());
     182        3024 :   std::memmove(data + to, data + from, count);
     183             : 
     184        3024 :   return *array;
     185             : }
     186             : 
     187       12360 : BUILTIN(TypedArrayPrototypeFill) {
     188             :   HandleScope scope(isolate);
     189             : 
     190             :   Handle<JSTypedArray> array;
     191             :   const char* method = "%TypedArray%.prototype.fill";
     192        8240 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     193             :       isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
     194             : 
     195        3616 :   Handle<Object> obj_value = args.atOrUndefined(isolate, 1);
     196        7232 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     197             :       isolate, obj_value, Object::ToNumber(obj_value));
     198             : 
     199        3616 :   int64_t len = array->length_value();
     200             :   int64_t start = 0;
     201             :   int64_t end = len;
     202             : 
     203        3616 :   if (args.length() > 2) {
     204             :     Handle<Object> num = args.atOrUndefined(isolate, 2);
     205        1890 :     if (!num->IsUndefined(isolate)) {
     206        1890 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     207             :           isolate, num, Object::ToInteger(isolate, num));
     208        1890 :       start = CapRelativeIndex(num, 0, len);
     209             : 
     210             :       num = args.atOrUndefined(isolate, 3);
     211        1890 :       if (!num->IsUndefined(isolate)) {
     212        1260 :         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     213             :             isolate, num, Object::ToInteger(isolate, num));
     214        1260 :         end = CapRelativeIndex(num, 0, len);
     215             :       }
     216             :     }
     217             :   }
     218             : 
     219        3616 :   int64_t count = end - start;
     220        4246 :   if (count <= 0) return *array;
     221             : 
     222        2986 :   if (V8_UNLIKELY(array->WasNeutered())) return *array;
     223             : 
     224             :   // Ensure processed indexes are within array bounds
     225             :   DCHECK_GE(start, 0);
     226             :   DCHECK_LT(start, len);
     227             :   DCHECK_GE(end, 0);
     228             :   DCHECK_LE(end, len);
     229             :   DCHECK_LE(count, len);
     230             : 
     231        2986 :   return array->GetElementsAccessor()->Fill(isolate, array, obj_value,
     232             :                                             static_cast<uint32_t>(start),
     233        5972 :                                             static_cast<uint32_t>(end));
     234             : }
     235             : 
     236        9996 : BUILTIN(TypedArrayPrototypeIncludes) {
     237             :   HandleScope scope(isolate);
     238             : 
     239             :   Handle<JSTypedArray> array;
     240             :   const char* method = "%TypedArray%.prototype.includes";
     241        6664 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     242             :       isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
     243             : 
     244        3276 :   if (args.length() < 2) return isolate->heap()->false_value();
     245             : 
     246        3150 :   int64_t len = array->length_value();
     247        3150 :   if (len == 0) return isolate->heap()->false_value();
     248             : 
     249             :   int64_t index = 0;
     250        2772 :   if (args.length() > 2) {
     251             :     Handle<Object> num;
     252        2142 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     253             :         isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
     254        1890 :     index = CapRelativeIndex(num, 0, len);
     255             :   }
     256             : 
     257             :   // TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
     258        2520 :   if (V8_UNLIKELY(array->WasNeutered())) return isolate->heap()->false_value();
     259             : 
     260        2520 :   Handle<Object> search_element = args.atOrUndefined(isolate, 1);
     261        2520 :   ElementsAccessor* elements = array->GetElementsAccessor();
     262             :   Maybe<bool> result = elements->IncludesValue(isolate, array, search_element,
     263             :                                                static_cast<uint32_t>(index),
     264        5040 :                                                static_cast<uint32_t>(len));
     265        2520 :   MAYBE_RETURN(result, isolate->heap()->exception());
     266        5040 :   return *isolate->factory()->ToBoolean(result.FromJust());
     267             : }
     268             : 
     269        5670 : BUILTIN(TypedArrayPrototypeIndexOf) {
     270             :   HandleScope scope(isolate);
     271             : 
     272             :   Handle<JSTypedArray> array;
     273             :   const char* method = "%TypedArray%.prototype.indexOf";
     274        3780 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     275             :       isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
     276             : 
     277        1638 :   int64_t len = array->length_value();
     278        1638 :   if (len == 0) return Smi::FromInt(-1);
     279             : 
     280             :   int64_t index = 0;
     281        1512 :   if (args.length() > 2) {
     282             :     Handle<Object> num;
     283         756 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     284             :         isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
     285         756 :     index = CapRelativeIndex(num, 0, len);
     286             :   }
     287             : 
     288             :   // TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
     289        1512 :   if (V8_UNLIKELY(array->WasNeutered())) return Smi::FromInt(-1);
     290             : 
     291        1512 :   Handle<Object> search_element = args.atOrUndefined(isolate, 1);
     292        1512 :   ElementsAccessor* elements = array->GetElementsAccessor();
     293             :   Maybe<int64_t> result = elements->IndexOfValue(isolate, array, search_element,
     294             :                                                  static_cast<uint32_t>(index),
     295        3024 :                                                  static_cast<uint32_t>(len));
     296        1512 :   MAYBE_RETURN(result, isolate->heap()->exception());
     297        3024 :   return *isolate->factory()->NewNumberFromInt64(result.FromJust());
     298             : }
     299             : 
     300        5292 : BUILTIN(TypedArrayPrototypeLastIndexOf) {
     301             :   HandleScope scope(isolate);
     302             : 
     303             :   Handle<JSTypedArray> array;
     304             :   const char* method = "%TypedArray%.prototype.lastIndexOf";
     305        3528 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     306             :       isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
     307             : 
     308        1512 :   int64_t len = array->length_value();
     309        1512 :   if (len == 0) return Smi::FromInt(-1);
     310             : 
     311        1386 :   int64_t index = len - 1;
     312        1386 :   if (args.length() > 2) {
     313             :     Handle<Object> num;
     314         756 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     315             :         isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
     316             :     // Set a negative value (-1) for returning -1 if num is negative and
     317             :     // len + num is still negative. Upper bound is len - 1.
     318        1512 :     index = std::min<int64_t>(CapRelativeIndex(num, -1, len), len - 1);
     319             :   }
     320             : 
     321        1386 :   if (index < 0) return Smi::FromInt(-1);
     322             : 
     323             :   // TODO(cwhan.tunz): throw. See the above comment in CopyWithin.
     324        1260 :   if (V8_UNLIKELY(array->WasNeutered())) return Smi::FromInt(-1);
     325             : 
     326        1260 :   Handle<Object> search_element = args.atOrUndefined(isolate, 1);
     327        1260 :   ElementsAccessor* elements = array->GetElementsAccessor();
     328             :   Maybe<int64_t> result = elements->LastIndexOfValue(
     329        2520 :       isolate, array, search_element, static_cast<uint32_t>(index));
     330        1260 :   MAYBE_RETURN(result, isolate->heap()->exception());
     331        2520 :   return *isolate->factory()->NewNumberFromInt64(result.FromJust());
     332             : }
     333             : 
     334        1512 : BUILTIN(TypedArrayPrototypeReverse) {
     335             :   HandleScope scope(isolate);
     336             : 
     337             :   Handle<JSTypedArray> array;
     338             :   const char* method = "%TypedArray%.prototype.reverse";
     339        1008 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     340             :       isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
     341             : 
     342         252 :   ElementsAccessor* elements = array->GetElementsAccessor();
     343         504 :   elements->Reverse(*array);
     344         252 :   return *array;
     345             : }
     346             : 
     347       41364 : BUILTIN(TypedArrayPrototypeSlice) {
     348             :   HandleScope scope(isolate);
     349             : 
     350             :   Handle<JSTypedArray> array;
     351             :   const char* method = "%TypedArray%.prototype.slice";
     352       27576 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     353             :       isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
     354             : 
     355       13536 :   int64_t len = array->length_value();
     356             :   int64_t start = 0;
     357             :   int64_t end = len;
     358             :   {
     359             :     Handle<Object> num = args.atOrUndefined(isolate, 1);
     360       13536 :     if (!num->IsUndefined(isolate)) {
     361        7977 :       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, num,
     362             :                                          Object::ToInteger(isolate, num));
     363        7977 :       start = CapRelativeIndex(num, 0, len);
     364             : 
     365             :       num = args.atOrUndefined(isolate, 2);
     366        7977 :       if (!num->IsUndefined(isolate)) {
     367        5331 :         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, num,
     368             :                                            Object::ToInteger(isolate, num));
     369        5331 :         end = CapRelativeIndex(num, 0, len);
     370             :       }
     371             :     }
     372             :   }
     373             : 
     374       27072 :   int64_t count = std::max<int64_t>(end - start, 0);
     375             : 
     376             :   Handle<JSTypedArray> result_array;
     377       27072 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     378             :       isolate, result_array,
     379             :       TypedArraySpeciesCreateByLength(isolate, array, method, count));
     380             : 
     381             :   // TODO(cwhan.tunz): neutering check of the result_array should be done in
     382             :   // TypedArraySpeciesCreate, but currently ValidateTypedArray does not throw
     383             :   // for neutered buffer, so this is a temporary neutering check for the result
     384             :   // array
     385       13158 :   if (V8_UNLIKELY(result_array->WasNeutered())) return *result_array;
     386             : 
     387             :   // TODO(cwhan.tunz): should throw.
     388       13158 :   if (V8_UNLIKELY(array->WasNeutered())) return *result_array;
     389             : 
     390       13158 :   if (count == 0) return *result_array;
     391             : 
     392        8874 :   ElementsAccessor* accessor = array->GetElementsAccessor();
     393             :   return *accessor->Slice(array, static_cast<uint32_t>(start),
     394       35496 :                           static_cast<uint32_t>(end), result_array);
     395             : }
     396             : 
     397             : }  // namespace internal
     398             : }  // namespace v8

Generated by: LCOV version 1.10