[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/wave2future/node/debugProcess/src/v8_typed_array.cc [Back]  [Original]

// V8 Typed Array implementation.
// (c) Dean McNamee , 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   // calloc, etc
#include   // memmove

#include 

#include "v8_typed_array.h"

namespace {

v8::Handle ThrowError(const char* msg) {
  return v8::ThrowException(v8::Exception::Error(v8::String::New(msg)));
}

v8::Handle ThrowTypeError(const char* msg) {
  return v8::ThrowException(v8::Exception::TypeError(v8::String::New(msg)));
}

v8::Handle ThrowRangeError(const char* msg) {
  return v8::ThrowException(v8::Exception::RangeError(v8::String::New(msg)));
}

struct BatchedMethods {
  const char* name;
  v8::Handle (*func)(const v8::Arguments& args);
};

class ArrayBuffer {
 public:
  static v8::Persistent GetTemplate() {
    static v8::Persistent ft_cache;
    if (!ft_cache.IsEmpty())
      return ft_cache;

    v8::HandleScope scope;
    ft_cache = v8::Persistent::New(
        v8::FunctionTemplate::New(&ArrayBuffer::V8New));
    ft_cache->SetClassName(v8::String::New("ArrayBuffer"));
    v8::Local instance = ft_cache->InstanceTemplate();
    instance->SetInternalFieldCount(1);  // Buffer.

    return ft_cache;
  }

  static bool HasInstance(v8::Handle value) {
    return GetTemplate()->HasInstance(value);
  }

 private:
  static void WeakCallback(v8::Persistent value, void* data) {
    v8::Object* obj = v8::Object::Cast(*value);

    void* ptr = obj->GetIndexedPropertiesExternalArrayData();
    int element_size = v8_typed_array::SizeOfArrayElementForType(
        obj->GetIndexedPropertiesExternalArrayDataType());
    int size =
        obj->GetIndexedPropertiesExternalArrayDataLength() * element_size;

    v8::V8::AdjustAmountOfExternalAllocatedMemory(-size);

    value.ClearWeak();
    value.Dispose();

    free(ptr);
  }

  static v8::Handle V8New(const v8::Arguments& args) {
    if (!args.IsConstructCall())
      return ThrowTypeError("Constructor cannot be called as a function.");

    // 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();
    void* buf = calloc(num_bytes, 1);
    if (!buf)
      return ThrowError("Unable to allocate ArrayBuffer.");

    args.This()->SetPointerInInternalField(0, buf);

    args.This()->Set(v8::String::New("byteLength"),
                     v8::Integer::NewFromUnsigned(num_bytes),
                     (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);

    v8::V8::AdjustAmountOfExternalAllocatedMemory(num_bytes);

    v8::Persistent persistent =
        v8::Persistent::New(args.This());
    persistent.MakeWeak(NULL, &ArrayBuffer::WeakCallback);

    return args.This();
  }
};

static bool checkAlignment(unsigned int val, unsigned int bytes) {
  return (val & (bytes - 1)) == 0;  // Handles bytes == 0.
}

template 
class TypedArray {
 public:
  static v8::Persistent GetTemplate() {
    static v8::Persistent ft_cache;
    if (!ft_cache.IsEmpty())
      return ft_cache;

    v8::HandleScope scope;
    ft_cache = v8::Persistent::New(
        v8::FunctionTemplate::New(&TypedArray::V8New));
    v8::Local instance = ft_cache->InstanceTemplate();
    instance->SetInternalFieldCount(0);

    ft_cache->Set(v8::String::New("BYTES_PER_ELEMENT"),
                  v8::Uint32::New(TBytes), v8::ReadOnly);
    instance->Set(v8::String::New("BYTES_PER_ELEMENT"),
                  v8::Uint32::New(TBytes), v8::ReadOnly);

    v8::Local default_signature = v8::Signature::New(ft_cache);

    static BatchedMethods methods[] = {
      { "set", &TypedArray::set },
      { "slice", &TypedArray::subarray },
      { "subarray", &TypedArray::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(),
                                              default_signature));
    }

    return ft_cache;
  }

  static bool HasInstance(v8::Handle value) {
    return GetTemplate()->HasInstance(value);
  }

 private:
  static v8::Handle V8New(const v8::Arguments& args) {
    if (!args.IsConstructCall())
      return ThrowTypeError("Constructor cannot be called as a function.");

    // To match Chrome, we allow "new Float32Array()".
    // if (args.Length() != 1)
    //   return ThrowError("Wrong number of arguments.");

    v8::Local buffer;
    unsigned int length = 0;
    unsigned int byte_offset = 0;

    if (ArrayBuffer::HasInstance(args[0])) {  // ArrayBuffer constructor.
      buffer = v8::Local::Cast(args[0]);
      unsigned int buflen =
          buffer->GetIndexedPropertiesExternalArrayDataLength();

      if (args[1]->Int32Value() < 0)
        return ThrowRangeError("Byte offset out of range.");
      byte_offset = args[1]->Uint32Value();

      if (!checkAlignment(byte_offset, TBytes))
        return ThrowRangeError("Byte offset is not aligned.");

      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.");
      }

      // TODO(deanm): Error check.
      void* buf = buffer->GetPointerFromInternalField(0);
      args.This()->SetIndexedPropertiesToExternalArrayData(
          reinterpret_cast(buf) + byte_offset, TEAType, length);
    } else if (args[0]->IsObject()) {  // TypedArray / type[] constructor.
      v8::Local obj = v8::Local::Cast(args[0]);
      length = obj->Get(v8::String::New("length"))->Uint32Value();

      // TODO(deanm): Handle integer overflow.
      v8::Handle argv[1] = {
          v8::Integer::NewFromUnsigned(length * TBytes)};
      buffer = ArrayBuffer::GetTemplate()->
                 GetFunction()->NewInstance(1, argv);

      void* buf = buffer->GetPointerFromInternalField(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::Handle argv[1] = {
          v8::Integer::NewFromUnsigned(length * TBytes)};

      buffer = ArrayBuffer::GetTemplate()->
                 GetFunction()->NewInstance(1, argv);
      void* buf = buffer->GetPointerFromInternalField(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),
                     (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
    args.This()->Set(v8::String::New("byteOffset"),
                     v8::Integer::NewFromUnsigned(byte_offset),
                     (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
    args.This()->Set(v8::String::New("byteLength"),
                     v8::Integer::NewFromUnsigned(length * TBytes),
                     (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));

    return args.This();
  }

  static v8::Handle set(const v8::Arguments& args) {
    if (args.Length() < 1)
      return ThrowError("Wrong number of arguments.");

    if (!args[0]->IsObject())
      return ThrowTypeError("Type error.");

    v8::Handle obj = v8::Handle::Cast(args[0]);

    if (TypedArray::HasInstance(obj)) {  // ArrayBufferView.
      v8::Handle src_buffer = v8::Handle::Cast(
          obj->Get(v8::String::New("buffer")));
      v8::Handle dst_buffer = v8::Handle::Cast(
          args.This()->Get(v8::String::New("buffer")));

      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(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();
  }

  static v8::Handle 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::Handle argv[] = {
        args.This()->Get(v8::String::New("buffer")),
        v8::Integer::New(byte_offset),
        v8::Integer::New(end - begin)};
    return TypedArray::GetTemplate()->
        GetFunction()->NewInstance(3, argv);
  }
};

class Int8Array : public TypedArray { };
class Uint8Array : public TypedArray { };
class Int16Array : public TypedArray { };
class Uint16Array : public TypedArray { };
class Int32Array : public TypedArray { };
class Uint32Array : public TypedArray { };
class Float32Array : public TypedArray { };
class Float64Array : public TypedArray { };

template 
v8::Handle cTypeToValue(T) {
  return v8::Undefined();
}

template 
v8::Handle cTypeToValue(unsigned char val) {
  return v8::Integer::NewFromUnsigned(val);
}

template 
v8::Handle cTypeToValue(char val) {
  return v8::Integer::New(val);
}

template 
v8::Handle cTypeToValue(unsigned short val) {
  return v8::Integer::NewFromUnsigned(val);
}

template 
v8::Handle cTypeToValue(short val) {
  return v8::Integer::New(val);
}

template 
v8::Handle cTypeToValue(unsigned int val) {
  return v8::Integer::NewFromUnsigned(val);
}

template 
v8::Handle cTypeToValue(int val) {
  return v8::Integer::New(val);
}

template 
v8::Handle cTypeToValue(float val) {
  return v8::Number::New(val);
}

template 
v8::Handle cTypeToValue(double val) {
  return v8::Number::New(val);
}


template 
T valueToCType(v8::Handle value) {
  return 0;
}

template 
unsigned char valueToCType(v8::Handle value) {
  return value->Uint32Value();
}

template 
char valueToCType(v8::Handle value) {
  return value->Int32Value();
}

template 
unsigned short valueToCType(v8::Handle value) {
  return value->Uint32Value();
}

template 
short valueToCType(v8::Handle value) {
  return value->Int32Value();
}

template 
unsigned int valueToCType(v8::Handle value) {
  return value->Uint32Value();
}

template 
int valueToCType(v8::Handle value) {
  return value->Int32Value();
}

template 
float valueToCType(v8::Handle value) {
  return value->NumberValue();
}

template 
double valueToCType(v8::Handle value) {
  return value->NumberValue();
}


class DataView {
 public:
  static v8::Persistent GetTemplate() {
    static v8::Persistent ft_cache;
    if (!ft_cache.IsEmpty())
      return ft_cache;

    v8::HandleScope scope;
    ft_cache = v8::Persistent::New(
        v8::FunctionTemplate::New(&DataView::V8New));
    ft_cache->SetClassName(v8::String::New("DataView"));
    v8::Local instance = ft_cache->InstanceTemplate();
    instance->SetInternalFieldCount(0);

    v8::Local 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(),
                                              default_signature));
    }

    return ft_cache;
  }

  static bool HasInstance(v8::Handle value) {
    return GetTemplate()->HasInstance(value);
  }

 private:
  static v8::Handle V8New(const v8::Arguments& args) {
    if (!args.IsConstructCall())
      return ThrowTypeError("Constructor cannot be called as a function.");

    if (args.Length() < 1)
      return ThrowError("Wrong number of arguments.");

    if (!args[0]->IsObject())
      return ThrowError("Object must be an ArrayBuffer.");

    v8::Handle buffer = v8::Handle::Cast(args[0]);
    if (!buffer->HasIndexedPropertiesInExternalArrayData())
      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(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),
                     (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
    args.This()->Set(v8::String::New("byteLength"),
                     v8::Integer::NewFromUnsigned(byte_length),
                     (v8::PropertyAttribute)(v8::ReadOnly|v8::DontDelete));
    return args.This();
  }

  // TODO(deanm): This isn't beautiful or optimal.
  static void swizzle(char* buf, size_t len) {
    for (size_t i = 0; i < len / 2; ++i) {
      char t = buf[i];
      buf[i] = buf[len - i - 1];
      buf[len - i - 1] = t;
    }
  }

  template 
  static T getValue(void* ptr, unsigned int index, bool swiz) {
    char buf[sizeof(T)];
    memcpy(buf, reinterpret_cast(ptr) + index, sizeof(T));
    if (swiz)
      swizzle(buf, sizeof(T));
    T val;
    memcpy(&val, buf, sizeof(T));
    return val;
  }

  template 
  static void setValue(void* ptr, unsigned int index, T val, bool swiz) {
    char buf[sizeof(T)];
    memcpy(buf, &val, sizeof(T));
    if (swiz)
      swizzle(buf, sizeof(T));
    memcpy(reinterpret_cast(ptr) + index, buf, sizeof(T));
  }

  template 
  static v8::Handle getGeneric(const v8::Arguments& args) {
    if (args.Length() < 1)
      return ThrowError("Wrong number of arguments.");

    unsigned int index = args[0]->Uint32Value();
    bool little_endian = args[1]->BooleanValue();
    // TODO(deanm): All of these things should be cacheable.
    int element_size = v8_typed_array::SizeOfArrayElementForType(
        args.This()->GetIndexedPropertiesExternalArrayDataType());
    int size = args.This()->GetIndexedPropertiesExternalArrayDataLength() *
               element_size;

    if (index + sizeof(T) > (unsigned)size)  // TODO(deanm): integer overflow.
      return ThrowError("Index out of range.");

    void* ptr = args.This()->GetIndexedPropertiesExternalArrayData();
    return cTypeToValue(getValue(ptr, index, !little_endian));
  }

  template 
  static v8::Handle setGeneric(const v8::Arguments& args) {
    if (args.Length() < 2)
      return ThrowError("Wrong number of arguments.");

    unsigned int index = args[0]->Int32Value();
    bool little_endian = args[2]->BooleanValue();
    // TODO(deanm): All of these things should be cacheable.
    int element_size = v8_typed_array::SizeOfArrayElementForType(
        args.This()->GetIndexedPropertiesExternalArrayDataType());
    int size = args.This()->GetIndexedPropertiesExternalArrayDataLength() *
               element_size;

    if (index + sizeof(T) > (unsigned)size)  // TODO(deanm): integer overflow.
      return ThrowError("Index out of range.");

    void* ptr = args.This()->GetIndexedPropertiesExternalArrayData();
    setValue(ptr, index, valueToCType(args[1]), !little_endian);
    return v8::Undefined();
  }

  static v8::Handle getUint8(const v8::Arguments& args) {
    return getGeneric(args);
  }

  static v8::Handle getInt8(const v8::Arguments& args) {
    return getGeneric(args);
  }

  static v8::Handle getUint16(const v8::Arguments& args) {
    return getGeneric(args);
  }

  static v8::Handle getInt16(const v8::Arguments& args) {
    return getGeneric(args);
  }

  static v8::Handle getUint32(const v8::Arguments& args) {
    return getGeneric(args);
  }

  static v8::Handle getInt32(const v8::Arguments& args) {
    return getGeneric(args);
  }

  static v8::Handle getFloat32(const v8::Arguments& args) {
    return getGeneric(args);
  }

  static v8::Handle getFloat64(const v8::Arguments& args) {
    return getGeneric(args);
  }

  static v8::Handle setUint8(const v8::Arguments& args) {
    return setGeneric(args);
  }

  static v8::Handle setInt8(const v8::Arguments& args) {
    return setGeneric(args);
  }

  static v8::Handle setUint16(const v8::Arguments& args) {
    return setGeneric(args);
  }

  static v8::Handle setInt16(const v8::Arguments& args) {
    return setGeneric(args);
  }

  static v8::Handle setUint32(const v8::Arguments& args) {
    return setGeneric(args);
  }

  static v8::Handle setInt32(const v8::Arguments& args) {
    return setGeneric(args);
  }

  static v8::Handle setFloat32(const v8::Arguments& args) {
    return setGeneric(args);
  }

  static v8::Handle setFloat64(const v8::Arguments& args) {
    return setGeneric(args);
  }
};


}  // namespace

namespace v8_typed_array {

void AttachBindings(v8::Handle obj) {
  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("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:
      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

Web Proxy Viewer  |  New URL  |  Original Page