LCOV - code coverage report
Current view: top level - src/objects - js-array-buffer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 81 96 84.4 %
Date: 2019-04-18 Functions: 11 13 84.6 %

          Line data    Source code
       1             : // Copyright 2018 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/objects/js-array-buffer.h"
       6             : #include "src/objects/js-array-buffer-inl.h"
       7             : 
       8             : #include "src/counters.h"
       9             : #include "src/property-descriptor.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : namespace {
      15             : 
      16        3421 : bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s,
      17             :                                  Handle<Object>* index) {
      18             :   DCHECK(s->IsString() || s->IsSmi());
      19             : 
      20             :   Handle<Object> result;
      21        3421 :   if (s->IsSmi()) {
      22             :     result = s;
      23             :   } else {
      24        3403 :     result = String::ToNumber(isolate, Handle<String>::cast(s));
      25        3403 :     if (!result->IsMinusZero()) {
      26        6788 :       Handle<String> str = Object::ToString(isolate, result).ToHandleChecked();
      27             :       // Avoid treating strings like "2E1" and "20" as the same key.
      28        3394 :       if (!str->SameValue(*s)) return false;
      29             :     }
      30             :   }
      31         216 :   *index = result;
      32         216 :   return true;
      33             : }
      34             : 
      35             : inline int ConvertToMb(size_t size) {
      36        6428 :   return static_cast<int>(size / static_cast<size_t>(MB));
      37             : }
      38             : 
      39             : }  // anonymous namespace
      40             : 
      41        5096 : void JSArrayBuffer::Detach() {
      42        5096 :   CHECK(is_detachable());
      43        5096 :   CHECK(!was_detached());
      44        5096 :   CHECK(is_external());
      45             :   set_backing_store(nullptr);
      46             :   set_byte_length(0);
      47             :   set_was_detached(true);
      48             :   set_is_detachable(false);
      49             :   // Invalidate the detaching protector.
      50             :   Isolate* const isolate = GetIsolate();
      51        5096 :   if (isolate->IsArrayBufferDetachingIntact()) {
      52         426 :     isolate->InvalidateArrayBufferDetachingProtector();
      53             :   }
      54        5096 : }
      55             : 
      56           0 : void JSArrayBuffer::FreeBackingStoreFromMainThread() {
      57           0 :   if (allocation_base() == nullptr) {
      58             :     return;
      59             :   }
      60           0 :   FreeBackingStore(GetIsolate(), {allocation_base(), allocation_length(),
      61           0 :                                   backing_store(), is_wasm_memory()});
      62             :   // Zero out the backing store and allocation base to avoid dangling
      63             :   // pointers.
      64             :   set_backing_store(nullptr);
      65             : }
      66             : 
      67             : // static
      68      513571 : void JSArrayBuffer::FreeBackingStore(Isolate* isolate, Allocation allocation) {
      69      513571 :   if (allocation.is_wasm_memory) {
      70             :     wasm::WasmMemoryTracker* memory_tracker =
      71             :         isolate->wasm_engine()->memory_tracker();
      72      176188 :     memory_tracker->FreeMemoryIfIsWasmMemory(isolate, allocation.backing_store);
      73             :   } else {
      74      337383 :     isolate->array_buffer_allocator()->Free(allocation.allocation_base,
      75      674766 :                                             allocation.length);
      76             :   }
      77      513601 : }
      78             : 
      79      512484 : void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
      80             :                           bool is_external, void* data, size_t byte_length,
      81             :                           SharedFlag shared_flag, bool is_wasm_memory) {
      82             :   DCHECK_EQ(array_buffer->GetEmbedderFieldCount(),
      83             :             v8::ArrayBuffer::kEmbedderFieldCount);
      84             :   DCHECK_LE(byte_length, JSArrayBuffer::kMaxByteLength);
      85     2562494 :   for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
      86     1024986 :     array_buffer->SetEmbedderField(i, Smi::kZero);
      87             :   }
      88             :   array_buffer->set_byte_length(byte_length);
      89             :   array_buffer->set_bit_field(0);
      90             :   array_buffer->clear_padding();
      91             :   array_buffer->set_is_external(is_external);
      92      512503 :   array_buffer->set_is_detachable(shared_flag == SharedFlag::kNotShared);
      93      512503 :   array_buffer->set_is_shared(shared_flag == SharedFlag::kShared);
      94             :   array_buffer->set_is_wasm_memory(is_wasm_memory);
      95             :   // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
      96             :   // are currently being constructed in the |ArrayBufferTracker|. The
      97             :   // registration method below handles the case of registering a buffer that has
      98             :   // already been promoted.
      99             :   array_buffer->set_backing_store(data);
     100             : 
     101      512503 :   if (data && !is_external) {
     102      501532 :     isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
     103             :   }
     104      512504 : }
     105             : 
     106           0 : void JSArrayBuffer::SetupAsEmpty(Handle<JSArrayBuffer> array_buffer,
     107             :                                  Isolate* isolate) {
     108          45 :   Setup(array_buffer, isolate, false, nullptr, 0, SharedFlag::kNotShared);
     109           0 : }
     110             : 
     111      329712 : bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
     112             :                                         Isolate* isolate,
     113             :                                         size_t allocated_length,
     114             :                                         bool initialize,
     115             :                                         SharedFlag shared_flag) {
     116             :   void* data;
     117      329712 :   CHECK_NOT_NULL(isolate->array_buffer_allocator());
     118      329712 :   if (allocated_length != 0) {
     119      319673 :     if (allocated_length >= MB)
     120             :       isolate->counters()->array_buffer_big_allocations()->AddSample(
     121         368 :           ConvertToMb(allocated_length));
     122      319676 :     if (shared_flag == SharedFlag::kShared)
     123             :       isolate->counters()->shared_array_allocations()->AddSample(
     124        6015 :           ConvertToMb(allocated_length));
     125      319676 :     if (initialize) {
     126      318538 :       data = isolate->array_buffer_allocator()->Allocate(allocated_length);
     127             :     } else {
     128             :       data = isolate->array_buffer_allocator()->AllocateUninitialized(
     129        1138 :           allocated_length);
     130             :     }
     131      319675 :     if (data == nullptr) {
     132             :       isolate->counters()->array_buffer_new_size_failures()->AddSample(
     133          45 :           ConvertToMb(allocated_length));
     134             :       SetupAsEmpty(array_buffer, isolate);
     135          45 :       return false;
     136             :     }
     137             :   } else {
     138             :     data = nullptr;
     139             :   }
     140             : 
     141             :   const bool is_external = false;
     142             :   JSArrayBuffer::Setup(array_buffer, isolate, is_external, data,
     143      329669 :                        allocated_length, shared_flag);
     144      329681 :   return true;
     145             : }
     146             : 
     147       17422 : Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
     148             :     Handle<JSTypedArray> typed_array) {
     149             :   DCHECK(typed_array->is_on_heap());
     150             : 
     151             :   Isolate* isolate = typed_array->GetIsolate();
     152             : 
     153             :   DCHECK(IsFixedTypedArrayElementsKind(typed_array->GetElementsKind()));
     154             : 
     155             :   Handle<FixedTypedArrayBase> fixed_typed_array(
     156             :       FixedTypedArrayBase::cast(typed_array->elements()), isolate);
     157             : 
     158             :   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
     159             :                                isolate);
     160             :   // This code does not know how to materialize from wasm buffers.
     161             :   DCHECK(!buffer->is_wasm_memory());
     162             : 
     163             :   void* backing_store =
     164       17422 :       isolate->array_buffer_allocator()->AllocateUninitialized(
     165       52266 :           fixed_typed_array->DataSize());
     166       17422 :   if (backing_store == nullptr) {
     167             :     isolate->heap()->FatalProcessOutOfMemory(
     168           0 :         "JSTypedArray::MaterializeArrayBuffer");
     169             :   }
     170             :   buffer->set_is_external(false);
     171             :   DCHECK_EQ(buffer->byte_length(),
     172             :             static_cast<uintptr_t>(fixed_typed_array->DataSize()));
     173             :   // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
     174             :   // are currently being constructed in the |ArrayBufferTracker|. The
     175             :   // registration method below handles the case of registering a buffer that has
     176             :   // already been promoted.
     177             :   buffer->set_backing_store(backing_store);
     178             :   // RegisterNewArrayBuffer expects a valid length for adjusting counters.
     179       17422 :   isolate->heap()->RegisterNewArrayBuffer(*buffer);
     180       17422 :   memcpy(buffer->backing_store(), fixed_typed_array->DataPtr(),
     181       34844 :          fixed_typed_array->DataSize());
     182             :   Handle<FixedTypedArrayBase> new_elements =
     183             :       isolate->factory()->NewFixedTypedArrayWithExternalPointer(
     184       17422 :           typed_array->type(), static_cast<uint8_t*>(buffer->backing_store()));
     185             : 
     186       34844 :   typed_array->set_elements(*new_elements);
     187             :   DCHECK(!typed_array->is_on_heap());
     188             : 
     189       17422 :   return buffer;
     190             : }
     191             : 
     192    82613078 : Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
     193    82613078 :   if (!is_on_heap()) {
     194             :     Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
     195             :                                        GetIsolate());
     196    82595645 :     return array_buffer;
     197             :   }
     198             :   Handle<JSTypedArray> self(*this, GetIsolate());
     199       17422 :   return MaterializeArrayBuffer(self);
     200             : }
     201             : 
     202             : // ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
     203             : // static
     204        3610 : Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
     205             :                                             Handle<JSTypedArray> o,
     206             :                                             Handle<Object> key,
     207             :                                             PropertyDescriptor* desc,
     208             :                                             Maybe<ShouldThrow> should_throw) {
     209             :   // 1. Assert: IsPropertyKey(P) is true.
     210             :   DCHECK(key->IsName() || key->IsNumber());
     211             :   // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
     212             :   // 3. If Type(P) is String, then
     213        3817 :   if (key->IsString() || key->IsSmi()) {
     214             :     // 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
     215             :     // 3b. If numericIndex is not undefined, then
     216             :     Handle<Object> numeric_index;
     217        3421 :     if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
     218             :       // 3b i. If IsInteger(numericIndex) is false, return false.
     219             :       // 3b ii. If numericIndex = -0, return false.
     220             :       // 3b iii. If numericIndex < 0, return false.
     221             :       // FIXME: the standard allows up to 2^53 elements.
     222             :       uint32_t index;
     223         423 :       if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
     224          81 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     225             :                        NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
     226             :       }
     227             :       // 3b iv. Let length be O.[[ArrayLength]].
     228             :       size_t length = o->length();
     229             :       // 3b v. If numericIndex ≥ length, return false.
     230         189 :       if (o->WasDetached() || index >= length) {
     231          27 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     232             :                        NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
     233             :       }
     234             :       // 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
     235         180 :       if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
     236         513 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     237             :                        NewTypeError(MessageTemplate::kRedefineDisallowed, key));
     238             :       }
     239             :       // 3b vii. If Desc has a [[Configurable]] field and if
     240             :       //         Desc.[[Configurable]] is true, return false.
     241             :       // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
     242             :       //          is false, return false.
     243             :       // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
     244             :       //        false, return false.
     245          18 :       if ((desc->has_configurable() && desc->configurable()) ||
     246          18 :           (desc->has_enumerable() && !desc->enumerable()) ||
     247           9 :           (desc->has_writable() && !desc->writable())) {
     248          27 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     249             :                        NewTypeError(MessageTemplate::kRedefineDisallowed, key));
     250             :       }
     251             :       // 3b x. If Desc has a [[Value]] field, then
     252             :       //   3b x 1. Let value be Desc.[[Value]].
     253             :       //   3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
     254           0 :       if (desc->has_value()) {
     255           0 :         if (!desc->has_configurable()) desc->set_configurable(false);
     256           0 :         if (!desc->has_enumerable()) desc->set_enumerable(true);
     257           0 :         if (!desc->has_writable()) desc->set_writable(true);
     258           0 :         Handle<Object> value = desc->value();
     259           0 :         RETURN_ON_EXCEPTION_VALUE(isolate,
     260             :                                   SetOwnElementIgnoreAttributes(
     261             :                                       o, index, value, desc->ToAttributes()),
     262             :                                   Nothing<bool>());
     263             :       }
     264             :       // 3b xi. Return true.
     265             :       return Just(true);
     266             :     }
     267             :   }
     268             :   // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
     269        3394 :   return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
     270             : }
     271             : 
     272    41231531 : ExternalArrayType JSTypedArray::type() {
     273    41231531 :   switch (elements()->map()->instance_type()) {
     274             : #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype) \
     275             :   case FIXED_##TYPE##_ARRAY_TYPE:                            \
     276             :     return kExternal##Type##Array;
     277             : 
     278        1769 :     TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
     279             : #undef INSTANCE_TYPE_TO_ARRAY_TYPE
     280             : 
     281             :     default:
     282           0 :       UNREACHABLE();
     283             :   }
     284             : }
     285             : 
     286        8112 : size_t JSTypedArray::element_size() {
     287        8112 :   switch (elements()->map()->instance_type()) {
     288             : #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype) \
     289             :   case FIXED_##TYPE##_ARRAY_TYPE:                              \
     290             :     return sizeof(ctype);
     291             : 
     292         693 :     TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
     293             : #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
     294             : 
     295             :     default:
     296           0 :       UNREACHABLE();
     297             :   }
     298             : }
     299             : 
     300             : }  // namespace internal
     301      122036 : }  // namespace v8

Generated by: LCOV version 1.10