LCOV - code coverage report
Current view: top level - src/builtins - builtins-arraybuffer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 68 75 90.7 %
Date: 2017-04-26 Functions: 15 24 62.5 %

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

Generated by: LCOV version 1.10