/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "jsfriendapi.h" #include "js/ArrayBuffer.h" // JS::NewArrayBuffer #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 #include "js/GlobalObject.h" // JS_NewGlobalObject #include "js/PropertyAndElement.h" // JS_SetProperty #include "js/ScalarType.h" // js::Scalar::Type #include "jsapi-tests/tests.h" #include "vm/ProxyObject.h" #include "vm/Realm.h" #include "vm/Uint8Clamped.h" // js::uint8_clamped_t #include "vm/JSObject-inl.h" #include "vm/Realm-inl.h" #include "vm/TypedArrayObject-inl.h" // TypeIDOfType using namespace js; template static JSObject* Create(JSContext* cx, size_t len) { return ViewType::create(cx, len).asObject(); } template <> JSObject* Create(JSContext* cx, size_t len) { JS::Rooted buffer(cx, JS::NewArrayBuffer(cx, len)); if (!buffer) { return nullptr; } return JS_NewDataView(cx, buffer, 0, len); } template struct InternalType { using Type = uint8_t; }; #define INT_TYPE(ExternalType, NativeType, Name) \ template <> \ struct InternalType> { \ using Type = NativeType; \ }; JS_FOR_EACH_TYPED_ARRAY(INT_TYPE) #undef INT_TYPE BEGIN_TEST(testArrayBufferView_type) { CHECK((TestViewType, 7, 7>(cx))); CHECK((TestViewType, 33, 33>(cx))); CHECK((TestViewType, 7, 7>(cx))); CHECK((TestViewType, 3, 6>(cx))); CHECK((TestViewType, 17, 34>(cx))); CHECK((TestViewType, 15, 60>(cx))); CHECK((TestViewType, 8, 32>(cx))); CHECK((TestViewType, 7, 28>(cx))); CHECK((TestViewType, 9, 72>(cx))); CHECK((TestViewType(cx))); JS::Rooted hasTypedObject(cx); EVAL("typeof TypedObject !== 'undefined'", &hasTypedObject); if (hasTypedObject.isTrue()) { JS::Rooted tval(cx); EVAL( "var T = new TypedObject.StructType({ x: TypedObject.uint32 });\n" "new T(new ArrayBuffer(4));", &tval); JS::Rooted tobj(cx, &tval.toObject()); CHECK(!JS_IsArrayBufferViewObject(tobj)); } return true; } template struct ScalarTypeOf { static constexpr js::Scalar::Type value = js::Scalar::MaxTypedArrayViewType; }; template struct ScalarTypeOf> { static constexpr js::Scalar::Type value = EType; }; template bool TestViewType(JSContext* cx) { JS::Rooted obj(cx, Create(cx, ExpectedLength)); CHECK(obj); CHECK(JS_IsArrayBufferViewObject(obj)); CHECK(JS_GetArrayBufferViewByteLength(obj) == ExpectedByteLength); { JS::AutoCheckCannotGC nogc; bool shared1; JSObject* unwrapped = js::UnwrapArrayBufferView(obj); uint8_t* data1 = (uint8_t*)JS_GetArrayBufferViewData(unwrapped, &shared1, nogc); auto view = ViewType::unwrap(obj); CHECK(JS_GetArrayBufferViewType(obj) == ScalarTypeOf::value); if (JS_IsTypedArrayObject(unwrapped)) { CHECK(unwrapped->as().type() == TypeIDOfType::Type>::id); } bool shared2; size_t len; uint8_t* data2 = reinterpret_cast(view.getLengthAndData(&len, &shared2, nogc)); CHECK(obj == view.asObject()); CHECK(data1 == data2); CHECK(shared1 == shared2); CHECK(len == ExpectedLength); JS::Heap hv(view); bool shared3; size_t len3; uint8_t* data3 = reinterpret_cast(hv.getLengthAndData(&len3, &shared3, nogc)); CHECK(obj == hv.asObject()); CHECK(data1 == data3); CHECK(shared1 == shared3); CHECK(len3 == ExpectedLength); } JS::RealmOptions options; JS::RootedObject otherGlobal( cx, JS_NewGlobalObject(cx, basicGlobalClass(), nullptr, JS::DontFireOnNewGlobalHook, options)); CHECK(otherGlobal); JS::Rooted buffer(cx); { AutoRealm ar(cx, otherGlobal); buffer = JS::NewArrayBuffer(cx, 8); CHECK(buffer); CHECK(buffer->as().byteLength() == 8); } CHECK(buffer->compartment() == otherGlobal->compartment()); CHECK(JS_WrapObject(cx, &buffer)); CHECK(buffer->compartment() == global->compartment()); JS::Rooted dataview(cx, JS_NewDataView(cx, buffer, 4, 4)); CHECK(dataview); CHECK(dataview->is()); JS::Rooted val(cx); val = ObjectValue(*dataview); CHECK(JS_SetProperty(cx, global, "view", val)); EVAL("view.buffer", &val); CHECK(val.toObject().is()); CHECK(dataview->compartment() == global->compartment()); JS::Rooted otherView(cx, js::UncheckedUnwrap(dataview)); CHECK(otherView->compartment() == otherGlobal->compartment()); JS::Rooted otherBuffer(cx, js::UncheckedUnwrap(&val.toObject())); CHECK(otherBuffer->compartment() == otherGlobal->compartment()); EVAL("Object.getPrototypeOf(view) === DataView.prototype", &val); CHECK(val.toBoolean() == true); return true; } END_TEST(testArrayBufferView_type)