First cut at impementing ES6 TypedArrays in V8.
authordslomov@chromium.org <dslomov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 16 Apr 2013 14:16:30 +0000 (14:16 +0000)
committerdslomov@chromium.org <dslomov@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 16 Apr 2013 14:16:30 +0000 (14:16 +0000)
BUG=

Review URL: https://codereview.chromium.org/13975012

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14285 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

13 files changed:
src/bootstrapper.cc
src/messages.js
src/objects-debug.cc
src/objects-inl.h
src/objects-printer.cc
src/objects-visiting.cc
src/objects.cc
src/objects.h
src/runtime.cc
src/runtime.h
src/typedarray.js
src/v8conversions.h
test/mjsunit/harmony/typedarrays.js

index df98448..12f0cda 100644 (file)
@@ -199,6 +199,8 @@ class Genesis BASE_EMBEDDED {
                                           const char* name,
                                           ElementsKind elements_kind);
   bool InstallNatives();
+
+  void InstallTypedArray(const char* name);
   bool InstallExperimentalNatives();
   void InstallBuiltinFunctionIds();
   void InstallJSFunctionResultCaches();
@@ -1258,6 +1260,14 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
 }
 
 
+void Genesis::InstallTypedArray(const char* name) {
+  Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
+  InstallFunction(global, name, JS_TYPED_ARRAY_TYPE,
+                  JSTypedArray::kSize, isolate()->initial_object_prototype(),
+                  Builtins::kIllegal, true);
+}
+
+
 void Genesis::InitializeExperimentalGlobal() {
   Handle<JSObject> global = Handle<JSObject>(native_context()->global_object());
 
@@ -1298,6 +1308,17 @@ void Genesis::InitializeExperimentalGlobal() {
                       isolate()->initial_object_prototype(),
                       Builtins::kIllegal, true);
     }
+    {
+      // -- T y p e d A r r a y s
+      InstallTypedArray("__Int8Array");
+      InstallTypedArray("__Uint8Array");
+      InstallTypedArray("__Int16Array");
+      InstallTypedArray("__Uint16Array");
+      InstallTypedArray("__Int32Array");
+      InstallTypedArray("__Uint32Array");
+      InstallTypedArray("__Float32Array");
+      InstallTypedArray("__Float64Array");
+    }
   }
 
   if (FLAG_harmony_generators) {
index febebfa..67fe3cc 100644 (file)
@@ -102,6 +102,9 @@ var kMessages = {
   // RangeError
   invalid_array_length:          ["Invalid array length"],
   invalid_array_buffer_length:   ["Invalid array buffer length"],
+  invalid_typed_array_offset:    ["Start offset is too large"],
+  invalid_typed_array_length:    ["Length is too large"],
+  invalid_typed_array_alignment: ["%0", "of", "%1", "should be a multiple of", "%3"],
   stack_overflow:                ["Maximum call stack size exceeded"],
   invalid_time_value:            ["Invalid time value"],
   // SyntaxError
index bbafa12..24730a0 100644 (file)
@@ -201,6 +201,9 @@ void HeapObject::HeapObjectVerify() {
     case JS_ARRAY_BUFFER_TYPE:
       JSArrayBuffer::cast(this)->JSArrayBufferVerify();
       break;
+    case JS_TYPED_ARRAY_TYPE:
+      JSTypedArray::cast(this)->JSTypedArrayVerify();
+      break;
 
 #define MAKE_STRUCT_CASE(NAME, Name, name) \
   case NAME##_TYPE:                        \
@@ -738,6 +741,28 @@ void JSArrayBuffer::JSArrayBufferVerify() {
 }
 
 
+void JSTypedArray::JSTypedArrayVerify() {
+  CHECK(IsJSTypedArray());
+  JSObjectVerify();
+  VerifyPointer(buffer());
+  CHECK(buffer()->IsJSArrayBuffer() || buffer()->IsUndefined());
+
+  VerifyPointer(byte_offset());
+  CHECK(byte_offset()->IsSmi() || byte_offset()->IsHeapNumber()
+        || byte_offset()->IsUndefined());
+
+  VerifyPointer(byte_length());
+  CHECK(byte_length()->IsSmi() || byte_length()->IsHeapNumber()
+        || byte_length()->IsUndefined());
+
+  VerifyPointer(length());
+  CHECK(length()->IsSmi() || length()->IsHeapNumber()
+        || length()->IsUndefined());
+
+  VerifyPointer(elements());
+}
+
+
 void Foreign::ForeignVerify() {
   CHECK(IsForeign());
 }
index bffe414..efc1764 100644 (file)
@@ -676,6 +676,7 @@ bool Object::IsBoolean() {
 
 TYPE_CHECKER(JSArray, JS_ARRAY_TYPE)
 TYPE_CHECKER(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE)
+TYPE_CHECKER(JSTypedArray, JS_TYPED_ARRAY_TYPE)
 TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE)
 
 
@@ -1605,6 +1606,8 @@ int JSObject::GetHeaderSize() {
       return JSArray::kSize;
     case JS_ARRAY_BUFFER_TYPE:
       return JSArrayBuffer::kSize;
+    case JS_TYPED_ARRAY_TYPE:
+      return JSTypedArray::kSize;
     case JS_SET_TYPE:
       return JSSet::kSize;
     case JS_MAP_TYPE:
@@ -2492,6 +2495,7 @@ CAST_ACCESSOR(JSBuiltinsObject)
 CAST_ACCESSOR(Code)
 CAST_ACCESSOR(JSArray)
 CAST_ACCESSOR(JSArrayBuffer)
+CAST_ACCESSOR(JSTypedArray)
 CAST_ACCESSOR(JSRegExp)
 CAST_ACCESSOR(JSProxy)
 CAST_ACCESSOR(JSFunctionProxy)
@@ -5207,6 +5211,12 @@ void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) {
 ACCESSORS(JSArrayBuffer, byte_length, Object, kByteLengthOffset)
 
 
+ACCESSORS(JSTypedArray, buffer, Object, kBufferOffset)
+ACCESSORS(JSTypedArray, byte_offset, Object, kByteOffsetOffset)
+ACCESSORS(JSTypedArray, byte_length, Object, kByteLengthOffset)
+ACCESSORS(JSTypedArray, length, Object, kLengthOffset)
+
+
 ACCESSORS(JSRegExp, data, Object, kDataOffset)
 
 
index 9e1ef63..aa71a96 100644 (file)
@@ -187,6 +187,8 @@ void HeapObject::HeapObjectPrint(FILE* out) {
       break;
     case JS_ARRAY_BUFFER_TYPE:
       JSArrayBuffer::cast(this)->JSArrayBufferPrint(out);
+    case JS_TYPED_ARRAY_TYPE:
+      JSTypedArray::cast(this)->JSTypedArrayPrint(out);
 #define MAKE_STRUCT_CASE(NAME, Name, name) \
   case NAME##_TYPE:                        \
     Name::cast(this)->Name##Print(out);    \
@@ -809,6 +811,22 @@ void JSArrayBuffer::JSArrayBufferPrint(FILE* out) {
 }
 
 
+void JSTypedArray::JSTypedArrayPrint(FILE* out) {
+  HeapObject::PrintHeader(out, "JSTypedArray");
+  PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+  PrintF(out, " - buffer =");
+  buffer()->ShortPrint(out);
+  PrintF(out, "\n - byte_offset = ");
+  byte_offset()->ShortPrint(out);
+  PrintF(out, "\n - byte_length = ");
+  byte_length()->ShortPrint(out);
+  PrintF(out, " - length = ");
+  length()->ShortPrint(out);
+  PrintF("\n");
+  PrintElements(out);
+}
+
+
 void JSFunction::JSFunctionPrint(FILE* out) {
   HeapObject::PrintHeader(out, "Function");
   PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
index 7c17b36..7b5c8be 100644 (file)
@@ -146,6 +146,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
     case JS_BUILTINS_OBJECT_TYPE:
     case JS_MESSAGE_OBJECT_TYPE:
     case JS_ARRAY_BUFFER_TYPE:
+    case JS_TYPED_ARRAY_TYPE:
       return GetVisitorIdForSize(kVisitJSObject,
                                  kVisitJSObjectGeneric,
                                  instance_size);
index a39c75b..33be173 100644 (file)
@@ -1556,6 +1556,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size,
     case JS_DATE_TYPE:
     case JS_ARRAY_TYPE:
     case JS_ARRAY_BUFFER_TYPE:
+    case JS_TYPED_ARRAY_TYPE:
     case JS_SET_TYPE:
     case JS_MAP_TYPE:
     case JS_WEAK_MAP_TYPE:
index d20eba5..898b176 100644 (file)
@@ -57,6 +57,7 @@
 //         - JSObject
 //           - JSArray
 //           - JSArrayBuffer
+//           - JSTypedArray
 //           - JSSet
 //           - JSMap
 //           - JSWeakMap
@@ -403,6 +404,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits;
   V(JS_GLOBAL_PROXY_TYPE)                                                      \
   V(JS_ARRAY_TYPE)                                                             \
   V(JS_ARRAY_BUFFER_TYPE)                                                      \
+  V(JS_TYPED_ARRAY_TYPE)                                                       \
   V(JS_PROXY_TYPE)                                                             \
   V(JS_WEAK_MAP_TYPE)                                                          \
   V(JS_REGEXP_TYPE)                                                            \
@@ -735,6 +737,7 @@ enum InstanceType {
   JS_GLOBAL_PROXY_TYPE,
   JS_ARRAY_TYPE,
   JS_ARRAY_BUFFER_TYPE,
+  JS_TYPED_ARRAY_TYPE,
   JS_SET_TYPE,
   JS_MAP_TYPE,
   JS_WEAK_MAP_TYPE,
@@ -982,6 +985,7 @@ class MaybeObject BASE_EMBEDDED {
   V(Boolean)                                   \
   V(JSArray)                                   \
   V(JSArrayBuffer)                             \
+  V(JSTypedArray)                              \
   V(JSProxy)                                   \
   V(JSFunctionProxy)                           \
   V(JSSet)                                     \
@@ -8559,6 +8563,38 @@ class JSArrayBuffer: public JSObject {
 };
 
 
+class JSTypedArray: public JSObject {
+ public:
+  // [buffer]: ArrayBuffer that this typed array views.
+  DECL_ACCESSORS(buffer, Object)
+
+  // [byte_length]: offset of typed array in bytes.
+  DECL_ACCESSORS(byte_offset, Object)
+
+  // [byte_length]: length of typed array in bytes.
+  DECL_ACCESSORS(byte_length, Object)
+
+  // [length]: length of typed array in elements.
+  DECL_ACCESSORS(length, Object)
+
+  // Casting.
+  static inline JSTypedArray* cast(Object* obj);
+
+  // Dispatched behavior.
+  DECLARE_PRINTER(JSTypedArray)
+  DECLARE_VERIFIER(JSTypedArray)
+
+  static const int kBufferOffset = JSObject::kHeaderSize;
+  static const int kByteOffsetOffset = kBufferOffset + kPointerSize;
+  static const int kByteLengthOffset = kByteOffsetOffset + kPointerSize;
+  static const int kLengthOffset = kByteLengthOffset + kPointerSize;
+  static const int kSize = kLengthOffset + kPointerSize;
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray);
+};
+
+
 // Foreign describes objects pointing from JavaScript to C structures.
 // Since they cannot contain references to JS HeapObjects they can be
 // placed in old_data_space.
index 843b8d7..dffa959 100644 (file)
@@ -61,6 +61,7 @@
 #include "string-search.h"
 #include "stub-cache.h"
 #include "uri.h"
+#include "v8conversions.h"
 #include "v8threads.h"
 #include "vm-state-inl.h"
 
@@ -638,19 +639,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
 }
 
 
-static size_t ArrayBufferAllocatedLength(Isolate* isolate,
-                                         JSArrayBuffer* buffer) {
-  NoHandleAllocation hc(isolate);
-  Object* byte_length = buffer->byte_length();
-  if (byte_length->IsSmi()) {
-    return Smi::cast(byte_length)->value();
-  } else {
-    double value = HeapNumber::cast(byte_length)->value();
-    return static_cast<size_t>(value);
-  }
-}
-
-
 static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
                                     Persistent<Value> object,
                                     void* data) {
@@ -658,8 +646,8 @@ static void ArrayBufferWeakCallback(v8::Isolate* external_isolate,
   HandleScope scope(isolate);
   Handle<Object> internal_object = Utils::OpenHandle(*object);
 
-  size_t allocated_length = ArrayBufferAllocatedLength(
-      isolate, JSArrayBuffer::cast(*internal_object));
+  size_t allocated_length = NumberToSize(
+      isolate, JSArrayBuffer::cast(*internal_object)->byte_length());
   isolate->heap()->AdjustAmountOfExternalAllocatedMemory(
       -static_cast<intptr_t>(allocated_length));
   if (data != NULL)
@@ -744,12 +732,12 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
   CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
   CONVERT_DOUBLE_ARG_CHECKED(first, 2);
   size_t start = static_cast<size_t>(first);
-  size_t target_length = ArrayBufferAllocatedLength(isolate, *target);
+  size_t target_length = NumberToSize(isolate, target->byte_length());
 
   if (target_length == 0)
     return isolate->heap()->undefined_value();
 
-  ASSERT(ArrayBufferAllocatedLength(isolate, *source) - target_length >= start);
+  ASSERT(NumberToSize(isolate, source->byte_length()) - target_length >= start);
   uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
   uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
   CopyBytes(target_data, source_data + start, target_length);
@@ -757,6 +745,114 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) {
 }
 
 
+enum TypedArrayId {
+  // arrayIds below should be synchromized with typedarray.js natives.
+  ARRAY_ID_UINT8 = 1,
+  ARRAY_ID_INT8 = 2,
+  ARRAY_ID_UINT16 = 3,
+  ARRAY_ID_INT16 = 4,
+  ARRAY_ID_UINT32 = 5,
+  ARRAY_ID_INT32 = 6,
+  ARRAY_ID_FLOAT32 = 7,
+  ARRAY_ID_FLOAT64 = 8
+};
+
+
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayInitialize) {
+  HandleScope scope(isolate);
+  ASSERT(args.length() == 5);
+  CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
+  CONVERT_SMI_ARG_CHECKED(arrayId, 1);
+  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 2);
+  CONVERT_ARG_HANDLE_CHECKED(Object, byte_offset_object, 3);
+  CONVERT_ARG_HANDLE_CHECKED(Object, byte_length_object, 4);
+
+  ExternalArrayType arrayType;
+  ElementsKind elementsKind;
+  size_t elementSize;
+  switch (arrayId) {
+    case ARRAY_ID_UINT8:
+      elementsKind = EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
+      arrayType = kExternalUnsignedByteArray;
+      elementSize = 1;
+      break;
+    case ARRAY_ID_INT8:
+      elementsKind = EXTERNAL_BYTE_ELEMENTS;
+      arrayType = kExternalByteArray;
+      elementSize = 1;
+      break;
+    case ARRAY_ID_UINT16:
+      elementsKind = EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
+      arrayType = kExternalUnsignedShortArray;
+      elementSize = 2;
+      break;
+    case ARRAY_ID_INT16:
+      elementsKind = EXTERNAL_SHORT_ELEMENTS;
+      arrayType = kExternalShortArray;
+      elementSize = 2;
+      break;
+    case ARRAY_ID_UINT32:
+      elementsKind = EXTERNAL_UNSIGNED_INT_ELEMENTS;
+      arrayType = kExternalUnsignedIntArray;
+      elementSize = 4;
+      break;
+    case ARRAY_ID_INT32:
+      elementsKind = EXTERNAL_INT_ELEMENTS;
+      arrayType = kExternalIntArray;
+      elementSize = 4;
+      break;
+    case ARRAY_ID_FLOAT32:
+      elementsKind = EXTERNAL_FLOAT_ELEMENTS;
+      arrayType = kExternalFloatArray;
+      elementSize = 4;
+      break;
+    case ARRAY_ID_FLOAT64:
+      elementsKind = EXTERNAL_DOUBLE_ELEMENTS;
+      arrayType = kExternalDoubleArray;
+      elementSize = 8;
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  holder->set_buffer(*buffer);
+  holder->set_byte_offset(*byte_offset_object);
+  holder->set_byte_length(*byte_length_object);
+
+  size_t byte_offset = NumberToSize(isolate, *byte_offset_object);
+  size_t byte_length = NumberToSize(isolate, *byte_length_object);
+  ASSERT(byte_length % elementSize == 0);
+  size_t length = byte_length / elementSize;
+
+  holder->set_length(
+      *isolate->factory()->NewNumber(static_cast<double>(length)));
+  Handle<ExternalArray> elements =
+      isolate->factory()->NewExternalArray(
+          length, arrayType,
+          static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
+  Handle<Map> map =
+      isolate->factory()->GetElementsTransitionMap(holder, elementsKind);
+  holder->set_map(*map);
+  holder->set_elements(*elements);
+  return isolate->heap()->undefined_value();
+}
+
+
+#define TYPED_ARRAY_GETTER(getter, accessor) \
+  RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArrayGet##getter) { \
+    HandleScope scope(isolate);                                   \
+    ASSERT(args.length() == 1);                                   \
+    CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);          \
+    return holder->accessor();                                    \
+  }
+
+TYPED_ARRAY_GETTER(Buffer, buffer)
+TYPED_ARRAY_GETTER(ByteLength, byte_length)
+TYPED_ARRAY_GETTER(ByteOffset, byte_offset)
+TYPED_ARRAY_GETTER(Length, length)
+
+#undef TYPED_ARRAY_GETTER
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
   HandleScope scope(isolate);
   ASSERT(args.length() == 1);
index 8a4d6d5..cbf70e9 100644 (file)
@@ -219,6 +219,7 @@ namespace internal {
   F(NumberToExponential, 2, 1) \
   F(NumberToPrecision, 2, 1)
 
+
 #define RUNTIME_FUNCTION_LIST_ALWAYS_2(F) \
   /* Reflection */ \
   F(FunctionSetInstanceClassName, 2, 1) \
@@ -350,6 +351,12 @@ namespace internal {
   F(ArrayBufferGetByteLength, 1, 1)\
   F(ArrayBufferSliceImpl, 3, 1) \
   \
+  F(TypedArrayInitialize, 5, 1) \
+  F(TypedArrayGetBuffer, 1, 1) \
+  F(TypedArrayGetByteLength, 1, 1) \
+  F(TypedArrayGetByteOffset, 1, 1) \
+  F(TypedArrayGetLength, 1, 1) \
+  \
   /* Statements */ \
   F(NewClosure, 3, 1) \
   F(NewObject, 1, 1) \
index 2a71543..24fcf1e 100644 (file)
@@ -82,14 +82,74 @@ function ArrayBufferSlice(start, end) {
   return result;
 }
 
+// --------------- Typed Arrays ---------------------
+
+function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
+  return function (buffer, byteOffset, length) {
+    if (%_IsConstructCall()) {
+      if (!IS_ARRAYBUFFER(buffer)) {
+        throw MakeTypeError("Type error!");
+      }
+      var offset = IS_UNDEFINED(byteOffset)
+        ? 0 : offset = TO_POSITIVE_INTEGER(byteOffset);
+
+      if (offset % elementSize !== 0) {
+        throw MakeRangeError("invalid_typed_array_alignment",
+            "start offset", name, elementSize);
+      }
+      var bufferByteLength = %ArrayBufferGetByteLength(buffer);
+      if (offset >= bufferByteLength) {
+        throw MakeRangeError("invalid_typed_array_offset");
+      }
+
+      var newByteLength;
+      var newLength;
+      if (IS_UNDEFINED(length)) {
+        if (bufferByteLength % elementSize !== 0) {
+          throw MakeRangeError("invalid_typed_array_alignment",
+            "byte length", name, elementSize);
+        }
+        newByteLength = bufferByteLength - offset;
+        newLength = newByteLength / elementSize;
+      } else {
+        var newLength = TO_POSITIVE_INTEGER(length);
+        newByteLength = newLength * elementSize;
+      }
+      if (newByteLength > bufferByteLength) {
+        throw MakeRangeError("invalid_typed_array_length");
+      }
+      %TypedArrayInitialize(this, arrayId, buffer, offset, newByteLength);
+    } else {
+      return new constructor(buffer, byteOffset, length);
+    }
+  }
+}
+
+function TypedArrayGetBuffer() {
+  return %TypedArrayGetBuffer(this);
+}
+
+function TypedArrayGetByteLength() {
+  return %TypedArrayGetByteLength(this);
+}
+
+function TypedArrayGetByteOffset() {
+  return %TypedArrayGetByteOffset(this);
+}
+
+function TypedArrayGetLength() {
+  return %TypedArrayGetLength(this);
+}
+
 
 // -------------------------------------------------------------------
 
 function SetUpArrayBuffer() {
   %CheckIsBootstrapping();
 
-  // Set up the Uint16Array constructor function.
+  // Set up the ArrayBuffer constructor function.
   %SetCode($ArrayBuffer, ArrayBufferConstructor);
+  %FunctionSetPrototype($ArrayBuffer, new $Object());
 
   // Set up the constructor property on the ArrayBuffer prototype object.
   %SetProperty($ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM);
@@ -102,3 +162,31 @@ function SetUpArrayBuffer() {
 }
 
 SetUpArrayBuffer();
+
+function SetupTypedArray(arrayId, name, constructor, elementSize) {
+  var f = CreateTypedArrayConstructor(name, elementSize,
+                                      arrayId, constructor);
+  %SetCode(constructor, f);
+  %FunctionSetPrototype(constructor, new $Object());
+
+  %SetProperty(constructor.prototype,
+               "constructor", constructor, DONT_ENUM);
+  %SetProperty(constructor.prototype,
+               "BYTES_PER_ELEMENT", elementSize,
+               READ_ONLY | DONT_ENUM | DONT_DELETE);
+  InstallGetter(constructor.prototype, "buffer", TypedArrayGetBuffer);
+  InstallGetter(constructor.prototype, "byteOffset", TypedArrayGetByteOffset);
+  InstallGetter(constructor.prototype, "byteLength", TypedArrayGetByteLength);
+  InstallGetter(constructor.prototype, "length", TypedArrayGetLength);
+}
+
+// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
+SetupTypedArray(1, "Uint8Array", global.__Uint8Array, 1);
+SetupTypedArray(2, "Int8Array", global.__Int8Array, 1);
+SetupTypedArray(3, "Uint16Array", global.__Uint16Array, 2);
+SetupTypedArray(4, "Int16Array", global.__Int16Array, 2);
+SetupTypedArray(5, "Uint32Array", global.__Uint32Array, 4);
+SetupTypedArray(6, "Int32Array", global.__Int32Array, 4);
+SetupTypedArray(7, "Float32Array", global.__Float32Array, 4);
+SetupTypedArray(8, "Float64Array", global.__Float64Array, 8);
+
index 0147d8c..9d618af 100644 (file)
@@ -55,6 +55,19 @@ double StringToDouble(UnicodeCache* unicode_cache,
 // Converts a string into an integer.
 double StringToInt(UnicodeCache* unicode_cache, String* str, int radix);
 
+// Converts a number into size_t.
+inline size_t NumberToSize(Isolate* isolate,
+                           Object* number) {
+  NoHandleAllocation hc(isolate);
+  if (number->IsSmi()) {
+    return Smi::cast(number)->value();
+  } else {
+    ASSERT(number->IsHeapNumber());
+    double value = HeapNumber::cast(number)->value();
+    return static_cast<size_t>(value);
+  }
+}
+
 } }  // namespace v8::internal
 
 #endif  // V8_V8CONVERSIONS_H_
index 9b01ba6..75ff3da 100644 (file)
@@ -27,6 +27,8 @@
 
 // Flags: --harmony-typed-arrays
 
+// ArrayBuffer
+
 function TestByteLength(param, expectedByteLength) {
   var ab = new __ArrayBuffer(param);
   assertSame(expectedByteLength, ab.byteLength);
@@ -104,8 +106,98 @@ function TestArrayBufferSlice() {
 
 TestArrayBufferSlice();
 
+// Typed arrays
+
+function TestTypedArray(proto, elementSize, typicalElement) {
+  var ab = new __ArrayBuffer(256*elementSize);
+
+  var a1 = new proto(ab, 128*elementSize, 128);
+  assertSame(ab, a1.buffer);
+  assertSame(elementSize, a1.BYTES_PER_ELEMENT);
+  assertSame(128, a1.length);
+  assertSame(128*elementSize, a1.byteLength);
+  assertSame(128*elementSize, a1.byteOffset);
+
+
+  var a2 = new proto(ab, 64*elementSize, 128);
+  assertSame(ab, a2.buffer);
+  assertSame(elementSize, a2.BYTES_PER_ELEMENT);
+  assertSame(128, a2.length);
+  assertSame(128*elementSize, a2.byteLength);
+  assertSame(64*elementSize, a2.byteOffset);
+
+  var a3 = new proto(ab, 192*elementSize);
+  assertSame(ab, a3.buffer);
+  assertSame(64, a3.length);
+  assertSame(64*elementSize, a3.byteLength);
+  assertSame(192*elementSize, a3.byteOffset);
+
+  var a4 = new proto(ab);
+  assertSame(ab, a4.buffer);
+  assertSame(256, a4.length);
+  assertSame(256*elementSize, a4.byteLength);
+  assertSame(0, a4.byteOffset);
+
+
+  var i;
+  for (i = 0; i < 128; i++) {
+    a1[i] = typicalElement;
+  }
+
+  for (i = 0; i < 128; i++) {
+    assertSame(typicalElement, a1[i]);
+  }
+
+  for (i = 0; i < 64; i++) {
+    assertSame(0, a2[i]);
+  }
+
+  for (i = 64; i < 128; i++) {
+    assertSame(typicalElement, a2[i]);
+  }
+
+  for (i = 0; i < 64; i++) {
+    assertSame(typicalElement, a3[i]);
+  }
+
+  for (i = 0; i < 128; i++) {
+    assertSame(0, a4[i]);
+  }
+
+  for (i = 128; i < 256; i++) {
+    assertSame(typicalElement, a4[i]);
+  }
+
+  assertThrows(function () { new proto(ab, 256*elementSize); }, RangeError);
+
+  if (elementSize !== 1) {
+    assertThrows(function() { new proto(ab, 128*elementSize - 1, 10); },
+                 RangeError);
+    var unalignedArrayBuffer = new __ArrayBuffer(10*elementSize + 1);
+    var goodArray = new proto(unalignedArrayBuffer, 0, 10);
+    assertSame(10, goodArray.length);
+    assertSame(10*elementSize, goodArray.byteLength);
+    assertThrows(function() { new proto(unalignedArrayBuffer)}, RangeError);
+    assertThrows(function() { new proto(unalignedArrayBuffer, 5*elementSize)},
+                 RangeError);
+  }
+
+}
+
+TestTypedArray(__Uint8Array, 1, 0xFF);
+TestTypedArray(__Int8Array, 1, -0x7F);
+TestTypedArray(__Uint16Array, 2, 0xFFFF);
+TestTypedArray(__Int16Array, 2, -0x7FFF);
+TestTypedArray(__Uint32Array, 4, 0xFFFFFFFF);
+TestTypedArray(__Int32Array, 4, -0x7FFFFFFF);
+TestTypedArray(__Float32Array, 4, 0.5);
+TestTypedArray(__Float64Array, 8, 0.5);
+
+
+// General tests for properties
+
 // Test property attribute [[Enumerable]]
-function TestEnumerable(func) {
+function TestEnumerable(func, obj) {
   function props(x) {
     var array = [];
     for (var p in x) array.push(p);
@@ -113,9 +205,11 @@ function TestEnumerable(func) {
   }
   assertArrayEquals([], props(func));
   assertArrayEquals([], props(func.prototype));
-  assertArrayEquals([], props(new func()));
+  if (obj)
+    assertArrayEquals([], props(obj));
 }
-TestEnumerable(__ArrayBuffer);
+TestEnumerable(__ArrayBuffer, new __ArrayBuffer());
+TestEnumerable(__Uint8Array);
 
 
 // Test arbitrary properties on ArrayBuffer
@@ -131,6 +225,5 @@ function TestArbitrary(m) {
 }
 TestArbitrary(new __ArrayBuffer(256));
 
-
 // Test direct constructor call
 assertTrue(__ArrayBuffer() instanceof __ArrayBuffer);