/* -*- 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 "vm/StencilObject.h" #include "mozilla/Assertions.h" // MOZ_ASSERT #include "mozilla/PodOperations.h" // mozilla::PodCopy #include // size_t #include // uint8_t, INT32_MAX #include "jsapi.h" // JS_NewObject #include "js/Class.h" // JSClassOps, JSClass, JSCLASS_* #include "js/ErrorReport.h" // JS_ReportErrorASCII #include "js/experimental/JSStencil.h" // JS::Stencil, JS::StencilAddRef, JS::StencilRelease #include "js/RootingAPI.h" // JS::Rooted #include "js/Utility.h" // js_free #include "vm/JSContext.h" // JSContext #include "vm/JSObject.h" // JSObject using namespace js; /*static */ const JSClassOps StencilObject::classOps_ = { nullptr, // addProperty nullptr, // delProperty nullptr, // enumerate nullptr, // newEnumerate nullptr, // resolve nullptr, // mayResolve StencilObject::finalize, // finalize nullptr, // call nullptr, // construct nullptr, // trace }; /*static */ const JSClass StencilObject::class_ = { "StencilObject", JSCLASS_HAS_RESERVED_SLOTS(StencilObject::ReservedSlots) | JSCLASS_BACKGROUND_FINALIZE, &StencilObject::classOps_}; bool StencilObject::hasStencil() const { // The stencil may not be present yet if we GC during initialization. return !getReservedSlot(StencilSlot).isUndefined(); } JS::Stencil* StencilObject::stencil() const { void* ptr = getReservedSlot(StencilSlot).toPrivate(); MOZ_ASSERT(ptr); return static_cast(ptr); } /* static */ StencilObject* StencilObject::create(JSContext* cx, RefPtr stencil) { JS::Rooted obj(cx, JS_NewObject(cx, &class_)); if (!obj) { return nullptr; } obj->as().setReservedSlot( StencilSlot, PrivateValue(stencil.forget().take())); return &obj->as(); } /* static */ void StencilObject::finalize(JS::GCContext* gcx, JSObject* obj) { if (obj->as().hasStencil()) { JS::StencilRelease(obj->as().stencil()); } } /*static */ const JSClassOps StencilXDRBufferObject::classOps_ = { nullptr, // addProperty nullptr, // delProperty nullptr, // enumerate nullptr, // newEnumerate nullptr, // resolve nullptr, // mayResolve StencilXDRBufferObject::finalize, // finalize nullptr, // call nullptr, // construct nullptr, // trace }; /*static */ const JSClass StencilXDRBufferObject::class_ = { "StencilXDRBufferObject", JSCLASS_HAS_RESERVED_SLOTS(StencilXDRBufferObject::ReservedSlots) | JSCLASS_BACKGROUND_FINALIZE, &StencilXDRBufferObject::classOps_}; bool StencilXDRBufferObject::hasBuffer() const { // The stencil may not be present yet if we GC during initialization. return !getReservedSlot(BufferSlot).isUndefined(); } const uint8_t* StencilXDRBufferObject::buffer() const { void* ptr = getReservedSlot(BufferSlot).toPrivate(); MOZ_ASSERT(ptr); return static_cast(ptr); } uint8_t* StencilXDRBufferObject::writableBuffer() { void* ptr = getReservedSlot(BufferSlot).toPrivate(); MOZ_ASSERT(ptr); return static_cast(ptr); } size_t StencilXDRBufferObject::bufferLength() const { return getReservedSlot(LengthSlot).toInt32(); } /* static */ StencilXDRBufferObject* StencilXDRBufferObject::create( JSContext* cx, uint8_t* buffer, size_t length) { if (length >= INT32_MAX) { JS_ReportErrorASCII(cx, "XDR buffer is too long"); return nullptr; } JS::Rooted obj(cx, JS_NewObject(cx, &class_)); if (!obj) { return nullptr; } auto ownedBuffer = cx->make_pod_array(length); if (!ownedBuffer) { return nullptr; } mozilla::PodCopy(ownedBuffer.get(), buffer, length); obj->as().setReservedSlot( BufferSlot, PrivateValue(ownedBuffer.release())); obj->as().setReservedSlot(LengthSlot, Int32Value(length)); return &obj->as(); } /* static */ void StencilXDRBufferObject::finalize(JS::GCContext* gcx, JSObject* obj) { if (obj->as().hasBuffer()) { js_free(obj->as().writableBuffer()); } }