OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
310 #endif // V8_SHARED | 310 #endif // V8_SHARED |
311 if (raw_value > static_cast<int32_t>(kMaxLength)) { | 311 if (raw_value > static_cast<int32_t>(kMaxLength)) { |
312 ThrowException( | 312 ThrowException( |
313 String::New("Array length exceeds maximum length.")); | 313 String::New("Array length exceeds maximum length.")); |
314 } | 314 } |
315 return static_cast<size_t>(raw_value); | 315 return static_cast<size_t>(raw_value); |
316 } | 316 } |
317 | 317 |
318 | 318 |
319 const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; | 319 const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; |
320 const char kArrayBufferReferencePropName[] = "d8::_array_buffer_ref_"; | |
321 | 320 |
322 static const int kExternalArrayAllocationHeaderSize = 2; | 321 |
322 Handle<Value> Shell::CreateExternalArrayBuffer(int32_t length) { | |
323 static const int32_t kMaxSize = 0x7fffffff; | |
324 // Make sure the total size fits into a (signed) int. | |
325 if (length < 0 || length > kMaxSize) { | |
326 return ThrowException(String::New("ArrayBuffer exceeds maximum size (2G)")); | |
327 } | |
328 uint8_t* data = new uint8_t[length]; | |
329 if (data == NULL) { | |
330 return ThrowException(String::New("Memory allocation failed.")); | |
331 } | |
332 memset(data, 0, length); | |
333 | |
334 Handle<Object> buffer = Object::New(); | |
335 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); | |
336 Persistent<Object> persistent_array = Persistent<Object>::New(buffer); | |
337 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); | |
338 persistent_array.MarkIndependent(); | |
339 V8::AdjustAmountOfExternalAllocatedMemory(length); | |
340 | |
341 buffer->SetIndexedPropertiesToExternalArrayData( | |
342 data, v8::kExternalByteArray, length); | |
343 buffer->Set(String::New("byteLength"), Int32::New(length), ReadOnly); | |
344 | |
345 return buffer; | |
346 } | |
347 | |
348 | |
349 Handle<Value> Shell::CreateExternalArrayBuffer(const Arguments& args) { | |
350 if (args.Length() == 0) { | |
351 return ThrowException( | |
352 String::New("ArrayBuffer constructor must have one parameter.")); | |
353 } | |
354 TryCatch try_catch; | |
355 int32_t length = convertToUint(args[0], &try_catch); | |
356 if (try_catch.HasCaught()) return try_catch.Exception(); | |
357 | |
358 return CreateExternalArrayBuffer(length); | |
359 } | |
360 | |
323 | 361 |
324 Handle<Value> Shell::CreateExternalArray(const Arguments& args, | 362 Handle<Value> Shell::CreateExternalArray(const Arguments& args, |
325 ExternalArrayType type, | 363 ExternalArrayType type, |
326 size_t element_size) { | 364 int32_t element_size) { |
327 TryCatch try_catch; | 365 TryCatch try_catch; |
328 bool is_array_buffer_construct = element_size == 0; | 366 ASSERT(element_size == 1 || element_size == 2 || |
329 if (is_array_buffer_construct) { | 367 element_size == 4 || element_size == 8); |
330 type = v8::kExternalByteArray; | 368 |
331 element_size = 1; | 369 // Currently, only the following constructors are supported: |
332 } | 370 // TypedArray(unsigned long length) |
333 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || | 371 // TypedArray(ArrayBuffer buffer, |
334 element_size == 8); | 372 // optional unsigned long byteOffset, |
373 // optional unsigned long length) | |
374 Handle<Object> buffer; | |
375 int32_t length; | |
376 int32_t byteLength; | |
377 int32_t byteOffset; | |
335 if (args.Length() == 0) { | 378 if (args.Length() == 0) { |
336 return ThrowException( | 379 return ThrowException( |
337 String::New("Array constructor must have at least one parameter.")); | 380 String::New("Array constructor must have at least one parameter.")); |
338 } | 381 } |
339 bool first_arg_is_array_buffer = | 382 if (args[0]->IsObject() && |
340 args[0]->IsObject() && | 383 !args[0]->ToObject()->GetHiddenValue( |
341 !args[0]->ToObject()->GetHiddenValue( | 384 String::New(kArrayBufferMarkerPropName)).IsEmpty()) { |
342 String::New(kArrayBufferMarkerPropName)).IsEmpty(); | 385 buffer = args[0]->ToObject(); |
343 // Currently, only the following constructors are supported: | 386 int32_t bufferLength = |
344 // ArrayBuffer(unsigned long length) | |
345 // TypedArray(unsigned long length) | |
346 // TypedArray(ArrayBuffer buffer, | |
347 // optional unsigned long byteOffset, | |
348 // optional unsigned long length) | |
349 size_t length; | |
350 size_t byteLength; | |
351 size_t byteOffset; | |
352 void* data = NULL; | |
353 Handle<Object> array = Object::New(); | |
354 if (is_array_buffer_construct) { | |
355 byteLength = convertToUint(args[0], &try_catch); | |
356 if (try_catch.HasCaught()) return try_catch.Exception(); | |
357 byteOffset = 0; | |
358 length = byteLength; | |
359 | |
360 array->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); | |
361 } else if (first_arg_is_array_buffer) { | |
362 Handle<Object> buffer = args[0]->ToObject(); | |
363 data = buffer->GetIndexedPropertiesExternalArrayData(); | |
364 byteLength = | |
365 convertToUint(buffer->Get(String::New("byteLength")), &try_catch); | 387 convertToUint(buffer->Get(String::New("byteLength")), &try_catch); |
366 if (try_catch.HasCaught()) return try_catch.Exception(); | 388 if (try_catch.HasCaught()) return try_catch.Exception(); |
367 if (data == NULL && byteLength != 0) { | |
368 return ThrowException(String::New("ArrayBuffer does not have data")); | |
369 } | |
370 | 389 |
371 if (args.Length() < 2 || args[1]->IsUndefined()) { | 390 if (args.Length() < 2 || args[1]->IsUndefined()) { |
372 byteOffset = 0; | 391 byteOffset = 0; |
373 } else { | 392 } else { |
374 byteOffset = convertToUint(args[1], &try_catch); | 393 byteOffset = convertToUint(args[1], &try_catch); |
375 if (try_catch.HasCaught()) return try_catch.Exception(); | 394 if (try_catch.HasCaught()) return try_catch.Exception(); |
376 if (byteOffset > byteLength) { | 395 if (byteOffset > bufferLength) { |
377 return ThrowException(String::New("byteOffset out of bounds")); | 396 return ThrowException(String::New("byteOffset out of bounds")); |
378 } | 397 } |
379 if (byteOffset % element_size != 0) { | 398 if (byteOffset % element_size != 0) { |
380 return ThrowException( | 399 return ThrowException( |
381 String::New("byteOffset must be multiple of element_size")); | 400 String::New("byteOffset must be multiple of element_size")); |
382 } | 401 } |
383 } | 402 } |
384 | 403 |
385 if (args.Length() < 3 || args[2]->IsUndefined()) { | 404 if (args.Length() < 3 || args[2]->IsUndefined()) { |
405 byteLength = bufferLength - byteOffset; | |
406 length = byteLength / element_size; | |
386 if (byteLength % element_size != 0) { | 407 if (byteLength % element_size != 0) { |
387 return ThrowException( | 408 return ThrowException( |
388 String::New("buffer size must be multiple of element_size")); | 409 String::New("buffer size must be multiple of element_size")); |
389 } | 410 } |
390 length = (byteLength - byteOffset) / element_size; | |
391 } else { | 411 } else { |
392 length = convertToUint(args[2], &try_catch); | 412 length = convertToUint(args[2], &try_catch); |
393 if (try_catch.HasCaught()) return try_catch.Exception(); | 413 if (try_catch.HasCaught()) return try_catch.Exception(); |
414 byteLength = length * element_size; | |
415 if (byteOffset + byteLength > bufferLength) { | |
416 return ThrowException(String::New("length out of bounds")); | |
417 } | |
394 } | 418 } |
395 | |
396 if (byteOffset + length * element_size > byteLength) { | |
397 return ThrowException(String::New("length out of bounds")); | |
398 } | |
399 byteLength = byteOffset + length * element_size; | |
400 | |
401 // Hold a reference to the ArrayBuffer so its buffer doesn't get collected. | |
402 array->SetHiddenValue( | |
403 String::New(kArrayBufferReferencePropName), args[0]); | |
404 } else { | 419 } else { |
405 length = convertToUint(args[0], &try_catch); | 420 length = convertToUint(args[0], &try_catch); |
406 byteLength = length * element_size; | 421 byteLength = length * element_size; |
407 byteOffset = 0; | 422 byteOffset = 0; |
423 Handle<Value> result = CreateExternalArrayBuffer(byteLength); | |
424 if (!result->IsObject()) return result; | |
425 buffer = result->ToObject(); | |
408 } | 426 } |
409 | 427 |
410 Persistent<Object> persistent_array = Persistent<Object>::New(array); | 428 void* data = buffer->GetIndexedPropertiesExternalArrayData(); |
411 if (data == NULL && byteLength != 0) { | 429 ASSERT(data != NULL); |
412 ASSERT(byteOffset == 0); | |
413 // Prepend the size of the allocated chunk to the data itself. | |
414 int total_size = | |
415 byteLength + kExternalArrayAllocationHeaderSize * sizeof(size_t); | |
416 static const int kMaxSize = 0x7fffffff; | |
417 // Make sure the total size fits into a (signed) int. | |
418 if (total_size > kMaxSize) { | |
419 return ThrowException(String::New("Array exceeds maximum size (2G)")); | |
420 } | |
421 data = malloc(total_size); | |
422 if (data == NULL) { | |
423 return ThrowException(String::New("Memory allocation failed.")); | |
424 } | |
425 *reinterpret_cast<size_t*>(data) = total_size; | |
426 data = reinterpret_cast<size_t*>(data) + kExternalArrayAllocationHeaderSize; | |
427 memset(data, 0, byteLength); | |
428 V8::AdjustAmountOfExternalAllocatedMemory(total_size); | |
429 } | |
430 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); | |
431 persistent_array.MarkIndependent(); | |
432 | 430 |
431 Handle<Object> array = Object::New(); | |
433 array->SetIndexedPropertiesToExternalArrayData( | 432 array->SetIndexedPropertiesToExternalArrayData( |
434 reinterpret_cast<uint8_t*>(data) + byteOffset, type, | 433 static_cast<uint8_t*>(data) + byteOffset, type, length); |
435 static_cast<int>(length)); | 434 array->Set(String::New("byteLength"), Int32::New(byteLength), ReadOnly); |
436 array->Set(String::New("byteLength"), | 435 array->Set(String::New("byteOffset"), Int32::New(byteOffset), ReadOnly); |
437 Int32::New(static_cast<int32_t>(byteLength)), ReadOnly); | 436 array->Set(String::New("length"), Int32::New(length), ReadOnly); |
438 if (!is_array_buffer_construct) { | 437 array->Set(String::New("BYTES_PER_ELEMENT"), Int32::New(element_size)); |
439 array->Set(String::New("byteOffset"), | 438 array->Set(String::New("buffer"), buffer, ReadOnly); |
440 Int32::New(static_cast<int32_t>(byteOffset)), ReadOnly); | 439 |
441 array->Set(String::New("length"), | |
442 Int32::New(static_cast<int32_t>(length)), ReadOnly); | |
443 array->Set(String::New("BYTES_PER_ELEMENT"), | |
444 Int32::New(static_cast<int32_t>(element_size))); | |
445 // We currently support 'buffer' property only if constructed from a buffer. | |
446 if (first_arg_is_array_buffer) { | |
447 array->Set(String::New("buffer"), args[0], ReadOnly); | |
448 } | |
449 } | |
450 return array; | 440 return array; |
451 } | 441 } |
452 | 442 |
453 | 443 |
454 void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { | 444 void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { |
455 HandleScope scope; | 445 HandleScope scope; |
456 Handle<String> prop_name = String::New(kArrayBufferReferencePropName); | 446 Local<Value> length = object->ToObject()->Get(String::New("byteLength")); |
457 Handle<Object> converted_object = object->ToObject(); | 447 V8::AdjustAmountOfExternalAllocatedMemory(-length->Uint32Value()); |
458 Local<Value> prop_value = converted_object->GetHiddenValue(prop_name); | 448 delete[] static_cast<uint8_t*>(data); |
459 if (data != NULL && prop_value.IsEmpty()) { | |
460 data = reinterpret_cast<size_t*>(data) - kExternalArrayAllocationHeaderSize; | |
461 V8::AdjustAmountOfExternalAllocatedMemory( | |
462 -static_cast<int>(*reinterpret_cast<size_t*>(data))); | |
463 free(data); | |
464 } | |
465 object.Dispose(); | 449 object.Dispose(); |
466 } | 450 } |
467 | 451 |
468 | 452 |
469 Handle<Value> Shell::ArrayBuffer(const Arguments& args) { | 453 Handle<Value> Shell::ArrayBuffer(const Arguments& args) { |
470 return CreateExternalArray(args, v8::kExternalByteArray, 0); | 454 return CreateExternalArrayBuffer(args); |
471 } | 455 } |
472 | 456 |
473 | 457 |
474 Handle<Value> Shell::Int8Array(const Arguments& args) { | 458 Handle<Value> Shell::Int8Array(const Arguments& args) { |
475 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t)); | 459 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t)); |
476 } | 460 } |
477 | 461 |
478 | 462 |
479 Handle<Value> Shell::Uint8Array(const Arguments& args) { | 463 Handle<Value> Shell::Uint8Array(const Arguments& args) { |
480 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t)); | 464 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t)); |
(...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1028 int read = static_cast<int>(fread(&chars[i], 1, size - i, file)); | 1012 int read = static_cast<int>(fread(&chars[i], 1, size - i, file)); |
1029 i += read; | 1013 i += read; |
1030 } | 1014 } |
1031 fclose(file); | 1015 fclose(file); |
1032 *size_out = size; | 1016 *size_out = size; |
1033 return chars; | 1017 return chars; |
1034 } | 1018 } |
1035 | 1019 |
1036 | 1020 |
1037 Handle<Value> Shell::ReadBuffer(const Arguments& args) { | 1021 Handle<Value> Shell::ReadBuffer(const Arguments& args) { |
1022 STATIC_ASSERT(sizeof(char) == sizeof(uint8_t)); // NOLINT | |
1038 String::Utf8Value filename(args[0]); | 1023 String::Utf8Value filename(args[0]); |
1039 int length; | 1024 int length; |
1040 if (*filename == NULL) { | 1025 if (*filename == NULL) { |
1041 return ThrowException(String::New("Error loading file")); | 1026 return ThrowException(String::New("Error loading file")); |
1042 } | 1027 } |
1043 char* data = ReadChars(*filename, &length); | 1028 |
1029 void* data = ReadChars(*filename, &length); | |
Michael Starzinger
2012/06/01 09:43:28
Why this change? I would prefer it to stay "char*"
rossberg
2012/06/01 11:42:35
Actually, changed it to uint8_t, which is more ade
| |
1044 if (data == NULL) { | 1030 if (data == NULL) { |
1045 return ThrowException(String::New("Error reading file")); | 1031 return ThrowException(String::New("Error reading file")); |
1046 } | 1032 } |
1047 | |
1048 Handle<Object> buffer = Object::New(); | 1033 Handle<Object> buffer = Object::New(); |
1049 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); | 1034 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); |
1050 | |
1051 Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer); | 1035 Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer); |
1052 persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback); | 1036 persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback); |
1053 persistent_buffer.MarkIndependent(); | 1037 persistent_buffer.MarkIndependent(); |
Michael Starzinger
2012/06/01 09:43:28
I think we are missing a positive adjustment of th
rossberg
2012/06/01 11:42:35
Done.
| |
1054 | 1038 |
1055 buffer->SetIndexedPropertiesToExternalArrayData( | 1039 buffer->SetIndexedPropertiesToExternalArrayData( |
1056 reinterpret_cast<uint8_t*>(data), kExternalUnsignedByteArray, length); | 1040 reinterpret_cast<uint8_t*>(data), kExternalUnsignedByteArray, length); |
1057 buffer->Set(String::New("byteLength"), | 1041 buffer->Set(String::New("byteLength"), |
1058 Int32::New(static_cast<int32_t>(length)), ReadOnly); | 1042 Int32::New(static_cast<int32_t>(length)), ReadOnly); |
1059 return buffer; | 1043 return buffer; |
1060 } | 1044 } |
1061 | 1045 |
1062 | 1046 |
1063 #ifndef V8_SHARED | 1047 #ifndef V8_SHARED |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1213 if (!Shell::ExecuteString(source, file_name, false, true)) { | 1197 if (!Shell::ExecuteString(source, file_name, false, true)) { |
1214 Shell::Exit(1); | 1198 Shell::Exit(1); |
1215 } | 1199 } |
1216 } | 1200 } |
1217 } | 1201 } |
1218 } | 1202 } |
1219 | 1203 |
1220 | 1204 |
1221 Handle<String> SourceGroup::ReadFile(const char* name) { | 1205 Handle<String> SourceGroup::ReadFile(const char* name) { |
1222 int size; | 1206 int size; |
1223 const char* chars = ReadChars(name, &size); | 1207 char* chars = ReadChars(name, &size); |
1224 if (chars == NULL) return Handle<String>(); | 1208 if (chars == NULL) return Handle<String>(); |
1225 Handle<String> result = String::New(chars, size); | 1209 Handle<String> result = String::New(chars, size); |
1226 delete[] chars; | 1210 delete[] chars; |
1227 return result; | 1211 return result; |
1228 } | 1212 } |
1229 | 1213 |
1230 | 1214 |
1231 #ifndef V8_SHARED | 1215 #ifndef V8_SHARED |
1232 i::Thread::Options SourceGroup::GetThreadOptions() { | 1216 i::Thread::Options SourceGroup::GetThreadOptions() { |
1233 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less | 1217 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less |
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1556 } | 1540 } |
1557 | 1541 |
1558 } // namespace v8 | 1542 } // namespace v8 |
1559 | 1543 |
1560 | 1544 |
1561 #ifndef GOOGLE3 | 1545 #ifndef GOOGLE3 |
1562 int main(int argc, char* argv[]) { | 1546 int main(int argc, char* argv[]) { |
1563 return v8::Shell::Main(argc, argv); | 1547 return v8::Shell::Main(argc, argv); |
1564 } | 1548 } |
1565 #endif | 1549 #endif |
OLD | NEW |