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-03-21 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        6403 :   return static_cast<int>(size / static_cast<size_t>(MB));
      37             : }
      38             : 
      39             : }  // anonymous namespace
      40             : 
      41        5160 : void JSArrayBuffer::Detach() {
      42        5160 :   CHECK(is_detachable());
      43        5160 :   CHECK(!was_detached());
      44        5160 :   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        5160 :   if (isolate->IsArrayBufferDetachingIntact()) {
      52         434 :     isolate->InvalidateArrayBufferDetachingProtector();
      53             :   }
      54        5160 : }
      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      511393 : void JSArrayBuffer::FreeBackingStore(Isolate* isolate, Allocation allocation) {
      69      511393 :   if (allocation.is_wasm_memory) {
      70             :     wasm::WasmMemoryTracker* memory_tracker =
      71             :         isolate->wasm_engine()->memory_tracker();
      72      177107 :     memory_tracker->FreeMemoryIfIsWasmMemory(isolate, allocation.backing_store);
      73             :   } else {
      74      334286 :     isolate->array_buffer_allocator()->Free(allocation.allocation_base,
      75      668572 :                                             allocation.length);
      76             :   }
      77      511418 : }
      78             : 
      79      510524 : 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     2552814 :   for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
      86     1021090 :     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      510579 :   array_buffer->set_is_detachable(shared_flag == SharedFlag::kNotShared);
      93      510579 :   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      510579 :   if (data && !is_external) {
     102      499616 :     isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
     103             :   }
     104      510583 : }
     105             : 
     106           0 : void JSArrayBuffer::SetupAsEmpty(Handle<JSArrayBuffer> array_buffer,
     107             :                                  Isolate* isolate) {
     108          37 :   Setup(array_buffer, isolate, false, nullptr, 0, SharedFlag::kNotShared);
     109           0 : }
     110             : 
     111      326799 : 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      326799 :   CHECK_NOT_NULL(isolate->array_buffer_allocator());
     118      326799 :   if (allocated_length != 0) {
     119      316771 :     if (allocated_length >= MB)
     120             :       isolate->counters()->array_buffer_big_allocations()->AddSample(
     121         351 :           ConvertToMb(allocated_length));
     122      316765 :     if (shared_flag == SharedFlag::kShared)
     123             :       isolate->counters()->shared_array_allocations()->AddSample(
     124        6015 :           ConvertToMb(allocated_length));
     125      316765 :     if (initialize) {
     126      315635 :       data = isolate->array_buffer_allocator()->Allocate(allocated_length);
     127             :     } else {
     128             :       data = isolate->array_buffer_allocator()->AllocateUninitialized(
     129        1130 :           allocated_length);
     130             :     }
     131      316779 :     if (data == nullptr) {
     132             :       isolate->counters()->array_buffer_new_size_failures()->AddSample(
     133          37 :           ConvertToMb(allocated_length));
     134             :       SetupAsEmpty(array_buffer, isolate);
     135          37 :       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      326770 :                        allocated_length, shared_flag);
     144      326792 :   return true;
     145             : }
     146             : 
     147       17158 : 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       17158 :       isolate->array_buffer_allocator()->AllocateUninitialized(
     165       51474 :           fixed_typed_array->DataSize());
     166       17158 :   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       17158 :   isolate->heap()->RegisterNewArrayBuffer(*buffer);
     180       17158 :   memcpy(buffer->backing_store(), fixed_typed_array->DataPtr(),
     181       34316 :          fixed_typed_array->DataSize());
     182             :   Handle<FixedTypedArrayBase> new_elements =
     183             :       isolate->factory()->NewFixedTypedArrayWithExternalPointer(
     184             :           fixed_typed_array->length(), typed_array->type(),
     185       34316 :           static_cast<uint8_t*>(buffer->backing_store()));
     186             : 
     187       34316 :   typed_array->set_elements(*new_elements);
     188             :   DCHECK(!typed_array->is_on_heap());
     189             : 
     190       17158 :   return buffer;
     191             : }
     192             : 
     193    63850035 : Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
     194    63850035 :   if (!is_on_heap()) {
     195             :     Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
     196             :                                        GetIsolate());
     197    63832961 :     return array_buffer;
     198             :   }
     199             :   Handle<JSTypedArray> self(*this, GetIsolate());
     200       17158 :   return MaterializeArrayBuffer(self);
     201             : }
     202             : 
     203             : // ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
     204             : // static
     205        3610 : Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
     206             :                                             Handle<JSTypedArray> o,
     207             :                                             Handle<Object> key,
     208             :                                             PropertyDescriptor* desc,
     209             :                                             Maybe<ShouldThrow> should_throw) {
     210             :   // 1. Assert: IsPropertyKey(P) is true.
     211             :   DCHECK(key->IsName() || key->IsNumber());
     212             :   // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
     213             :   // 3. If Type(P) is String, then
     214        3817 :   if (key->IsString() || key->IsSmi()) {
     215             :     // 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
     216             :     // 3b. If numericIndex is not undefined, then
     217             :     Handle<Object> numeric_index;
     218        3421 :     if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
     219             :       // 3b i. If IsInteger(numericIndex) is false, return false.
     220             :       // 3b ii. If numericIndex = -0, return false.
     221             :       // 3b iii. If numericIndex < 0, return false.
     222             :       // FIXME: the standard allows up to 2^53 elements.
     223             :       uint32_t index;
     224         423 :       if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
     225          81 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     226             :                        NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
     227             :       }
     228             :       // 3b iv. Let length be O.[[ArrayLength]].
     229             :       size_t length = o->length_value();
     230             :       // 3b v. If numericIndex ≥ length, return false.
     231         189 :       if (o->WasDetached() || index >= length) {
     232          27 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     233             :                        NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
     234             :       }
     235             :       // 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
     236         180 :       if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
     237         513 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     238             :                        NewTypeError(MessageTemplate::kRedefineDisallowed, key));
     239             :       }
     240             :       // 3b vii. If Desc has a [[Configurable]] field and if
     241             :       //         Desc.[[Configurable]] is true, return false.
     242             :       // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
     243             :       //          is false, return false.
     244             :       // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
     245             :       //        false, return false.
     246          18 :       if ((desc->has_configurable() && desc->configurable()) ||
     247          18 :           (desc->has_enumerable() && !desc->enumerable()) ||
     248           9 :           (desc->has_writable() && !desc->writable())) {
     249          27 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     250             :                        NewTypeError(MessageTemplate::kRedefineDisallowed, key));
     251             :       }
     252             :       // 3b x. If Desc has a [[Value]] field, then
     253             :       //   3b x 1. Let value be Desc.[[Value]].
     254             :       //   3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
     255           0 :       if (desc->has_value()) {
     256           0 :         if (!desc->has_configurable()) desc->set_configurable(false);
     257           0 :         if (!desc->has_enumerable()) desc->set_enumerable(true);
     258           0 :         if (!desc->has_writable()) desc->set_writable(true);
     259           0 :         Handle<Object> value = desc->value();
     260           0 :         RETURN_ON_EXCEPTION_VALUE(isolate,
     261             :                                   SetOwnElementIgnoreAttributes(
     262             :                                       o, index, value, desc->ToAttributes()),
     263             :                                   Nothing<bool>());
     264             :       }
     265             :       // 3b xi. Return true.
     266             :       return Just(true);
     267             :     }
     268             :   }
     269             :   // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
     270        3394 :   return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
     271             : }
     272             : 
     273    31849454 : ExternalArrayType JSTypedArray::type() {
     274    31849454 :   switch (elements()->map()->instance_type()) {
     275             : #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype) \
     276             :   case FIXED_##TYPE##_ARRAY_TYPE:                            \
     277             :     return kExternal##Type##Array;
     278             : 
     279        1769 :     TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
     280             : #undef INSTANCE_TYPE_TO_ARRAY_TYPE
     281             : 
     282             :     default:
     283           0 :       UNREACHABLE();
     284             :   }
     285             : }
     286             : 
     287        8112 : size_t JSTypedArray::element_size() {
     288        8112 :   switch (elements()->map()->instance_type()) {
     289             : #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype) \
     290             :   case FIXED_##TYPE##_ARRAY_TYPE:                              \
     291             :     return sizeof(ctype);
     292             : 
     293         693 :     TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
     294             : #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
     295             : 
     296             :     default:
     297           0 :       UNREACHABLE();
     298             :   }
     299             : }
     300             : 
     301             : }  // namespace internal
     302      120216 : }  // namespace v8

Generated by: LCOV version 1.10