runtime-typedarray.cc 6.16 KB
Newer Older
1 2 3 4
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "src/common/message-template.h"
6
#include "src/execution/arguments-inl.h"
7
#include "src/heap/factory.h"
8
#include "src/heap/heap-inl.h"
9
#include "src/logging/counters.h"
10
#include "src/objects/elements.h"
11
#include "src/objects/js-array-buffer-inl.h"
12
#include "src/objects/objects-inl.h"
13
#include "src/runtime/runtime-utils.h"
14 15 16 17 18
#include "src/runtime/runtime.h"

namespace v8 {
namespace internal {

19
RUNTIME_FUNCTION(Runtime_ArrayBufferDetach) {
20
  HandleScope scope(isolate);
21
  DCHECK_EQ(1, args.length());
22 23 24 25 26 27 28 29
  Handle<Object> argument = args.at(0);
  // This runtime function is exposed in ClusterFuzz and as such has to
  // support arbitrary arguments.
  if (!argument->IsJSArrayBuffer()) {
    THROW_NEW_ERROR_RETURN_FAILURE(
        isolate, NewTypeError(MessageTemplate::kNotTypedArray));
  }
  Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(argument);
30
  array_buffer->Detach();
31
  return ReadOnlyRoots(isolate).undefined_value();
32 33
}

34 35 36
RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) {
  HandleScope scope(isolate);
  DCHECK_EQ(3, args.length());
37
  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target, 0);
38
  CONVERT_ARG_HANDLE_CHECKED(Object, source, 1);
39 40
  CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 2);

41 42 43 44
  size_t length;
  CHECK(TryNumberToSize(*length_obj, &length));

  ElementsAccessor* accessor = target->GetElementsAccessor();
45
  return accessor->CopyElements(source, target, length, 0);
46 47
}

48 49
RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
  HandleScope scope(isolate);
50
  DCHECK_EQ(1, args.length());
51 52 53 54
  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
  return *holder->GetBuffer();
}

55

56 57
namespace {

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
template <typename T>
bool CompareNum(T x, T y) {
  if (x < y) {
    return true;
  } else if (x > y) {
    return false;
  } else if (!std::is_integral<T>::value) {
    double _x = x, _y = y;
    if (x == 0 && x == y) {
      /* -0.0 is less than +0.0 */
      return std::signbit(_x) && !std::signbit(_y);
    } else if (!std::isnan(_x) && std::isnan(_y)) {
      /* number is less than NaN */
      return true;
    }
73
  }
74 75
  return false;
}
76 77 78 79 80 81 82

}  // namespace

RUNTIME_FUNCTION(Runtime_TypedArraySortFast) {
  HandleScope scope(isolate);
  DCHECK_EQ(1, args.length());

83 84 85
  // Validation is handled in the Torque builtin.
  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, array, 0);
  DCHECK(!array->WasDetached());
86

87
  size_t length = array->length();
88
  DCHECK_LT(1, length);
89

90 91 92
  // In case of a SAB, the data is copied into temporary memory, as
  // std::sort might crash in case the underlying data is concurrently
  // modified while sorting.
93
  CHECK(array->buffer().IsJSArrayBuffer());
94 95 96 97
  Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(array->buffer()), isolate);
  const bool copy_data = buffer->is_shared();

  Handle<ByteArray> array_copy;
98 99
  std::vector<uint8_t> offheap_copy;
  void* data_copy_ptr = nullptr;
100 101
  if (copy_data) {
    const size_t bytes = array->byte_length();
102 103 104 105 106 107 108 109 110 111
    if (bytes <= static_cast<unsigned>(
                     ByteArray::LengthFor(kMaxRegularHeapObjectSize))) {
      array_copy = isolate->factory()->NewByteArray(static_cast<int>(bytes));
      data_copy_ptr = array_copy->GetDataStartAddress();
    } else {
      // Allocate copy in C++ heap.
      offheap_copy.resize(bytes);
      data_copy_ptr = &offheap_copy[0];
    }
    std::memcpy(data_copy_ptr, static_cast<void*>(array->DataPtr()), bytes);
112 113 114 115
  }

  DisallowHeapAllocation no_gc;

116
  switch (array->type()) {
117 118
#define TYPED_ARRAY_SORT(Type, type, TYPE, ctype)                          \
  case kExternal##Type##Array: {                                           \
119 120
    ctype* data = copy_data ? reinterpret_cast<ctype*>(data_copy_ptr)      \
                            : static_cast<ctype*>(array->DataPtr());       \
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
    if (kExternal##Type##Array == kExternalFloat64Array ||                 \
        kExternal##Type##Array == kExternalFloat32Array) {                 \
      if (COMPRESS_POINTERS_BOOL && alignof(ctype) > kTaggedSize) {        \
        /* TODO(ishell, v8:8875): See UnalignedSlot<T> for details. */     \
        std::sort(UnalignedSlot<ctype>(data),                              \
                  UnalignedSlot<ctype>(data + length), CompareNum<ctype>); \
      } else {                                                             \
        std::sort(data, data + length, CompareNum<ctype>);                 \
      }                                                                    \
    } else {                                                               \
      if (COMPRESS_POINTERS_BOOL && alignof(ctype) > kTaggedSize) {        \
        /* TODO(ishell, v8:8875): See UnalignedSlot<T> for details. */     \
        std::sort(UnalignedSlot<ctype>(data),                              \
                  UnalignedSlot<ctype>(data + length));                    \
      } else {                                                             \
        std::sort(data, data + length);                                    \
      }                                                                    \
    }                                                                      \
    break;                                                                 \
140 141 142 143 144 145
  }

    TYPED_ARRAYS(TYPED_ARRAY_SORT)
#undef TYPED_ARRAY_SORT
  }

146
  if (copy_data) {
147 148
    DCHECK_NOT_NULL(data_copy_ptr);
    DCHECK_NE(array_copy.is_null(), offheap_copy.empty());
149
    const size_t bytes = array->byte_length();
150
    std::memcpy(static_cast<void*>(array->DataPtr()), data_copy_ptr, bytes);
151 152
  }

153 154
  return *array;
}
155

156 157
RUNTIME_FUNCTION(Runtime_TypedArraySet) {
  HandleScope scope(isolate);
158 159 160 161 162
  DCHECK_EQ(4, args.length());
  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target, 0);
  CONVERT_ARG_HANDLE_CHECKED(Object, source, 1);
  CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 2);
  CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 3);
163

164 165
  size_t length;
  CHECK(TryNumberToSize(*length_obj, &length));
166

167 168
  size_t offset;
  CHECK(TryNumberToSize(*offset_obj, &offset));
169 170

  ElementsAccessor* accessor = target->GetElementsAccessor();
171
  return accessor->CopyElements(source, target, length, offset);
172 173
}

174 175
}  // namespace internal
}  // namespace v8