From 944c577c7b171cb26617eb3b2cfa33c6ea17af30 Mon Sep 17 00:00:00 2001 From: "dslomov@chromium.org" Date: Thu, 28 Mar 2013 12:50:18 +0000 Subject: [PATCH] First steps towards implementing ArrayBuffer &co in V8 BUG= Review URL: https://codereview.chromium.org/13064003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14091 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/bootstrapper.cc | 15 ++++ src/flag-definitions.h | 3 + src/macros.py | 2 + src/messages.js | 1 + src/objects-debug.cc | 11 +++ src/objects-inl.h | 19 +++++ src/objects-printer.cc | 12 ++++ src/objects-visiting.cc | 1 + src/objects.cc | 1 + src/objects.h | 28 ++++++++ src/runtime.cc | 137 ++++++++++++++++++++++++++++++++++++ src/runtime.h | 6 ++ src/typedarray.js | 98 ++++++++++++++++++++++++++ test/mjsunit/harmony/typedarrays.js | 136 +++++++++++++++++++++++++++++++++++ tools/gyp/v8.gyp | 3 +- 15 files changed, 472 insertions(+), 1 deletion(-) create mode 100644 src/typedarray.js create mode 100644 test/mjsunit/harmony/typedarrays.js diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 380c81e..f57a1f6 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1311,6 +1311,16 @@ void Genesis::InitializeExperimentalGlobal() { prototype, Builtins::kIllegal, true); } } + + if (FLAG_harmony_typed_arrays) { + { // -- A r r a y B u f f e r + Handle prototype = + factory()->NewJSObject(isolate()->object_function(), TENURED); + InstallFunction(global, "__ArrayBuffer", JS_ARRAY_BUFFER_TYPE, + JSArrayBuffer::kSize, prototype, + Builtins::kIllegal, true); + } + } } @@ -1918,6 +1928,11 @@ bool Genesis::InstallExperimentalNatives() { "native object-observe.js") == 0) { if (!CompileExperimentalBuiltin(isolate(), i)) return false; } + if (FLAG_harmony_typed_arrays && + strcmp(ExperimentalNatives::GetScriptName(i).start(), + "native typedarray.js") == 0) { + if (!CompileExperimentalBuiltin(isolate(), i)) return false; + } } InstallExperimentalNativeFunctions(); diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 06d114f..db36183 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -148,6 +148,8 @@ DEFINE_bool(harmony_collections, false, "enable harmony collections (sets, maps, and weak maps)") DEFINE_bool(harmony_observation, false, "enable harmony object observation (implies harmony collections") +DEFINE_bool(harmony_typed_arrays, false, + "enable harmony typed arrays") DEFINE_bool(harmony, false, "enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) @@ -157,6 +159,7 @@ DEFINE_implication(harmony, harmony_collections) DEFINE_implication(harmony, harmony_observation) DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_implication(harmony_observation, harmony_collections) +DEFINE_implication(harmony, harmony_typed_arrays) // Flags for experimental implementation features. DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes") diff --git a/src/macros.py b/src/macros.py index 52e87fc..92ed437 100644 --- a/src/macros.py +++ b/src/macros.py @@ -116,6 +116,7 @@ macro IS_ERROR(arg) = (%_ClassOf(arg) === 'Error'); macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script'); macro IS_ARGUMENTS(arg) = (%_ClassOf(arg) === 'Arguments'); macro IS_GLOBAL(arg) = (%_ClassOf(arg) === 'global'); +macro IS_ARRAYBUFFER(arg) = (%_ClassOf(arg) === '__ArrayBuffer'); macro IS_UNDETECTABLE(arg) = (%_IsUndetectableObject(arg)); macro FLOOR(arg) = $floor(arg); @@ -142,6 +143,7 @@ const kBoundArgumentsStartIndex = 2; macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg)); macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0))); macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg))); +macro TO_POSITIVE_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? (arg > 0 ? arg : 0) : %NumberToPositiveInteger(ToNumber(arg))); macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg))); macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0)); macro TO_UINT32(arg) = (arg >>> 0); diff --git a/src/messages.js b/src/messages.js index d03628a..d51d384 100644 --- a/src/messages.js +++ b/src/messages.js @@ -100,6 +100,7 @@ var kMessages = { observe_notify_non_notifier: ["notify called on non-notifier object"], // RangeError invalid_array_length: ["Invalid array length"], + invalid_array_buffer_length: ["Invalid array buffer length"], 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 92867db..44cab53 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -195,6 +195,9 @@ void HeapObject::HeapObjectVerify() { case JS_MESSAGE_OBJECT_TYPE: JSMessageObject::cast(this)->JSMessageObjectVerify(); break; + case JS_ARRAY_BUFFER_TYPE: + JSArrayBuffer::cast(this)->JSArrayBufferVerify(); + break; #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: \ @@ -712,6 +715,14 @@ void JSFunctionProxy::JSFunctionProxyVerify() { VerifyPointer(construct_trap()); } +void JSArrayBuffer::JSArrayBufferVerify() { + CHECK(IsJSArrayBuffer()); + JSObjectVerify(); + VerifyPointer(byte_length()); + CHECK(byte_length()->IsSmi() || byte_length()->IsHeapNumber() + || byte_length()->IsUndefined()); +} + void Foreign::ForeignVerify() { CHECK(IsForeign()); diff --git a/src/objects-inl.h b/src/objects-inl.h index 5c84880..61e9101 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -674,6 +674,7 @@ bool Object::IsBoolean() { TYPE_CHECKER(JSArray, JS_ARRAY_TYPE) +TYPE_CHECKER(JSArrayBuffer, JS_ARRAY_BUFFER_TYPE) TYPE_CHECKER(JSRegExp, JS_REGEXP_TYPE) @@ -1562,6 +1563,8 @@ int JSObject::GetHeaderSize() { return JSDate::kSize; case JS_ARRAY_TYPE: return JSArray::kSize; + case JS_ARRAY_BUFFER_TYPE: + return JSArrayBuffer::kSize; case JS_SET_TYPE: return JSSet::kSize; case JS_MAP_TYPE: @@ -2448,6 +2451,7 @@ CAST_ACCESSOR(JSGlobalObject) CAST_ACCESSOR(JSBuiltinsObject) CAST_ACCESSOR(Code) CAST_ACCESSOR(JSArray) +CAST_ACCESSOR(JSArrayBuffer) CAST_ACCESSOR(JSRegExp) CAST_ACCESSOR(JSProxy) CAST_ACCESSOR(JSFunctionProxy) @@ -5131,6 +5135,21 @@ bool Code::contains(byte* inner_pointer) { ACCESSORS(JSArray, length, Object, kLengthOffset) +void* JSArrayBuffer::backing_store() { + intptr_t ptr = READ_INTPTR_FIELD(this, kBackingStoreOffset); + return reinterpret_cast(ptr); +} + + +void JSArrayBuffer::set_backing_store(void* value, WriteBarrierMode mode) { + intptr_t ptr = reinterpret_cast(value); + WRITE_INTPTR_FIELD(this, kBackingStoreOffset, ptr); +} + + +ACCESSORS(JSArrayBuffer, byte_length, Object, kByteLengthOffset) + + ACCESSORS(JSRegExp, data, Object, kDataOffset) diff --git a/src/objects-printer.cc b/src/objects-printer.cc index 86382e1..8342232 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -184,6 +184,8 @@ void HeapObject::HeapObjectPrint(FILE* out) { case JS_GLOBAL_PROPERTY_CELL_TYPE: JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out); break; + case JS_ARRAY_BUFFER_TYPE: + JSArrayBuffer::cast(this)->JSArrayBufferPrint(out); #define MAKE_STRUCT_CASE(NAME, Name, name) \ case NAME##_TYPE: \ Name::cast(this)->Name##Print(out); \ @@ -795,6 +797,16 @@ void JSWeakMap::JSWeakMapPrint(FILE* out) { } +void JSArrayBuffer::JSArrayBufferPrint(FILE* out) { + HeapObject::PrintHeader(out, "JSArrayBuffer"); + PrintF(out, " - map = 0x%p\n", reinterpret_cast(map())); + PrintF(out, " - backing_store = -0x%p\n", backing_store()); + PrintF(out, " - byte_length = "); + byte_length()->ShortPrint(out); + PrintF(out, "\n"); +} + + 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 4fe0624..fa53562 100644 --- a/src/objects-visiting.cc +++ b/src/objects-visiting.cc @@ -144,6 +144,7 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( case JS_GLOBAL_OBJECT_TYPE: case JS_BUILTINS_OBJECT_TYPE: case JS_MESSAGE_OBJECT_TYPE: + case JS_ARRAY_BUFFER_TYPE: return GetVisitorIdForSize(kVisitJSObject, kVisitJSObjectGeneric, instance_size); diff --git a/src/objects.cc b/src/objects.cc index 4192911..332e9f7 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1546,6 +1546,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case JS_VALUE_TYPE: case JS_DATE_TYPE: case JS_ARRAY_TYPE: + case JS_ARRAY_BUFFER_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 e81966c..bd3a284 100644 --- a/src/objects.h +++ b/src/objects.h @@ -56,6 +56,7 @@ // - JSReceiver (suitable for property access) // - JSObject // - JSArray +// - JSArrayBuffer // - JSSet // - JSMap // - JSWeakMap @@ -399,6 +400,7 @@ const int kStubMinorKeyBits = kBitsPerInt - kSmiTagSize - kStubMajorKeyBits; V(JS_BUILTINS_OBJECT_TYPE) \ V(JS_GLOBAL_PROXY_TYPE) \ V(JS_ARRAY_TYPE) \ + V(JS_ARRAY_BUFFER_TYPE) \ V(JS_PROXY_TYPE) \ V(JS_WEAK_MAP_TYPE) \ V(JS_REGEXP_TYPE) \ @@ -729,6 +731,7 @@ enum InstanceType { JS_BUILTINS_OBJECT_TYPE, JS_GLOBAL_PROXY_TYPE, JS_ARRAY_TYPE, + JS_ARRAY_BUFFER_TYPE, JS_SET_TYPE, JS_MAP_TYPE, JS_WEAK_MAP_TYPE, @@ -974,6 +977,7 @@ class MaybeObject BASE_EMBEDDED { V(Foreign) \ V(Boolean) \ V(JSArray) \ + V(JSArrayBuffer) \ V(JSProxy) \ V(JSFunctionProxy) \ V(JSSet) \ @@ -8472,6 +8476,30 @@ class JSWeakMap: public JSObject { }; +class JSArrayBuffer: public JSObject { + public: + // [backing_store]: backing memory for thsi array + DECL_ACCESSORS(backing_store, void) + + // [byte_length]: length in bytes + DECL_ACCESSORS(byte_length, Object) + + // Casting. + static inline JSArrayBuffer* cast(Object* obj); + + // Dispatched behavior. + DECLARE_PRINTER(JSArrayBuffer) + DECLARE_VERIFIER(JSArrayBuffer) + + static const int kBackingStoreOffset = JSObject::kHeaderSize; + static const int kByteLengthOffset = kBackingStoreOffset + kPointerSize; + static const int kSize = kByteLengthOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer); +}; + + // 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 71c7c0b..d8c9c27 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -26,6 +26,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include #include "v8.h" @@ -778,6 +779,124 @@ 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) { + Isolate* isolate = reinterpret_cast(external_isolate); + HandleScope scope(isolate); + Handle internal_object = Utils::OpenHandle(*object); + + size_t allocated_length = ArrayBufferAllocatedLength( + isolate, JSArrayBuffer::cast(*internal_object)); + isolate->heap()->AdjustAmountOfExternalAllocatedMemory(-allocated_length); + if (data != NULL) + free(data); + object.Dispose(external_isolate); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferInitialize) { + HandleScope scope(isolate); + ASSERT(args.length() == 2); + CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0); + CONVERT_ARG_HANDLE_CHECKED(Object, byteLength, 1); + size_t allocated_length; + if (byteLength->IsSmi()) { + allocated_length = Smi::cast(*byteLength)->value(); + } else { + ASSERT(byteLength->IsHeapNumber()); + double value = HeapNumber::cast(*byteLength)->value(); + + ASSERT(value >= 0); + + if (value > std::numeric_limits::max()) { + return isolate->Throw( + *isolate->factory()->NewRangeError("invalid_array_buffer_length", + HandleVector(NULL, 0))); + } + + allocated_length = static_cast(value); + } + + void* data; + if (allocated_length != 0) { + data = malloc(allocated_length); + + if (data == NULL) { + return isolate->Throw(*isolate->factory()-> + NewRangeError("invalid_array_buffer_length", + HandleVector(NULL, 0))); + } + + memset(data, 0, allocated_length); + } else { + data = NULL; + } + holder->set_backing_store(data); + + Object* byte_length; + { + MaybeObject* maybe_byte_length = + isolate->heap()->NumberFromDouble(allocated_length); + if (!maybe_byte_length->ToObject(&byte_length)) return maybe_byte_length; + } + CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber()); + holder->set_byte_length(byte_length); + + v8::Isolate* external_isolate = reinterpret_cast(isolate); + v8::Handle external_holder(*holder); + Persistent weak_handle = Persistent::New( + external_isolate, external_holder); + weak_handle.MakeWeak(external_isolate, data, ArrayBufferWeakCallback); + weak_handle.MarkIndependent(external_isolate); + isolate->heap()->AdjustAmountOfExternalAllocatedMemory(allocated_length); + + return *holder; +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferGetByteLength) { + NoHandleAllocation ha(isolate); + ASSERT(args.length() == 1); + CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0); + return holder->byte_length(); +} + + +RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayBufferSliceImpl) { + HandleScope scope(isolate); + ASSERT(args.length() == 3); + CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0); + CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1); + CONVERT_DOUBLE_ARG_CHECKED(first, 2); + size_t start = static_cast(first); + size_t source_length = ArrayBufferAllocatedLength(isolate, *source); + size_t target_length = ArrayBufferAllocatedLength(isolate, *target); + + if (target_length == 0) + return isolate->heap()->undefined_value(); + + ASSERT(source_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); + return isolate->heap()->undefined_value(); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) { HandleScope scope(isolate); ASSERT(args.length() == 1); @@ -5798,6 +5917,24 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) { } +// ES6 draft 9.1.11 +RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPositiveInteger) { + NoHandleAllocation ha(isolate); + ASSERT(args.length() == 1); + + CONVERT_DOUBLE_ARG_CHECKED(number, 0); + + // We do not include 0 so that we don't have to treat +0 / -0 cases. + if (number > 0 && number <= Smi::kMaxValue) { + return Smi::FromInt(static_cast(number)); + } + if (number <= 0) { + return Smi::FromInt(0); + } + return isolate->heap()->NumberFromDouble(DoubleToInteger(number)); +} + + RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) { NoHandleAllocation ha(isolate); ASSERT(args.length() == 1); diff --git a/src/runtime.h b/src/runtime.h index c3f241e..b16acd1 100644 --- a/src/runtime.h +++ b/src/runtime.h @@ -129,6 +129,7 @@ namespace internal { F(NumberToString, 1, 1) \ F(NumberToStringSkipCache, 1, 1) \ F(NumberToInteger, 1, 1) \ + F(NumberToPositiveInteger, 1, 1) \ F(NumberToIntegerMapMinusZero, 1, 1) \ F(NumberToJSUint32, 1, 1) \ F(NumberToJSInt32, 1, 1) \ @@ -340,6 +341,11 @@ namespace internal { F(ObservationWeakMapCreate, 0, 1) \ F(UnwrapGlobalProxy, 1, 1) \ \ + /* Harmony typed arrays */ \ + F(ArrayBufferInitialize, 2, 1)\ + F(ArrayBufferGetByteLength, 1, 1)\ + F(ArrayBufferSliceImpl, 3, 1) \ + \ /* Statements */ \ F(NewClosure, 3, 1) \ F(NewObject, 1, 1) \ diff --git a/src/typedarray.js b/src/typedarray.js new file mode 100644 index 0000000..c3e3ebd --- /dev/null +++ b/src/typedarray.js @@ -0,0 +1,98 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +"use strict"; + +var $ArrayBuffer = global.__ArrayBuffer; + +function ArrayBufferConstructor(byteLength) { // length = 1 + if (%_IsConstructCall()) { + var l = TO_POSITIVE_INTEGER(byteLength); + %ArrayBufferInitialize(this, l); + } else { + return new $ArrayBuffer(byteLength); + } +} + +function ArrayBufferGetByteLength() { + if (!IS_ARRAYBUFFER(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['ArrayBuffer.prototype.byteLength', this]); + } + return %ArrayBufferGetByteLength(this); +} + +// ES6 Draft 15.13.5.5.3 +function ArrayBufferSlice(start, end) { + if (!IS_ARRAYBUFFER(this)) { + throw MakeTypeError('incompatible_method_receiver', + ['ArrayBuffer.prototype.slice', this]); + } + + var relativeStart = TO_INTEGER(start); + var first; + if (relativeStart < 0) { + first = MathMax(this.byteLength + relativeStart, 0); + } else { + first = MathMin(relativeStart, this.byteLength); + } + var relativeEnd = IS_UNDEFINED(end) ? this.byteLength : TO_INTEGER(end); + var fin; + if (relativeEnd < 0) { + fin = MathMax(this.byteLength + relativeEnd, 0); + } else { + fin = MathMin(relativeEnd, this.byteLength); + } + + var newLen = fin - first; + // TODO(dslomov): implement inheritance + var result = new $ArrayBuffer(newLen); + + %ArrayBufferSliceImpl(this, result, first); + return result; +} + + + +// ------------------------------------------------------------------- + +(function () { + %CheckIsBootstrapping(); + + // Set up the Uint16Array constructor function. + %SetCode($ArrayBuffer, ArrayBufferConstructor); + + // Set up the constructor property on the ArrayBuffer prototype object. + %SetProperty($ArrayBuffer.prototype, "constructor", $ArrayBuffer, DONT_ENUM); + + InstallGetter($ArrayBuffer.prototype, "byteLength", ArrayBufferGetByteLength); + + InstallFunctions($ArrayBuffer.prototype, DONT_ENUM, $Array( + "slice", ArrayBufferSlice + )); + +})(); diff --git a/test/mjsunit/harmony/typedarrays.js b/test/mjsunit/harmony/typedarrays.js new file mode 100644 index 0000000..9b01ba6 --- /dev/null +++ b/test/mjsunit/harmony/typedarrays.js @@ -0,0 +1,136 @@ +// Copyright 2013 the V8 project authors. All rights reserved. +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Flags: --harmony-typed-arrays + +function TestByteLength(param, expectedByteLength) { + var ab = new __ArrayBuffer(param); + assertSame(expectedByteLength, ab.byteLength); +} + +function TestArrayBufferCreation() { + TestByteLength(1, 1); + TestByteLength(256, 256); + TestByteLength(-10, 0); + TestByteLength(2.567, 2); + TestByteLength(-2.567, 0); + + TestByteLength("abc", 0); + + TestByteLength(0, 0); + + assertThrows(function() { + var ab1 = new __ArrayBuffer(0xFFFFFFFFFFFF) + }, RangeError); + + var ab = new __ArrayBuffer(); + assertSame(0, ab.byteLength); +} + +TestArrayBufferCreation(); + +function TestByteLengthNotWritable() { + var ab = new __ArrayBuffer(1024); + assertSame(1024, ab.byteLength); + + assertThrows(function() { "use strict"; ab.byteLength = 42; }, TypeError); +} + +TestByteLengthNotWritable(); + +function TestSlice(expectedResultLen, initialLen, start, end) { + var ab = new __ArrayBuffer(initialLen); + var slice = ab.slice(start, end); + assertSame(expectedResultLen, slice.byteLength); +} + +function TestArrayBufferSlice() { + var ab = new __ArrayBuffer(1024); + var ab1 = ab.slice(512, 1024); + assertSame(512, ab1.byteLength); + + TestSlice(512, 1024, 512, 1024); + TestSlice(512, 1024, 512); + + TestSlice(0, 0, 1, 20); + TestSlice(100, 100, 0, 100); + TestSlice(100, 100, 0, 1000); + TestSlice(0, 100, 5, 1); + + TestSlice(1, 100, -11, -10); + TestSlice(9, 100, -10, 99); + TestSlice(0, 100, -10, 80); + TestSlice(10, 100, 80, -10); + + TestSlice(10, 100, 90, "100"); + TestSlice(10, 100, "90", "100"); + + TestSlice(0, 100, 90, "abc"); + TestSlice(10, 100, "abc", 10); + + TestSlice(10, 100, 0.96, 10.96); + TestSlice(10, 100, 0.96, 10.01); + TestSlice(10, 100, 0.01, 10.01); + TestSlice(10, 100, 0.01, 10.96); + + + TestSlice(10, 100, 90); + TestSlice(10, 100, -10); +} + +TestArrayBufferSlice(); + +// Test property attribute [[Enumerable]] +function TestEnumerable(func) { + function props(x) { + var array = []; + for (var p in x) array.push(p); + return array.sort(); + } + assertArrayEquals([], props(func)); + assertArrayEquals([], props(func.prototype)); + assertArrayEquals([], props(new func())); +} +TestEnumerable(__ArrayBuffer); + + +// Test arbitrary properties on ArrayBuffer +function TestArbitrary(m) { + function TestProperty(map, property, value) { + map[property] = value; + assertEquals(value, map[property]); + } + for (var i = 0; i < 20; i++) { + TestProperty(m, i, 'val' + i); + TestProperty(m, 'foo' + i, 'bar' + i); + } +} +TestArbitrary(new __ArrayBuffer(256)); + + +// Test direct constructor call +assertTrue(__ArrayBuffer() instanceof __ArrayBuffer); diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index 2d6eaf9..b117553 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -797,7 +797,8 @@ '../../src/symbol.js', '../../src/proxy.js', '../../src/collection.js', - '../../src/object-observe.js' + '../../src/object-observe.js', + '../../src/typedarray.js' ], }, 'actions': [ -- 2.7.4