summaryrefslogtreecommitdiff
path: root/src/v8_typed_array.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/v8_typed_array.cc')
-rw-r--r--src/v8_typed_array.cc874
1 files changed, 0 insertions, 874 deletions
diff --git a/src/v8_typed_array.cc b/src/v8_typed_array.cc
deleted file mode 100644
index 4040110578..0000000000
--- a/src/v8_typed_array.cc
+++ /dev/null
@@ -1,874 +0,0 @@
-// V8 Typed Array implementation.
-// (c) Dean McNamee <dean@gmail.com>, 2011.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to
-// deal in the Software without restriction, including without limitation the
-// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-// sell copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-// IN THE SOFTWARE.
-
-#include <stdlib.h> // calloc, etc
-#include <string.h> // memmove
-#include <stdint.h>
-
-#include "v8_typed_array.h"
-#include "v8_typed_array_bswap.h"
-#include "node_buffer.h"
-#include "node.h"
-#include "v8.h"
-
-namespace {
-
-using node::ThrowError;
-using node::ThrowRangeError;
-using node::ThrowTypeError;
-
-struct BatchedMethods {
- const char* name;
- v8::Handle<v8::Value> (*func)(const v8::Arguments& args);
-};
-
-class ArrayBuffer {
- public:
- static v8::Persistent<v8::FunctionTemplate> GetTemplate() {
- static v8::Persistent<v8::FunctionTemplate> ft_cache;
- if (!ft_cache.IsEmpty())
- return ft_cache;
-
- v8::HandleScope scope(node::node_isolate);
- ft_cache = v8::Persistent<v8::FunctionTemplate>::New(node::node_isolate,
- v8::FunctionTemplate::New(&ArrayBuffer::V8New));
- ft_cache->SetClassName(v8::String::New("ArrayBuffer"));
- v8::Local<v8::ObjectTemplate> instance = ft_cache->InstanceTemplate();
- instance->SetInternalFieldCount(1); // Buffer.
-
- v8::Local<v8::Signature> default_signature = v8::Signature::New(ft_cache);
-
- instance->Set(v8::String::New("slice"),
- v8::FunctionTemplate::New(&ArrayBuffer::slice,
- v8::Handle<v8::Value>(),
- default_signature));
-
- return ft_cache;
- }
-
- static bool HasInstance(v8::Handle<v8::Value> value) {
- return GetTemplate()->HasInstance(value);
- }
-
- private:
- static void WeakCallback(v8::Isolate* isolate,
- v8::Persistent<v8::Object>* pobj,
- void* data) {
- v8::HandleScope handle_scope(isolate);
- v8::Local<v8::Object> obj = v8::Local<v8::Object>::New(*pobj);
-
- void* ptr = obj->GetIndexedPropertiesExternalArrayData();
- int element_size = v8_typed_array::SizeOfArrayElementForType(
- obj->GetIndexedPropertiesExternalArrayDataType());
- int size =
- obj->GetIndexedPropertiesExternalArrayDataLength() * element_size;
-
- node::node_isolate->AdjustAmountOfExternalAllocatedMemory(-size);
-
- (*pobj).ClearWeak(isolate);
- (*pobj).Dispose(isolate);
-
- free(ptr);
- }
-
- static v8::Handle<v8::Value> V8New(const v8::Arguments& args) {
- if (!args.IsConstructCall())
- return node::FromConstructorTemplate(GetTemplate(), args);
-
- // To match Chrome, we allow "new ArrayBuffer()".
- // if (args.Length() != 1)
- // return ThrowError("Wrong number of arguments.");
-
- if (args[0]->Int32Value() < 0) {
- return ThrowRangeError("ArrayBufferView size is not a small enough "
- "positive integer.");
- }
-
- size_t num_bytes = args[0]->Uint32Value();
- if (num_bytes > node::Buffer::kMaxLength) {
- return ThrowRangeError("length > kMaxLength");
- }
-
- void* buf = calloc(num_bytes, 1);
- if (!buf)
- return ThrowError("Unable to allocate ArrayBuffer.");
-
- args.This()->SetAlignedPointerInInternalField(0, buf);
-
- args.This()->Set(v8::String::New("byteLength"),
- v8::Integer::NewFromUnsigned(num_bytes,
- node::node_isolate),
- (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
-
- // NOTE(deanm): This is not in the spec, you shouldn't be able to index
- // the ArrayBuffer. However, it currently simplifies some handling in our
- // implementation, so we make ArrayView operator[] act like an Uint8Array.
- // , This allows DataView to work with both ArrayBuffers and TypedArrays.
- args.This()->SetIndexedPropertiesToExternalArrayData(
- buf, v8::kExternalUnsignedByteArray, num_bytes);
-
- node::node_isolate->AdjustAmountOfExternalAllocatedMemory(num_bytes);
-
- v8::Persistent<v8::Object> persistent =
- v8::Persistent<v8::Object>::New(node::node_isolate, args.This());
- persistent.MakeWeak(node::node_isolate,
- static_cast<void*>(NULL),
- &ArrayBuffer::WeakCallback);
-
- return args.This();
- }
-
- static v8::Handle<v8::Value> slice(const v8::Arguments& args) {
- if (args.Length() < 1)
- return ThrowError("Wrong number of arguments.");
-
- unsigned int length =
- args.This()->Get(v8::String::New("byteLength"))->Uint32Value();
- int begin = args[0]->Int32Value();
- int end = length;
- if (args.Length() > 1)
- end = args[1]->Int32Value();
-
- if (begin < 0) begin = length + begin;
- if (begin < 0) begin = 0;
- if (static_cast<unsigned>(begin) > length) begin = length;
-
- if (end < 0) end = length + end;
- if (end < 0) end = 0;
- if (static_cast<unsigned>(end) > length) end = length;
-
- if (begin > end) begin = end;
-
- unsigned int slice_length = end - begin;
- v8::Local<v8::Value> argv[] = {
- v8::Integer::New(slice_length, node::node_isolate)};
- v8::Local<v8::Object> buffer = ArrayBuffer::GetTemplate()->
- GetFunction()->NewInstance(1, argv);
-
- // constructor failed
- if (buffer.IsEmpty()) return v8::Undefined(node::node_isolate);
-
- void* src = args.This()->GetAlignedPointerFromInternalField(0);
- void* dest = buffer->GetAlignedPointerFromInternalField(0);
- memcpy(dest, static_cast<char*>(src) + begin, slice_length);
-
- return buffer;
- }
-};
-
-static bool checkAlignment(size_t val, unsigned int bytes) {
- return (val & (bytes - 1)) == 0; // Handles bytes == 0.
-}
-
-template <v8::ExternalArrayType TEAType>
-struct TEANameTrait {
- static const char* const name;
-};
-
-template <> const char* const
- TEANameTrait<v8::kExternalByteArray>::name = "Int8Array";
-template <> const char* const
- TEANameTrait<v8::kExternalUnsignedByteArray>::name = "Uint8Array";
-template <> const char* const
- TEANameTrait<v8::kExternalPixelArray>::name = "Uint8ClampedArray";
-template <> const char* const
- TEANameTrait<v8::kExternalShortArray>::name = "Int16Array";
-template <> const char* const
- TEANameTrait<v8::kExternalUnsignedShortArray>::name = "Uint16Array";
-template <> const char* const
- TEANameTrait<v8::kExternalIntArray>::name = "Int32Array";
-template <> const char* const
- TEANameTrait<v8::kExternalUnsignedIntArray>::name = "Uint32Array";
-template <> const char* const
- TEANameTrait<v8::kExternalFloatArray>::name = "Float32Array";
-template <> const char* const
- TEANameTrait<v8::kExternalDoubleArray>::name = "Float64Array";
-
-template <unsigned int TBytes, v8::ExternalArrayType TEAType>
-class TypedArray {
- public:
- static v8::Persistent<v8::FunctionTemplate> GetTemplate() {
- static v8::Persistent<v8::FunctionTemplate> ft_cache;
- if (!ft_cache.IsEmpty())
- return ft_cache;
-
- v8::HandleScope scope(node::node_isolate);
- ft_cache = v8::Persistent<v8::FunctionTemplate>::New(node::node_isolate,
- v8::FunctionTemplate::New(&TypedArray<TBytes, TEAType>::V8New));
- ft_cache->SetClassName(v8::String::New(TEANameTrait<TEAType>::name));
- v8::Local<v8::ObjectTemplate> instance = ft_cache->InstanceTemplate();
- instance->SetInternalFieldCount(0);
-
- ft_cache->Set(v8::String::New("BYTES_PER_ELEMENT"),
- v8::Uint32::New(TBytes, node::node_isolate), v8::ReadOnly);
- instance->Set(v8::String::New("BYTES_PER_ELEMENT"),
- v8::Uint32::New(TBytes, node::node_isolate), v8::ReadOnly);
-
- v8::Local<v8::Signature> default_signature = v8::Signature::New(ft_cache);
-
- static BatchedMethods methods[] = {
- { "get", &TypedArray<TBytes, TEAType>::get },
- { "set", &TypedArray<TBytes, TEAType>::set },
- { "slice", &TypedArray<TBytes, TEAType>::subarray },
- { "subarray", &TypedArray<TBytes, TEAType>::subarray },
- };
-
- for (size_t i = 0; i < sizeof(methods) / sizeof(*methods); ++i) {
- instance->Set(v8::String::New(methods[i].name),
- v8::FunctionTemplate::New(methods[i].func,
- v8::Handle<v8::Value>(),
- default_signature));
- }
-
- return ft_cache;
- }
-
- static bool HasInstance(v8::Handle<v8::Value> value) {
- return GetTemplate()->HasInstance(value);
- }
-
- private:
- static v8::Handle<v8::Value> V8New(const v8::Arguments& args) {
- if (!args.IsConstructCall())
- return node::FromConstructorTemplate(GetTemplate(), args);
-
- // To match Chrome, we allow "new Float32Array()".
- // if (args.Length() != 1)
- // return ThrowError("Wrong number of arguments.");
-
- v8::Local<v8::Object> buffer;
- unsigned int length = 0;
- unsigned int byte_offset = 0;
-
- if (ArrayBuffer::HasInstance(args[0])) { // ArrayBuffer constructor.
- buffer = v8::Local<v8::Object>::Cast(args[0]);
- size_t buflen =
- buffer->GetIndexedPropertiesExternalArrayDataLength();
-
- if (!args[1]->IsUndefined() && args[1]->Int32Value() < 0)
- return ThrowRangeError("Byte offset out of range.");
- byte_offset = args[1]->Uint32Value();
-
- if (args.Length() > 2) {
- if (args[2]->Int32Value() < 0)
- return ThrowRangeError("Length out of range.");
- length = args[2]->Uint32Value();
- } else {
- if (buflen < byte_offset ||
- !checkAlignment(buflen - byte_offset, TBytes)) {
- return ThrowRangeError("Byte offset / length is not aligned.");
- }
- length = (buflen - byte_offset) / TBytes;
- }
-
- // NOTE(deanm): Sloppy integer overflow checks.
- if (byte_offset > buflen || byte_offset + length > buflen ||
- byte_offset + length * TBytes > buflen) {
- return ThrowRangeError("Length is out of range.");
- }
-
- void* buf = buffer->GetIndexedPropertiesExternalArrayData();
- char* begin = reinterpret_cast<char*>(buf) + byte_offset;
-
- if (!checkAlignment(reinterpret_cast<uintptr_t>(begin), TBytes))
- return ThrowRangeError("Byte offset is not aligned.");
-
- args.This()->SetIndexedPropertiesToExternalArrayData(
- begin, TEAType, length);
- }
- else if (args[0]->IsObject()) { // TypedArray / type[] constructor.
- v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(args[0]);
- length = obj->Get(v8::String::New("length"))->Uint32Value();
-
- // TODO(deanm): Handle integer overflow.
- v8::Local<v8::Value> argv[1] = {
- v8::Integer::NewFromUnsigned(length * TBytes, node::node_isolate)};
- buffer = ArrayBuffer::GetTemplate()->
- GetFunction()->NewInstance(1, argv);
- // constructor failed
- if (buffer.IsEmpty()) return v8::Undefined(node::node_isolate);
-
- void* buf = buffer->GetAlignedPointerFromInternalField(0);
- args.This()->SetIndexedPropertiesToExternalArrayData(
- buf, TEAType, length);
- // TODO(deanm): check for failure.
- for (uint32_t i = 0; i < length; ++i) {
- // Use the v8 setter to deal with typing. Maybe slow?
- args.This()->Set(i, obj->Get(i));
- }
- } else { // length constructor.
- // Try to match Chrome, Float32Array(""), Float32Array(true/false) is
- // okay, but Float32Array(null) throws a TypeError and
- // Float32Array(undefined) throw a RangeError.
- if (args.Length() > 0 && (args[0]->IsUndefined() || args[0]->IsNull()))
- return ThrowTypeError("Type error");
-
- if (args[0]->Int32Value() < 0) {
- return ThrowRangeError("ArrayBufferView size is not a small enough "
- "positive integer.");
- }
-
- length = args[0]->Uint32Value();
- // TODO(deanm): Handle integer overflow.
- v8::Local<v8::Value> argv[1] = {
- v8::Integer::NewFromUnsigned(length * TBytes, node::node_isolate)};
-
- buffer = ArrayBuffer::GetTemplate()->
- GetFunction()->NewInstance(1, argv);
- // constructor failed
- if (buffer.IsEmpty()) return v8::Undefined(node::node_isolate);
-
- void* buf = buffer->GetAlignedPointerFromInternalField(0);
- args.This()->SetIndexedPropertiesToExternalArrayData(
- buf, TEAType, length);
- // TODO(deanm): check for failure.
- }
-
- args.This()->Set(v8::String::New("buffer"),
- buffer,
- (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
- args.This()->Set(v8::String::New("length"),
- v8::Integer::NewFromUnsigned(length, node::node_isolate),
- (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
- args.This()->Set(v8::String::New("byteOffset"),
- v8::Integer::NewFromUnsigned(byte_offset,
- node::node_isolate),
- (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
- args.This()->Set(v8::String::New("byteLength"),
- v8::Integer::NewFromUnsigned(length * TBytes,
- node::node_isolate),
- (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
-
- return args.This();
- }
-
- static v8::Handle<v8::Value> get(const v8::Arguments& args) {
- if (args.Length() < 1)
- return ThrowError("Wrong number of arguments.");
-
- if (args[0]->IsNumber())
- return args.This()->Get(args[0]->Uint32Value());
-
- return v8::Undefined(node::node_isolate);
- }
-
- static v8::Handle<v8::Value> set(const v8::Arguments& args) {
- if (args.Length() < 1)
- return ThrowError("Wrong number of arguments.");
-
- //if (!args[0]->IsObject())
- // return ThrowTypeError("Type error.");
-
- if (args[0]->IsNumber()) { // index, <type> value
- args.This()->Set(args[0]->Uint32Value(), args[1]);
- } else if (args[0]->IsObject()) {
- v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(args[0]);
-
- if (TypedArray<TBytes, TEAType>::HasInstance(obj)) { // ArrayBufferView.
- if (args[1]->Int32Value() < 0)
- return ThrowRangeError("Offset may not be negative.");
-
- unsigned int offset = args[1]->Uint32Value();
- unsigned int src_length =
- obj->Get(v8::String::New("length"))->Uint32Value();
- unsigned int dst_length =
- args.This()->Get(v8::String::New("length"))->Uint32Value();
- if (offset > dst_length)
- return ThrowRangeError("Offset out of range.");
-
- if (src_length > dst_length - offset)
- return ThrowRangeError("Offset/length out of range.");
-
- // We don't want to get the buffer pointer, because that means we'll have
- // to just do the calculations for byteOffset / byteLength again.
- // Instead just use the pointer on the external array data.
- void* src_ptr = obj->GetIndexedPropertiesExternalArrayData();
- void* dst_ptr = args.This()->GetIndexedPropertiesExternalArrayData();
-
- // From the spec:
- // If the input array is a TypedArray, the two arrays may use the same
- // underlying ArrayBuffer. In this situation, setting the values takes
- // place as if all the data is first copied into a temporary buffer that
- // does not overlap either of the arrays, and then the data from the
- // temporary buffer is copied into the current array.
- memmove(reinterpret_cast<char*>(dst_ptr) + offset * TBytes, src_ptr,
- src_length * TBytes);
- } else { // type[]
- if (args[1]->Int32Value() < 0)
- return ThrowRangeError("Offset may not be negative.");
-
- unsigned int src_length =
- obj->Get(v8::String::New("length"))->Uint32Value();
- unsigned int dst_length =
- args.This()->Get(v8::String::New("length"))->Uint32Value();
- unsigned int offset = args[1]->Uint32Value();
-
- if (offset > dst_length)
- return ThrowRangeError("Offset out of range.");
-
- if (src_length > dst_length - offset)
- return ThrowRangeError("Offset/length out of range.");
-
- for (uint32_t i = 0; i < src_length; ++i) {
- // Use the v8 setter to deal with typing. Maybe slow?
- args.This()->Set(i + offset, obj->Get(i));
- }
- }
- }
-
- return v8::Undefined(node::node_isolate);
- }
-
- static v8::Handle<v8::Value> subarray(const v8::Arguments& args) {
- // TODO(deanm): The unsigned / signed type mixing makes me super nervous.
-
- unsigned int length =
- args.This()->Get(v8::String::New("length"))->Uint32Value();
- int begin = args[0]->Int32Value();
- int end = length;
- if (args.Length() > 1)
- end = args[1]->Int32Value();
-
- if (begin < 0) begin = length + begin;
- if (begin < 0) begin = 0;
- if ((unsigned)begin > length) begin = length;
-
- if (end < 0) end = length + end;
- if (end < 0) end = 0;
- if ((unsigned)end > length) end = length;
-
- if (begin > end) begin = end;
-
- int byte_offset = begin * TBytes +
- args.This()->Get(v8::String::New("byteOffset"))->Uint32Value();
-
- // Call through to the ArrayBuffer, byteOffset, length constructor.
- v8::Local<v8::Value> argv[] = {
- args.This()->Get(v8::String::New("buffer")),
- v8::Integer::New(byte_offset, node::node_isolate),
- v8::Integer::New(end - begin, node::node_isolate)};
- return TypedArray<TBytes, TEAType>::GetTemplate()->
- GetFunction()->NewInstance(3, argv);
- }
-};
-
-class Int8Array : public TypedArray<1, v8::kExternalByteArray> { };
-class Uint8Array : public TypedArray<1, v8::kExternalUnsignedByteArray> { };
-class Uint8ClampedArray : public TypedArray<1, v8::kExternalPixelArray> { };
-class Int16Array : public TypedArray<2, v8::kExternalShortArray> { };
-class Uint16Array : public TypedArray<2, v8::kExternalUnsignedShortArray> { };
-class Int32Array : public TypedArray<4, v8::kExternalIntArray> { };
-class Uint32Array : public TypedArray<4, v8::kExternalUnsignedIntArray> { };
-class Float32Array : public TypedArray<4, v8::kExternalFloatArray> { };
-class Float64Array : public TypedArray<8, v8::kExternalDoubleArray> { };
-
-template <typename T>
-v8::Handle<v8::Value> cTypeToValue(T) {
- return v8::Undefined(node::node_isolate);
-}
-
-template <>
-v8::Handle<v8::Value> cTypeToValue(unsigned char val) {
- return v8::Integer::NewFromUnsigned(val, node::node_isolate);
-}
-
-template <>
-v8::Handle<v8::Value> cTypeToValue(signed char val) {
- return v8::Integer::New(val, node::node_isolate);
-}
-
-template <>
-v8::Handle<v8::Value> cTypeToValue(unsigned short val) {
- return v8::Integer::NewFromUnsigned(val, node::node_isolate);
-}
-
-template <>
-v8::Handle<v8::Value> cTypeToValue(short val) {
- return v8::Integer::New(val, node::node_isolate);
-}
-
-template <>
-v8::Handle<v8::Value> cTypeToValue(unsigned int val) {
- return v8::Integer::NewFromUnsigned(val, node::node_isolate);
-}
-
-template <>
-v8::Handle<v8::Value> cTypeToValue(int val) {
- return v8::Integer::New(val, node::node_isolate);
-}
-
-template <>
-v8::Handle<v8::Value> cTypeToValue(float val) {
- return v8::Number::New(val);
-}
-
-template <>
-v8::Handle<v8::Value> cTypeToValue(double val) {
- return v8::Number::New(val);
-}
-
-
-template <typename T>
-T valueToCType(v8::Handle<v8::Value> value) {
- return 0;
-}
-
-template <>
-unsigned char valueToCType(v8::Handle<v8::Value> value) {
- return value->Uint32Value();
-}
-
-template <>
-signed char valueToCType(v8::Handle<v8::Value> value) {
- return value->Int32Value();
-}
-
-template <>
-unsigned short valueToCType(v8::Handle<v8::Value> value) {
- return value->Uint32Value();
-}
-
-template <>
-short valueToCType(v8::Handle<v8::Value> value) {
- return value->Int32Value();
-}
-
-template <>
-unsigned int valueToCType(v8::Handle<v8::Value> value) {
- return value->Uint32Value();
-}
-
-template <>
-int valueToCType(v8::Handle<v8::Value> value) {
- return value->Int32Value();
-}
-
-template <>
-float valueToCType(v8::Handle<v8::Value> value) {
- return static_cast<float>(value->NumberValue());
-}
-
-template <>
-double valueToCType(v8::Handle<v8::Value> value) {
- return value->NumberValue();
-}
-
-
-class DataView {
- public:
- static v8::Persistent<v8::FunctionTemplate> GetTemplate() {
- static v8::Persistent<v8::FunctionTemplate> ft_cache;
- if (!ft_cache.IsEmpty())
- return ft_cache;
-
- v8::HandleScope scope(node::node_isolate);
- ft_cache = v8::Persistent<v8::FunctionTemplate>::New(node::node_isolate,
- v8::FunctionTemplate::New(&DataView::V8New));
- ft_cache->SetClassName(v8::String::New("DataView"));
- v8::Local<v8::ObjectTemplate> instance = ft_cache->InstanceTemplate();
- instance->SetInternalFieldCount(0);
-
- v8::Local<v8::Signature> default_signature = v8::Signature::New(ft_cache);
-
- static BatchedMethods methods[] = {
- { "getUint8", &DataView::getUint8 },
- { "getInt8", &DataView::getInt8 },
- { "getUint16", &DataView::getUint16 },
- { "getInt16", &DataView::getInt16 },
- { "getUint32", &DataView::getUint32 },
- { "getInt32", &DataView::getInt32 },
- { "getFloat32", &DataView::getFloat32 },
- { "getFloat64", &DataView::getFloat64 },
- { "setUint8", &DataView::setUint8 },
- { "setInt8", &DataView::setInt8 },
- { "setUint16", &DataView::setUint16 },
- { "setInt16", &DataView::setInt16 },
- { "setUint32", &DataView::setUint32 },
- { "setInt32", &DataView::setInt32 },
- { "setFloat32", &DataView::setFloat32 },
- { "setFloat64", &DataView::setFloat64 },
- };
-
- for (size_t i = 0; i < sizeof(methods) / sizeof(*methods); ++i) {
- instance->Set(v8::String::New(methods[i].name),
- v8::FunctionTemplate::New(methods[i].func,
- v8::Handle<v8::Value>(),
- default_signature));
- }
-
- return ft_cache;
- }
-
- static bool HasInstance(v8::Handle<v8::Value> value) {
- return GetTemplate()->HasInstance(value);
- }
-
- private:
- static v8::Handle<v8::Value> V8New(const v8::Arguments& args) {
- if (!args.IsConstructCall())
- return node::FromConstructorTemplate(GetTemplate(), args);
-
- if (args.Length() < 1)
- return ThrowError("Wrong number of arguments.");
-
- if (!args[0]->IsObject())
- return ThrowError("Object must be an ArrayBuffer.");
-
- v8::Handle<v8::Object> buffer = v8::Handle<v8::Object>::Cast(args[0]);
- if (!ArrayBuffer::HasInstance(buffer))
- return ThrowError("Object must be an ArrayBuffer.");
-
- unsigned int byte_length =
- buffer->GetIndexedPropertiesExternalArrayDataLength();
- unsigned int byte_offset = args[1]->Uint32Value();
-
- if (args[1]->Int32Value() < 0 || byte_offset >= byte_length)
- return ThrowRangeError("byteOffset out of range.");
-
- if (!args[2]->IsUndefined()) {
- if (args[2]->Int32Value() < 0)
- return ThrowRangeError("byteLength out of range.");
- unsigned int new_byte_length = args[2]->Uint32Value();
- if (new_byte_length > byte_length)
- return ThrowRangeError("byteLength out of range.");
- if (byte_offset + new_byte_length > byte_length)
- return ThrowRangeError("byteOffset/byteLength out of range.");
- byte_length = new_byte_length;
- } else {
- // Adjust the original byte_length from total length to length to end.
- byte_length -= byte_offset;
- }
-
- void* buf = buffer->GetIndexedPropertiesExternalArrayData();
-
- // Like ArrayBuffer, we violate the spec and add an operator[].
- args.This()->SetIndexedPropertiesToExternalArrayData(
- reinterpret_cast<char*>(buf) + byte_offset,
- v8::kExternalUnsignedByteArray, byte_length);
-
- args.This()->Set(v8::String::New("buffer"),
- buffer,
- (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
- args.This()->Set(v8::String::New("byteOffset"),
- v8::Integer::NewFromUnsigned(byte_offset,
- node::node_isolate),
- (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
- args.This()->Set(v8::String::New("byteLength"),
- v8::Integer::NewFromUnsigned(byte_length,
- node::node_isolate),
- (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
- return args.This();
- }
-
- template <typename T>
- static v8::Handle<v8::Value> getGeneric(const v8::Arguments& args) {
- if (args.Length() < 1)
- return ThrowError("Wrong number of arguments.");
-
- unsigned int index = args[0]->Uint32Value();
- // NOTE(deanm): args[1]->BooleanValue when the argument was not passed in
- // gives us the right answer, but seems to be very slow. This seems to be
- // the cost of calling BooleanValue() on undefined.
- bool little_endian = args.Length() > 1 ? args[1]->BooleanValue() : false;
- // TODO(deanm): All of these things should be cacheable.
- int element_size = v8_typed_array::SizeOfArrayElementForType(
- args.This()->GetIndexedPropertiesExternalArrayDataType());
- assert(element_size > 0);
- int size = args.This()->GetIndexedPropertiesExternalArrayDataLength();
- assert(size >= 0);
-
- if (static_cast<uint64_t>(index) + sizeof(T) >
- static_cast<uint64_t>(size) * element_size) {
- return ThrowError("Index out of range.");
- }
-
- void* ptr = reinterpret_cast<char*>(
- args.This()->GetIndexedPropertiesExternalArrayData()) + index;
-
- T val;
-#if V8_TYPED_ARRAY_LITTLE_ENDIAN
- if (!little_endian) {
-#else
- if (little_endian) {
-#endif
- val = v8_typed_array::LoadAndSwapBytes<T>(ptr);
- } else {
- memcpy(&val, ptr, sizeof(T));
- }
- return cTypeToValue<T>(val);
- }
-
- template <typename T>
- static v8::Handle<v8::Value> setGeneric(const v8::Arguments& args) {
- if (args.Length() < 2)
- return ThrowError("Wrong number of arguments.");
-
- unsigned int index = args[0]->Int32Value();
- // NOTE(deanm): args[1]->BooleanValue when the argument was not passed in
- // gives us the right answer, but seems to be very slow. This seems to be
- // the cost of calling BooleanValue() on undefined.
- bool little_endian = args.Length() > 2 ? args[2]->BooleanValue() : false;
- // TODO(deanm): All of these things should be cacheable.
- int element_size = v8_typed_array::SizeOfArrayElementForType(
- args.This()->GetIndexedPropertiesExternalArrayDataType());
- assert(element_size > 0);
- int size = args.This()->GetIndexedPropertiesExternalArrayDataLength();
- assert(size >= 0);
-
- if (static_cast<uint64_t>(index) + sizeof(T) >
- static_cast<uint64_t>(size) * element_size) {
- return ThrowError("Index out of range.");
- }
-
- void* ptr = reinterpret_cast<char*>(
- args.This()->GetIndexedPropertiesExternalArrayData()) + index;
-
- T val = valueToCType<T>(args[1]);
-#if V8_TYPED_ARRAY_LITTLE_ENDIAN
- if (!little_endian) {
-#else
- if (little_endian) {
-#endif
- v8_typed_array::SwapBytesAndStore<T>(ptr, val);
- } else {
- memcpy(ptr, &val, sizeof(T));
- }
- return v8::Undefined(node::node_isolate);
- }
-
- static v8::Handle<v8::Value> getUint8(const v8::Arguments& args) {
- return getGeneric<unsigned char>(args);
- }
-
- static v8::Handle<v8::Value> getInt8(const v8::Arguments& args) {
- return getGeneric<signed char>(args);
- }
-
- static v8::Handle<v8::Value> getUint16(const v8::Arguments& args) {
- return getGeneric<unsigned short>(args);
- }
-
- static v8::Handle<v8::Value> getInt16(const v8::Arguments& args) {
- return getGeneric<short>(args);
- }
-
- static v8::Handle<v8::Value> getUint32(const v8::Arguments& args) {
- return getGeneric<unsigned int>(args);
- }
-
- static v8::Handle<v8::Value> getInt32(const v8::Arguments& args) {
- return getGeneric<int>(args);
- }
-
- static v8::Handle<v8::Value> getFloat32(const v8::Arguments& args) {
- return getGeneric<float>(args);
- }
-
- static v8::Handle<v8::Value> getFloat64(const v8::Arguments& args) {
- return getGeneric<double>(args);
- }
-
- static v8::Handle<v8::Value> setUint8(const v8::Arguments& args) {
- return setGeneric<unsigned char>(args);
- }
-
- static v8::Handle<v8::Value> setInt8(const v8::Arguments& args) {
- return setGeneric<signed char>(args);
- }
-
- static v8::Handle<v8::Value> setUint16(const v8::Arguments& args) {
- return setGeneric<unsigned short>(args);
- }
-
- static v8::Handle<v8::Value> setInt16(const v8::Arguments& args) {
- return setGeneric<short>(args);
- }
-
- static v8::Handle<v8::Value> setUint32(const v8::Arguments& args) {
- return setGeneric<unsigned int>(args);
- }
-
- static v8::Handle<v8::Value> setInt32(const v8::Arguments& args) {
- return setGeneric<int>(args);
- }
-
- static v8::Handle<v8::Value> setFloat32(const v8::Arguments& args) {
- return setGeneric<float>(args);
- }
-
- static v8::Handle<v8::Value> setFloat64(const v8::Arguments& args) {
- return setGeneric<double>(args);
- }
-};
-
-
-} // namespace
-
-namespace v8_typed_array {
-
-void AttachBindings(v8::Handle<v8::Object> obj) {
- v8::HandleScope scope(node::node_isolate);
-
- obj->Set(v8::String::New("ArrayBuffer"),
- ArrayBuffer::GetTemplate()->GetFunction());
- obj->Set(v8::String::New("Int8Array"),
- Int8Array::GetTemplate()->GetFunction());
- obj->Set(v8::String::New("Uint8Array"),
- Uint8Array::GetTemplate()->GetFunction());
- obj->Set(v8::String::New("Uint8ClampedArray"),
- Uint8ClampedArray::GetTemplate()->GetFunction());
- obj->Set(v8::String::New("Int16Array"),
- Int16Array::GetTemplate()->GetFunction());
- obj->Set(v8::String::New("Uint16Array"),
- Uint16Array::GetTemplate()->GetFunction());
- obj->Set(v8::String::New("Int32Array"),
- Int32Array::GetTemplate()->GetFunction());
- obj->Set(v8::String::New("Uint32Array"),
- Uint32Array::GetTemplate()->GetFunction());
- obj->Set(v8::String::New("Float32Array"),
- Float32Array::GetTemplate()->GetFunction());
- obj->Set(v8::String::New("Float64Array"),
- Float64Array::GetTemplate()->GetFunction());
- obj->Set(v8::String::New("DataView"),
- DataView::GetTemplate()->GetFunction());
-}
-
-int SizeOfArrayElementForType(v8::ExternalArrayType type) {
- switch (type) {
- case v8::kExternalByteArray:
- case v8::kExternalUnsignedByteArray:
- case v8::kExternalPixelArray:
- return 1;
- case v8::kExternalShortArray:
- case v8::kExternalUnsignedShortArray:
- return 2;
- case v8::kExternalIntArray:
- case v8::kExternalUnsignedIntArray:
- case v8::kExternalFloatArray:
- return 4;
- case v8::kExternalDoubleArray:
- return 8;
- default:
- return 0;
- }
-}
-
-} // namespace v8_typed_array