1 // Copyright 2014 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.
7 #include "src/arguments.h"
8 #include "src/runtime/runtime.h"
9 #include "src/runtime/runtime-utils.h"
15 void Runtime::FreeArrayBuffer(Isolate* isolate,
16 JSArrayBuffer* phantom_array_buffer) {
17 if (phantom_array_buffer->should_be_freed()) {
18 DCHECK(phantom_array_buffer->is_external());
19 free(phantom_array_buffer->backing_store());
21 if (phantom_array_buffer->is_external()) return;
23 size_t allocated_length =
24 NumberToSize(isolate, phantom_array_buffer->byte_length());
26 reinterpret_cast<v8::Isolate*>(isolate)
27 ->AdjustAmountOfExternalAllocatedMemory(
28 -static_cast<int64_t>(allocated_length));
29 CHECK(V8::ArrayBufferAllocator() != NULL);
30 V8::ArrayBufferAllocator()->Free(phantom_array_buffer->backing_store(),
35 void Runtime::SetupArrayBuffer(Isolate* isolate,
36 Handle<JSArrayBuffer> array_buffer,
37 bool is_external, void* data,
38 size_t allocated_length) {
39 DCHECK(array_buffer->GetInternalFieldCount() ==
40 v8::ArrayBuffer::kInternalFieldCount);
41 for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
42 array_buffer->SetInternalField(i, Smi::FromInt(0));
44 array_buffer->set_backing_store(data);
45 array_buffer->set_flag(Smi::FromInt(0));
46 array_buffer->set_is_external(is_external);
47 array_buffer->set_is_neuterable(true);
49 Handle<Object> byte_length =
50 isolate->factory()->NewNumberFromSize(allocated_length);
51 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
52 array_buffer->set_byte_length(*byte_length);
54 array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
55 isolate->heap()->set_array_buffers_list(*array_buffer);
56 array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
60 bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate,
61 Handle<JSArrayBuffer> array_buffer,
62 size_t allocated_length,
65 CHECK(V8::ArrayBufferAllocator() != NULL);
66 // Prevent creating array buffers when serializing.
67 DCHECK(!isolate->serializer_enabled());
68 if (allocated_length != 0) {
70 data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
73 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
75 if (data == NULL) return false;
80 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
82 reinterpret_cast<v8::Isolate*>(isolate)
83 ->AdjustAmountOfExternalAllocatedMemory(allocated_length);
89 void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
90 Isolate* isolate = array_buffer->GetIsolate();
91 // Firstly, iterate over the views which are referenced directly by the array
93 for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
94 !view_obj->IsUndefined();) {
95 Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
96 if (view->IsJSTypedArray()) {
97 JSTypedArray::cast(*view)->Neuter();
98 } else if (view->IsJSDataView()) {
99 JSDataView::cast(*view)->Neuter();
103 view_obj = handle(view->weak_next(), isolate);
106 // Secondly, iterate over the global list of new space views to find views
107 // that belong to the neutered array buffer.
108 Heap* heap = isolate->heap();
109 for (Handle<Object> view_obj(heap->new_array_buffer_views_list(), isolate);
110 !view_obj->IsUndefined();) {
111 Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
112 if (view->buffer() == *array_buffer) {
113 if (view->IsJSTypedArray()) {
114 JSTypedArray::cast(*view)->Neuter();
115 } else if (view->IsJSDataView()) {
116 JSDataView::cast(*view)->Neuter();
121 view_obj = handle(view->weak_next(), isolate);
123 array_buffer->Neuter();
127 RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) {
128 HandleScope scope(isolate);
129 DCHECK(args.length() == 2);
130 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
131 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1);
132 if (!holder->byte_length()->IsUndefined()) {
133 // ArrayBuffer is already initialized; probably a fuzz test.
136 size_t allocated_length = 0;
137 if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) {
138 THROW_NEW_ERROR_RETURN_FAILURE(
139 isolate, NewRangeError("invalid_array_buffer_length",
140 HandleVector<Object>(NULL, 0)));
142 if (!Runtime::SetupArrayBufferAllocatingData(isolate, holder,
144 THROW_NEW_ERROR_RETURN_FAILURE(
145 isolate, NewRangeError("invalid_array_buffer_length",
146 HandleVector<Object>(NULL, 0)));
152 RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
153 SealHandleScope shs(isolate);
154 DCHECK(args.length() == 1);
155 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
156 return holder->byte_length();
160 RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
161 HandleScope scope(isolate);
162 DCHECK(args.length() == 3);
163 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
164 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
165 CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2);
166 RUNTIME_ASSERT(!source.is_identical_to(target));
168 RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start));
169 size_t target_length = NumberToSize(isolate, target->byte_length());
171 if (target_length == 0) return isolate->heap()->undefined_value();
173 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
174 RUNTIME_ASSERT(start <= source_byte_length);
175 RUNTIME_ASSERT(source_byte_length - start >= target_length);
176 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
177 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
178 CopyBytes(target_data, source_data + start, target_length);
179 return isolate->heap()->undefined_value();
183 RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) {
184 HandleScope scope(isolate);
185 DCHECK(args.length() == 1);
186 CONVERT_ARG_CHECKED(Object, object, 0);
187 return isolate->heap()->ToBoolean(object->IsJSArrayBufferView());
191 RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
192 HandleScope scope(isolate);
193 DCHECK(args.length() == 1);
194 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
195 if (array_buffer->backing_store() == NULL) {
196 CHECK(Smi::FromInt(0) == array_buffer->byte_length());
197 return isolate->heap()->undefined_value();
199 DCHECK(!array_buffer->is_external());
200 void* backing_store = array_buffer->backing_store();
201 size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
202 array_buffer->set_is_external(true);
203 Runtime::NeuterArrayBuffer(array_buffer);
204 V8::ArrayBufferAllocator()->Free(backing_store, byte_length);
205 return isolate->heap()->undefined_value();
209 void Runtime::ArrayIdToTypeAndSize(int arrayId, ExternalArrayType* array_type,
210 ElementsKind* external_elements_kind,
211 ElementsKind* fixed_elements_kind,
212 size_t* element_size) {
214 #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \
215 case ARRAY_ID_##TYPE: \
216 *array_type = kExternal##Type##Array; \
217 *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \
218 *fixed_elements_kind = TYPE##_ELEMENTS; \
219 *element_size = size; \
222 TYPED_ARRAYS(ARRAY_ID_CASE)
231 RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
232 HandleScope scope(isolate);
233 DCHECK(args.length() == 5);
234 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
235 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
236 CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
237 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3);
238 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4);
240 RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
241 arrayId <= Runtime::ARRAY_ID_LAST);
243 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
244 size_t element_size = 1; // Bogus initialization.
245 ElementsKind external_elements_kind =
246 EXTERNAL_INT8_ELEMENTS; // Bogus initialization.
247 ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
248 Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
249 &fixed_elements_kind, &element_size);
250 RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
252 size_t byte_offset = 0;
253 size_t byte_length = 0;
254 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset));
255 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length));
257 if (maybe_buffer->IsJSArrayBuffer()) {
258 Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
259 size_t array_buffer_byte_length =
260 NumberToSize(isolate, buffer->byte_length());
261 RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
262 RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
264 RUNTIME_ASSERT(maybe_buffer->IsNull());
267 RUNTIME_ASSERT(byte_length % element_size == 0);
268 size_t length = byte_length / element_size;
270 if (length > static_cast<unsigned>(Smi::kMaxValue)) {
271 THROW_NEW_ERROR_RETURN_FAILURE(
272 isolate, NewRangeError("invalid_typed_array_length",
273 HandleVector<Object>(NULL, 0)));
276 // All checks are done, now we can modify objects.
278 DCHECK(holder->GetInternalFieldCount() ==
279 v8::ArrayBufferView::kInternalFieldCount);
280 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
281 holder->SetInternalField(i, Smi::FromInt(0));
283 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
284 holder->set_length(*length_obj);
285 holder->set_byte_offset(*byte_offset_object);
286 holder->set_byte_length(*byte_length_object);
288 Heap* heap = isolate->heap();
289 if (!maybe_buffer->IsNull()) {
290 Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
291 holder->set_buffer(*buffer);
293 if (heap->InNewSpace(*holder)) {
294 holder->set_weak_next(heap->new_array_buffer_views_list());
295 heap->set_new_array_buffer_views_list(*holder);
297 holder->set_weak_next(buffer->weak_first_view());
298 buffer->set_weak_first_view(*holder);
301 Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
302 static_cast<int>(length), array_type,
303 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
305 JSObject::GetElementsTransitionMap(holder, external_elements_kind);
306 JSObject::SetMapAndElements(holder, map, elements);
307 DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind()));
309 holder->set_buffer(Smi::FromInt(0));
310 holder->set_weak_next(isolate->heap()->undefined_value());
311 Handle<FixedTypedArrayBase> elements =
312 isolate->factory()->NewFixedTypedArray(static_cast<int>(length),
314 holder->set_elements(*elements);
316 return isolate->heap()->undefined_value();
320 // Initializes a typed array from an array-like object.
321 // If an array-like object happens to be a typed array of the same type,
322 // initializes backing store using memove.
324 // Returns true if backing store was initialized or false otherwise.
325 RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
326 HandleScope scope(isolate);
327 DCHECK(args.length() == 4);
328 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
329 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
330 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
331 CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
333 RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
334 arrayId <= Runtime::ARRAY_ID_LAST);
336 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
337 size_t element_size = 1; // Bogus initialization.
338 ElementsKind external_elements_kind =
339 EXTERNAL_INT8_ELEMENTS; // Bogus intialization.
340 ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
341 Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
342 &fixed_elements_kind, &element_size);
344 RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
346 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
347 if (source->IsJSTypedArray() &&
348 JSTypedArray::cast(*source)->type() == array_type) {
349 length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
352 RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length));
354 if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
355 (length > (kMaxInt / element_size))) {
356 THROW_NEW_ERROR_RETURN_FAILURE(
357 isolate, NewRangeError("invalid_typed_array_length",
358 HandleVector<Object>(NULL, 0)));
360 size_t byte_length = length * element_size;
362 DCHECK(holder->GetInternalFieldCount() ==
363 v8::ArrayBufferView::kInternalFieldCount);
364 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
365 holder->SetInternalField(i, Smi::FromInt(0));
368 // NOTE: not initializing backing store.
369 // We assume that the caller of this function will initialize holder
371 // for(i = 0; i < length; i++) { holder[i] = source[i]; }
372 // We assume that the caller of this function is always a typed array
374 // If source is a typed array, this loop will always run to completion,
375 // so we are sure that the backing store will be initialized.
376 // Otherwise, the indexing operation might throw, so the loop will not
377 // run to completion and the typed array might remain partly initialized.
378 // However we further assume that the caller of this function is a typed array
379 // constructor, and the exception will propagate out of the constructor,
380 // therefore uninitialized memory will not be accessible by a user program.
382 // TODO(dslomov): revise this once we support subclassing.
384 if (!Runtime::SetupArrayBufferAllocatingData(isolate, buffer, byte_length,
386 THROW_NEW_ERROR_RETURN_FAILURE(
387 isolate, NewRangeError("invalid_array_buffer_length",
388 HandleVector<Object>(NULL, 0)));
391 holder->set_buffer(*buffer);
392 holder->set_byte_offset(Smi::FromInt(0));
393 Handle<Object> byte_length_obj(
394 isolate->factory()->NewNumberFromSize(byte_length));
395 holder->set_byte_length(*byte_length_obj);
396 holder->set_length(*length_obj);
398 Heap* heap = isolate->heap();
399 if (heap->InNewSpace(*holder)) {
400 holder->set_weak_next(heap->new_array_buffer_views_list());
401 heap->set_new_array_buffer_views_list(*holder);
403 holder->set_weak_next(buffer->weak_first_view());
404 buffer->set_weak_first_view(*holder);
407 Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
408 static_cast<int>(length), array_type,
409 static_cast<uint8_t*>(buffer->backing_store()));
411 JSObject::GetElementsTransitionMap(holder, external_elements_kind);
412 JSObject::SetMapAndElements(holder, map, elements);
414 if (source->IsJSTypedArray()) {
415 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
417 if (typed_array->type() == holder->type()) {
418 uint8_t* backing_store =
419 static_cast<uint8_t*>(typed_array->GetBuffer()->backing_store());
420 size_t source_byte_offset =
421 NumberToSize(isolate, typed_array->byte_offset());
422 memcpy(buffer->backing_store(), backing_store + source_byte_offset,
424 return isolate->heap()->true_value();
428 return isolate->heap()->false_value();
432 #define BUFFER_VIEW_GETTER(Type, getter, accessor) \
433 RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \
434 HandleScope scope(isolate); \
435 DCHECK(args.length() == 1); \
436 CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \
437 return holder->accessor(); \
440 BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
441 BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
442 BUFFER_VIEW_GETTER(TypedArray, Length, length)
443 BUFFER_VIEW_GETTER(DataView, Buffer, buffer)
445 #undef BUFFER_VIEW_GETTER
447 RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
448 HandleScope scope(isolate);
449 DCHECK(args.length() == 1);
450 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
451 return *holder->GetBuffer();
455 // Return codes for Runtime_TypedArraySetFastCases.
456 // Should be synchronized with typedarray.js natives.
457 enum TypedArraySetResultCodes {
458 // Set from typed array of the same type.
459 // This is processed by TypedArraySetFastCases
460 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
461 // Set from typed array of the different type, overlapping in memory.
462 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
463 // Set from typed array of the different type, non-overlapping.
464 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
465 // Set from non-typed array.
466 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
470 RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
471 HandleScope scope(isolate);
472 DCHECK(args.length() == 3);
473 if (!args[0]->IsJSTypedArray()) {
474 THROW_NEW_ERROR_RETURN_FAILURE(
476 NewTypeError("not_typed_array", HandleVector<Object>(NULL, 0)));
479 if (!args[1]->IsJSTypedArray())
480 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
482 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0);
483 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1);
484 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
486 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
487 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
489 RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset));
490 size_t target_length = NumberToSize(isolate, target->length());
491 size_t source_length = NumberToSize(isolate, source->length());
492 size_t target_byte_length = NumberToSize(isolate, target->byte_length());
493 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
494 if (offset > target_length || offset + source_length > target_length ||
495 offset + source_length < offset) { // overflow
496 THROW_NEW_ERROR_RETURN_FAILURE(
497 isolate, NewRangeError("typed_array_set_source_too_large",
498 HandleVector<Object>(NULL, 0)));
501 size_t target_offset = NumberToSize(isolate, target->byte_offset());
502 size_t source_offset = NumberToSize(isolate, source->byte_offset());
503 uint8_t* target_base =
504 static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
506 uint8_t* source_base =
507 static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
510 // Typed arrays of the same type: use memmove.
511 if (target->type() == source->type()) {
512 memmove(target_base + offset * target->element_size(), source_base,
514 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
517 // Typed arrays of different types over the same backing store
518 if ((source_base <= target_base &&
519 source_base + source_byte_length > target_base) ||
520 (target_base <= source_base &&
521 target_base + target_byte_length > source_base)) {
522 // We do not support overlapping ArrayBuffers
523 DCHECK(target->GetBuffer()->backing_store() ==
524 source->GetBuffer()->backing_store());
525 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
526 } else { // Non-overlapping typed arrays
527 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
532 RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
533 DCHECK(args.length() == 0);
534 DCHECK_OBJECT_SIZE(FLAG_typed_array_max_size_in_heap +
535 FixedTypedArrayBase::kDataOffset);
536 return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
540 RUNTIME_FUNCTION(Runtime_IsTypedArray) {
541 HandleScope scope(isolate);
542 DCHECK(args.length() == 1);
543 return isolate->heap()->ToBoolean(args[0]->IsJSTypedArray());
547 RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
548 HandleScope scope(isolate);
549 DCHECK(args.length() == 4);
550 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
551 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
552 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2);
553 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3);
555 DCHECK(holder->GetInternalFieldCount() ==
556 v8::ArrayBufferView::kInternalFieldCount);
557 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
558 holder->SetInternalField(i, Smi::FromInt(0));
560 size_t buffer_length = 0;
564 TryNumberToSize(isolate, buffer->byte_length(), &buffer_length));
565 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset));
566 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length));
568 // TODO(jkummerow): When we have a "safe numerics" helper class, use it here.
569 // Entire range [offset, offset + length] must be in bounds.
570 RUNTIME_ASSERT(offset <= buffer_length);
571 RUNTIME_ASSERT(offset + length <= buffer_length);
573 RUNTIME_ASSERT(offset + length >= offset);
575 holder->set_buffer(*buffer);
576 holder->set_byte_offset(*byte_offset);
577 holder->set_byte_length(*byte_length);
579 Heap* heap = isolate->heap();
580 if (heap->InNewSpace(*holder)) {
581 holder->set_weak_next(heap->new_array_buffer_views_list());
582 heap->set_new_array_buffer_views_list(*holder);
584 holder->set_weak_next(buffer->weak_first_view());
585 buffer->set_weak_first_view(*holder);
588 return isolate->heap()->undefined_value();
592 inline static bool NeedToFlipBytes(bool is_little_endian) {
593 #ifdef V8_TARGET_LITTLE_ENDIAN
594 return !is_little_endian;
596 return is_little_endian;
602 inline void CopyBytes(uint8_t* target, uint8_t* source) {
603 for (int i = 0; i < n; i++) {
604 *(target++) = *(source++);
610 inline void FlipBytes(uint8_t* target, uint8_t* source) {
611 source = source + (n - 1);
612 for (int i = 0; i < n; i++) {
613 *(target++) = *(source--);
618 template <typename T>
619 inline static bool DataViewGetValue(Isolate* isolate,
620 Handle<JSDataView> data_view,
621 Handle<Object> byte_offset_obj,
622 bool is_little_endian, T* result) {
623 size_t byte_offset = 0;
624 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
627 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
629 size_t data_view_byte_offset =
630 NumberToSize(isolate, data_view->byte_offset());
631 size_t data_view_byte_length =
632 NumberToSize(isolate, data_view->byte_length());
633 if (byte_offset + sizeof(T) > data_view_byte_length ||
634 byte_offset + sizeof(T) < byte_offset) { // overflow
640 uint8_t bytes[sizeof(T)];
644 size_t buffer_offset = data_view_byte_offset + byte_offset;
645 DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
646 buffer_offset + sizeof(T));
648 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
649 if (NeedToFlipBytes(is_little_endian)) {
650 FlipBytes<sizeof(T)>(value.bytes, source);
652 CopyBytes<sizeof(T)>(value.bytes, source);
654 *result = value.data;
659 template <typename T>
660 static bool DataViewSetValue(Isolate* isolate, Handle<JSDataView> data_view,
661 Handle<Object> byte_offset_obj,
662 bool is_little_endian, T data) {
663 size_t byte_offset = 0;
664 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
667 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
669 size_t data_view_byte_offset =
670 NumberToSize(isolate, data_view->byte_offset());
671 size_t data_view_byte_length =
672 NumberToSize(isolate, data_view->byte_length());
673 if (byte_offset + sizeof(T) > data_view_byte_length ||
674 byte_offset + sizeof(T) < byte_offset) { // overflow
680 uint8_t bytes[sizeof(T)];
685 size_t buffer_offset = data_view_byte_offset + byte_offset;
686 DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
687 buffer_offset + sizeof(T));
689 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
690 if (NeedToFlipBytes(is_little_endian)) {
691 FlipBytes<sizeof(T)>(target, value.bytes);
693 CopyBytes<sizeof(T)>(target, value.bytes);
699 #define DATA_VIEW_GETTER(TypeName, Type, Converter) \
700 RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) { \
701 HandleScope scope(isolate); \
702 DCHECK(args.length() == 3); \
703 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
704 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \
705 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \
707 if (DataViewGetValue(isolate, holder, offset, is_little_endian, \
709 return *isolate->factory()->Converter(result); \
711 THROW_NEW_ERROR_RETURN_FAILURE( \
712 isolate, NewRangeError("invalid_data_view_accessor_offset", \
713 HandleVector<Object>(NULL, 0))); \
717 DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint)
718 DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt)
719 DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint)
720 DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt)
721 DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint)
722 DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt)
723 DATA_VIEW_GETTER(Float32, float, NewNumber)
724 DATA_VIEW_GETTER(Float64, double, NewNumber)
726 #undef DATA_VIEW_GETTER
729 template <typename T>
730 static T DataViewConvertValue(double value);
734 int8_t DataViewConvertValue<int8_t>(double value) {
735 return static_cast<int8_t>(DoubleToInt32(value));
740 int16_t DataViewConvertValue<int16_t>(double value) {
741 return static_cast<int16_t>(DoubleToInt32(value));
746 int32_t DataViewConvertValue<int32_t>(double value) {
747 return DoubleToInt32(value);
752 uint8_t DataViewConvertValue<uint8_t>(double value) {
753 return static_cast<uint8_t>(DoubleToUint32(value));
758 uint16_t DataViewConvertValue<uint16_t>(double value) {
759 return static_cast<uint16_t>(DoubleToUint32(value));
764 uint32_t DataViewConvertValue<uint32_t>(double value) {
765 return DoubleToUint32(value);
770 float DataViewConvertValue<float>(double value) {
771 return static_cast<float>(value);
776 double DataViewConvertValue<double>(double value) {
781 #define DATA_VIEW_SETTER(TypeName, Type) \
782 RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) { \
783 HandleScope scope(isolate); \
784 DCHECK(args.length() == 4); \
785 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
786 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \
787 CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); \
788 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \
789 Type v = DataViewConvertValue<Type>(value->Number()); \
790 if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) { \
791 return isolate->heap()->undefined_value(); \
793 THROW_NEW_ERROR_RETURN_FAILURE( \
794 isolate, NewRangeError("invalid_data_view_accessor_offset", \
795 HandleVector<Object>(NULL, 0))); \
799 DATA_VIEW_SETTER(Uint8, uint8_t)
800 DATA_VIEW_SETTER(Int8, int8_t)
801 DATA_VIEW_SETTER(Uint16, uint16_t)
802 DATA_VIEW_SETTER(Int16, int16_t)
803 DATA_VIEW_SETTER(Uint32, uint32_t)
804 DATA_VIEW_SETTER(Int32, int32_t)
805 DATA_VIEW_SETTER(Float32, float)
806 DATA_VIEW_SETTER(Float64, double)
808 #undef DATA_VIEW_SETTER
810 } // namespace v8::internal