LCOV - code coverage report
Current view: top level - src/objects - js-array-buffer.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 84 100 84.0 %
Date: 2019-02-19 Functions: 12 14 85.7 %

          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        6842 :   if (s->IsSmi()) {
      22             :     result = s;
      23             :   } else {
      24        3403 :     result = String::ToNumber(isolate, Handle<String>::cast(s));
      25        6806 :     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        6410 :   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           0 :     return;
      59             :   }
      60             :   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      624847 : void JSArrayBuffer::FreeBackingStore(Isolate* isolate, Allocation allocation) {
      69      400653 :   if (allocation.is_wasm_memory) {
      70             :     wasm::WasmMemoryTracker* memory_tracker =
      71      176459 :         isolate->wasm_engine()->memory_tracker();
      72      176468 :     if (!memory_tracker->FreeMemoryIfIsWasmMemory(isolate,
      73      176459 :                                                   allocation.backing_store)) {
      74           0 :       CHECK(FreePages(GetPlatformPageAllocator(), allocation.allocation_base,
      75             :                       allocation.length));
      76             :     }
      77             :   } else {
      78             :     isolate->array_buffer_allocator()->Free(allocation.allocation_base,
      79      224194 :                                             allocation.length);
      80             :   }
      81      400664 : }
      82             : 
      83      405804 : void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
      84             :                           bool is_external, void* data, size_t byte_length,
      85             :                           SharedFlag shared_flag, bool is_wasm_memory) {
      86             :   DCHECK_EQ(array_buffer->GetEmbedderFieldCount(),
      87             :             v8::ArrayBuffer::kEmbedderFieldCount);
      88             :   DCHECK_LE(byte_length, JSArrayBuffer::kMaxByteLength);
      89     1217417 :   for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
      90      811612 :     array_buffer->SetEmbedderField(i, Smi::kZero);
      91             :   }
      92             :   array_buffer->set_byte_length(byte_length);
      93             :   array_buffer->set_bit_field(0);
      94      811613 :   array_buffer->clear_padding();
      95             :   array_buffer->set_is_external(is_external);
      96      405807 :   array_buffer->set_is_detachable(shared_flag == SharedFlag::kNotShared);
      97      405807 :   array_buffer->set_is_shared(shared_flag == SharedFlag::kShared);
      98             :   array_buffer->set_is_wasm_memory(is_wasm_memory);
      99             :   // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
     100             :   // are currently being constructed in the |ArrayBufferTracker|. The
     101             :   // registration method below handles the case of registering a buffer that has
     102             :   // already been promoted.
     103             :   array_buffer->set_backing_store(data);
     104             : 
     105      405805 :   if (data && !is_external) {
     106      395078 :     isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
     107             :   }
     108      405807 : }
     109             : 
     110           0 : void JSArrayBuffer::SetupAsEmpty(Handle<JSArrayBuffer> array_buffer,
     111             :                                  Isolate* isolate) {
     112          45 :   Setup(array_buffer, isolate, false, nullptr, 0, SharedFlag::kNotShared);
     113           0 : }
     114             : 
     115      223052 : bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
     116      436066 :                                         Isolate* isolate,
     117             :                                         size_t allocated_length,
     118             :                                         bool initialize,
     119             :                                         SharedFlag shared_flag) {
     120             :   void* data;
     121      223052 :   CHECK_NOT_NULL(isolate->array_buffer_allocator());
     122      223052 :   if (allocated_length != 0) {
     123      213012 :     if (allocated_length >= MB)
     124             :       isolate->counters()->array_buffer_big_allocations()->AddSample(
     125         350 :           ConvertToMb(allocated_length));
     126      213014 :     if (shared_flag == SharedFlag::kShared)
     127             :       isolate->counters()->shared_array_allocations()->AddSample(
     128        6015 :           ConvertToMb(allocated_length));
     129      213014 :     if (initialize) {
     130      211900 :       data = isolate->array_buffer_allocator()->Allocate(allocated_length);
     131             :     } else {
     132             :       data = isolate->array_buffer_allocator()->AllocateUninitialized(
     133        1114 :           allocated_length);
     134             :     }
     135      213013 :     if (data == nullptr) {
     136             :       isolate->counters()->array_buffer_new_size_failures()->AddSample(
     137          45 :           ConvertToMb(allocated_length));
     138             :       SetupAsEmpty(array_buffer, isolate);
     139          45 :       return false;
     140             :     }
     141             :   } else {
     142             :     data = nullptr;
     143             :   }
     144             : 
     145             :   const bool is_external = false;
     146             :   JSArrayBuffer::Setup(array_buffer, isolate, is_external, data,
     147      223008 :                        allocated_length, shared_flag);
     148      223009 :   return true;
     149             : }
     150             : 
     151       10868 : Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
     152             :     Handle<JSTypedArray> typed_array) {
     153             :   DCHECK(typed_array->is_on_heap());
     154             : 
     155       10868 :   Isolate* isolate = typed_array->GetIsolate();
     156             : 
     157             :   DCHECK(IsFixedTypedArrayElementsKind(typed_array->GetElementsKind()));
     158             : 
     159             :   Handle<FixedTypedArrayBase> fixed_typed_array(
     160       21736 :       FixedTypedArrayBase::cast(typed_array->elements()), isolate);
     161             : 
     162             :   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
     163             :                                isolate);
     164             :   // This code does not know how to materialize from wasm buffers.
     165             :   DCHECK(!buffer->is_wasm_memory());
     166             : 
     167             :   void* backing_store =
     168             :       isolate->array_buffer_allocator()->AllocateUninitialized(
     169       21736 :           fixed_typed_array->DataSize());
     170       10868 :   if (backing_store == nullptr) {
     171             :     isolate->heap()->FatalProcessOutOfMemory(
     172           0 :         "JSTypedArray::MaterializeArrayBuffer");
     173             :   }
     174             :   buffer->set_is_external(false);
     175             :   DCHECK_EQ(buffer->byte_length(),
     176             :             static_cast<uintptr_t>(fixed_typed_array->DataSize()));
     177             :   // Initialize backing store at last to avoid handling of |JSArrayBuffers| that
     178             :   // are currently being constructed in the |ArrayBufferTracker|. The
     179             :   // registration method below handles the case of registering a buffer that has
     180             :   // already been promoted.
     181             :   buffer->set_backing_store(backing_store);
     182             :   // RegisterNewArrayBuffer expects a valid length for adjusting counters.
     183       10868 :   isolate->heap()->RegisterNewArrayBuffer(*buffer);
     184             :   memcpy(buffer->backing_store(), fixed_typed_array->DataPtr(),
     185       21736 :          fixed_typed_array->DataSize());
     186             :   Handle<FixedTypedArrayBase> new_elements =
     187             :       isolate->factory()->NewFixedTypedArrayWithExternalPointer(
     188             :           fixed_typed_array->length(), typed_array->type(),
     189       21736 :           static_cast<uint8_t*>(buffer->backing_store()));
     190             : 
     191       21736 :   typed_array->set_elements(*new_elements);
     192             :   DCHECK(!typed_array->is_on_heap());
     193             : 
     194       10868 :   return buffer;
     195             : }
     196             : 
     197    40404249 : Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
     198    40404249 :   if (!is_on_heap()) {
     199             :     Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
     200             :                                        GetIsolate());
     201    40393355 :     return array_buffer;
     202             :   }
     203             :   Handle<JSTypedArray> self(*this, GetIsolate());
     204       10868 :   return MaterializeArrayBuffer(self);
     205             : }
     206             : 
     207             : // ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
     208             : // static
     209        3610 : Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
     210             :                                             Handle<JSTypedArray> o,
     211             :                                             Handle<Object> key,
     212             :                                             PropertyDescriptor* desc,
     213             :                                             Maybe<ShouldThrow> should_throw) {
     214             :   // 1. Assert: IsPropertyKey(P) is true.
     215             :   DCHECK(key->IsName() || key->IsNumber());
     216             :   // 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
     217             :   // 3. If Type(P) is String, then
     218        7634 :   if (key->IsString() || key->IsSmi()) {
     219             :     // 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
     220             :     // 3b. If numericIndex is not undefined, then
     221             :     Handle<Object> numeric_index;
     222        3421 :     if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
     223             :       // 3b i. If IsInteger(numericIndex) is false, return false.
     224             :       // 3b ii. If numericIndex = -0, return false.
     225             :       // 3b iii. If numericIndex < 0, return false.
     226             :       // FIXME: the standard allows up to 2^53 elements.
     227             :       uint32_t index;
     228         639 :       if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
     229          81 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     230             :                        NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
     231             :       }
     232             :       // 3b iv. Let length be O.[[ArrayLength]].
     233             :       size_t length = o->length_value();
     234             :       // 3b v. If numericIndex ≥ length, return false.
     235         189 :       if (o->WasDetached() || index >= length) {
     236          27 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     237             :                        NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
     238             :       }
     239             :       // 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
     240         180 :       if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
     241         513 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     242             :                        NewTypeError(MessageTemplate::kRedefineDisallowed, key));
     243             :       }
     244             :       // 3b vii. If Desc has a [[Configurable]] field and if
     245             :       //         Desc.[[Configurable]] is true, return false.
     246             :       // 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
     247             :       //          is false, return false.
     248             :       // 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
     249             :       //        false, return false.
     250          18 :       if ((desc->has_configurable() && desc->configurable()) ||
     251          18 :           (desc->has_enumerable() && !desc->enumerable()) ||
     252           9 :           (desc->has_writable() && !desc->writable())) {
     253          27 :         RETURN_FAILURE(isolate, GetShouldThrow(isolate, should_throw),
     254             :                        NewTypeError(MessageTemplate::kRedefineDisallowed, key));
     255             :       }
     256             :       // 3b x. If Desc has a [[Value]] field, then
     257             :       //   3b x 1. Let value be Desc.[[Value]].
     258             :       //   3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
     259           0 :       if (desc->has_value()) {
     260           0 :         if (!desc->has_configurable()) desc->set_configurable(false);
     261           0 :         if (!desc->has_enumerable()) desc->set_enumerable(true);
     262           0 :         if (!desc->has_writable()) desc->set_writable(true);
     263           0 :         Handle<Object> value = desc->value();
     264           0 :         RETURN_ON_EXCEPTION_VALUE(isolate,
     265             :                                   SetOwnElementIgnoreAttributes(
     266             :                                       o, index, value, desc->ToAttributes()),
     267             :                                   Nothing<bool>());
     268             :       }
     269             :       // 3b xi. Return true.
     270             :       return Just(true);
     271             :     }
     272             :   }
     273             :   // 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
     274        3394 :   return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
     275             : }
     276             : 
     277    20212566 : ExternalArrayType JSTypedArray::type() {
     278    40425131 :   switch (elements()->map()->instance_type()) {
     279             : #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype) \
     280             :   case FIXED_##TYPE##_ARRAY_TYPE:                            \
     281             :     return kExternal##Type##Array;
     282             : 
     283        1668 :     TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
     284             : #undef INSTANCE_TYPE_TO_ARRAY_TYPE
     285             : 
     286             :     default:
     287           0 :       UNREACHABLE();
     288             :   }
     289             : }
     290             : 
     291        7800 : size_t JSTypedArray::element_size() {
     292       15600 :   switch (elements()->map()->instance_type()) {
     293             : #define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype) \
     294             :   case FIXED_##TYPE##_ARRAY_TYPE:                              \
     295             :     return sizeof(ctype);
     296             : 
     297         693 :     TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
     298             : #undef INSTANCE_TYPE_TO_ELEMENT_SIZE
     299             : 
     300             :     default:
     301           0 :       UNREACHABLE();
     302             :   }
     303             : }
     304             : 
     305             : }  // namespace internal
     306      178779 : }  // namespace v8

Generated by: LCOV version 1.10