From c1a19275d3425621ce1ec2272fd075556cb705a9 Mon Sep 17 00:00:00 2001 From: "dslomov@chromium.org" Date: Tue, 16 Apr 2013 14:16:30 +0000 Subject: [PATCH] First cut at impementing ES6 TypedArrays in V8. 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 --- src/bootstrapper.cc | 21 ++++++ src/messages.js | 3 + src/objects-debug.cc | 25 +++++++ src/objects-inl.h | 10 +++ src/objects-printer.cc | 18 +++++ src/objects-visiting.cc | 1 + src/objects.cc | 1 + src/objects.h | 36 ++++++++++ src/runtime.cc | 130 +++++++++++++++++++++++++++++++----- src/runtime.h | 7 ++ src/typedarray.js | 90 ++++++++++++++++++++++++- src/v8conversions.h | 13 ++++ test/mjsunit/harmony/typedarrays.js | 101 ++++++++++++++++++++++++++-- 13 files changed, 434 insertions(+), 22 deletions(-) diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index df98448..12f0cda 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -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 inner_global, } +void Genesis::InstallTypedArray(const char* name) { + Handle global = Handle(native_context()->global_object()); + InstallFunction(global, name, JS_TYPED_ARRAY_TYPE, + JSTypedArray::kSize, isolate()->initial_object_prototype(), + Builtins::kIllegal, true); +} + + void Genesis::InitializeExperimentalGlobal() { Handle global = Handle(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) { diff --git a/src/messages.js b/src/messages.js index febebfa..67fe3cc 100644 --- a/src/messages.js +++ b/src/messages.js @@ -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 diff --git a/src/objects-debug.cc b/src/objects-debug.cc index bbafa12..24730a0 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -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()); } diff --git a/src/objects-inl.h b/src/objects-inl.h index bffe414..efc1764 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -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) diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 9e1ef63..aa71a96 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -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(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(map())); diff --git a/src/objects-visiting.cc b/src/objects-visiting.cc index 7c17b36..7b5c8be 100644 --- a/src/objects-visiting.cc +++ b/src/objects-visiting.cc @@ -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); diff --git a/src/objects.cc b/src/objects.cc index a39c75b..33be173 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -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: diff --git a/src/objects.h b/src/objects.h index d20eba5..898b176 100644 --- a/src/objects.h +++ b/src/objects.h @@ -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. diff --git a/src/runtime.cc b/src/runtime.cc index 843b8d7..dffa959 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -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(value); - } -} - - static void ArrayBufferWeakCallback(v8::Isolate* external_isolate, Persistent object, void* data) { @@ -658,8 +646,8 @@ static void ArrayBufferWeakCallback(v8::Isolate* external_isolate, HandleScope scope(isolate); Handle 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(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(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(source->backing_store()); uint8_t* target_data = reinterpret_cast(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(length))); + Handle elements = + isolate->factory()->NewExternalArray( + length, arrayType, + static_cast(buffer->backing_store()) + byte_offset); + Handle 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); diff --git a/src/runtime.h b/src/runtime.h index 8a4d6d5..cbf70e9 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -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) \ diff --git a/src/typedarray.js b/src/typedarray.js index 2a71543..24fcf1e 100644 --- a/src/typedarray.js +++ b/src/typedarray.js @@ -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); + diff --git a/src/v8conversions.h b/src/v8conversions.h index 0147d8c..9d618af 100644 --- a/src/v8conversions.h +++ b/src/v8conversions.h @@ -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(value); + } +} + } } // namespace v8::internal #endif // V8_V8CONVERSIONS_H_ diff --git a/test/mjsunit/harmony/typedarrays.js b/test/mjsunit/harmony/typedarrays.js index 9b01ba6..75ff3da 100644 --- a/test/mjsunit/harmony/typedarrays.js +++ b/test/mjsunit/harmony/typedarrays.js @@ -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); -- 2.7.4