From 4308fb462d8a606916808c6d97adb58b3bdbbdd2 Mon Sep 17 00:00:00 2001 From: "dslomov@chromium.org" Date: Mon, 24 Jun 2013 11:23:50 +0000 Subject: [PATCH] API for DataView. R=svenpanne@chromium.org Review URL: https://codereview.chromium.org/17155014 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15282 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8.h | 82 +++++++++++++++--- src/api.cc | 118 +++++++++++++++++--------- src/api.h | 8 ++ test/cctest/test-api.cc | 124 +++++++++++++++++----------- test/cctest/test-weaktypedarrays.cc | 41 +++++---- 5 files changed, 260 insertions(+), 113 deletions(-) diff --git a/include/v8.h b/include/v8.h index 628c5d1af..de3a40ff3 100644 --- a/include/v8.h +++ b/include/v8.h @@ -1361,6 +1361,12 @@ class V8EXPORT Value : public Data { */ bool IsArrayBuffer() const; + /** + * Returns true if this value is an ArrayBufferView. + * This is an experimental feature. + */ + bool IsArrayBufferView() const; + /** * Returns true if this value is one of TypedArrays. * This is an experimental feature. @@ -1421,6 +1427,12 @@ class V8EXPORT Value : public Data { */ bool IsFloat64Array() const; + /** + * Returns true if this value is a DataView. + * This is an experimental feature. + */ + bool IsDataView() const; + Local ToBoolean() const; Local ToNumber() const; Local ToString() const; @@ -2459,33 +2471,51 @@ class V8EXPORT ArrayBuffer : public Object { /** - * A base class for an instance of TypedArray series of constructors - * (ES6 draft 15.13.6). + * A base class for an instance of one of "views" over ArrayBuffer, + * including TypedArrays and DataView (ES6 draft 15.13). + * * This API is experimental and may change significantly. */ -class V8EXPORT TypedArray : public Object { +class V8EXPORT ArrayBufferView : public Object { public: /** * Returns underlying ArrayBuffer. */ Local Buffer(); /** - * Byte offset in |Buffer| + * Byte offset in |Buffer|. */ size_t ByteOffset(); /** - * Numbe of elements in this typed array. - */ - size_t Length(); - /** - * Size of typed array in bytes (e.g. for Int16Array, 2*|Length|). + * Size of a view in bytes. */ size_t ByteLength(); /** - * Base address of typed array. + * Base address of a view. */ void* BaseAddress(); + V8_INLINE(static ArrayBufferView* Cast(Value* obj)); + + private: + ArrayBufferView(); + static void CheckCast(Value* obj); +}; + + +/** + * A base class for an instance of TypedArray series of constructors + * (ES6 draft 15.13.6). + * This API is experimental and may change significantly. + */ +class V8EXPORT TypedArray : public ArrayBufferView { + public: + /** + * Number of elements in this typed array + * (e.g. for Int16Array, |ByteLength|/2). + */ + size_t Length(); + V8_INLINE(static TypedArray* Cast(Value* obj)); private: @@ -2637,6 +2667,22 @@ class V8EXPORT Float64Array : public TypedArray { }; +/** + * An instance of DataView constructor (ES6 draft 15.13.7). + * This API is experimental and may change significantly. + */ +class V8EXPORT DataView : public ArrayBufferView { + public: + static Local New(Handle array_buffer, + size_t byte_offset, size_t length); + V8_INLINE(static DataView* Cast(Value* obj)); + + private: + DataView(); + static void CheckCast(Value* obj); +}; + + /** * An instance of the built-in Date constructor (ECMA-262, 15.9). */ @@ -6163,6 +6209,14 @@ ArrayBuffer* ArrayBuffer::Cast(v8::Value* value) { } +ArrayBufferView* ArrayBufferView::Cast(v8::Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); +} + + TypedArray* TypedArray::Cast(v8::Value* value) { #ifdef V8_ENABLE_CHECKS CheckCast(value); @@ -6243,6 +6297,14 @@ Uint8ClampedArray* Uint8ClampedArray::Cast(v8::Value* value) { } +DataView* DataView::Cast(v8::Value* value) { +#ifdef V8_ENABLE_CHECKS + CheckCast(value); +#endif + return static_cast(value); +} + + Function* Function::Cast(v8::Value* value) { #ifdef V8_ENABLE_CHECKS CheckCast(value); diff --git a/src/api.cc b/src/api.cc index 4b5c5a994..a138e39f2 100644 --- a/src/api.cc +++ b/src/api.cc @@ -2594,6 +2594,11 @@ bool Value::IsArrayBuffer() const { } +bool Value::IsArrayBufferView() const { + return Utils::OpenHandle(this)->IsJSArrayBufferView(); +} + + bool Value::IsTypedArray() const { if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsArrayBuffer()")) return false; @@ -2627,6 +2632,11 @@ TYPED_ARRAY_LIST(VALUE_IS_TYPED_ARRAY) #undef VALUE_IS_TYPED_ARRAY +bool Value::IsDataView() const { + return Utils::OpenHandle(this)->IsJSDataView(); +} + + bool Value::IsObject() const { if (IsDeadCheck(i::Isolate::Current(), "v8::Value::IsObject()")) return false; return Utils::OpenHandle(this)->IsJSObject(); @@ -2973,6 +2983,14 @@ void v8::ArrayBuffer::CheckCast(Value* that) { } +void v8::ArrayBufferView::CheckCast(Value* that) { + i::Handle obj = Utils::OpenHandle(that); + ApiCheck(obj->IsJSArrayBufferView(), + "v8::ArrayBufferView::Cast()", + "Could not convert to ArrayBufferView"); +} + + void v8::TypedArray::CheckCast(Value* that) { if (IsDeadCheck(i::Isolate::Current(), "v8::TypedArray::Cast()")) return; i::Handle obj = Utils::OpenHandle(that); @@ -2999,6 +3017,14 @@ TYPED_ARRAY_LIST(CHECK_TYPED_ARRAY_CAST) #undef CHECK_TYPED_ARRAY_CAST +void v8::DataView::CheckCast(Value* that) { + i::Handle obj = Utils::OpenHandle(that); + ApiCheck(obj->IsJSDataView(), + "v8::DataView::Cast()", + "Could not convert to DataView"); +} + + void v8::Date::CheckCast(v8::Value* that) { i::Isolate* isolate = i::Isolate::Current(); if (IsDeadCheck(isolate, "v8::Date::Cast()")) return; @@ -6230,33 +6256,35 @@ Local v8::ArrayBuffer::New(void* data, size_t byte_length) { } -Local v8::TypedArray::Buffer() { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - if (IsDeadCheck(isolate, "v8::TypedArray::Buffer()")) - return Local(); - i::Handle obj = Utils::OpenHandle(this); +Local v8::ArrayBufferView::Buffer() { + i::Handle obj = Utils::OpenHandle(this); ASSERT(obj->buffer()->IsJSArrayBuffer()); i::Handle buffer(i::JSArrayBuffer::cast(obj->buffer())); return Utils::ToLocal(buffer); } -size_t v8::TypedArray::ByteOffset() { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - if (IsDeadCheck(isolate, "v8::TypedArray::ByteOffset()")) return 0; - i::Handle obj = Utils::OpenHandle(this); +size_t v8::ArrayBufferView::ByteOffset() { + i::Handle obj = Utils::OpenHandle(this); return static_cast(obj->byte_offset()->Number()); } -size_t v8::TypedArray::ByteLength() { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - if (IsDeadCheck(isolate, "v8::TypedArray::ByteLength()")) return 0; - i::Handle obj = Utils::OpenHandle(this); +size_t v8::ArrayBufferView::ByteLength() { + i::Handle obj = Utils::OpenHandle(this); return static_cast(obj->byte_length()->Number()); } +void* v8::ArrayBufferView::BaseAddress() { + i::Handle obj = Utils::OpenHandle(this); + i::Handle buffer(i::JSArrayBuffer::cast(obj->buffer())); + void* buffer_data = buffer->backing_store(); + size_t byte_offset = static_cast(obj->byte_offset()->Number()); + return static_cast(buffer_data) + byte_offset; +} + + size_t v8::TypedArray::Length() { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::TypedArray::Length()")) return 0; @@ -6265,16 +6293,28 @@ size_t v8::TypedArray::Length() { } -void* v8::TypedArray::BaseAddress() { - i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); - if (IsDeadCheck(isolate, "v8::TypedArray::BaseAddress()")) return NULL; - i::Handle obj = Utils::OpenHandle(this); - i::Handle buffer(i::JSArrayBuffer::cast(obj->buffer())); - void* buffer_data = buffer->backing_store(); - size_t byte_offset = static_cast(obj->byte_offset()->Number()); - return static_cast(buffer_data) + byte_offset; -} +static inline void SetupArrayBufferView( + i::Isolate* isolate, + i::Handle obj, + i::Handle buffer, + size_t byte_offset, + size_t byte_length) { + ASSERT(byte_offset + byte_length <= + static_cast(buffer->byte_length()->Number())); + + obj->set_buffer(*buffer); + obj->set_weak_next(buffer->weak_first_view()); + buffer->set_weak_first_view(*obj); + + i::Handle byte_offset_object = + isolate->factory()->NewNumberFromSize(byte_offset); + obj->set_byte_offset(*byte_offset_object); + + i::Handle byte_length_object = + isolate->factory()->NewNumberFromSize(byte_length); + obj->set_byte_length(*byte_length_object); +} template NewTypedArray( i::Handle buffer = Utils::OpenHandle(*array_buffer); ASSERT(byte_offset % sizeof(ElementType) == 0); - ASSERT(byte_offset + length * sizeof(ElementType) <= - static_cast(buffer->byte_length()->Number())); - - obj->set_buffer(*buffer); - - obj->set_weak_next(buffer->weak_first_view()); - buffer->set_weak_first_view(*obj); - i::Handle byte_offset_object = isolate->factory()->NewNumber( - static_cast(byte_offset)); - obj->set_byte_offset(*byte_offset_object); + SetupArrayBufferView( + isolate, obj, buffer, byte_offset, length * sizeof(ElementType)); - i::Handle byte_length_object = isolate->factory()->NewNumber( - static_cast(length * sizeof(ElementType))); - obj->set_byte_length(*byte_length_object); - - i::Handle length_object = isolate->factory()->NewNumber( - static_cast(length)); + i::Handle length_object = + isolate->factory()->NewNumberFromSize(length); obj->set_length(*length_object); i::Handle elements = @@ -6353,6 +6381,20 @@ TYPED_ARRAY_NEW(Float64Array, double, kExternalDoubleArray, #undef TYPED_ARRAY_NEW +Local DataView::New(Handle array_buffer, + size_t byte_offset, size_t byte_length) { + i::Isolate* isolate = i::Isolate::Current(); + EnsureInitializedForIsolate( + isolate, "v8::DataView::New(void*, size_t, size_t)"); + LOG_API(isolate, "v8::DataView::New(void*, size_t, size_t)"); + ENTER_V8(isolate); + i::Handle obj = isolate->factory()->NewJSDataView(); + i::Handle buffer = Utils::OpenHandle(*array_buffer); + SetupArrayBufferView( + isolate, obj, buffer, byte_offset, byte_length); + return Utils::ToLocal(obj); +} + Local v8::Symbol::New(Isolate* isolate) { i::Isolate* i_isolate = reinterpret_cast(isolate); diff --git a/src/api.h b/src/api.h index 50d4b388c..0f33bc815 100644 --- a/src/api.h +++ b/src/api.h @@ -170,6 +170,7 @@ class RegisteredExtension { V(Object, JSObject) \ V(Array, JSArray) \ V(ArrayBuffer, JSArrayBuffer) \ + V(ArrayBufferView, JSArrayBufferView) \ V(TypedArray, JSTypedArray) \ V(Uint8Array, JSTypedArray) \ V(Uint8ClampedArray, JSTypedArray) \ @@ -180,6 +181,7 @@ class RegisteredExtension { V(Int32Array, JSTypedArray) \ V(Float32Array, JSTypedArray) \ V(Float64Array, JSTypedArray) \ + V(DataView, JSDataView) \ V(String, String) \ V(Symbol, Symbol) \ V(Script, Object) \ @@ -217,6 +219,10 @@ class Utils { v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); + static inline Local ToLocal( + v8::internal::Handle obj); + static inline Local ToLocal( + v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); @@ -348,6 +354,8 @@ MAKE_TO_LOCAL(ToLocal, JSRegExp, RegExp) MAKE_TO_LOCAL(ToLocal, JSObject, Object) MAKE_TO_LOCAL(ToLocal, JSArray, Array) MAKE_TO_LOCAL(ToLocal, JSArrayBuffer, ArrayBuffer) +MAKE_TO_LOCAL(ToLocal, JSArrayBufferView, ArrayBufferView) +MAKE_TO_LOCAL(ToLocal, JSDataView, DataView) MAKE_TO_LOCAL(ToLocal, JSTypedArray, TypedArray) MAKE_TO_LOCAL_TYPED_ARRAY(Uint8Array, kExternalUnsignedByteArray) diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index d70b762a0..e417477ad 100755 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -2666,12 +2666,31 @@ THREADED_TEST(ArrayBuffer_External) { } +static void CheckDataViewIsNeutered(v8::Handle dv) { + CHECK_EQ(0, static_cast(dv->ByteLength())); + CHECK_EQ(0, static_cast(dv->ByteOffset())); +} + + static void CheckIsNeutered(v8::Handle ta) { CHECK_EQ(0, static_cast(ta->ByteLength())); CHECK_EQ(0, static_cast(ta->Length())); CHECK_EQ(0, static_cast(ta->ByteOffset())); } + +static void CheckIsTypedArrayVarNeutered(const char* name) { + i::ScopedVector source(1024); + i::OS::SNPrintF(source, + "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", + name, name, name); + CHECK(CompileRun(source.start())->IsTrue()); + v8::Handle ta = + v8::Handle::Cast(CompileRun(name)); + CheckIsNeutered(ta); +} + + template static Handle CreateAndCheck(Handle ab, int byteOffset, @@ -2713,6 +2732,10 @@ THREADED_TEST(ArrayBuffer_NeuteringApi) { v8::Handle f64a = CreateAndCheck(buffer, 8, 127); + v8::Handle dv = v8::DataView::New(buffer, 1, 1023); + CHECK_EQ(1, static_cast(dv->ByteOffset())); + CHECK_EQ(1023, static_cast(dv->ByteLength())); + ScopedArrayBufferContents contents(buffer->Externalize()); buffer->Neuter(); CHECK_EQ(0, static_cast(buffer->ByteLength())); @@ -2725,6 +2748,7 @@ THREADED_TEST(ArrayBuffer_NeuteringApi) { CheckIsNeutered(i32a); CheckIsNeutered(f32a); CheckIsNeutered(f64a); + CheckDataViewIsNeutered(dv); } THREADED_TEST(ArrayBuffer_NeuteringScript) { @@ -2748,39 +2772,26 @@ THREADED_TEST(ArrayBuffer_NeuteringScript) { v8::Handle ab = Local::Cast(CompileRun("ab")); - v8::Handle u8a = - v8::Handle::Cast(CompileRun("u8a")); - v8::Handle u8c = - v8::Handle::Cast(CompileRun("u8c")); - v8::Handle i8a = - v8::Handle::Cast(CompileRun("i8a")); - - v8::Handle u16a = - v8::Handle::Cast(CompileRun("u16a")); - v8::Handle i16a = - v8::Handle::Cast(CompileRun("i16a")); - v8::Handle u32a = - v8::Handle::Cast(CompileRun("u32a")); - v8::Handle i32a = - v8::Handle::Cast(CompileRun("i32a")); - v8::Handle f32a = - v8::Handle::Cast(CompileRun("f32a")); - v8::Handle f64a = - v8::Handle::Cast(CompileRun("f64a")); + v8::Handle dv = + v8::Handle::Cast(CompileRun("dv")); ScopedArrayBufferContents contents(ab->Externalize()); ab->Neuter(); CHECK_EQ(0, static_cast(ab->ByteLength())); - CheckIsNeutered(u8a); - CheckIsNeutered(u8c); - CheckIsNeutered(i8a); - CheckIsNeutered(u16a); - CheckIsNeutered(i16a); - CheckIsNeutered(u32a); - CheckIsNeutered(i32a); - CheckIsNeutered(f32a); - CheckIsNeutered(f64a); + CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value()); + + CheckIsTypedArrayVarNeutered("u8a"); + CheckIsTypedArrayVarNeutered("u8c"); + CheckIsTypedArrayVarNeutered("i8a"); + CheckIsTypedArrayVarNeutered("u16a"); + CheckIsTypedArrayVarNeutered("i16a"); + CheckIsTypedArrayVarNeutered("u32a"); + CheckIsTypedArrayVarNeutered("i32a"); + CheckIsTypedArrayVarNeutered("f32a"); + CheckIsTypedArrayVarNeutered("f64a"); + CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue()); + CheckDataViewIsNeutered(dv); } @@ -15458,8 +15469,6 @@ template backing_store(kElementCount+2); @@ -15543,8 +15552,27 @@ THREADED_TEST(Uint8ClampedArray) { } -#define IS_TYPED_ARRAY_TEST(TypedArray) \ - THREADED_TEST(Is##TypedArray) { \ +THREADED_TEST(DataView) { + const int kSize = 50; + + i::ScopedVector backing_store(kSize+2); + + LocalContext env; + v8::Isolate* isolate = env->GetIsolate(); + v8::HandleScope handle_scope(isolate); + + Local ab = v8::ArrayBuffer::New( + backing_store.start(), 2 + kSize); + Local dv = + v8::DataView::New(ab, 2, kSize); + CHECK_EQ(2, static_cast(dv->ByteOffset())); + CHECK_EQ(kSize, static_cast(dv->ByteLength())); + CHECK_EQ(ab, dv->Buffer()); +} + + +#define IS_ARRAY_BUFFER_VIEW_TEST(View) \ + THREADED_TEST(Is##View) { \ i::FLAG_harmony_array_buffer = true; \ i::FLAG_harmony_typed_arrays = true; \ LocalContext env; \ @@ -15553,21 +15581,23 @@ THREADED_TEST(Uint8ClampedArray) { \ Handle result = CompileRun( \ "var ab = new ArrayBuffer(128);" \ - "new " #TypedArray "(ab)"); \ - CHECK(result->Is##TypedArray()); \ - } - -IS_TYPED_ARRAY_TEST(Uint8Array) -IS_TYPED_ARRAY_TEST(Int8Array) -IS_TYPED_ARRAY_TEST(Uint16Array) -IS_TYPED_ARRAY_TEST(Int16Array) -IS_TYPED_ARRAY_TEST(Uint32Array) -IS_TYPED_ARRAY_TEST(Int32Array) -IS_TYPED_ARRAY_TEST(Float32Array) -IS_TYPED_ARRAY_TEST(Float64Array) -IS_TYPED_ARRAY_TEST(Uint8ClampedArray) - -#undef IS_TYPED_ARRAY_TEST + "new " #View "(ab)"); \ + CHECK(result->IsArrayBufferView()); \ + CHECK(result->Is##View()); \ + } + +IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array) +IS_ARRAY_BUFFER_VIEW_TEST(Int8Array) +IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array) +IS_ARRAY_BUFFER_VIEW_TEST(Int16Array) +IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array) +IS_ARRAY_BUFFER_VIEW_TEST(Int32Array) +IS_ARRAY_BUFFER_VIEW_TEST(Float32Array) +IS_ARRAY_BUFFER_VIEW_TEST(Float64Array) +IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray) +IS_ARRAY_BUFFER_VIEW_TEST(DataView) + +#undef IS_ARRAY_BUFFER_VIEW_TEST diff --git a/test/cctest/test-weaktypedarrays.cc b/test/cctest/test-weaktypedarrays.cc index 6d0a247f5..fe1ef0494 100644 --- a/test/cctest/test-weaktypedarrays.cc +++ b/test/cctest/test-weaktypedarrays.cc @@ -74,7 +74,7 @@ static int CountViews(JSArrayBuffer* array_buffer) { } static bool HasViewInWeakList(JSArrayBuffer* array_buffer, - JSObject* ta) { + JSArrayBufferView* ta) { for (Object* o = array_buffer->weak_first_view(); !o->IsUndefined(); o = JSArrayBufferView::cast(o)->weak_next()) { @@ -178,8 +178,8 @@ TEST(WeakArrayBuffersFromScript) { } } -template -void TestTypedArrayFromApi() { +template +void TestViewFromApi() { v8::V8::Initialize(); LocalContext context; Isolate* isolate = GetIsolateFrom(&context); @@ -189,20 +189,20 @@ void TestTypedArrayFromApi() { Handle iab = v8::Utils::OpenHandle(*ab); { v8::HandleScope s2(context->GetIsolate()); - v8::Handle ta1 = TypedArray::New(ab, 0, 256); + v8::Handle ta1 = View::New(ab, 0, 256); { v8::HandleScope s3(context->GetIsolate()); - v8::Handle ta2 = TypedArray::New(ab, 0, 128); + v8::Handle ta2 = View::New(ab, 0, 128); - Handle ita1 = v8::Utils::OpenHandle(*ta1); - Handle ita2 = v8::Utils::OpenHandle(*ta2); + Handle ita1 = v8::Utils::OpenHandle(*ta1); + Handle ita2 = v8::Utils::OpenHandle(*ta2); CHECK_EQ(2, CountViews(*iab)); CHECK(HasViewInWeakList(*iab, *ita1)); CHECK(HasViewInWeakList(*iab, *ita2)); } isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); CHECK_EQ(1, CountViews(*iab)); - Handle ita1 = v8::Utils::OpenHandle(*ta1); + Handle ita1 = v8::Utils::OpenHandle(*ta1); CHECK(HasViewInWeakList(*iab, *ita1)); } isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); @@ -212,47 +212,52 @@ void TestTypedArrayFromApi() { TEST(Uint8ArrayFromApi) { - TestTypedArrayFromApi(); + TestViewFromApi(); } TEST(Int8ArrayFromApi) { - TestTypedArrayFromApi(); + TestViewFromApi(); } TEST(Uint16ArrayFromApi) { - TestTypedArrayFromApi(); + TestViewFromApi(); } TEST(Int16ArrayFromApi) { - TestTypedArrayFromApi(); + TestViewFromApi(); } TEST(Uint32ArrayFromApi) { - TestTypedArrayFromApi(); + TestViewFromApi(); } TEST(Int32ArrayFromApi) { - TestTypedArrayFromApi(); + TestViewFromApi(); } TEST(Float32ArrayFromApi) { - TestTypedArrayFromApi(); + TestViewFromApi(); } TEST(Float64ArrayFromApi) { - TestTypedArrayFromApi(); + TestViewFromApi(); } TEST(Uint8ClampedArrayFromApi) { - TestTypedArrayFromApi(); + TestViewFromApi(); +} + + +TEST(DataViewFromApi) { + TestViewFromApi(); } template @@ -378,5 +383,5 @@ TEST(Uint8ClampedArrayFromScript) { TEST(DataViewFromScript) { - TestTypedArrayFromScript("DataView"); + TestTypedArrayFromScript("DataView"); } -- 2.34.1