testArrayBufferView.cpp (5637B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 */ 4 5 /* This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 8 9 #include "jsfriendapi.h" 10 11 #include "js/ArrayBuffer.h" // JS::NewArrayBuffer 12 #include "js/experimental/TypedData.h" // JS_GetArrayBufferView{Type,ByteLength,Data}, JS_GetObjectAsArrayBufferView, JS_GetObjectAs{{Ui,I}nt{8,16,32},Float{32,64}}Array, JS_IsArrayBufferViewObject, JS_NewDataView, JS_New{{Ui,I}nt{8,16,32},Float{32,64},Uint8Clamped}Array 13 #include "js/GlobalObject.h" // JS_NewGlobalObject 14 #include "js/PropertyAndElement.h" // JS_SetProperty 15 #include "js/ScalarType.h" // js::Scalar::Type 16 #include "jsapi-tests/tests.h" 17 #include "vm/ProxyObject.h" 18 #include "vm/Realm.h" 19 #include "vm/Uint8Clamped.h" // js::uint8_clamped_t 20 21 #include "vm/JSObject-inl.h" 22 #include "vm/Realm-inl.h" 23 #include "vm/TypedArrayObject-inl.h" // TypeIDOfType 24 25 using namespace js; 26 27 template <class ViewType> 28 static JSObject* Create(JSContext* cx, size_t len) { 29 return ViewType::create(cx, len).asObject(); 30 } 31 32 template <> 33 JSObject* Create<JS::DataView>(JSContext* cx, size_t len) { 34 JS::Rooted<JSObject*> buffer(cx, JS::NewArrayBuffer(cx, len)); 35 if (!buffer) { 36 return nullptr; 37 } 38 return JS_NewDataView(cx, buffer, 0, len); 39 } 40 41 template <class T> 42 struct InternalType { 43 using Type = uint8_t; 44 }; 45 46 #define INT_TYPE(ExternalType, NativeType, Name) \ 47 template <> \ 48 struct InternalType<JS::TypedArray<js::Scalar::Name>> { \ 49 using Type = NativeType; \ 50 }; 51 JS_FOR_EACH_TYPED_ARRAY(INT_TYPE) 52 #undef INT_TYPE 53 54 BEGIN_TEST(testArrayBufferView_type) { 55 CHECK((TestViewType<JS::TypedArray<Scalar::Uint8>, 7, 7>(cx))); 56 CHECK((TestViewType<JS::TypedArray<Scalar::Int8>, 33, 33>(cx))); 57 CHECK((TestViewType<JS::TypedArray<Scalar::Uint8Clamped>, 7, 7>(cx))); 58 CHECK((TestViewType<JS::TypedArray<Scalar::Uint16>, 3, 6>(cx))); 59 CHECK((TestViewType<JS::TypedArray<Scalar::Int16>, 17, 34>(cx))); 60 CHECK((TestViewType<JS::TypedArray<Scalar::Uint32>, 15, 60>(cx))); 61 CHECK((TestViewType<JS::TypedArray<Scalar::Int32>, 8, 32>(cx))); 62 CHECK((TestViewType<JS::TypedArray<Scalar::Float32>, 7, 28>(cx))); 63 CHECK((TestViewType<JS::TypedArray<Scalar::Float64>, 9, 72>(cx))); 64 CHECK((TestViewType<JS::DataView, 8, 8>(cx))); 65 66 return true; 67 } 68 69 template <class T> 70 struct ScalarTypeOf { 71 static constexpr js::Scalar::Type value = js::Scalar::MaxTypedArrayViewType; 72 }; 73 74 template <js::Scalar::Type EType> 75 struct ScalarTypeOf<JS::TypedArray<EType>> { 76 static constexpr js::Scalar::Type value = EType; 77 }; 78 template <class ViewType, uint32_t ExpectedLength, uint32_t ExpectedByteLength> 79 bool TestViewType(JSContext* cx) { 80 JS::Rooted<JSObject*> obj(cx, Create<ViewType>(cx, ExpectedLength)); 81 CHECK(obj); 82 83 CHECK(JS_IsArrayBufferViewObject(obj)); 84 85 CHECK(JS_GetArrayBufferViewByteLength(obj) == ExpectedByteLength); 86 87 { 88 JS::AutoCheckCannotGC nogc; 89 bool shared1; 90 JSObject* unwrapped = js::UnwrapArrayBufferView(obj); 91 uint8_t* data1 = 92 (uint8_t*)JS_GetArrayBufferViewData(unwrapped, &shared1, nogc); 93 94 auto view = ViewType::unwrap(obj); 95 CHECK(JS_GetArrayBufferViewType(obj) == ScalarTypeOf<ViewType>::value); 96 97 if (JS_IsTypedArrayObject(unwrapped)) { 98 CHECK(unwrapped->as<TypedArrayObject>().type() == 99 TypeIDOfType<typename InternalType<ViewType>::Type>::id); 100 } 101 102 bool shared2; 103 mozilla::Span<typename ViewType::DataType> span2 = 104 view.getData(&shared2, nogc); 105 CHECK(obj == view.asObject()); 106 CHECK(data1 == reinterpret_cast<uint8_t*>(span2.data())); 107 CHECK(shared1 == shared2); 108 CHECK(span2.Length() == ExpectedLength); 109 110 JS::Heap<ViewType> hv(view); 111 112 bool shared3; 113 mozilla::Span<typename ViewType::DataType> span3 = 114 hv.getData(&shared3, nogc); 115 CHECK(obj == hv.asObject()); 116 CHECK(data1 == reinterpret_cast<uint8_t*>(span3.data())); 117 CHECK(shared1 == shared3); 118 CHECK(span3.Length() == ExpectedLength); 119 } 120 121 JS::RealmOptions options; 122 JS::RootedObject otherGlobal( 123 cx, JS_NewGlobalObject(cx, basicGlobalClass(), nullptr, 124 JS::DontFireOnNewGlobalHook, options)); 125 CHECK(otherGlobal); 126 127 JS::Rooted<JSObject*> buffer(cx); 128 { 129 AutoRealm ar(cx, otherGlobal); 130 buffer = JS::NewArrayBuffer(cx, 8); 131 CHECK(buffer); 132 CHECK(buffer->as<ArrayBufferObject>().byteLength() == 8); 133 } 134 CHECK(buffer->compartment() == otherGlobal->compartment()); 135 CHECK(JS_WrapObject(cx, &buffer)); 136 CHECK(buffer->compartment() == global->compartment()); 137 138 JS::Rooted<JSObject*> dataview(cx, JS_NewDataView(cx, buffer, 4, 4)); 139 CHECK(dataview); 140 CHECK(dataview->is<ProxyObject>()); 141 142 JS::Rooted<JS::Value> val(cx); 143 144 val = ObjectValue(*dataview); 145 CHECK(JS_SetProperty(cx, global, "view", val)); 146 147 EVAL("view.buffer", &val); 148 CHECK(val.toObject().is<ProxyObject>()); 149 150 CHECK(dataview->compartment() == global->compartment()); 151 JS::Rooted<JSObject*> otherView(cx, js::UncheckedUnwrap(dataview)); 152 CHECK(otherView->compartment() == otherGlobal->compartment()); 153 JS::Rooted<JSObject*> otherBuffer(cx, js::UncheckedUnwrap(&val.toObject())); 154 CHECK(otherBuffer->compartment() == otherGlobal->compartment()); 155 156 EVAL("Object.getPrototypeOf(view) === DataView.prototype", &val); 157 CHECK(val.toBoolean() == true); 158 159 return true; 160 } 161 162 END_TEST(testArrayBufferView_type)