Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: src/runtime/runtime-typedarray.cc

Issue 598913004: Split more runtime functions into seperate files. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/runtime/runtime-test.cc ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "src/v8.h"
6
7 #include "src/arguments.h"
8 #include "src/runtime/runtime.h"
9 #include "src/runtime/runtime-utils.h"
10
11
12 namespace v8 {
13 namespace internal {
14
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());
20 }
21 if (phantom_array_buffer->is_external()) return;
22
23 size_t allocated_length =
24 NumberToSize(isolate, phantom_array_buffer->byte_length());
25
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(),
31 allocated_length);
32 }
33
34
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));
43 }
44 array_buffer->set_backing_store(data);
45 array_buffer->set_flag(Smi::FromInt(0));
46 array_buffer->set_is_external(is_external);
47
48 Handle<Object> byte_length =
49 isolate->factory()->NewNumberFromSize(allocated_length);
50 CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
51 array_buffer->set_byte_length(*byte_length);
52
53 array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
54 isolate->heap()->set_array_buffers_list(*array_buffer);
55 array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
56 }
57
58
59 bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate,
60 Handle<JSArrayBuffer> array_buffer,
61 size_t allocated_length,
62 bool initialize) {
63 void* data;
64 CHECK(V8::ArrayBufferAllocator() != NULL);
65 if (allocated_length != 0) {
66 if (initialize) {
67 data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
68 } else {
69 data =
70 V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
71 }
72 if (data == NULL) return false;
73 } else {
74 data = NULL;
75 }
76
77 SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
78
79 reinterpret_cast<v8::Isolate*>(isolate)
80 ->AdjustAmountOfExternalAllocatedMemory(allocated_length);
81
82 return true;
83 }
84
85
86 void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
87 Isolate* isolate = array_buffer->GetIsolate();
88 for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
89 !view_obj->IsUndefined();) {
90 Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
91 if (view->IsJSTypedArray()) {
92 JSTypedArray::cast(*view)->Neuter();
93 } else if (view->IsJSDataView()) {
94 JSDataView::cast(*view)->Neuter();
95 } else {
96 UNREACHABLE();
97 }
98 view_obj = handle(view->weak_next(), isolate);
99 }
100 array_buffer->Neuter();
101 }
102
103
104 RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) {
105 HandleScope scope(isolate);
106 DCHECK(args.length() == 2);
107 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
108 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1);
109 if (!holder->byte_length()->IsUndefined()) {
110 // ArrayBuffer is already initialized; probably a fuzz test.
111 return *holder;
112 }
113 size_t allocated_length = 0;
114 if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) {
115 THROW_NEW_ERROR_RETURN_FAILURE(
116 isolate, NewRangeError("invalid_array_buffer_length",
117 HandleVector<Object>(NULL, 0)));
118 }
119 if (!Runtime::SetupArrayBufferAllocatingData(isolate, holder,
120 allocated_length)) {
121 THROW_NEW_ERROR_RETURN_FAILURE(
122 isolate, NewRangeError("invalid_array_buffer_length",
123 HandleVector<Object>(NULL, 0)));
124 }
125 return *holder;
126 }
127
128
129 RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
130 SealHandleScope shs(isolate);
131 DCHECK(args.length() == 1);
132 CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
133 return holder->byte_length();
134 }
135
136
137 RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
138 HandleScope scope(isolate);
139 DCHECK(args.length() == 3);
140 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
141 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
142 CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2);
143 RUNTIME_ASSERT(!source.is_identical_to(target));
144 size_t start = 0;
145 RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start));
146 size_t target_length = NumberToSize(isolate, target->byte_length());
147
148 if (target_length == 0) return isolate->heap()->undefined_value();
149
150 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
151 RUNTIME_ASSERT(start <= source_byte_length);
152 RUNTIME_ASSERT(source_byte_length - start >= target_length);
153 uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
154 uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
155 CopyBytes(target_data, source_data + start, target_length);
156 return isolate->heap()->undefined_value();
157 }
158
159
160 RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) {
161 HandleScope scope(isolate);
162 DCHECK(args.length() == 1);
163 CONVERT_ARG_CHECKED(Object, object, 0);
164 return isolate->heap()->ToBoolean(object->IsJSArrayBufferView());
165 }
166
167
168 RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
169 HandleScope scope(isolate);
170 DCHECK(args.length() == 1);
171 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
172 if (array_buffer->backing_store() == NULL) {
173 CHECK(Smi::FromInt(0) == array_buffer->byte_length());
174 return isolate->heap()->undefined_value();
175 }
176 DCHECK(!array_buffer->is_external());
177 void* backing_store = array_buffer->backing_store();
178 size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
179 array_buffer->set_is_external(true);
180 Runtime::NeuterArrayBuffer(array_buffer);
181 V8::ArrayBufferAllocator()->Free(backing_store, byte_length);
182 return isolate->heap()->undefined_value();
183 }
184
185
186 void Runtime::ArrayIdToTypeAndSize(int arrayId, ExternalArrayType* array_type,
187 ElementsKind* external_elements_kind,
188 ElementsKind* fixed_elements_kind,
189 size_t* element_size) {
190 switch (arrayId) {
191 #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \
192 case ARRAY_ID_##TYPE: \
193 *array_type = kExternal##Type##Array; \
194 *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \
195 *fixed_elements_kind = TYPE##_ELEMENTS; \
196 *element_size = size; \
197 break;
198
199 TYPED_ARRAYS(ARRAY_ID_CASE)
200 #undef ARRAY_ID_CASE
201
202 default:
203 UNREACHABLE();
204 }
205 }
206
207
208 RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
209 HandleScope scope(isolate);
210 DCHECK(args.length() == 5);
211 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
212 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
213 CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
214 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3);
215 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4);
216
217 RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
218 arrayId <= Runtime::ARRAY_ID_LAST);
219
220 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
221 size_t element_size = 1; // Bogus initialization.
222 ElementsKind external_elements_kind =
223 EXTERNAL_INT8_ELEMENTS; // Bogus initialization.
224 ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
225 Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
226 &fixed_elements_kind, &element_size);
227 RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
228
229 size_t byte_offset = 0;
230 size_t byte_length = 0;
231 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset));
232 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length));
233
234 if (maybe_buffer->IsJSArrayBuffer()) {
235 Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
236 size_t array_buffer_byte_length =
237 NumberToSize(isolate, buffer->byte_length());
238 RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
239 RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
240 } else {
241 RUNTIME_ASSERT(maybe_buffer->IsNull());
242 }
243
244 RUNTIME_ASSERT(byte_length % element_size == 0);
245 size_t length = byte_length / element_size;
246
247 if (length > static_cast<unsigned>(Smi::kMaxValue)) {
248 THROW_NEW_ERROR_RETURN_FAILURE(
249 isolate, NewRangeError("invalid_typed_array_length",
250 HandleVector<Object>(NULL, 0)));
251 }
252
253 // All checks are done, now we can modify objects.
254
255 DCHECK(holder->GetInternalFieldCount() ==
256 v8::ArrayBufferView::kInternalFieldCount);
257 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
258 holder->SetInternalField(i, Smi::FromInt(0));
259 }
260 Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
261 holder->set_length(*length_obj);
262 holder->set_byte_offset(*byte_offset_object);
263 holder->set_byte_length(*byte_length_object);
264
265 if (!maybe_buffer->IsNull()) {
266 Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
267 holder->set_buffer(*buffer);
268 holder->set_weak_next(buffer->weak_first_view());
269 buffer->set_weak_first_view(*holder);
270
271 Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
272 static_cast<int>(length), array_type,
273 static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
274 Handle<Map> map =
275 JSObject::GetElementsTransitionMap(holder, external_elements_kind);
276 JSObject::SetMapAndElements(holder, map, elements);
277 DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind()));
278 } else {
279 holder->set_buffer(Smi::FromInt(0));
280 holder->set_weak_next(isolate->heap()->undefined_value());
281 Handle<FixedTypedArrayBase> elements =
282 isolate->factory()->NewFixedTypedArray(static_cast<int>(length),
283 array_type);
284 holder->set_elements(*elements);
285 }
286 return isolate->heap()->undefined_value();
287 }
288
289
290 // Initializes a typed array from an array-like object.
291 // If an array-like object happens to be a typed array of the same type,
292 // initializes backing store using memove.
293 //
294 // Returns true if backing store was initialized or false otherwise.
295 RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
296 HandleScope scope(isolate);
297 DCHECK(args.length() == 4);
298 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
299 CONVERT_SMI_ARG_CHECKED(arrayId, 1);
300 CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
301 CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
302
303 RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
304 arrayId <= Runtime::ARRAY_ID_LAST);
305
306 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
307 size_t element_size = 1; // Bogus initialization.
308 ElementsKind external_elements_kind =
309 EXTERNAL_INT8_ELEMENTS; // Bogus intialization.
310 ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
311 Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
312 &fixed_elements_kind, &element_size);
313
314 RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
315
316 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
317 if (source->IsJSTypedArray() &&
318 JSTypedArray::cast(*source)->type() == array_type) {
319 length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
320 }
321 size_t length = 0;
322 RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length));
323
324 if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
325 (length > (kMaxInt / element_size))) {
326 THROW_NEW_ERROR_RETURN_FAILURE(
327 isolate, NewRangeError("invalid_typed_array_length",
328 HandleVector<Object>(NULL, 0)));
329 }
330 size_t byte_length = length * element_size;
331
332 DCHECK(holder->GetInternalFieldCount() ==
333 v8::ArrayBufferView::kInternalFieldCount);
334 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
335 holder->SetInternalField(i, Smi::FromInt(0));
336 }
337
338 // NOTE: not initializing backing store.
339 // We assume that the caller of this function will initialize holder
340 // with the loop
341 // for(i = 0; i < length; i++) { holder[i] = source[i]; }
342 // We assume that the caller of this function is always a typed array
343 // constructor.
344 // If source is a typed array, this loop will always run to completion,
345 // so we are sure that the backing store will be initialized.
346 // Otherwise, the indexing operation might throw, so the loop will not
347 // run to completion and the typed array might remain partly initialized.
348 // However we further assume that the caller of this function is a typed array
349 // constructor, and the exception will propagate out of the constructor,
350 // therefore uninitialized memory will not be accessible by a user program.
351 //
352 // TODO(dslomov): revise this once we support subclassing.
353
354 if (!Runtime::SetupArrayBufferAllocatingData(isolate, buffer, byte_length,
355 false)) {
356 THROW_NEW_ERROR_RETURN_FAILURE(
357 isolate, NewRangeError("invalid_array_buffer_length",
358 HandleVector<Object>(NULL, 0)));
359 }
360
361 holder->set_buffer(*buffer);
362 holder->set_byte_offset(Smi::FromInt(0));
363 Handle<Object> byte_length_obj(
364 isolate->factory()->NewNumberFromSize(byte_length));
365 holder->set_byte_length(*byte_length_obj);
366 holder->set_length(*length_obj);
367 holder->set_weak_next(buffer->weak_first_view());
368 buffer->set_weak_first_view(*holder);
369
370 Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
371 static_cast<int>(length), array_type,
372 static_cast<uint8_t*>(buffer->backing_store()));
373 Handle<Map> map =
374 JSObject::GetElementsTransitionMap(holder, external_elements_kind);
375 JSObject::SetMapAndElements(holder, map, elements);
376
377 if (source->IsJSTypedArray()) {
378 Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
379
380 if (typed_array->type() == holder->type()) {
381 uint8_t* backing_store =
382 static_cast<uint8_t*>(typed_array->GetBuffer()->backing_store());
383 size_t source_byte_offset =
384 NumberToSize(isolate, typed_array->byte_offset());
385 memcpy(buffer->backing_store(), backing_store + source_byte_offset,
386 byte_length);
387 return isolate->heap()->true_value();
388 }
389 }
390
391 return isolate->heap()->false_value();
392 }
393
394
395 #define BUFFER_VIEW_GETTER(Type, getter, accessor) \
396 RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \
397 HandleScope scope(isolate); \
398 DCHECK(args.length() == 1); \
399 CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \
400 return holder->accessor(); \
401 }
402
403 BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
404 BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
405 BUFFER_VIEW_GETTER(TypedArray, Length, length)
406 BUFFER_VIEW_GETTER(DataView, Buffer, buffer)
407
408 #undef BUFFER_VIEW_GETTER
409
410 RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
411 HandleScope scope(isolate);
412 DCHECK(args.length() == 1);
413 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
414 return *holder->GetBuffer();
415 }
416
417
418 // Return codes for Runtime_TypedArraySetFastCases.
419 // Should be synchronized with typedarray.js natives.
420 enum TypedArraySetResultCodes {
421 // Set from typed array of the same type.
422 // This is processed by TypedArraySetFastCases
423 TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
424 // Set from typed array of the different type, overlapping in memory.
425 TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
426 // Set from typed array of the different type, non-overlapping.
427 TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
428 // Set from non-typed array.
429 TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
430 };
431
432
433 RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
434 HandleScope scope(isolate);
435 DCHECK(args.length() == 3);
436 if (!args[0]->IsJSTypedArray()) {
437 THROW_NEW_ERROR_RETURN_FAILURE(
438 isolate,
439 NewTypeError("not_typed_array", HandleVector<Object>(NULL, 0)));
440 }
441
442 if (!args[1]->IsJSTypedArray())
443 return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
444
445 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0);
446 CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1);
447 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
448
449 Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
450 Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
451 size_t offset = 0;
452 RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset));
453 size_t target_length = NumberToSize(isolate, target->length());
454 size_t source_length = NumberToSize(isolate, source->length());
455 size_t target_byte_length = NumberToSize(isolate, target->byte_length());
456 size_t source_byte_length = NumberToSize(isolate, source->byte_length());
457 if (offset > target_length || offset + source_length > target_length ||
458 offset + source_length < offset) { // overflow
459 THROW_NEW_ERROR_RETURN_FAILURE(
460 isolate, NewRangeError("typed_array_set_source_too_large",
461 HandleVector<Object>(NULL, 0)));
462 }
463
464 size_t target_offset = NumberToSize(isolate, target->byte_offset());
465 size_t source_offset = NumberToSize(isolate, source->byte_offset());
466 uint8_t* target_base =
467 static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
468 target_offset;
469 uint8_t* source_base =
470 static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
471 source_offset;
472
473 // Typed arrays of the same type: use memmove.
474 if (target->type() == source->type()) {
475 memmove(target_base + offset * target->element_size(), source_base,
476 source_byte_length);
477 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
478 }
479
480 // Typed arrays of different types over the same backing store
481 if ((source_base <= target_base &&
482 source_base + source_byte_length > target_base) ||
483 (target_base <= source_base &&
484 target_base + target_byte_length > source_base)) {
485 // We do not support overlapping ArrayBuffers
486 DCHECK(target->GetBuffer()->backing_store() ==
487 source->GetBuffer()->backing_store());
488 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
489 } else { // Non-overlapping typed arrays
490 return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
491 }
492 }
493
494
495 RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
496 DCHECK(args.length() == 0);
497 DCHECK_OBJECT_SIZE(FLAG_typed_array_max_size_in_heap +
498 FixedTypedArrayBase::kDataOffset);
499 return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
500 }
501
502
503 RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
504 HandleScope scope(isolate);
505 DCHECK(args.length() == 4);
506 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
507 CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
508 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2);
509 CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3);
510
511 DCHECK(holder->GetInternalFieldCount() ==
512 v8::ArrayBufferView::kInternalFieldCount);
513 for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
514 holder->SetInternalField(i, Smi::FromInt(0));
515 }
516 size_t buffer_length = 0;
517 size_t offset = 0;
518 size_t length = 0;
519 RUNTIME_ASSERT(
520 TryNumberToSize(isolate, buffer->byte_length(), &buffer_length));
521 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset));
522 RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length));
523
524 // TODO(jkummerow): When we have a "safe numerics" helper class, use it here.
525 // Entire range [offset, offset + length] must be in bounds.
526 RUNTIME_ASSERT(offset <= buffer_length);
527 RUNTIME_ASSERT(offset + length <= buffer_length);
528 // No overflow.
529 RUNTIME_ASSERT(offset + length >= offset);
530
531 holder->set_buffer(*buffer);
532 holder->set_byte_offset(*byte_offset);
533 holder->set_byte_length(*byte_length);
534
535 holder->set_weak_next(buffer->weak_first_view());
536 buffer->set_weak_first_view(*holder);
537
538 return isolate->heap()->undefined_value();
539 }
540
541
542 inline static bool NeedToFlipBytes(bool is_little_endian) {
543 #ifdef V8_TARGET_LITTLE_ENDIAN
544 return !is_little_endian;
545 #else
546 return is_little_endian;
547 #endif
548 }
549
550
551 template <int n>
552 inline void CopyBytes(uint8_t* target, uint8_t* source) {
553 for (int i = 0; i < n; i++) {
554 *(target++) = *(source++);
555 }
556 }
557
558
559 template <int n>
560 inline void FlipBytes(uint8_t* target, uint8_t* source) {
561 source = source + (n - 1);
562 for (int i = 0; i < n; i++) {
563 *(target++) = *(source--);
564 }
565 }
566
567
568 template <typename T>
569 inline static bool DataViewGetValue(Isolate* isolate,
570 Handle<JSDataView> data_view,
571 Handle<Object> byte_offset_obj,
572 bool is_little_endian, T* result) {
573 size_t byte_offset = 0;
574 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
575 return false;
576 }
577 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
578
579 size_t data_view_byte_offset =
580 NumberToSize(isolate, data_view->byte_offset());
581 size_t data_view_byte_length =
582 NumberToSize(isolate, data_view->byte_length());
583 if (byte_offset + sizeof(T) > data_view_byte_length ||
584 byte_offset + sizeof(T) < byte_offset) { // overflow
585 return false;
586 }
587
588 union Value {
589 T data;
590 uint8_t bytes[sizeof(T)];
591 };
592
593 Value value;
594 size_t buffer_offset = data_view_byte_offset + byte_offset;
595 DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
596 buffer_offset + sizeof(T));
597 uint8_t* source =
598 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
599 if (NeedToFlipBytes(is_little_endian)) {
600 FlipBytes<sizeof(T)>(value.bytes, source);
601 } else {
602 CopyBytes<sizeof(T)>(value.bytes, source);
603 }
604 *result = value.data;
605 return true;
606 }
607
608
609 template <typename T>
610 static bool DataViewSetValue(Isolate* isolate, Handle<JSDataView> data_view,
611 Handle<Object> byte_offset_obj,
612 bool is_little_endian, T data) {
613 size_t byte_offset = 0;
614 if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
615 return false;
616 }
617 Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
618
619 size_t data_view_byte_offset =
620 NumberToSize(isolate, data_view->byte_offset());
621 size_t data_view_byte_length =
622 NumberToSize(isolate, data_view->byte_length());
623 if (byte_offset + sizeof(T) > data_view_byte_length ||
624 byte_offset + sizeof(T) < byte_offset) { // overflow
625 return false;
626 }
627
628 union Value {
629 T data;
630 uint8_t bytes[sizeof(T)];
631 };
632
633 Value value;
634 value.data = data;
635 size_t buffer_offset = data_view_byte_offset + byte_offset;
636 DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
637 buffer_offset + sizeof(T));
638 uint8_t* target =
639 static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
640 if (NeedToFlipBytes(is_little_endian)) {
641 FlipBytes<sizeof(T)>(target, value.bytes);
642 } else {
643 CopyBytes<sizeof(T)>(target, value.bytes);
644 }
645 return true;
646 }
647
648
649 #define DATA_VIEW_GETTER(TypeName, Type, Converter) \
650 RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) { \
651 HandleScope scope(isolate); \
652 DCHECK(args.length() == 3); \
653 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
654 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \
655 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \
656 Type result; \
657 if (DataViewGetValue(isolate, holder, offset, is_little_endian, \
658 &result)) { \
659 return *isolate->factory()->Converter(result); \
660 } else { \
661 THROW_NEW_ERROR_RETURN_FAILURE( \
662 isolate, NewRangeError("invalid_data_view_accessor_offset", \
663 HandleVector<Object>(NULL, 0))); \
664 } \
665 }
666
667 DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint)
668 DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt)
669 DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint)
670 DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt)
671 DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint)
672 DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt)
673 DATA_VIEW_GETTER(Float32, float, NewNumber)
674 DATA_VIEW_GETTER(Float64, double, NewNumber)
675
676 #undef DATA_VIEW_GETTER
677
678
679 template <typename T>
680 static T DataViewConvertValue(double value);
681
682
683 template <>
684 int8_t DataViewConvertValue<int8_t>(double value) {
685 return static_cast<int8_t>(DoubleToInt32(value));
686 }
687
688
689 template <>
690 int16_t DataViewConvertValue<int16_t>(double value) {
691 return static_cast<int16_t>(DoubleToInt32(value));
692 }
693
694
695 template <>
696 int32_t DataViewConvertValue<int32_t>(double value) {
697 return DoubleToInt32(value);
698 }
699
700
701 template <>
702 uint8_t DataViewConvertValue<uint8_t>(double value) {
703 return static_cast<uint8_t>(DoubleToUint32(value));
704 }
705
706
707 template <>
708 uint16_t DataViewConvertValue<uint16_t>(double value) {
709 return static_cast<uint16_t>(DoubleToUint32(value));
710 }
711
712
713 template <>
714 uint32_t DataViewConvertValue<uint32_t>(double value) {
715 return DoubleToUint32(value);
716 }
717
718
719 template <>
720 float DataViewConvertValue<float>(double value) {
721 return static_cast<float>(value);
722 }
723
724
725 template <>
726 double DataViewConvertValue<double>(double value) {
727 return value;
728 }
729
730
731 #define DATA_VIEW_SETTER(TypeName, Type) \
732 RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) { \
733 HandleScope scope(isolate); \
734 DCHECK(args.length() == 4); \
735 CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
736 CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \
737 CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); \
738 CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \
739 Type v = DataViewConvertValue<Type>(value->Number()); \
740 if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) { \
741 return isolate->heap()->undefined_value(); \
742 } else { \
743 THROW_NEW_ERROR_RETURN_FAILURE( \
744 isolate, NewRangeError("invalid_data_view_accessor_offset", \
745 HandleVector<Object>(NULL, 0))); \
746 } \
747 }
748
749 DATA_VIEW_SETTER(Uint8, uint8_t)
750 DATA_VIEW_SETTER(Int8, int8_t)
751 DATA_VIEW_SETTER(Uint16, uint16_t)
752 DATA_VIEW_SETTER(Int16, int16_t)
753 DATA_VIEW_SETTER(Uint32, uint32_t)
754 DATA_VIEW_SETTER(Int32, int32_t)
755 DATA_VIEW_SETTER(Float32, float)
756 DATA_VIEW_SETTER(Float64, double)
757
758 #undef DATA_VIEW_SETTER
759 }
760 } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/runtime/runtime-test.cc ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698