LCOV - code coverage report
Current view: top level - src/builtins - builtins-arraybuffer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 69 76 90.8 %
Date: 2019-04-17 Functions: 14 22 63.6 %

          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/conversions.h"
       8             : #include "src/counters.h"
       9             : #include "src/heap/heap-inl.h"  // For ToBoolean. TODO(jkummerow): Drop.
      10             : #include "src/maybe-handles-inl.h"
      11             : #include "src/objects-inl.h"
      12             : #include "src/objects/js-array-buffer-inl.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : #define CHECK_SHARED(expected, name, method)                                \
      18             :   if (name->is_shared() != expected) {                                      \
      19             :     THROW_NEW_ERROR_RETURN_FAILURE(                                         \
      20             :         isolate,                                                            \
      21             :         NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,          \
      22             :                      isolate->factory()->NewStringFromAsciiChecked(method), \
      23             :                      name));                                                \
      24             :   }
      25             : 
      26             : // -----------------------------------------------------------------------------
      27             : // ES#sec-arraybuffer-objects
      28             : 
      29             : namespace {
      30             : 
      31      322599 : Object ConstructBuffer(Isolate* isolate, Handle<JSFunction> target,
      32             :                        Handle<JSReceiver> new_target, Handle<Object> length,
      33             :                        bool initialize) {
      34             :   Handle<JSObject> result;
      35      645198 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      36             :       isolate, result,
      37             :       JSObject::New(target, new_target, Handle<AllocationSite>::null()));
      38             :   size_t byte_length;
      39      322599 :   if (!TryNumberToSize(*length, &byte_length) ||
      40             :       byte_length > JSArrayBuffer::kMaxByteLength) {
      41           0 :     JSArrayBuffer::SetupAsEmpty(Handle<JSArrayBuffer>::cast(result), isolate);
      42           0 :     THROW_NEW_ERROR_RETURN_FAILURE(
      43             :         isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
      44             :   }
      45             :   SharedFlag shared_flag =
      46      645202 :       (*target == target->native_context()->array_buffer_fun())
      47             :           ? SharedFlag::kNotShared
      48      322599 :           : SharedFlag::kShared;
      49      322599 :   if (!JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer>::cast(result),
      50             :                                           isolate, byte_length, initialize,
      51             :                                           shared_flag)) {
      52          88 :     THROW_NEW_ERROR_RETURN_FAILURE(
      53             :         isolate, NewRangeError(MessageTemplate::kArrayBufferAllocationFailed));
      54             :   }
      55      322576 :   return *result;
      56             : }
      57             : 
      58             : }  // namespace
      59             : 
      60             : // ES #sec-arraybuffer-constructor
      61     1608262 : BUILTIN(ArrayBufferConstructor) {
      62             :   HandleScope scope(isolate);
      63             :   Handle<JSFunction> target = args.target();
      64             :   DCHECK(*target == target->native_context()->array_buffer_fun() ||
      65             :          *target == target->native_context()->shared_array_buffer_fun());
      66      321662 :   if (args.new_target()->IsUndefined(isolate)) {  // [[Call]]
      67         162 :     THROW_NEW_ERROR_RETURN_FAILURE(
      68             :         isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
      69             :                               handle(target->shared()->Name(), isolate)));
      70             :   }
      71             :   // [[Construct]]
      72      321608 :   Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
      73             :   Handle<Object> length = args.atOrUndefined(isolate, 1);
      74             : 
      75             :   Handle<Object> number_length;
      76      321608 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_length,
      77             :                                      Object::ToInteger(isolate, length));
      78      321608 :   if (number_length->Number() < 0.0) {
      79         126 :     THROW_NEW_ERROR_RETURN_FAILURE(
      80             :         isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
      81             :     }
      82             : 
      83      321545 :     return ConstructBuffer(isolate, target, new_target, number_length, true);
      84             : }
      85             : 
      86             : // This is a helper to construct an ArrayBuffer with uinitialized memory.
      87             : // This means the caller must ensure the buffer is totally initialized in
      88             : // all cases, or we will expose uinitialized memory to user code.
      89        5325 : BUILTIN(ArrayBufferConstructor_DoNotInitialize) {
      90             :   HandleScope scope(isolate);
      91        3195 :   Handle<JSFunction> target(isolate->native_context()->array_buffer_fun(),
      92        1065 :                             isolate);
      93        1065 :   Handle<Object> length = args.atOrUndefined(isolate, 1);
      94        2130 :   return ConstructBuffer(isolate, target, target, length, false);
      95             : }
      96             : 
      97             : // ES6 section 24.1.4.1 get ArrayBuffer.prototype.byteLength
      98       61940 : BUILTIN(ArrayBufferPrototypeGetByteLength) {
      99             :   const char* const kMethodName = "get ArrayBuffer.prototype.byteLength";
     100             :   HandleScope scope(isolate);
     101       12442 :   CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName);
     102       12397 :   CHECK_SHARED(false, array_buffer, kMethodName);
     103             :   // TODO(franzih): According to the ES6 spec, we should throw a TypeError
     104             :   // here if the JSArrayBuffer is detached.
     105       24722 :   return *isolate->factory()->NewNumberFromSize(array_buffer->byte_length());
     106             : }
     107             : 
     108             : // ES7 sharedmem 6.3.4.1 get SharedArrayBuffer.prototype.byteLength
     109      329725 : BUILTIN(SharedArrayBufferPrototypeGetByteLength) {
     110             :   const char* const kMethodName = "get SharedArrayBuffer.prototype.byteLength";
     111             :   HandleScope scope(isolate);
     112       65999 :   CHECK_RECEIVER(JSArrayBuffer, array_buffer,
     113             :                  "get SharedArrayBuffer.prototype.byteLength");
     114       65954 :   CHECK_SHARED(true, array_buffer, kMethodName);
     115      131836 :   return *isolate->factory()->NewNumberFromSize(array_buffer->byte_length());
     116             : }
     117             : 
     118             : // ES6 section 24.1.3.1 ArrayBuffer.isView ( arg )
     119        1585 : BUILTIN(ArrayBufferIsView) {
     120             :   SealHandleScope shs(isolate);
     121             :   DCHECK_EQ(2, args.length());
     122             :   Object arg = args[1];
     123         317 :   return isolate->heap()->ToBoolean(arg->IsJSArrayBufferView());
     124             : }
     125             : 
     126         495 : static Object SliceHelper(BuiltinArguments args, Isolate* isolate,
     127             :                           const char* kMethodName, bool is_shared) {
     128             :   HandleScope scope(isolate);
     129             :   Handle<Object> start = args.at(1);
     130             :   Handle<Object> end = args.atOrUndefined(isolate, 2);
     131             : 
     132             :   // * If Type(O) is not Object, throw a TypeError exception.
     133             :   // * If O does not have an [[ArrayBufferData]] internal slot, throw a
     134             :   //   TypeError exception.
     135         495 :   CHECK_RECEIVER(JSArrayBuffer, array_buffer, kMethodName);
     136             :   // * [AB] If IsSharedArrayBuffer(O) is true, throw a TypeError exception.
     137             :   // * [SAB] If IsSharedArrayBuffer(O) is false, throw a TypeError exception.
     138         495 :   CHECK_SHARED(is_shared, array_buffer, kMethodName);
     139             : 
     140             :   // * [AB] If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
     141         990 :   if (!is_shared && array_buffer->was_detached()) {
     142           0 :     THROW_NEW_ERROR_RETURN_FAILURE(
     143             :         isolate, NewTypeError(MessageTemplate::kDetachedOperation,
     144             :                               isolate->factory()->NewStringFromAsciiChecked(
     145             :                                   kMethodName)));
     146             :   }
     147             : 
     148             :   // * [AB] Let len be O.[[ArrayBufferByteLength]].
     149             :   // * [SAB] Let len be O.[[ArrayBufferByteLength]].
     150         495 :   double const len = array_buffer->byte_length();
     151             : 
     152             :   // * Let relativeStart be ? ToInteger(start).
     153             :   Handle<Object> relative_start;
     154         495 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, relative_start,
     155             :                                      Object::ToInteger(isolate, start));
     156             : 
     157             :   // * If relativeStart < 0, let first be max((len + relativeStart), 0); else
     158             :   //   let first be min(relativeStart, len).
     159             :   double const first = (relative_start->Number() < 0)
     160          72 :                            ? Max(len + relative_start->Number(), 0.0)
     161         495 :                            : Min(relative_start->Number(), len);
     162         495 :   Handle<Object> first_obj = isolate->factory()->NewNumber(first);
     163             : 
     164             :   // * If end is undefined, let relativeEnd be len; else let relativeEnd be ?
     165             :   //   ToInteger(end).
     166             :   double relative_end;
     167         495 :   if (end->IsUndefined(isolate)) {
     168             :     relative_end = len;
     169             :   } else {
     170             :     Handle<Object> relative_end_obj;
     171         387 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, relative_end_obj,
     172             :                                        Object::ToInteger(isolate, end));
     173             :     relative_end = relative_end_obj->Number();
     174             :   }
     175             : 
     176             :   // * If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let
     177             :   //   final be min(relativeEnd, len).
     178          36 :   double const final_ = (relative_end < 0) ? Max(len + relative_end, 0.0)
     179         495 :                                            : Min(relative_end, len);
     180             : 
     181             :   // * Let newLen be max(final-first, 0).
     182         495 :   double const new_len = Max(final_ - first, 0.0);
     183         495 :   Handle<Object> new_len_obj = isolate->factory()->NewNumber(new_len);
     184             : 
     185             :   // * [AB] Let ctor be ? SpeciesConstructor(O, %ArrayBuffer%).
     186             :   // * [SAB] Let ctor be ? SpeciesConstructor(O, %SharedArrayBuffer%).
     187             :   Handle<JSFunction> constructor_fun = is_shared
     188             :                                            ? isolate->shared_array_buffer_fun()
     189         495 :                                            : isolate->array_buffer_fun();
     190             :   Handle<Object> ctor;
     191         990 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     192             :       isolate, ctor,
     193             :       Object::SpeciesConstructor(
     194             :           isolate, Handle<JSReceiver>::cast(args.receiver()), constructor_fun));
     195             : 
     196             :   // * Let new be ? Construct(ctor, newLen).
     197             :   Handle<JSReceiver> new_;
     198             :   {
     199             :     const int argc = 1;
     200             : 
     201             :     ScopedVector<Handle<Object>> argv(argc);
     202         495 :     argv[0] = new_len_obj;
     203             : 
     204             :     Handle<Object> new_obj;
     205         990 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     206             :         isolate, new_obj, Execution::New(isolate, ctor, argc, argv.start()));
     207             : 
     208             :     new_ = Handle<JSReceiver>::cast(new_obj);
     209             :   }
     210             : 
     211             :   // * If new does not have an [[ArrayBufferData]] internal slot, throw a
     212             :   //   TypeError exception.
     213         495 :   if (!new_->IsJSArrayBuffer()) {
     214           0 :     THROW_NEW_ERROR_RETURN_FAILURE(
     215             :         isolate,
     216             :         NewTypeError(MessageTemplate::kIncompatibleMethodReceiver,
     217             :                      isolate->factory()->NewStringFromAsciiChecked(kMethodName),
     218             :                      new_));
     219             :   }
     220             : 
     221             :   // * [AB] If IsSharedArrayBuffer(new) is true, throw a TypeError exception.
     222             :   // * [SAB] If IsSharedArrayBuffer(new) is false, throw a TypeError exception.
     223             :   Handle<JSArrayBuffer> new_array_buffer = Handle<JSArrayBuffer>::cast(new_);
     224         495 :   CHECK_SHARED(is_shared, new_array_buffer, kMethodName);
     225             : 
     226             :   // * [AB] If IsDetachedBuffer(new) is true, throw a TypeError exception.
     227         990 :   if (!is_shared && new_array_buffer->was_detached()) {
     228          27 :     THROW_NEW_ERROR_RETURN_FAILURE(
     229             :         isolate, NewTypeError(MessageTemplate::kDetachedOperation,
     230             :                               isolate->factory()->NewStringFromAsciiChecked(
     231             :                                   kMethodName)));
     232             :   }
     233             : 
     234             :   // * [AB] If SameValue(new, O) is true, throw a TypeError exception.
     235         972 :   if (!is_shared && new_->SameValue(*args.receiver())) {
     236          18 :     THROW_NEW_ERROR_RETURN_FAILURE(
     237             :         isolate, NewTypeError(MessageTemplate::kArrayBufferSpeciesThis));
     238             :   }
     239             : 
     240             :   // * [SAB] If new.[[ArrayBufferData]] and O.[[ArrayBufferData]] are the same
     241             :   //         Shared Data Block values, throw a TypeError exception.
     242         477 :   if (is_shared &&
     243             :       new_array_buffer->backing_store() == array_buffer->backing_store()) {
     244           0 :     THROW_NEW_ERROR_RETURN_FAILURE(
     245             :         isolate, NewTypeError(MessageTemplate::kSharedArrayBufferSpeciesThis));
     246             :   }
     247             : 
     248             :   // * If new.[[ArrayBufferByteLength]] < newLen, throw a TypeError exception.
     249         477 :   if (new_array_buffer->byte_length() < new_len) {
     250          18 :     THROW_NEW_ERROR_RETURN_FAILURE(
     251             :         isolate,
     252             :         NewTypeError(is_shared ? MessageTemplate::kSharedArrayBufferTooShort
     253             :                                : MessageTemplate::kArrayBufferTooShort));
     254             :   }
     255             : 
     256             :   // * [AB] NOTE: Side-effects of the above steps may have detached O.
     257             :   // * [AB] If IsDetachedBuffer(O) is true, throw a TypeError exception.
     258         936 :   if (!is_shared && array_buffer->was_detached()) {
     259          81 :     THROW_NEW_ERROR_RETURN_FAILURE(
     260             :         isolate, NewTypeError(MessageTemplate::kDetachedOperation,
     261             :                               isolate->factory()->NewStringFromAsciiChecked(
     262             :                                   kMethodName)));
     263             :   }
     264             : 
     265             :   // * Let fromBuf be O.[[ArrayBufferData]].
     266             :   // * Let toBuf be new.[[ArrayBufferData]].
     267             :   // * Perform CopyDataBlockBytes(toBuf, 0, fromBuf, first, newLen).
     268             :   size_t first_size = 0, new_len_size = 0;
     269         441 :   CHECK(TryNumberToSize(*first_obj, &first_size));
     270         441 :   CHECK(TryNumberToSize(*new_len_obj, &new_len_size));
     271             :   DCHECK(new_array_buffer->byte_length() >= new_len_size);
     272             : 
     273         441 :   if (new_len_size != 0) {
     274             :     size_t from_byte_length = array_buffer->byte_length();
     275             :     USE(from_byte_length);
     276             :     DCHECK(first_size <= from_byte_length);
     277             :     DCHECK(from_byte_length - first_size >= new_len_size);
     278             :     uint8_t* from_data =
     279             :         reinterpret_cast<uint8_t*>(array_buffer->backing_store());
     280             :     uint8_t* to_data =
     281             :         reinterpret_cast<uint8_t*>(new_array_buffer->backing_store());
     282         342 :     CopyBytes(to_data, from_data + first_size, new_len_size);
     283             :   }
     284             : 
     285         441 :   return *new_;
     286             : }
     287             : 
     288             : // ES #sec-sharedarraybuffer.prototype.slice
     289           0 : BUILTIN(SharedArrayBufferPrototypeSlice) {
     290             :   const char* const kMethodName = "SharedArrayBuffer.prototype.slice";
     291           0 :   return SliceHelper(args, isolate, kMethodName, true);
     292             : }
     293             : 
     294             : // ES #sec-arraybuffer.prototype.slice
     295             : // ArrayBuffer.prototype.slice ( start, end )
     296         990 : BUILTIN(ArrayBufferPrototypeSlice) {
     297             :   const char* const kMethodName = "ArrayBuffer.prototype.slice";
     298         495 :   return SliceHelper(args, isolate, kMethodName, false);
     299             : }
     300             : 
     301             : }  // namespace internal
     302      121996 : }  // namespace v8

Generated by: LCOV version 1.10