/* THIS FILE IS AUTOGENERATED FROM WebGPU.webidl BY Codegen.py - DO NOT EDIT */ #include #include "AtomList.h" #include "BufferSourceBinding.h" #include "DOMExceptionBinding.h" #include "EventHandlerBinding.h" #include "EventTargetBinding.h" #include "MainThreadUtils.h" #include "WebGPUBinding.h" #include "WrapperFactory.h" #include "XrayWrapper.h" #include "js/Array.h" #include "js/CallAndConstruct.h" #include "js/Exception.h" #include "js/ForOfIterator.h" #include "js/MapAndSet.h" #include "js/Object.h" #include "js/PropertyAndElement.h" #include "js/PropertyDescriptor.h" #include "js/Symbol.h" #include "js/experimental/JitInfo.h" #include "jsapi.h" #include "jsfriendapi.h" #include "mozilla/Atomics.h" #include "mozilla/FloatingPoint.h" #include "mozilla/OwningNonNull.h" #include "mozilla/ProfilerLabels.h" #include "mozilla/dom/BindingCallContext.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/DOMJSClass.h" #include "mozilla/dom/HTMLCanvasElement.h" #include "mozilla/dom/HTMLImageElement.h" #include "mozilla/dom/HTMLVideoElement.h" #include "mozilla/dom/ImageBitmap.h" #include "mozilla/dom/NonRefcountedDOMObject.h" #include "mozilla/dom/Nullable.h" #include "mozilla/dom/OffscreenCanvas.h" #include "mozilla/dom/PrimitiveConversions.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/SimpleGlobalObject.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/dom/TypedArray.h" #include "mozilla/dom/UnionTypes.h" #include "mozilla/dom/VideoFrame.h" #include "mozilla/dom/WebIDLPrefs.h" #include "mozilla/dom/XrayExpandoClass.h" #include "mozilla/webgpu/Adapter.h" #include "mozilla/webgpu/BindGroup.h" #include "mozilla/webgpu/BindGroupLayout.h" #include "mozilla/webgpu/Buffer.h" #include "mozilla/webgpu/CanvasContext.h" #include "mozilla/webgpu/CommandBuffer.h" #include "mozilla/webgpu/CommandEncoder.h" #include "mozilla/webgpu/CompilationInfo.h" #include "mozilla/webgpu/CompilationMessage.h" #include "mozilla/webgpu/ComputePassEncoder.h" #include "mozilla/webgpu/ComputePipeline.h" #include "mozilla/webgpu/Device.h" #include "mozilla/webgpu/DeviceLostInfo.h" #include "mozilla/webgpu/Error.h" #include "mozilla/webgpu/ExternalTexture.h" #include "mozilla/webgpu/Instance.h" #include "mozilla/webgpu/InternalError.h" #include "mozilla/webgpu/OutOfMemoryError.h" #include "mozilla/webgpu/PipelineError.h" #include "mozilla/webgpu/PipelineLayout.h" #include "mozilla/webgpu/QuerySet.h" #include "mozilla/webgpu/Queue.h" #include "mozilla/webgpu/RenderBundle.h" #include "mozilla/webgpu/RenderBundleEncoder.h" #include "mozilla/webgpu/RenderPassEncoder.h" #include "mozilla/webgpu/RenderPipeline.h" #include "mozilla/webgpu/Sampler.h" #include "mozilla/webgpu/ShaderModule.h" #include "mozilla/webgpu/SupportedFeatures.h" #include "mozilla/webgpu/SupportedLimits.h" #include "mozilla/webgpu/Texture.h" #include "mozilla/webgpu/TextureView.h" #include "mozilla/webgpu/ValidationError.h" #include "nsContentUtils.h" #include "nsRFPService.h" namespace mozilla { namespace dom { namespace binding_detail {}; // Just to make sure it's known as a namespace using namespace mozilla::dom::binding_detail; namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUPowerPreference aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[19]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUFeatureName aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[3]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUBufferMapState aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[3]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUTextureDimension aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[6]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUTextureViewDimension aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[3]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUTextureAspect aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[95]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUTextureFormat aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[3]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUAddressMode aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUFilterMode aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUMipmapFilterMode aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[8]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUCompareFunction aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[3]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUBufferBindingType aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[3]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUSamplerBindingType aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[5]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUTextureSampleType aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[3]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUStorageTextureAccess aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[3]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUCompilationMessageType aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUPipelineErrorReason aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[1]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUAutoLayoutMode aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[5]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUPrimitiveTopology aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUFrontFace aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[3]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUCullMode aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[17]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUBlendFactor aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[5]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUBlendOperation aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[8]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUStencilOperation aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUIndexFormat aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[41]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUVertexFormat aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUVertexStepMode aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPULoadOp aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUStoreOp aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUQueryType aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUCanvasAlphaMode aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[2]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUDeviceLostReason aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } namespace binding_detail { constexpr nsLiteralCString EnumStrings::Values[3]; } // namespace binding_detail bool ToJSValue(JSContext* aCx, GPUErrorFilter aArgument, JS::MutableHandle aValue) { MOZ_ASSERT(uint32_t(aArgument) < std::size(binding_detail::EnumStrings::Values)); JSString* resultStr = JS_NewStringCopyN(aCx, binding_detail::EnumStrings::Values[uint32_t(aArgument)].BeginReading(), binding_detail::EnumStrings::Values[uint32_t(aArgument)].Length()); if (!resultStr) { return false; } aValue.setString(resultStr); return true; } void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, OwningGPUPipelineLayoutOrGPUAutoLayoutMode& aUnion, const char* aName, uint32_t aFlags) { if (aUnion.IsGPUPipelineLayout()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsGPUPipelineLayout(), "mGPUPipelineLayout", aFlags); } } void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture& aUnion, const char* aName, uint32_t aFlags) { if (aUnion.IsGPUSampler()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsGPUSampler(), "mGPUSampler", aFlags); } else if (aUnion.IsGPUTexture()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsGPUTexture(), "mGPUTexture", aFlags); } else if (aUnion.IsGPUTextureView()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsGPUTextureView(), "mGPUTextureView", aFlags); } else if (aUnion.IsGPUBuffer()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsGPUBuffer(), "mGPUBuffer", aFlags); } else if (aUnion.IsGPUBufferBinding()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsGPUBufferBinding(), "mGPUBufferBinding", aFlags); } else if (aUnion.IsGPUExternalTexture()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsGPUExternalTexture(), "mGPUExternalTexture", aFlags); } } void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, OwningGPUTextureOrGPUTextureView& aUnion, const char* aName, uint32_t aFlags) { if (aUnion.IsGPUTexture()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsGPUTexture(), "mGPUTexture", aFlags); } else if (aUnion.IsGPUTextureView()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsGPUTextureView(), "mGPUTextureView", aFlags); } } void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, OwningHTMLVideoElementOrVideoFrame& aUnion, const char* aName, uint32_t aFlags) { if (aUnion.IsHTMLVideoElement()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsHTMLVideoElement(), "mHTMLVideoElement", aFlags); } else if (aUnion.IsVideoFrame()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsVideoFrame(), "mVideoFrame", aFlags); } } void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas& aUnion, const char* aName, uint32_t aFlags) { if (aUnion.IsImageBitmap()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsImageBitmap(), "mImageBitmap", aFlags); } else if (aUnion.IsHTMLImageElement()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsHTMLImageElement(), "mHTMLImageElement", aFlags); } else if (aUnion.IsHTMLCanvasElement()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsHTMLCanvasElement(), "mHTMLCanvasElement", aFlags); } else if (aUnion.IsOffscreenCanvas()) { ImplCycleCollectionTraverse(aCallback, aUnion.GetAsOffscreenCanvas(), "mOffscreenCanvas", aFlags); } } void ImplCycleCollectionUnlink(OwningGPUPipelineLayoutOrGPUAutoLayoutMode& aUnion) { aUnion.Uninit(); } void ImplCycleCollectionUnlink(OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture& aUnion) { aUnion.Uninit(); } void ImplCycleCollectionUnlink(OwningGPUTextureOrGPUTextureView& aUnion) { aUnion.Uninit(); } void ImplCycleCollectionUnlink(OwningHTMLVideoElementOrVideoFrame& aUnion) { aUnion.Uninit(); } void ImplCycleCollectionUnlink(OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas& aUnion) { aUnion.Uninit(); } GPUBlendComponent::GPUBlendComponent() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUBlendComponent::InitIds(JSContext* cx, GPUBlendComponentAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->srcFactor_id.init(cx, "srcFactor") || !atomsCache->operation_id.init(cx, "operation") || !atomsCache->dstFactor_id.init(cx, "dstFactor")) { return false; } return true; } bool GPUBlendComponent::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUBlendComponentAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->dstFactor_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUBlendFactor", "'dstFactor' member of GPUBlendComponent", &index)) { return false; } MOZ_ASSERT(index >= 0); mDstFactor = static_cast(index); } } else { mDstFactor = GPUBlendFactor::Zero; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->operation_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUBlendOperation", "'operation' member of GPUBlendComponent", &index)) { return false; } MOZ_ASSERT(index >= 0); mOperation = static_cast(index); } } else { mOperation = GPUBlendOperation::Add; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->srcFactor_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUBlendFactor", "'srcFactor' member of GPUBlendComponent", &index)) { return false; } MOZ_ASSERT(index >= 0); mSrcFactor = static_cast(index); } } else { mSrcFactor = GPUBlendFactor::One; } mIsAnyMemberPresent = true; return true; } bool GPUBlendComponent::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUBlendComponent::TraceDictionary(JSTracer* trc) { } GPUBlendComponent& GPUBlendComponent::operator=(const GPUBlendComponent& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mDstFactor = aOther.mDstFactor; mOperation = aOther.mOperation; mSrcFactor = aOther.mSrcFactor; return *this; } GPUBufferBinding::GPUBufferBinding() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUBufferBinding::InitIds(JSContext* cx, GPUBufferBindingAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->size_id.init(cx, "size") || !atomsCache->offset_id.init(cx, "offset") || !atomsCache->buffer_id.init(cx, "buffer")) { return false; } return true; } bool GPUBufferBinding::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUBufferBindingAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->buffer_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(temp.ptr(), mBuffer, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("'buffer' member of GPUBufferBinding", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("'buffer' member of GPUBufferBinding"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'buffer' member of GPUBufferBinding"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->offset_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'offset' member of GPUBufferBinding", &mOffset)) { return false; } } else { mOffset = 0ULL; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->size_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mSize.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'size' member of GPUBufferBinding", &(mSize.Value()))) { return false; } mIsAnyMemberPresent = true; } return true; } bool GPUBufferBinding::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUBufferBinding::TraceDictionary(JSTracer* trc) { } GPUBufferBinding& GPUBufferBinding::operator=(const GPUBufferBinding& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mBuffer = aOther.mBuffer; mOffset = aOther.mOffset; mSize.Reset(); if (aOther.mSize.WasPassed()) { mSize.Construct(aOther.mSize.Value()); } return *this; } GPUBufferBindingLayout::GPUBufferBindingLayout() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUBufferBindingLayout::InitIds(JSContext* cx, GPUBufferBindingLayoutAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->type_id.init(cx, "type") || !atomsCache->minBindingSize_id.init(cx, "minBindingSize") || !atomsCache->hasDynamicOffset_id.init(cx, "hasDynamicOffset")) { return false; } return true; } bool GPUBufferBindingLayout::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUBufferBindingLayoutAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->hasDynamicOffset_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'hasDynamicOffset' member of GPUBufferBindingLayout", &mHasDynamicOffset)) { return false; } } else { mHasDynamicOffset = false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->minBindingSize_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'minBindingSize' member of GPUBufferBindingLayout", &mMinBindingSize)) { return false; } } else { mMinBindingSize = 0ULL; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->type_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUBufferBindingType", "'type' member of GPUBufferBindingLayout", &index)) { return false; } MOZ_ASSERT(index >= 0); mType = static_cast(index); } } else { mType = GPUBufferBindingType::Uniform; } mIsAnyMemberPresent = true; return true; } bool GPUBufferBindingLayout::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUBufferBindingLayout::TraceDictionary(JSTracer* trc) { } GPUBufferBindingLayout& GPUBufferBindingLayout::operator=(const GPUBufferBindingLayout& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mHasDynamicOffset = aOther.mHasDynamicOffset; mMinBindingSize = aOther.mMinBindingSize; mType = aOther.mType; return *this; } GPUCanvasConfiguration::GPUCanvasConfiguration() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUCanvasConfiguration::InitIds(JSContext* cx, GPUCanvasConfigurationAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->viewFormats_id.init(cx, "viewFormats") || !atomsCache->usage_id.init(cx, "usage") || !atomsCache->format_id.init(cx, "format") || !atomsCache->device_id.init(cx, "device") || !atomsCache->alphaMode_id.init(cx, "alphaMode")) { return false; } return true; } bool GPUCanvasConfiguration::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUCanvasConfigurationAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->alphaMode_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUCanvasAlphaMode", "'alphaMode' member of GPUCanvasConfiguration", &index)) { return false; } MOZ_ASSERT(index >= 0); mAlphaMode = static_cast(index); } } else { mAlphaMode = GPUCanvasAlphaMode::Opaque; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->device_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(temp.ptr(), mDevice, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("'device' member of GPUCanvasConfiguration", "GPUDevice"); return false; } } } else { cx.ThrowErrorMessage("'device' member of GPUCanvasConfiguration"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'device' member of GPUCanvasConfiguration"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->format_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureFormat", "'format' member of GPUCanvasConfiguration", &index)) { return false; } MOZ_ASSERT(index >= 0); mFormat = static_cast(index); } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'format' member of GPUCanvasConfiguration"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->usage_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'usage' member of GPUCanvasConfiguration", &mUsage)) { return false; } } else { mUsage = 16U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->viewFormats_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'viewFormats' member of GPUCanvasConfiguration", "sequence"); return false; } Sequence &arr = mViewFormats; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } GPUTextureFormat* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } GPUTextureFormat& slot = *slotPtr; { int index; if (!binding_detail::FindEnumStringIndex(cx, temp, binding_detail::EnumStrings::Values, "GPUTextureFormat", "element of 'viewFormats' member of GPUCanvasConfiguration", &index)) { return false; } MOZ_ASSERT(index >= 0); slot = static_cast(index); } } } else { cx.ThrowErrorMessage("'viewFormats' member of GPUCanvasConfiguration", "sequence"); return false; } } else { /* mViewFormats array is already empty; nothing to do */ } mIsAnyMemberPresent = true; return true; } bool GPUCanvasConfiguration::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } bool GPUCanvasConfiguration::ToObjectInternal(JSContext* cx, JS::MutableHandle rval) const { GPUCanvasConfigurationAtoms* atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } JS::Rooted obj(cx, JS_NewPlainObject(cx)); if (!obj) { return false; } rval.setObject(*obj); do { // block for our 'break' successCode and scope for 'temp' and 'currentValue' JS::Rooted temp(cx); GPUCanvasAlphaMode const & currentValue = mAlphaMode; if (!ToJSValue(cx, currentValue, &temp)) { return false; } if (!JS_DefinePropertyById(cx, obj, atomsCache->alphaMode_id, temp, JSPROP_ENUMERATE)) { return false; } break; } while(false); do { // block for our 'break' successCode and scope for 'temp' and 'currentValue' JS::Rooted temp(cx); OwningNonNull const & currentValue = mDevice; if (!GetOrCreateDOMReflector(cx, currentValue, &temp)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } if (!JS_DefinePropertyById(cx, obj, atomsCache->device_id, temp, JSPROP_ENUMERATE)) { return false; } break; } while(false); do { // block for our 'break' successCode and scope for 'temp' and 'currentValue' JS::Rooted temp(cx); GPUTextureFormat const & currentValue = mFormat; if (!ToJSValue(cx, currentValue, &temp)) { return false; } if (!JS_DefinePropertyById(cx, obj, atomsCache->format_id, temp, JSPROP_ENUMERATE)) { return false; } break; } while(false); do { // block for our 'break' successCode and scope for 'temp' and 'currentValue' JS::Rooted temp(cx); uint32_t const & currentValue = mUsage; temp.setNumber(currentValue); if (!JS_DefinePropertyById(cx, obj, atomsCache->usage_id, temp, JSPROP_ENUMERATE)) { return false; } break; } while(false); do { // block for our 'break' successCode and scope for 'temp' and 'currentValue' JS::Rooted temp(cx); Sequence const & currentValue = mViewFormats; uint32_t length = currentValue.Length(); JS::Rooted returnArray(cx, JS::NewArrayObject(cx, length)); if (!returnArray) { return false; } // Scope for 'tmp' { JS::Rooted tmp(cx); for (uint32_t sequenceIdx0 = 0; sequenceIdx0 < length; ++sequenceIdx0) { // Control block to let us common up the JS_DefineElement calls when there // are different ways to succeed at wrapping the object. do { if (!ToJSValue(cx, currentValue[sequenceIdx0], &tmp)) { return false; } break; } while (false); if (!JS_DefineElement(cx, returnArray, sequenceIdx0, tmp, JSPROP_ENUMERATE)) { return false; } } } temp.setObject(*returnArray); if (!JS_DefinePropertyById(cx, obj, atomsCache->viewFormats_id, temp, JSPROP_ENUMERATE)) { return false; } break; } while(false); return true; } void GPUCanvasConfiguration::TraceDictionary(JSTracer* trc) { } GPUCanvasConfiguration& GPUCanvasConfiguration::operator=(const GPUCanvasConfiguration& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mAlphaMode = aOther.mAlphaMode; mDevice = aOther.mDevice; mFormat = aOther.mFormat; mUsage = aOther.mUsage; mViewFormats = aOther.mViewFormats; return *this; } GPUColorDict::GPUColorDict() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUColorDict::InitIds(JSContext* cx, GPUColorDictAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->r_id.init(cx, "r") || !atomsCache->g_id.init(cx, "g") || !atomsCache->b_id.init(cx, "b") || !atomsCache->a_id.init(cx, "a")) { return false; } return true; } bool GPUColorDict::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUColorDictAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->a_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'a' member of GPUColorDict", &mA)) { return false; } else if (!std::isfinite(mA)) { cx.ThrowErrorMessage("'a' member of GPUColorDict"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'a' member of GPUColorDict"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->b_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'b' member of GPUColorDict", &mB)) { return false; } else if (!std::isfinite(mB)) { cx.ThrowErrorMessage("'b' member of GPUColorDict"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'b' member of GPUColorDict"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->g_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'g' member of GPUColorDict", &mG)) { return false; } else if (!std::isfinite(mG)) { cx.ThrowErrorMessage("'g' member of GPUColorDict"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'g' member of GPUColorDict"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->r_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'r' member of GPUColorDict", &mR)) { return false; } else if (!std::isfinite(mR)) { cx.ThrowErrorMessage("'r' member of GPUColorDict"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'r' member of GPUColorDict"); } return true; } bool GPUColorDict::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUColorDict::TraceDictionary(JSTracer* trc) { } GPUColorDict& GPUColorDict::operator=(const GPUColorDict& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mA = aOther.mA; mB = aOther.mB; mG = aOther.mG; mR = aOther.mR; return *this; } GPUComputePassTimestampWrites::GPUComputePassTimestampWrites() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUComputePassTimestampWrites::InitIds(JSContext* cx, GPUComputePassTimestampWritesAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->querySet_id.init(cx, "querySet") || !atomsCache->endOfPassWriteIndex_id.init(cx, "endOfPassWriteIndex") || !atomsCache->beginningOfPassWriteIndex_id.init(cx, "beginningOfPassWriteIndex")) { return false; } return true; } bool GPUComputePassTimestampWrites::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUComputePassTimestampWritesAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->beginningOfPassWriteIndex_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mBeginningOfPassWriteIndex.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'beginningOfPassWriteIndex' member of GPUComputePassTimestampWrites", &(mBeginningOfPassWriteIndex.Value()))) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->endOfPassWriteIndex_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mEndOfPassWriteIndex.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'endOfPassWriteIndex' member of GPUComputePassTimestampWrites", &(mEndOfPassWriteIndex.Value()))) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->querySet_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(temp.ptr(), mQuerySet, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("'querySet' member of GPUComputePassTimestampWrites", "GPUQuerySet"); return false; } } } else { cx.ThrowErrorMessage("'querySet' member of GPUComputePassTimestampWrites"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'querySet' member of GPUComputePassTimestampWrites"); } return true; } bool GPUComputePassTimestampWrites::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUComputePassTimestampWrites::TraceDictionary(JSTracer* trc) { } GPUComputePassTimestampWrites& GPUComputePassTimestampWrites::operator=(const GPUComputePassTimestampWrites& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mBeginningOfPassWriteIndex.Reset(); if (aOther.mBeginningOfPassWriteIndex.WasPassed()) { mBeginningOfPassWriteIndex.Construct(aOther.mBeginningOfPassWriteIndex.Value()); } mEndOfPassWriteIndex.Reset(); if (aOther.mEndOfPassWriteIndex.WasPassed()) { mEndOfPassWriteIndex.Construct(aOther.mEndOfPassWriteIndex.Value()); } mQuerySet = aOther.mQuerySet; return *this; } GPUExtent3DDict::GPUExtent3DDict() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUExtent3DDict::InitIds(JSContext* cx, GPUExtent3DDictAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->width_id.init(cx, "width") || !atomsCache->height_id.init(cx, "height") || !atomsCache->depthOrArrayLayers_id.init(cx, "depthOrArrayLayers")) { return false; } return true; } bool GPUExtent3DDict::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUExtent3DDictAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthOrArrayLayers_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'depthOrArrayLayers' member of GPUExtent3DDict", &mDepthOrArrayLayers)) { return false; } } else { mDepthOrArrayLayers = 1U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->height_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'height' member of GPUExtent3DDict", &mHeight)) { return false; } } else { mHeight = 1U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->width_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'width' member of GPUExtent3DDict", &mWidth)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'width' member of GPUExtent3DDict"); } return true; } bool GPUExtent3DDict::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUExtent3DDict::TraceDictionary(JSTracer* trc) { } GPUExtent3DDict& GPUExtent3DDict::operator=(const GPUExtent3DDict& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mDepthOrArrayLayers = aOther.mDepthOrArrayLayers; mHeight = aOther.mHeight; mWidth = aOther.mWidth; return *this; } GPUExternalTextureBindingLayout::GPUExternalTextureBindingLayout() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUExternalTextureBindingLayout::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } return true; } bool GPUExternalTextureBindingLayout::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUExternalTextureBindingLayout::TraceDictionary(JSTracer* trc) { } GPUExternalTextureBindingLayout& GPUExternalTextureBindingLayout::operator=(const GPUExternalTextureBindingLayout& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); return *this; } GPUMultisampleState::GPUMultisampleState() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUMultisampleState::InitIds(JSContext* cx, GPUMultisampleStateAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->mask_id.init(cx, "mask") || !atomsCache->count_id.init(cx, "count") || !atomsCache->alphaToCoverageEnabled_id.init(cx, "alphaToCoverageEnabled")) { return false; } return true; } bool GPUMultisampleState::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUMultisampleStateAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->alphaToCoverageEnabled_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'alphaToCoverageEnabled' member of GPUMultisampleState", &mAlphaToCoverageEnabled)) { return false; } } else { mAlphaToCoverageEnabled = false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->count_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'count' member of GPUMultisampleState", &mCount)) { return false; } } else { mCount = 1U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->mask_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'mask' member of GPUMultisampleState", &mMask)) { return false; } } else { mMask = 4294967295U; } mIsAnyMemberPresent = true; return true; } bool GPUMultisampleState::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUMultisampleState::TraceDictionary(JSTracer* trc) { } GPUMultisampleState& GPUMultisampleState::operator=(const GPUMultisampleState& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mAlphaToCoverageEnabled = aOther.mAlphaToCoverageEnabled; mCount = aOther.mCount; mMask = aOther.mMask; return *this; } GPUObjectDescriptorBase::GPUObjectDescriptorBase() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUObjectDescriptorBase::InitIds(JSContext* cx, GPUObjectDescriptorBaseAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->label_id.init(cx, "label")) { return false; } return true; } bool GPUObjectDescriptorBase::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUObjectDescriptorBaseAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->label_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, mLabel)) { return false; } if (!NormalizeUSVString(mLabel)) { JS_ReportOutOfMemory(cx); return false; } } else { mLabel.AssignLiteral(u""); } mIsAnyMemberPresent = true; return true; } bool GPUObjectDescriptorBase::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUObjectDescriptorBase::TraceDictionary(JSTracer* trc) { } GPUObjectDescriptorBase& GPUObjectDescriptorBase::operator=(const GPUObjectDescriptorBase& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mLabel = aOther.mLabel; return *this; } GPUOrigin2DDict::GPUOrigin2DDict() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUOrigin2DDict::InitIds(JSContext* cx, GPUOrigin2DDictAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->y_id.init(cx, "y") || !atomsCache->x_id.init(cx, "x")) { return false; } return true; } bool GPUOrigin2DDict::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUOrigin2DDictAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->x_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'x' member of GPUOrigin2DDict", &mX)) { return false; } } else { mX = 0U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->y_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'y' member of GPUOrigin2DDict", &mY)) { return false; } } else { mY = 0U; } mIsAnyMemberPresent = true; return true; } bool GPUOrigin2DDict::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUOrigin2DDict::TraceDictionary(JSTracer* trc) { } GPUOrigin2DDict& GPUOrigin2DDict::operator=(const GPUOrigin2DDict& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mX = aOther.mX; mY = aOther.mY; return *this; } GPUOrigin3DDict::GPUOrigin3DDict() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUOrigin3DDict::InitIds(JSContext* cx, GPUOrigin3DDictAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->z_id.init(cx, "z") || !atomsCache->y_id.init(cx, "y") || !atomsCache->x_id.init(cx, "x")) { return false; } return true; } bool GPUOrigin3DDict::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUOrigin3DDictAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->x_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'x' member of GPUOrigin3DDict", &mX)) { return false; } } else { mX = 0U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->y_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'y' member of GPUOrigin3DDict", &mY)) { return false; } } else { mY = 0U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->z_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'z' member of GPUOrigin3DDict", &mZ)) { return false; } } else { mZ = 0U; } mIsAnyMemberPresent = true; return true; } bool GPUOrigin3DDict::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUOrigin3DDict::TraceDictionary(JSTracer* trc) { } GPUOrigin3DDict& GPUOrigin3DDict::operator=(const GPUOrigin3DDict& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mX = aOther.mX; mY = aOther.mY; mZ = aOther.mZ; return *this; } GPUPipelineErrorInit::GPUPipelineErrorInit() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUPipelineErrorInit::InitIds(JSContext* cx, GPUPipelineErrorInitAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->reason_id.init(cx, "reason")) { return false; } return true; } bool GPUPipelineErrorInit::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUPipelineErrorInitAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->reason_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUPipelineErrorReason", "'reason' member of GPUPipelineErrorInit", &index)) { return false; } MOZ_ASSERT(index >= 0); mReason = static_cast(index); } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'reason' member of GPUPipelineErrorInit"); } return true; } bool GPUPipelineErrorInit::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUPipelineErrorInit::TraceDictionary(JSTracer* trc) { } GPUPipelineErrorInit& GPUPipelineErrorInit::operator=(const GPUPipelineErrorInit& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mReason = aOther.mReason; return *this; } bool GPUPipelineLayoutOrGPUAutoLayoutMode::TrySetToGPUPipelineLayout(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsGPUPipelineLayout(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUPipelineLayout(); tryNext = true; return true; } } } return true; } bool GPUPipelineLayoutOrGPUAutoLayoutMode::TrySetToGPUPipelineLayout(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUPipelineLayout(cx, value, tryNext, passedToJSImpl); } bool GPUPipelineLayoutOrGPUAutoLayoutMode::TrySetToGPUAutoLayoutMode(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot GPUAutoLayoutMode& memberSlot = RawSetAsGPUAutoLayoutMode(); { int index; if (!binding_detail::FindEnumStringIndex(cx, value, binding_detail::EnumStrings::Values, "GPUAutoLayoutMode", "GPUAutoLayoutMode branch of (GPUPipelineLayout or GPUAutoLayoutMode)", &index)) { return false; } MOZ_ASSERT(index >= 0); memberSlot = static_cast(index); } } return true; } bool GPUPipelineLayoutOrGPUAutoLayoutMode::TrySetToGPUAutoLayoutMode(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUAutoLayoutMode(cx, value, tryNext, passedToJSImpl); } bool GPUPipelineLayoutOrGPUAutoLayoutMode::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToGPUPipelineLayout(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { do { done = (failed = !TrySetToGPUAutoLayoutMode(cx, value, tryNext)) || !tryNext; break; } while (false); } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "GPUPipelineLayout"); return false; } return true; } bool GPUPipelineLayoutOrGPUAutoLayoutMode::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } bool GPUPipelineLayoutOrGPUAutoLayoutMode::ToJSVal(JSContext* cx, JS::Handle scopeObj, JS::MutableHandle rval) const { switch (mType) { case eUninitialized: { return false; } case eGPUPipelineLayout: { if (!GetOrCreateDOMReflector(cx, mValue.mGPUPipelineLayout.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eGPUAutoLayoutMode: { if (!ToJSValue(cx, mValue.mGPUAutoLayoutMode.Value(), rval)) { return false; } return true; } default: { return false; } } } OwningGPUPipelineLayoutOrGPUAutoLayoutMode::OwningGPUPipelineLayoutOrGPUAutoLayoutMode(OwningGPUPipelineLayoutOrGPUAutoLayoutMode&& aOther) : mType(eUninitialized) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eGPUPipelineLayout: { mType = eGPUPipelineLayout; mValue.mGPUPipelineLayout.SetValue(std::move(aOther.mValue.mGPUPipelineLayout.Value())); break; } case eGPUAutoLayoutMode: { mType = eGPUAutoLayoutMode; mValue.mGPUAutoLayoutMode.SetValue(std::move(aOther.mValue.mGPUAutoLayoutMode.Value())); break; } } } bool OwningGPUPipelineLayoutOrGPUAutoLayoutMode::TrySetToGPUPipelineLayout(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsGPUPipelineLayout(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUPipelineLayout(); tryNext = true; return true; } } } return true; } bool OwningGPUPipelineLayoutOrGPUAutoLayoutMode::TrySetToGPUPipelineLayout(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUPipelineLayout(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningGPUPipelineLayoutOrGPUAutoLayoutMode::RawSetAsGPUPipelineLayout() { if (mType == eGPUPipelineLayout) { return mValue.mGPUPipelineLayout.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUPipelineLayout; return mValue.mGPUPipelineLayout.SetValue(); } [[nodiscard]] OwningNonNull& OwningGPUPipelineLayoutOrGPUAutoLayoutMode::SetAsGPUPipelineLayout() { if (mType == eGPUPipelineLayout) { return mValue.mGPUPipelineLayout.Value(); } Uninit(); mType = eGPUPipelineLayout; return mValue.mGPUPipelineLayout.SetValue(); } void OwningGPUPipelineLayoutOrGPUAutoLayoutMode::DestroyGPUPipelineLayout() { MOZ_RELEASE_ASSERT(IsGPUPipelineLayout(), "Wrong type!"); mValue.mGPUPipelineLayout.Destroy(); mType = eUninitialized; } bool OwningGPUPipelineLayoutOrGPUAutoLayoutMode::TrySetToGPUAutoLayoutMode(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot GPUAutoLayoutMode& memberSlot = RawSetAsGPUAutoLayoutMode(); { int index; if (!binding_detail::FindEnumStringIndex(cx, value, binding_detail::EnumStrings::Values, "GPUAutoLayoutMode", "GPUAutoLayoutMode branch of (GPUPipelineLayout or GPUAutoLayoutMode)", &index)) { return false; } MOZ_ASSERT(index >= 0); memberSlot = static_cast(index); } } return true; } bool OwningGPUPipelineLayoutOrGPUAutoLayoutMode::TrySetToGPUAutoLayoutMode(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUAutoLayoutMode(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] GPUAutoLayoutMode& OwningGPUPipelineLayoutOrGPUAutoLayoutMode::RawSetAsGPUAutoLayoutMode() { if (mType == eGPUAutoLayoutMode) { return mValue.mGPUAutoLayoutMode.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUAutoLayoutMode; return mValue.mGPUAutoLayoutMode.SetValue(); } [[nodiscard]] GPUAutoLayoutMode& OwningGPUPipelineLayoutOrGPUAutoLayoutMode::SetAsGPUAutoLayoutMode() { if (mType == eGPUAutoLayoutMode) { return mValue.mGPUAutoLayoutMode.Value(); } Uninit(); mType = eGPUAutoLayoutMode; return mValue.mGPUAutoLayoutMode.SetValue(); } void OwningGPUPipelineLayoutOrGPUAutoLayoutMode::DestroyGPUAutoLayoutMode() { MOZ_RELEASE_ASSERT(IsGPUAutoLayoutMode(), "Wrong type!"); mValue.mGPUAutoLayoutMode.Destroy(); mType = eUninitialized; } bool OwningGPUPipelineLayoutOrGPUAutoLayoutMode::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToGPUPipelineLayout(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { do { done = (failed = !TrySetToGPUAutoLayoutMode(cx, value, tryNext)) || !tryNext; break; } while (false); } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "GPUPipelineLayout"); return false; } return true; } bool OwningGPUPipelineLayoutOrGPUAutoLayoutMode::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } void OwningGPUPipelineLayoutOrGPUAutoLayoutMode::Uninit() { switch (mType) { case eUninitialized: { break; } case eGPUPipelineLayout: { DestroyGPUPipelineLayout(); break; } case eGPUAutoLayoutMode: { DestroyGPUAutoLayoutMode(); break; } } } bool OwningGPUPipelineLayoutOrGPUAutoLayoutMode::ToJSVal(JSContext* cx, JS::Handle scopeObj, JS::MutableHandle rval) const { switch (mType) { case eUninitialized: { return false; } case eGPUPipelineLayout: { if (!GetOrCreateDOMReflector(cx, mValue.mGPUPipelineLayout.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eGPUAutoLayoutMode: { if (!ToJSValue(cx, mValue.mGPUAutoLayoutMode.Value(), rval)) { return false; } return true; } default: { return false; } } } OwningGPUPipelineLayoutOrGPUAutoLayoutMode& OwningGPUPipelineLayoutOrGPUAutoLayoutMode::operator=(OwningGPUPipelineLayoutOrGPUAutoLayoutMode&& aOther) { this->~OwningGPUPipelineLayoutOrGPUAutoLayoutMode(); new (this) OwningGPUPipelineLayoutOrGPUAutoLayoutMode (std::move(aOther)); return *this; } OwningGPUPipelineLayoutOrGPUAutoLayoutMode& OwningGPUPipelineLayoutOrGPUAutoLayoutMode::operator=(const OwningGPUPipelineLayoutOrGPUAutoLayoutMode& aOther) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eGPUPipelineLayout: { SetAsGPUPipelineLayout() = aOther.GetAsGPUPipelineLayout(); break; } case eGPUAutoLayoutMode: { SetAsGPUAutoLayoutMode() = aOther.GetAsGPUAutoLayoutMode(); break; } } return *this; } GPUPrimitiveState::GPUPrimitiveState() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUPrimitiveState::InitIds(JSContext* cx, GPUPrimitiveStateAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->unclippedDepth_id.init(cx, "unclippedDepth") || !atomsCache->topology_id.init(cx, "topology") || !atomsCache->stripIndexFormat_id.init(cx, "stripIndexFormat") || !atomsCache->frontFace_id.init(cx, "frontFace") || !atomsCache->cullMode_id.init(cx, "cullMode")) { return false; } return true; } bool GPUPrimitiveState::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUPrimitiveStateAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->cullMode_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUCullMode", "'cullMode' member of GPUPrimitiveState", &index)) { return false; } MOZ_ASSERT(index >= 0); mCullMode = static_cast(index); } } else { mCullMode = GPUCullMode::None; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->frontFace_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUFrontFace", "'frontFace' member of GPUPrimitiveState", &index)) { return false; } MOZ_ASSERT(index >= 0); mFrontFace = static_cast(index); } } else { mFrontFace = GPUFrontFace::Ccw; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stripIndexFormat_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mStripIndexFormat.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUIndexFormat", "'stripIndexFormat' member of GPUPrimitiveState", &index)) { return false; } MOZ_ASSERT(index >= 0); (mStripIndexFormat.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->topology_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUPrimitiveTopology", "'topology' member of GPUPrimitiveState", &index)) { return false; } MOZ_ASSERT(index >= 0); mTopology = static_cast(index); } } else { mTopology = GPUPrimitiveTopology::Triangle_list; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->unclippedDepth_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'unclippedDepth' member of GPUPrimitiveState", &mUnclippedDepth)) { return false; } } else { mUnclippedDepth = false; } mIsAnyMemberPresent = true; return true; } bool GPUPrimitiveState::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUPrimitiveState::TraceDictionary(JSTracer* trc) { } GPUPrimitiveState& GPUPrimitiveState::operator=(const GPUPrimitiveState& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mCullMode = aOther.mCullMode; mFrontFace = aOther.mFrontFace; mStripIndexFormat.Reset(); if (aOther.mStripIndexFormat.WasPassed()) { mStripIndexFormat.Construct(aOther.mStripIndexFormat.Value()); } mTopology = aOther.mTopology; mUnclippedDepth = aOther.mUnclippedDepth; return *this; } GPUProgrammableStage::GPUProgrammableStage() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUProgrammableStage::InitIds(JSContext* cx, GPUProgrammableStageAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->module_id.init(cx, "module") || !atomsCache->entryPoint_id.init(cx, "entryPoint") || !atomsCache->constants_id.init(cx, "constants")) { return false; } return true; } bool GPUProgrammableStage::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUProgrammableStageAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->constants_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mConstants.Construct(); if (temp.ref().isObject()) { auto& recordEntries = (mConstants.Value()).Entries(); JS::Rooted recordObj(cx, &temp.ref().toObject()); JS::RootedVector ids(cx); if (!js::GetPropertyKeys(cx, recordObj, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) { return false; } if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } JS::Rooted propNameValue(cx); JS::Rooted temp(cx); JS::Rooted curId(cx); JS::Rooted idVal(cx); // Use a hashset to keep track of ids seen, to avoid // introducing nasty O(N^2) behavior scanning for them all the // time. Ideally we'd use a data structure with O(1) lookup // _and_ ordering for the MozMap, but we don't have one lying // around. nsTHashtable idsSeen; for (size_t i = 0; i < ids.length(); ++i) { curId = ids[i]; JS::Rooted> desc(cx); if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId, &desc)) { return false; } if (desc.isNothing() || !desc->enumerable()) { continue; } idVal = js::IdToValue(curId); nsString propName; // This will just throw if idVal is a Symbol, like the spec says // to do. if (!ConvertJSValueToUSVString(cx, idVal, "key of 'constants' member of GPUProgrammableStage", propName)) { return false; } if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) { return false; } Record::EntryType* entry; if (!idsSeen.EnsureInserted(propName)) { // Find the existing entry. auto idx = recordEntries.IndexOf(propName); MOZ_ASSERT(idx != recordEntries.NoIndex, "Why is it not found?"); // Now blow it away to make it look like it was just added // to the array, because it's not obvious that it's // safe to write to its already-initialized mValue via our // normal codegen conversions. For example, the value // could be a union and this would change its type, but // codegen assumes we won't do that. entry = recordEntries.ReconstructElementAt(idx); } else { // Safe to do an infallible append here, because we did a // SetCapacity above to the right capacity. entry = recordEntries.AppendElement(); } entry->mKey = propName; double& slot = entry->mValue; if (!ValueToPrimitive(cx, temp, "Value in 'constants' member of GPUProgrammableStage", &slot)) { return false; } else if (!std::isfinite(slot)) { cx.ThrowErrorMessage("Value in 'constants' member of GPUProgrammableStage"); return false; } } } else { cx.ThrowErrorMessage("'constants' member of GPUProgrammableStage"); return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->entryPoint_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mEntryPoint.Construct(); if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, (mEntryPoint.Value()))) { return false; } if (!NormalizeUSVString((mEntryPoint.Value()))) { JS_ReportOutOfMemory(cx); return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->module_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(temp.ptr(), mModule, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("'module' member of GPUProgrammableStage", "GPUShaderModule"); return false; } } } else { cx.ThrowErrorMessage("'module' member of GPUProgrammableStage"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'module' member of GPUProgrammableStage"); } return true; } bool GPUProgrammableStage::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUProgrammableStage::TraceDictionary(JSTracer* trc) { } GPURenderPassTimestampWrites::GPURenderPassTimestampWrites() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPURenderPassTimestampWrites::InitIds(JSContext* cx, GPURenderPassTimestampWritesAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->querySet_id.init(cx, "querySet") || !atomsCache->endOfPassWriteIndex_id.init(cx, "endOfPassWriteIndex") || !atomsCache->beginningOfPassWriteIndex_id.init(cx, "beginningOfPassWriteIndex")) { return false; } return true; } bool GPURenderPassTimestampWrites::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPURenderPassTimestampWritesAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->beginningOfPassWriteIndex_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mBeginningOfPassWriteIndex.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'beginningOfPassWriteIndex' member of GPURenderPassTimestampWrites", &(mBeginningOfPassWriteIndex.Value()))) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->endOfPassWriteIndex_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mEndOfPassWriteIndex.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'endOfPassWriteIndex' member of GPURenderPassTimestampWrites", &(mEndOfPassWriteIndex.Value()))) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->querySet_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(temp.ptr(), mQuerySet, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("'querySet' member of GPURenderPassTimestampWrites", "GPUQuerySet"); return false; } } } else { cx.ThrowErrorMessage("'querySet' member of GPURenderPassTimestampWrites"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'querySet' member of GPURenderPassTimestampWrites"); } return true; } bool GPURenderPassTimestampWrites::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPURenderPassTimestampWrites::TraceDictionary(JSTracer* trc) { } GPURenderPassTimestampWrites& GPURenderPassTimestampWrites::operator=(const GPURenderPassTimestampWrites& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mBeginningOfPassWriteIndex.Reset(); if (aOther.mBeginningOfPassWriteIndex.WasPassed()) { mBeginningOfPassWriteIndex.Construct(aOther.mBeginningOfPassWriteIndex.Value()); } mEndOfPassWriteIndex.Reset(); if (aOther.mEndOfPassWriteIndex.WasPassed()) { mEndOfPassWriteIndex.Construct(aOther.mEndOfPassWriteIndex.Value()); } mQuerySet = aOther.mQuerySet; return *this; } GPURequestAdapterOptions::GPURequestAdapterOptions() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPURequestAdapterOptions::InitIds(JSContext* cx, GPURequestAdapterOptionsAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->xrCompatible_id.init(cx, "xrCompatible") || !atomsCache->powerPreference_id.init(cx, "powerPreference") || !atomsCache->forceFallbackAdapter_id.init(cx, "forceFallbackAdapter") || !atomsCache->featureLevel_id.init(cx, "featureLevel")) { return false; } return true; } bool GPURequestAdapterOptions::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPURequestAdapterOptionsAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->featureLevel_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, mFeatureLevel)) { return false; } } else { mFeatureLevel.AssignLiteral(u"core"); } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->forceFallbackAdapter_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'forceFallbackAdapter' member of GPURequestAdapterOptions", &mForceFallbackAdapter)) { return false; } } else { mForceFallbackAdapter = false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->powerPreference_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mPowerPreference.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUPowerPreference", "'powerPreference' member of GPURequestAdapterOptions", &index)) { return false; } MOZ_ASSERT(index >= 0); (mPowerPreference.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->xrCompatible_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'xrCompatible' member of GPURequestAdapterOptions", &mXrCompatible)) { return false; } } else { mXrCompatible = false; } mIsAnyMemberPresent = true; return true; } bool GPURequestAdapterOptions::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPURequestAdapterOptions::TraceDictionary(JSTracer* trc) { } GPURequestAdapterOptions& GPURequestAdapterOptions::operator=(const GPURequestAdapterOptions& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mFeatureLevel = aOther.mFeatureLevel; mForceFallbackAdapter = aOther.mForceFallbackAdapter; mPowerPreference.Reset(); if (aOther.mPowerPreference.WasPassed()) { mPowerPreference.Construct(aOther.mPowerPreference.Value()); } mXrCompatible = aOther.mXrCompatible; return *this; } GPUSamplerBindingLayout::GPUSamplerBindingLayout() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUSamplerBindingLayout::InitIds(JSContext* cx, GPUSamplerBindingLayoutAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->type_id.init(cx, "type")) { return false; } return true; } bool GPUSamplerBindingLayout::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUSamplerBindingLayoutAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->type_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUSamplerBindingType", "'type' member of GPUSamplerBindingLayout", &index)) { return false; } MOZ_ASSERT(index >= 0); mType = static_cast(index); } } else { mType = GPUSamplerBindingType::Filtering; } mIsAnyMemberPresent = true; return true; } bool GPUSamplerBindingLayout::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUSamplerBindingLayout::TraceDictionary(JSTracer* trc) { } GPUSamplerBindingLayout& GPUSamplerBindingLayout::operator=(const GPUSamplerBindingLayout& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mType = aOther.mType; return *this; } GPUStencilFaceState::GPUStencilFaceState() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUStencilFaceState::InitIds(JSContext* cx, GPUStencilFaceStateAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->passOp_id.init(cx, "passOp") || !atomsCache->failOp_id.init(cx, "failOp") || !atomsCache->depthFailOp_id.init(cx, "depthFailOp") || !atomsCache->compare_id.init(cx, "compare")) { return false; } return true; } bool GPUStencilFaceState::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUStencilFaceStateAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->compare_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUCompareFunction", "'compare' member of GPUStencilFaceState", &index)) { return false; } MOZ_ASSERT(index >= 0); mCompare = static_cast(index); } } else { mCompare = GPUCompareFunction::Always; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthFailOp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUStencilOperation", "'depthFailOp' member of GPUStencilFaceState", &index)) { return false; } MOZ_ASSERT(index >= 0); mDepthFailOp = static_cast(index); } } else { mDepthFailOp = GPUStencilOperation::Keep; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->failOp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUStencilOperation", "'failOp' member of GPUStencilFaceState", &index)) { return false; } MOZ_ASSERT(index >= 0); mFailOp = static_cast(index); } } else { mFailOp = GPUStencilOperation::Keep; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->passOp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUStencilOperation", "'passOp' member of GPUStencilFaceState", &index)) { return false; } MOZ_ASSERT(index >= 0); mPassOp = static_cast(index); } } else { mPassOp = GPUStencilOperation::Keep; } mIsAnyMemberPresent = true; return true; } bool GPUStencilFaceState::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUStencilFaceState::TraceDictionary(JSTracer* trc) { } GPUStencilFaceState& GPUStencilFaceState::operator=(const GPUStencilFaceState& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mCompare = aOther.mCompare; mDepthFailOp = aOther.mDepthFailOp; mFailOp = aOther.mFailOp; mPassOp = aOther.mPassOp; return *this; } GPUStorageTextureBindingLayout::GPUStorageTextureBindingLayout() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUStorageTextureBindingLayout::InitIds(JSContext* cx, GPUStorageTextureBindingLayoutAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->viewDimension_id.init(cx, "viewDimension") || !atomsCache->format_id.init(cx, "format") || !atomsCache->access_id.init(cx, "access")) { return false; } return true; } bool GPUStorageTextureBindingLayout::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUStorageTextureBindingLayoutAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->access_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUStorageTextureAccess", "'access' member of GPUStorageTextureBindingLayout", &index)) { return false; } MOZ_ASSERT(index >= 0); mAccess = static_cast(index); } } else { mAccess = GPUStorageTextureAccess::Write_only; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->format_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureFormat", "'format' member of GPUStorageTextureBindingLayout", &index)) { return false; } MOZ_ASSERT(index >= 0); mFormat = static_cast(index); } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'format' member of GPUStorageTextureBindingLayout"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->viewDimension_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureViewDimension", "'viewDimension' member of GPUStorageTextureBindingLayout", &index)) { return false; } MOZ_ASSERT(index >= 0); mViewDimension = static_cast(index); } } else { mViewDimension = GPUTextureViewDimension::_2d; } mIsAnyMemberPresent = true; return true; } bool GPUStorageTextureBindingLayout::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUStorageTextureBindingLayout::TraceDictionary(JSTracer* trc) { } GPUStorageTextureBindingLayout& GPUStorageTextureBindingLayout::operator=(const GPUStorageTextureBindingLayout& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mAccess = aOther.mAccess; mFormat = aOther.mFormat; mViewDimension = aOther.mViewDimension; return *this; } GPUTexelCopyBufferLayout::GPUTexelCopyBufferLayout() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUTexelCopyBufferLayout::InitIds(JSContext* cx, GPUTexelCopyBufferLayoutAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->rowsPerImage_id.init(cx, "rowsPerImage") || !atomsCache->offset_id.init(cx, "offset") || !atomsCache->bytesPerRow_id.init(cx, "bytesPerRow")) { return false; } return true; } bool GPUTexelCopyBufferLayout::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUTexelCopyBufferLayoutAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->bytesPerRow_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mBytesPerRow.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'bytesPerRow' member of GPUTexelCopyBufferLayout", &(mBytesPerRow.Value()))) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->offset_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'offset' member of GPUTexelCopyBufferLayout", &mOffset)) { return false; } } else { mOffset = 0ULL; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->rowsPerImage_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mRowsPerImage.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'rowsPerImage' member of GPUTexelCopyBufferLayout", &(mRowsPerImage.Value()))) { return false; } mIsAnyMemberPresent = true; } return true; } bool GPUTexelCopyBufferLayout::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUTexelCopyBufferLayout::TraceDictionary(JSTracer* trc) { } GPUTexelCopyBufferLayout& GPUTexelCopyBufferLayout::operator=(const GPUTexelCopyBufferLayout& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mBytesPerRow.Reset(); if (aOther.mBytesPerRow.WasPassed()) { mBytesPerRow.Construct(aOther.mBytesPerRow.Value()); } mOffset = aOther.mOffset; mRowsPerImage.Reset(); if (aOther.mRowsPerImage.WasPassed()) { mRowsPerImage.Construct(aOther.mRowsPerImage.Value()); } return *this; } GPUTextureBindingLayout::GPUTextureBindingLayout() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUTextureBindingLayout::InitIds(JSContext* cx, GPUTextureBindingLayoutAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->viewDimension_id.init(cx, "viewDimension") || !atomsCache->sampleType_id.init(cx, "sampleType") || !atomsCache->multisampled_id.init(cx, "multisampled")) { return false; } return true; } bool GPUTextureBindingLayout::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUTextureBindingLayoutAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->multisampled_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'multisampled' member of GPUTextureBindingLayout", &mMultisampled)) { return false; } } else { mMultisampled = false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->sampleType_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureSampleType", "'sampleType' member of GPUTextureBindingLayout", &index)) { return false; } MOZ_ASSERT(index >= 0); mSampleType = static_cast(index); } } else { mSampleType = GPUTextureSampleType::Float; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->viewDimension_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureViewDimension", "'viewDimension' member of GPUTextureBindingLayout", &index)) { return false; } MOZ_ASSERT(index >= 0); mViewDimension = static_cast(index); } } else { mViewDimension = GPUTextureViewDimension::_2d; } mIsAnyMemberPresent = true; return true; } bool GPUTextureBindingLayout::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUTextureBindingLayout::TraceDictionary(JSTracer* trc) { } GPUTextureBindingLayout& GPUTextureBindingLayout::operator=(const GPUTextureBindingLayout& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mMultisampled = aOther.mMultisampled; mSampleType = aOther.mSampleType; mViewDimension = aOther.mViewDimension; return *this; } bool GPUTextureOrGPUTextureView::TrySetToGPUTexture(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsGPUTexture(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUTexture(); tryNext = true; return true; } } } return true; } bool GPUTextureOrGPUTextureView::TrySetToGPUTexture(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUTexture(cx, value, tryNext, passedToJSImpl); } bool GPUTextureOrGPUTextureView::TrySetToGPUTextureView(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsGPUTextureView(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUTextureView(); tryNext = true; return true; } } } return true; } bool GPUTextureOrGPUTextureView::TrySetToGPUTextureView(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUTextureView(cx, value, tryNext, passedToJSImpl); } bool GPUTextureOrGPUTextureView::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToGPUTexture(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToGPUTextureView(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "GPUTexture, GPUTextureView"); return false; } return true; } bool GPUTextureOrGPUTextureView::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } bool GPUTextureOrGPUTextureView::ToJSVal(JSContext* cx, JS::Handle scopeObj, JS::MutableHandle rval) const { switch (mType) { case eUninitialized: { return false; } case eGPUTexture: { if (!GetOrCreateDOMReflector(cx, mValue.mGPUTexture.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eGPUTextureView: { if (!GetOrCreateDOMReflector(cx, mValue.mGPUTextureView.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } default: { return false; } } } OwningGPUTextureOrGPUTextureView::OwningGPUTextureOrGPUTextureView(OwningGPUTextureOrGPUTextureView&& aOther) : mType(eUninitialized) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eGPUTexture: { mType = eGPUTexture; mValue.mGPUTexture.SetValue(std::move(aOther.mValue.mGPUTexture.Value())); break; } case eGPUTextureView: { mType = eGPUTextureView; mValue.mGPUTextureView.SetValue(std::move(aOther.mValue.mGPUTextureView.Value())); break; } } } bool OwningGPUTextureOrGPUTextureView::TrySetToGPUTexture(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsGPUTexture(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUTexture(); tryNext = true; return true; } } } return true; } bool OwningGPUTextureOrGPUTextureView::TrySetToGPUTexture(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUTexture(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningGPUTextureOrGPUTextureView::RawSetAsGPUTexture() { if (mType == eGPUTexture) { return mValue.mGPUTexture.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUTexture; return mValue.mGPUTexture.SetValue(); } [[nodiscard]] OwningNonNull& OwningGPUTextureOrGPUTextureView::SetAsGPUTexture() { if (mType == eGPUTexture) { return mValue.mGPUTexture.Value(); } Uninit(); mType = eGPUTexture; return mValue.mGPUTexture.SetValue(); } void OwningGPUTextureOrGPUTextureView::DestroyGPUTexture() { MOZ_RELEASE_ASSERT(IsGPUTexture(), "Wrong type!"); mValue.mGPUTexture.Destroy(); mType = eUninitialized; } bool OwningGPUTextureOrGPUTextureView::TrySetToGPUTextureView(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsGPUTextureView(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUTextureView(); tryNext = true; return true; } } } return true; } bool OwningGPUTextureOrGPUTextureView::TrySetToGPUTextureView(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUTextureView(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningGPUTextureOrGPUTextureView::RawSetAsGPUTextureView() { if (mType == eGPUTextureView) { return mValue.mGPUTextureView.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUTextureView; return mValue.mGPUTextureView.SetValue(); } [[nodiscard]] OwningNonNull& OwningGPUTextureOrGPUTextureView::SetAsGPUTextureView() { if (mType == eGPUTextureView) { return mValue.mGPUTextureView.Value(); } Uninit(); mType = eGPUTextureView; return mValue.mGPUTextureView.SetValue(); } void OwningGPUTextureOrGPUTextureView::DestroyGPUTextureView() { MOZ_RELEASE_ASSERT(IsGPUTextureView(), "Wrong type!"); mValue.mGPUTextureView.Destroy(); mType = eUninitialized; } bool OwningGPUTextureOrGPUTextureView::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToGPUTexture(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToGPUTextureView(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "GPUTexture, GPUTextureView"); return false; } return true; } bool OwningGPUTextureOrGPUTextureView::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } void OwningGPUTextureOrGPUTextureView::Uninit() { switch (mType) { case eUninitialized: { break; } case eGPUTexture: { DestroyGPUTexture(); break; } case eGPUTextureView: { DestroyGPUTextureView(); break; } } } bool OwningGPUTextureOrGPUTextureView::ToJSVal(JSContext* cx, JS::Handle scopeObj, JS::MutableHandle rval) const { switch (mType) { case eUninitialized: { return false; } case eGPUTexture: { if (!GetOrCreateDOMReflector(cx, mValue.mGPUTexture.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eGPUTextureView: { if (!GetOrCreateDOMReflector(cx, mValue.mGPUTextureView.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } default: { return false; } } } OwningGPUTextureOrGPUTextureView& OwningGPUTextureOrGPUTextureView::operator=(OwningGPUTextureOrGPUTextureView&& aOther) { this->~OwningGPUTextureOrGPUTextureView(); new (this) OwningGPUTextureOrGPUTextureView (std::move(aOther)); return *this; } OwningGPUTextureOrGPUTextureView& OwningGPUTextureOrGPUTextureView::operator=(const OwningGPUTextureOrGPUTextureView& aOther) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eGPUTexture: { SetAsGPUTexture() = aOther.GetAsGPUTexture(); break; } case eGPUTextureView: { SetAsGPUTextureView() = aOther.GetAsGPUTextureView(); break; } } return *this; } GPUVertexAttribute::GPUVertexAttribute() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUVertexAttribute::InitIds(JSContext* cx, GPUVertexAttributeAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->shaderLocation_id.init(cx, "shaderLocation") || !atomsCache->offset_id.init(cx, "offset") || !atomsCache->format_id.init(cx, "format")) { return false; } return true; } bool GPUVertexAttribute::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUVertexAttributeAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->format_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUVertexFormat", "'format' member of GPUVertexAttribute", &index)) { return false; } MOZ_ASSERT(index >= 0); mFormat = static_cast(index); } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'format' member of GPUVertexAttribute"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->offset_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'offset' member of GPUVertexAttribute", &mOffset)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'offset' member of GPUVertexAttribute"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->shaderLocation_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'shaderLocation' member of GPUVertexAttribute", &mShaderLocation)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'shaderLocation' member of GPUVertexAttribute"); } return true; } bool GPUVertexAttribute::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUVertexAttribute::TraceDictionary(JSTracer* trc) { } GPUVertexAttribute& GPUVertexAttribute::operator=(const GPUVertexAttribute& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mFormat = aOther.mFormat; mOffset = aOther.mOffset; mShaderLocation = aOther.mShaderLocation; return *this; } bool HTMLVideoElementOrVideoFrame::TrySetToHTMLVideoElement(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsHTMLVideoElement(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyHTMLVideoElement(); tryNext = true; return true; } } } return true; } bool HTMLVideoElementOrVideoFrame::TrySetToHTMLVideoElement(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToHTMLVideoElement(cx, value, tryNext, passedToJSImpl); } bool HTMLVideoElementOrVideoFrame::TrySetToVideoFrame(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsVideoFrame(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyVideoFrame(); tryNext = true; return true; } } } return true; } bool HTMLVideoElementOrVideoFrame::TrySetToVideoFrame(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToVideoFrame(cx, value, tryNext, passedToJSImpl); } bool HTMLVideoElementOrVideoFrame::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToHTMLVideoElement(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToVideoFrame(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "HTMLVideoElement, VideoFrame"); return false; } return true; } bool HTMLVideoElementOrVideoFrame::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } bool HTMLVideoElementOrVideoFrame::ToJSVal(JSContext* cx, JS::Handle scopeObj, JS::MutableHandle rval) const { switch (mType) { case eUninitialized: { return false; } case eHTMLVideoElement: { if (!GetOrCreateDOMReflector(cx, mValue.mHTMLVideoElement.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eVideoFrame: { if (!GetOrCreateDOMReflector(cx, mValue.mVideoFrame.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } default: { return false; } } } OwningHTMLVideoElementOrVideoFrame::OwningHTMLVideoElementOrVideoFrame(OwningHTMLVideoElementOrVideoFrame&& aOther) : mType(eUninitialized) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eHTMLVideoElement: { mType = eHTMLVideoElement; mValue.mHTMLVideoElement.SetValue(std::move(aOther.mValue.mHTMLVideoElement.Value())); break; } case eVideoFrame: { mType = eVideoFrame; mValue.mVideoFrame.SetValue(std::move(aOther.mValue.mVideoFrame.Value())); break; } } } bool OwningHTMLVideoElementOrVideoFrame::TrySetToHTMLVideoElement(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsHTMLVideoElement(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyHTMLVideoElement(); tryNext = true; return true; } } } return true; } bool OwningHTMLVideoElementOrVideoFrame::TrySetToHTMLVideoElement(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToHTMLVideoElement(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningHTMLVideoElementOrVideoFrame::RawSetAsHTMLVideoElement() { if (mType == eHTMLVideoElement) { return mValue.mHTMLVideoElement.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eHTMLVideoElement; return mValue.mHTMLVideoElement.SetValue(); } [[nodiscard]] OwningNonNull& OwningHTMLVideoElementOrVideoFrame::SetAsHTMLVideoElement() { if (mType == eHTMLVideoElement) { return mValue.mHTMLVideoElement.Value(); } Uninit(); mType = eHTMLVideoElement; return mValue.mHTMLVideoElement.SetValue(); } void OwningHTMLVideoElementOrVideoFrame::DestroyHTMLVideoElement() { MOZ_RELEASE_ASSERT(IsHTMLVideoElement(), "Wrong type!"); mValue.mHTMLVideoElement.Destroy(); mType = eUninitialized; } bool OwningHTMLVideoElementOrVideoFrame::TrySetToVideoFrame(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsVideoFrame(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyVideoFrame(); tryNext = true; return true; } } } return true; } bool OwningHTMLVideoElementOrVideoFrame::TrySetToVideoFrame(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToVideoFrame(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningHTMLVideoElementOrVideoFrame::RawSetAsVideoFrame() { if (mType == eVideoFrame) { return mValue.mVideoFrame.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eVideoFrame; return mValue.mVideoFrame.SetValue(); } [[nodiscard]] OwningNonNull& OwningHTMLVideoElementOrVideoFrame::SetAsVideoFrame() { if (mType == eVideoFrame) { return mValue.mVideoFrame.Value(); } Uninit(); mType = eVideoFrame; return mValue.mVideoFrame.SetValue(); } void OwningHTMLVideoElementOrVideoFrame::DestroyVideoFrame() { MOZ_RELEASE_ASSERT(IsVideoFrame(), "Wrong type!"); mValue.mVideoFrame.Destroy(); mType = eUninitialized; } bool OwningHTMLVideoElementOrVideoFrame::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToHTMLVideoElement(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToVideoFrame(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "HTMLVideoElement, VideoFrame"); return false; } return true; } bool OwningHTMLVideoElementOrVideoFrame::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } void OwningHTMLVideoElementOrVideoFrame::Uninit() { switch (mType) { case eUninitialized: { break; } case eHTMLVideoElement: { DestroyHTMLVideoElement(); break; } case eVideoFrame: { DestroyVideoFrame(); break; } } } bool OwningHTMLVideoElementOrVideoFrame::ToJSVal(JSContext* cx, JS::Handle scopeObj, JS::MutableHandle rval) const { switch (mType) { case eUninitialized: { return false; } case eHTMLVideoElement: { if (!GetOrCreateDOMReflector(cx, mValue.mHTMLVideoElement.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eVideoFrame: { if (!GetOrCreateDOMReflector(cx, mValue.mVideoFrame.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } default: { return false; } } } OwningHTMLVideoElementOrVideoFrame& OwningHTMLVideoElementOrVideoFrame::operator=(OwningHTMLVideoElementOrVideoFrame&& aOther) { this->~OwningHTMLVideoElementOrVideoFrame(); new (this) OwningHTMLVideoElementOrVideoFrame (std::move(aOther)); return *this; } OwningHTMLVideoElementOrVideoFrame& OwningHTMLVideoElementOrVideoFrame::operator=(const OwningHTMLVideoElementOrVideoFrame& aOther) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eHTMLVideoElement: { SetAsHTMLVideoElement() = aOther.GetAsHTMLVideoElement(); break; } case eVideoFrame: { SetAsVideoFrame() = aOther.GetAsVideoFrame(); break; } } return *this; } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToImageBitmap(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsImageBitmap(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyImageBitmap(); tryNext = true; return true; } } } return true; } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToImageBitmap(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToImageBitmap(cx, value, tryNext, passedToJSImpl); } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToHTMLImageElement(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsHTMLImageElement(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyHTMLImageElement(); tryNext = true; return true; } } } return true; } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToHTMLImageElement(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToHTMLImageElement(cx, value, tryNext, passedToJSImpl); } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToHTMLCanvasElement(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsHTMLCanvasElement(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyHTMLCanvasElement(); tryNext = true; return true; } } } return true; } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToHTMLCanvasElement(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToHTMLCanvasElement(cx, value, tryNext, passedToJSImpl); } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToOffscreenCanvas(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsOffscreenCanvas(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyOffscreenCanvas(); tryNext = true; return true; } } } return true; } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToOffscreenCanvas(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToOffscreenCanvas(cx, value, tryNext, passedToJSImpl); } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToImageBitmap(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToHTMLImageElement(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToHTMLCanvasElement(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToOffscreenCanvas(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "ImageBitmap, HTMLImageElement, HTMLCanvasElement, OffscreenCanvas"); return false; } return true; } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } bool ImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::ToJSVal(JSContext* cx, JS::Handle scopeObj, JS::MutableHandle rval) const { switch (mType) { case eUninitialized: { return false; } case eImageBitmap: { if (!GetOrCreateDOMReflector(cx, mValue.mImageBitmap.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eHTMLImageElement: { if (!GetOrCreateDOMReflector(cx, mValue.mHTMLImageElement.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eHTMLCanvasElement: { if (!GetOrCreateDOMReflector(cx, mValue.mHTMLCanvasElement.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eOffscreenCanvas: { if (!GetOrCreateDOMReflector(cx, mValue.mOffscreenCanvas.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } default: { return false; } } } OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas(OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas&& aOther) : mType(eUninitialized) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eImageBitmap: { mType = eImageBitmap; mValue.mImageBitmap.SetValue(std::move(aOther.mValue.mImageBitmap.Value())); break; } case eHTMLImageElement: { mType = eHTMLImageElement; mValue.mHTMLImageElement.SetValue(std::move(aOther.mValue.mHTMLImageElement.Value())); break; } case eHTMLCanvasElement: { mType = eHTMLCanvasElement; mValue.mHTMLCanvasElement.SetValue(std::move(aOther.mValue.mHTMLCanvasElement.Value())); break; } case eOffscreenCanvas: { mType = eOffscreenCanvas; mValue.mOffscreenCanvas.SetValue(std::move(aOther.mValue.mOffscreenCanvas.Value())); break; } } } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToImageBitmap(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsImageBitmap(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyImageBitmap(); tryNext = true; return true; } } } return true; } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToImageBitmap(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToImageBitmap(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::RawSetAsImageBitmap() { if (mType == eImageBitmap) { return mValue.mImageBitmap.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eImageBitmap; return mValue.mImageBitmap.SetValue(); } [[nodiscard]] OwningNonNull& OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::SetAsImageBitmap() { if (mType == eImageBitmap) { return mValue.mImageBitmap.Value(); } Uninit(); mType = eImageBitmap; return mValue.mImageBitmap.SetValue(); } void OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::DestroyImageBitmap() { MOZ_RELEASE_ASSERT(IsImageBitmap(), "Wrong type!"); mValue.mImageBitmap.Destroy(); mType = eUninitialized; } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToHTMLImageElement(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsHTMLImageElement(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyHTMLImageElement(); tryNext = true; return true; } } } return true; } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToHTMLImageElement(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToHTMLImageElement(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::RawSetAsHTMLImageElement() { if (mType == eHTMLImageElement) { return mValue.mHTMLImageElement.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eHTMLImageElement; return mValue.mHTMLImageElement.SetValue(); } [[nodiscard]] OwningNonNull& OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::SetAsHTMLImageElement() { if (mType == eHTMLImageElement) { return mValue.mHTMLImageElement.Value(); } Uninit(); mType = eHTMLImageElement; return mValue.mHTMLImageElement.SetValue(); } void OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::DestroyHTMLImageElement() { MOZ_RELEASE_ASSERT(IsHTMLImageElement(), "Wrong type!"); mValue.mHTMLImageElement.Destroy(); mType = eUninitialized; } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToHTMLCanvasElement(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsHTMLCanvasElement(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyHTMLCanvasElement(); tryNext = true; return true; } } } return true; } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToHTMLCanvasElement(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToHTMLCanvasElement(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::RawSetAsHTMLCanvasElement() { if (mType == eHTMLCanvasElement) { return mValue.mHTMLCanvasElement.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eHTMLCanvasElement; return mValue.mHTMLCanvasElement.SetValue(); } [[nodiscard]] OwningNonNull& OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::SetAsHTMLCanvasElement() { if (mType == eHTMLCanvasElement) { return mValue.mHTMLCanvasElement.Value(); } Uninit(); mType = eHTMLCanvasElement; return mValue.mHTMLCanvasElement.SetValue(); } void OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::DestroyHTMLCanvasElement() { MOZ_RELEASE_ASSERT(IsHTMLCanvasElement(), "Wrong type!"); mValue.mHTMLCanvasElement.Destroy(); mType = eUninitialized; } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToOffscreenCanvas(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsOffscreenCanvas(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyOffscreenCanvas(); tryNext = true; return true; } } } return true; } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::TrySetToOffscreenCanvas(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToOffscreenCanvas(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::RawSetAsOffscreenCanvas() { if (mType == eOffscreenCanvas) { return mValue.mOffscreenCanvas.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eOffscreenCanvas; return mValue.mOffscreenCanvas.SetValue(); } [[nodiscard]] OwningNonNull& OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::SetAsOffscreenCanvas() { if (mType == eOffscreenCanvas) { return mValue.mOffscreenCanvas.Value(); } Uninit(); mType = eOffscreenCanvas; return mValue.mOffscreenCanvas.SetValue(); } void OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::DestroyOffscreenCanvas() { MOZ_RELEASE_ASSERT(IsOffscreenCanvas(), "Wrong type!"); mValue.mOffscreenCanvas.Destroy(); mType = eUninitialized; } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToImageBitmap(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToHTMLImageElement(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToHTMLCanvasElement(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToOffscreenCanvas(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "ImageBitmap, HTMLImageElement, HTMLCanvasElement, OffscreenCanvas"); return false; } return true; } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } void OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::Uninit() { switch (mType) { case eUninitialized: { break; } case eImageBitmap: { DestroyImageBitmap(); break; } case eHTMLImageElement: { DestroyHTMLImageElement(); break; } case eHTMLCanvasElement: { DestroyHTMLCanvasElement(); break; } case eOffscreenCanvas: { DestroyOffscreenCanvas(); break; } } } bool OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::ToJSVal(JSContext* cx, JS::Handle scopeObj, JS::MutableHandle rval) const { switch (mType) { case eUninitialized: { return false; } case eImageBitmap: { if (!GetOrCreateDOMReflector(cx, mValue.mImageBitmap.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eHTMLImageElement: { if (!GetOrCreateDOMReflector(cx, mValue.mHTMLImageElement.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eHTMLCanvasElement: { if (!GetOrCreateDOMReflector(cx, mValue.mHTMLCanvasElement.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } case eOffscreenCanvas: { if (!GetOrCreateDOMReflector(cx, mValue.mOffscreenCanvas.Value(), rval)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } default: { return false; } } } OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas& OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::operator=(OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas&& aOther) { this->~OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas(); new (this) OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas (std::move(aOther)); return *this; } OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas& OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas::operator=(const OwningImageBitmapOrHTMLImageElementOrHTMLCanvasElementOrOffscreenCanvas& aOther) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eImageBitmap: { SetAsImageBitmap() = aOther.GetAsImageBitmap(); break; } case eHTMLImageElement: { SetAsHTMLImageElement() = aOther.GetAsHTMLImageElement(); break; } case eHTMLCanvasElement: { SetAsHTMLCanvasElement() = aOther.GetAsHTMLCanvasElement(); break; } case eOffscreenCanvas: { SetAsOffscreenCanvas() = aOther.GetAsOffscreenCanvas(); break; } } return *this; } bool DoubleSequenceOrGPUColorDict::TrySetToDoubleSequence(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot binding_detail::AutoSequence& memberSlot = RawSetAsDoubleSequence(); JS::ForOfIterator iter(cx); if (!iter.init(value, JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { DestroyDoubleSequence(); tryNext = true; return true; } binding_detail::AutoSequence &arr = memberSlot; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } double* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } double& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of sequence branch of (sequence or GPUColorDict)", &slot)) { return false; } else if (!std::isfinite(slot)) { cx.ThrowErrorMessage("Element of sequence branch of (sequence or GPUColorDict)"); return false; } } } return true; } bool DoubleSequenceOrGPUColorDict::TrySetToDoubleSequence(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToDoubleSequence(cx, value, tryNext, passedToJSImpl); } bool DoubleSequenceOrGPUColorDict::TrySetToGPUColorDict(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot binding_detail::FastGPUColorDict& memberSlot = RawSetAsGPUColorDict(); if (!IsConvertibleToDictionary(value)) { DestroyGPUColorDict(); tryNext = true; return true; } if (!memberSlot.Init(cx, value, "GPUColorDict branch of (sequence or GPUColorDict)", passedToJSImpl)) { return false; } } return true; } bool DoubleSequenceOrGPUColorDict::TrySetToGPUColorDict(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUColorDict(cx, value, tryNext, passedToJSImpl); } bool DoubleSequenceOrGPUColorDict::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToDoubleSequence(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { done = (failed = !TrySetToGPUColorDict(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "sequence, GPUColorDict"); return false; } return true; } bool DoubleSequenceOrGPUColorDict::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } OwningDoubleSequenceOrGPUColorDict::OwningDoubleSequenceOrGPUColorDict(OwningDoubleSequenceOrGPUColorDict&& aOther) : mType(eUninitialized) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eDoubleSequence: { mType = eDoubleSequence; mValue.mDoubleSequence.SetValue(std::move(aOther.mValue.mDoubleSequence.Value())); break; } case eGPUColorDict: { mType = eGPUColorDict; mValue.mGPUColorDict.SetValue(std::move(aOther.mValue.mGPUColorDict.Value())); break; } } } bool OwningDoubleSequenceOrGPUColorDict::TrySetToDoubleSequence(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot Sequence& memberSlot = RawSetAsDoubleSequence(); JS::ForOfIterator iter(cx); if (!iter.init(value, JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { DestroyDoubleSequence(); tryNext = true; return true; } Sequence &arr = memberSlot; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } double* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } double& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of sequence branch of (sequence or GPUColorDict)", &slot)) { return false; } else if (!std::isfinite(slot)) { cx.ThrowErrorMessage("Element of sequence branch of (sequence or GPUColorDict)"); return false; } } } return true; } bool OwningDoubleSequenceOrGPUColorDict::TrySetToDoubleSequence(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToDoubleSequence(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] Sequence& OwningDoubleSequenceOrGPUColorDict::RawSetAsDoubleSequence() { if (mType == eDoubleSequence) { return mValue.mDoubleSequence.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eDoubleSequence; return mValue.mDoubleSequence.SetValue(); } [[nodiscard]] Sequence& OwningDoubleSequenceOrGPUColorDict::SetAsDoubleSequence() { if (mType == eDoubleSequence) { return mValue.mDoubleSequence.Value(); } Uninit(); mType = eDoubleSequence; return mValue.mDoubleSequence.SetValue(); } void OwningDoubleSequenceOrGPUColorDict::DestroyDoubleSequence() { MOZ_RELEASE_ASSERT(IsDoubleSequence(), "Wrong type!"); mValue.mDoubleSequence.Destroy(); mType = eUninitialized; } bool OwningDoubleSequenceOrGPUColorDict::TrySetToGPUColorDict(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot GPUColorDict& memberSlot = RawSetAsGPUColorDict(); if (!IsConvertibleToDictionary(value)) { DestroyGPUColorDict(); tryNext = true; return true; } if (!memberSlot.Init(cx, value, "GPUColorDict branch of (sequence or GPUColorDict)", passedToJSImpl)) { return false; } } return true; } bool OwningDoubleSequenceOrGPUColorDict::TrySetToGPUColorDict(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUColorDict(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] GPUColorDict& OwningDoubleSequenceOrGPUColorDict::RawSetAsGPUColorDict() { if (mType == eGPUColorDict) { return mValue.mGPUColorDict.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUColorDict; return mValue.mGPUColorDict.SetValue(); } [[nodiscard]] GPUColorDict& OwningDoubleSequenceOrGPUColorDict::SetAsGPUColorDict() { if (mType == eGPUColorDict) { return mValue.mGPUColorDict.Value(); } Uninit(); mType = eGPUColorDict; return mValue.mGPUColorDict.SetValue(); } void OwningDoubleSequenceOrGPUColorDict::DestroyGPUColorDict() { MOZ_RELEASE_ASSERT(IsGPUColorDict(), "Wrong type!"); mValue.mGPUColorDict.Destroy(); mType = eUninitialized; } bool OwningDoubleSequenceOrGPUColorDict::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToDoubleSequence(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { done = (failed = !TrySetToGPUColorDict(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "sequence, GPUColorDict"); return false; } return true; } bool OwningDoubleSequenceOrGPUColorDict::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } void OwningDoubleSequenceOrGPUColorDict::Uninit() { switch (mType) { case eUninitialized: { break; } case eDoubleSequence: { DestroyDoubleSequence(); break; } case eGPUColorDict: { DestroyGPUColorDict(); break; } } } OwningDoubleSequenceOrGPUColorDict& OwningDoubleSequenceOrGPUColorDict::operator=(OwningDoubleSequenceOrGPUColorDict&& aOther) { this->~OwningDoubleSequenceOrGPUColorDict(); new (this) OwningDoubleSequenceOrGPUColorDict (std::move(aOther)); return *this; } OwningDoubleSequenceOrGPUColorDict& OwningDoubleSequenceOrGPUColorDict::operator=(const OwningDoubleSequenceOrGPUColorDict& aOther) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eDoubleSequence: { SetAsDoubleSequence() = aOther.GetAsDoubleSequence(); break; } case eGPUColorDict: { SetAsGPUColorDict() = aOther.GetAsGPUColorDict(); break; } } return *this; } GPUBindGroupLayoutEntry::GPUBindGroupLayoutEntry() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUBindGroupLayoutEntry::InitIds(JSContext* cx, GPUBindGroupLayoutEntryAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->visibility_id.init(cx, "visibility") || !atomsCache->texture_id.init(cx, "texture") || !atomsCache->storageTexture_id.init(cx, "storageTexture") || !atomsCache->sampler_id.init(cx, "sampler") || !atomsCache->externalTexture_id.init(cx, "externalTexture") || !atomsCache->buffer_id.init(cx, "buffer") || !atomsCache->binding_id.init(cx, "binding")) { return false; } return true; } bool GPUBindGroupLayoutEntry::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUBindGroupLayoutEntryAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->binding_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'binding' member of GPUBindGroupLayoutEntry", &mBinding)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'binding' member of GPUBindGroupLayoutEntry"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->buffer_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mBuffer.Construct(); if (!(mBuffer.Value()).Init(cx, temp.ref(), "'buffer' member of GPUBindGroupLayoutEntry", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->externalTexture_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mExternalTexture.Construct(); if (!(mExternalTexture.Value()).Init(cx, temp.ref(), "'externalTexture' member of GPUBindGroupLayoutEntry", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->sampler_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mSampler.Construct(); if (!(mSampler.Value()).Init(cx, temp.ref(), "'sampler' member of GPUBindGroupLayoutEntry", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->storageTexture_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mStorageTexture.Construct(); if (!(mStorageTexture.Value()).Init(cx, temp.ref(), "'storageTexture' member of GPUBindGroupLayoutEntry", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->texture_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mTexture.Construct(); if (!(mTexture.Value()).Init(cx, temp.ref(), "'texture' member of GPUBindGroupLayoutEntry", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->visibility_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'visibility' member of GPUBindGroupLayoutEntry", &mVisibility)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'visibility' member of GPUBindGroupLayoutEntry"); } return true; } bool GPUBindGroupLayoutEntry::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUBindGroupLayoutEntry::TraceDictionary(JSTracer* trc) { } GPUBindGroupLayoutEntry& GPUBindGroupLayoutEntry::operator=(const GPUBindGroupLayoutEntry& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mBinding = aOther.mBinding; mBuffer.Reset(); if (aOther.mBuffer.WasPassed()) { mBuffer.Construct(aOther.mBuffer.Value()); } mExternalTexture.Reset(); if (aOther.mExternalTexture.WasPassed()) { mExternalTexture.Construct(aOther.mExternalTexture.Value()); } mSampler.Reset(); if (aOther.mSampler.WasPassed()) { mSampler.Construct(aOther.mSampler.Value()); } mStorageTexture.Reset(); if (aOther.mStorageTexture.WasPassed()) { mStorageTexture.Construct(aOther.mStorageTexture.Value()); } mTexture.Reset(); if (aOther.mTexture.WasPassed()) { mTexture.Construct(aOther.mTexture.Value()); } mVisibility = aOther.mVisibility; return *this; } GPUBlendState::GPUBlendState() : mAlpha(FastDictionaryInitializer()), mColor(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUBlendState::InitIds(JSContext* cx, GPUBlendStateAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->color_id.init(cx, "color") || !atomsCache->alpha_id.init(cx, "alpha")) { return false; } return true; } bool GPUBlendState::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUBlendStateAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->alpha_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mAlpha.Init(cx, temp.ref(), "'alpha' member of GPUBlendState", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'alpha' member of GPUBlendState"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->color_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mColor.Init(cx, temp.ref(), "'color' member of GPUBlendState", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'color' member of GPUBlendState"); } return true; } bool GPUBlendState::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUBlendState::TraceDictionary(JSTracer* trc) { } GPUBlendState& GPUBlendState::operator=(const GPUBlendState& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mAlpha = aOther.mAlpha; mColor = aOther.mColor; return *this; } GPUBufferDescriptor::GPUBufferDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUBufferDescriptor::InitIds(JSContext* cx, GPUBufferDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->usage_id.init(cx, "usage") || !atomsCache->size_id.init(cx, "size") || !atomsCache->mappedAtCreation_id.init(cx, "mappedAtCreation")) { return false; } return true; } bool GPUBufferDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUBufferDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->mappedAtCreation_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'mappedAtCreation' member of GPUBufferDescriptor", &mMappedAtCreation)) { return false; } } else { mMappedAtCreation = false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->size_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'size' member of GPUBufferDescriptor", &mSize)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'size' member of GPUBufferDescriptor"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->usage_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'usage' member of GPUBufferDescriptor", &mUsage)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'usage' member of GPUBufferDescriptor"); } return true; } bool GPUBufferDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUBufferDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUBufferDescriptor& GPUBufferDescriptor::operator=(const GPUBufferDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mMappedAtCreation = aOther.mMappedAtCreation; mSize = aOther.mSize; mUsage = aOther.mUsage; return *this; } GPUCommandBufferDescriptor::GPUCommandBufferDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUCommandBufferDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } return true; } bool GPUCommandBufferDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUCommandBufferDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUCommandBufferDescriptor& GPUCommandBufferDescriptor::operator=(const GPUCommandBufferDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); return *this; } GPUCommandEncoderDescriptor::GPUCommandEncoderDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUCommandEncoderDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } return true; } bool GPUCommandEncoderDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUCommandEncoderDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUCommandEncoderDescriptor& GPUCommandEncoderDescriptor::operator=(const GPUCommandEncoderDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); return *this; } GPUComputePassDescriptor::GPUComputePassDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUComputePassDescriptor::InitIds(JSContext* cx, GPUComputePassDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->timestampWrites_id.init(cx, "timestampWrites")) { return false; } return true; } bool GPUComputePassDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUComputePassDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->timestampWrites_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mTimestampWrites.Construct(); if (!(mTimestampWrites.Value()).Init(cx, temp.ref(), "'timestampWrites' member of GPUComputePassDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } return true; } bool GPUComputePassDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUComputePassDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUComputePassDescriptor& GPUComputePassDescriptor::operator=(const GPUComputePassDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mTimestampWrites.Reset(); if (aOther.mTimestampWrites.WasPassed()) { mTimestampWrites.Construct(aOther.mTimestampWrites.Value()); } return *this; } GPUDepthStencilState::GPUDepthStencilState() : mStencilBack(FastDictionaryInitializer()), mStencilFront(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUDepthStencilState::InitIds(JSContext* cx, GPUDepthStencilStateAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->stencilWriteMask_id.init(cx, "stencilWriteMask") || !atomsCache->stencilReadMask_id.init(cx, "stencilReadMask") || !atomsCache->stencilFront_id.init(cx, "stencilFront") || !atomsCache->stencilBack_id.init(cx, "stencilBack") || !atomsCache->format_id.init(cx, "format") || !atomsCache->depthWriteEnabled_id.init(cx, "depthWriteEnabled") || !atomsCache->depthCompare_id.init(cx, "depthCompare") || !atomsCache->depthBiasSlopeScale_id.init(cx, "depthBiasSlopeScale") || !atomsCache->depthBiasClamp_id.init(cx, "depthBiasClamp") || !atomsCache->depthBias_id.init(cx, "depthBias")) { return false; } return true; } bool GPUDepthStencilState::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUDepthStencilStateAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthBias_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'depthBias' member of GPUDepthStencilState", &mDepthBias)) { return false; } } else { mDepthBias = 0; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthBiasClamp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'depthBiasClamp' member of GPUDepthStencilState", &mDepthBiasClamp)) { return false; } else if (!std::isfinite(mDepthBiasClamp)) { cx.ThrowErrorMessage("'depthBiasClamp' member of GPUDepthStencilState"); return false; } } else { mDepthBiasClamp = 0.0F; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthBiasSlopeScale_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'depthBiasSlopeScale' member of GPUDepthStencilState", &mDepthBiasSlopeScale)) { return false; } else if (!std::isfinite(mDepthBiasSlopeScale)) { cx.ThrowErrorMessage("'depthBiasSlopeScale' member of GPUDepthStencilState"); return false; } } else { mDepthBiasSlopeScale = 0.0F; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthCompare_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mDepthCompare.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUCompareFunction", "'depthCompare' member of GPUDepthStencilState", &index)) { return false; } MOZ_ASSERT(index >= 0); (mDepthCompare.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthWriteEnabled_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mDepthWriteEnabled.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'depthWriteEnabled' member of GPUDepthStencilState", &(mDepthWriteEnabled.Value()))) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->format_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureFormat", "'format' member of GPUDepthStencilState", &index)) { return false; } MOZ_ASSERT(index >= 0); mFormat = static_cast(index); } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'format' member of GPUDepthStencilState"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stencilBack_id, temp.ptr())) { return false; } } if (!mStencilBack.Init(cx, (!isNull && !temp->isUndefined()) ? temp.ref() : JS::NullHandleValue, "'stencilBack' member of GPUDepthStencilState", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stencilFront_id, temp.ptr())) { return false; } } if (!mStencilFront.Init(cx, (!isNull && !temp->isUndefined()) ? temp.ref() : JS::NullHandleValue, "'stencilFront' member of GPUDepthStencilState", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stencilReadMask_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'stencilReadMask' member of GPUDepthStencilState", &mStencilReadMask)) { return false; } } else { mStencilReadMask = 4294967295U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stencilWriteMask_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'stencilWriteMask' member of GPUDepthStencilState", &mStencilWriteMask)) { return false; } } else { mStencilWriteMask = 4294967295U; } mIsAnyMemberPresent = true; return true; } bool GPUDepthStencilState::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUDepthStencilState::TraceDictionary(JSTracer* trc) { } GPUDepthStencilState& GPUDepthStencilState::operator=(const GPUDepthStencilState& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mDepthBias = aOther.mDepthBias; mDepthBiasClamp = aOther.mDepthBiasClamp; mDepthBiasSlopeScale = aOther.mDepthBiasSlopeScale; mDepthCompare.Reset(); if (aOther.mDepthCompare.WasPassed()) { mDepthCompare.Construct(aOther.mDepthCompare.Value()); } mDepthWriteEnabled.Reset(); if (aOther.mDepthWriteEnabled.WasPassed()) { mDepthWriteEnabled.Construct(aOther.mDepthWriteEnabled.Value()); } mFormat = aOther.mFormat; mStencilBack = aOther.mStencilBack; mStencilFront = aOther.mStencilFront; mStencilReadMask = aOther.mStencilReadMask; mStencilWriteMask = aOther.mStencilWriteMask; return *this; } GPUExternalTextureDescriptor::GPUExternalTextureDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUExternalTextureDescriptor::InitIds(JSContext* cx, GPUExternalTextureDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->source_id.init(cx, "source") || !atomsCache->colorSpace_id.init(cx, "colorSpace")) { return false; } return true; } bool GPUExternalTextureDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUExternalTextureDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->colorSpace_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "PredefinedColorSpace", "'colorSpace' member of GPUExternalTextureDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mColorSpace = static_cast(index); } } else { mColorSpace = PredefinedColorSpace::Srgb; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->source_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mSource.Init(cx, temp.ref(), "'source' member of GPUExternalTextureDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'source' member of GPUExternalTextureDescriptor"); } return true; } bool GPUExternalTextureDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUExternalTextureDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUExternalTextureDescriptor& GPUExternalTextureDescriptor::operator=(const GPUExternalTextureDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mColorSpace = aOther.mColorSpace; mSource = aOther.mSource; return *this; } GPUPipelineDescriptorBase::GPUPipelineDescriptorBase() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUPipelineDescriptorBase::InitIds(JSContext* cx, GPUPipelineDescriptorBaseAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->layout_id.init(cx, "layout")) { return false; } return true; } bool GPUPipelineDescriptorBase::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUPipelineDescriptorBaseAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->layout_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mLayout.Init(cx, temp.ref(), "'layout' member of GPUPipelineDescriptorBase", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'layout' member of GPUPipelineDescriptorBase"); } return true; } bool GPUPipelineDescriptorBase::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUPipelineDescriptorBase::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUPipelineDescriptorBase& GPUPipelineDescriptorBase::operator=(const GPUPipelineDescriptorBase& aOther) { GPUObjectDescriptorBase::operator=(aOther); mLayout = aOther.mLayout; return *this; } GPUPipelineLayoutDescriptor::GPUPipelineLayoutDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUPipelineLayoutDescriptor::InitIds(JSContext* cx, GPUPipelineLayoutDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->bindGroupLayouts_id.init(cx, "bindGroupLayouts")) { return false; } return true; } bool GPUPipelineLayoutDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUPipelineLayoutDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->bindGroupLayouts_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'bindGroupLayouts' member of GPUPipelineLayoutDescriptor", "sequence"); return false; } Sequence> &arr = mBindGroupLayouts; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } RefPtr* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } RefPtr& slot = *slotPtr; if (temp.isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(&temp, slot, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Element of 'bindGroupLayouts' member of GPUPipelineLayoutDescriptor", "GPUBindGroupLayout"); return false; } } } else if (temp.isNullOrUndefined()) { slot = nullptr; } else { cx.ThrowErrorMessage("Element of 'bindGroupLayouts' member of GPUPipelineLayoutDescriptor"); return false; } } } else { cx.ThrowErrorMessage("'bindGroupLayouts' member of GPUPipelineLayoutDescriptor", "sequence"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'bindGroupLayouts' member of GPUPipelineLayoutDescriptor"); } return true; } bool GPUPipelineLayoutDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUPipelineLayoutDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUPipelineLayoutDescriptor& GPUPipelineLayoutDescriptor::operator=(const GPUPipelineLayoutDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mBindGroupLayouts = aOther.mBindGroupLayouts; return *this; } GPUQuerySetDescriptor::GPUQuerySetDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUQuerySetDescriptor::InitIds(JSContext* cx, GPUQuerySetDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->type_id.init(cx, "type") || !atomsCache->count_id.init(cx, "count")) { return false; } return true; } bool GPUQuerySetDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUQuerySetDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->count_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'count' member of GPUQuerySetDescriptor", &mCount)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'count' member of GPUQuerySetDescriptor"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->type_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUQueryType", "'type' member of GPUQuerySetDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mType = static_cast(index); } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'type' member of GPUQuerySetDescriptor"); } return true; } bool GPUQuerySetDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUQuerySetDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUQuerySetDescriptor& GPUQuerySetDescriptor::operator=(const GPUQuerySetDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mCount = aOther.mCount; mType = aOther.mType; return *this; } GPUQueueDescriptor::GPUQueueDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUQueueDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } return true; } bool GPUQueueDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUQueueDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUQueueDescriptor& GPUQueueDescriptor::operator=(const GPUQueueDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); return *this; } GPURenderBundleDescriptor::GPURenderBundleDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPURenderBundleDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } return true; } bool GPURenderBundleDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPURenderBundleDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPURenderBundleDescriptor& GPURenderBundleDescriptor::operator=(const GPURenderBundleDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); return *this; } GPURenderPassDepthStencilAttachment::GPURenderPassDepthStencilAttachment() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPURenderPassDepthStencilAttachment::InitIds(JSContext* cx, GPURenderPassDepthStencilAttachmentAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->view_id.init(cx, "view") || !atomsCache->stencilStoreOp_id.init(cx, "stencilStoreOp") || !atomsCache->stencilReadOnly_id.init(cx, "stencilReadOnly") || !atomsCache->stencilLoadOp_id.init(cx, "stencilLoadOp") || !atomsCache->stencilClearValue_id.init(cx, "stencilClearValue") || !atomsCache->depthStoreOp_id.init(cx, "depthStoreOp") || !atomsCache->depthReadOnly_id.init(cx, "depthReadOnly") || !atomsCache->depthLoadOp_id.init(cx, "depthLoadOp") || !atomsCache->depthClearValue_id.init(cx, "depthClearValue")) { return false; } return true; } bool GPURenderPassDepthStencilAttachment::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPURenderPassDepthStencilAttachmentAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthClearValue_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mDepthClearValue.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'depthClearValue' member of GPURenderPassDepthStencilAttachment", &(mDepthClearValue.Value()))) { return false; } else if (!std::isfinite((mDepthClearValue.Value()))) { cx.ThrowErrorMessage("'depthClearValue' member of GPURenderPassDepthStencilAttachment"); return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthLoadOp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mDepthLoadOp.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPULoadOp", "'depthLoadOp' member of GPURenderPassDepthStencilAttachment", &index)) { return false; } MOZ_ASSERT(index >= 0); (mDepthLoadOp.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthReadOnly_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'depthReadOnly' member of GPURenderPassDepthStencilAttachment", &mDepthReadOnly)) { return false; } } else { mDepthReadOnly = false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthStoreOp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mDepthStoreOp.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUStoreOp", "'depthStoreOp' member of GPURenderPassDepthStencilAttachment", &index)) { return false; } MOZ_ASSERT(index >= 0); (mDepthStoreOp.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stencilClearValue_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'stencilClearValue' member of GPURenderPassDepthStencilAttachment", &mStencilClearValue)) { return false; } } else { mStencilClearValue = 0U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stencilLoadOp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mStencilLoadOp.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPULoadOp", "'stencilLoadOp' member of GPURenderPassDepthStencilAttachment", &index)) { return false; } MOZ_ASSERT(index >= 0); (mStencilLoadOp.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stencilReadOnly_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'stencilReadOnly' member of GPURenderPassDepthStencilAttachment", &mStencilReadOnly)) { return false; } } else { mStencilReadOnly = false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stencilStoreOp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mStencilStoreOp.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUStoreOp", "'stencilStoreOp' member of GPURenderPassDepthStencilAttachment", &index)) { return false; } MOZ_ASSERT(index >= 0); (mStencilStoreOp.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->view_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mView.Init(cx, temp.ref(), "'view' member of GPURenderPassDepthStencilAttachment", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'view' member of GPURenderPassDepthStencilAttachment"); } return true; } bool GPURenderPassDepthStencilAttachment::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPURenderPassDepthStencilAttachment::TraceDictionary(JSTracer* trc) { } GPURenderPassDepthStencilAttachment& GPURenderPassDepthStencilAttachment::operator=(const GPURenderPassDepthStencilAttachment& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mDepthClearValue.Reset(); if (aOther.mDepthClearValue.WasPassed()) { mDepthClearValue.Construct(aOther.mDepthClearValue.Value()); } mDepthLoadOp.Reset(); if (aOther.mDepthLoadOp.WasPassed()) { mDepthLoadOp.Construct(aOther.mDepthLoadOp.Value()); } mDepthReadOnly = aOther.mDepthReadOnly; mDepthStoreOp.Reset(); if (aOther.mDepthStoreOp.WasPassed()) { mDepthStoreOp.Construct(aOther.mDepthStoreOp.Value()); } mStencilClearValue = aOther.mStencilClearValue; mStencilLoadOp.Reset(); if (aOther.mStencilLoadOp.WasPassed()) { mStencilLoadOp.Construct(aOther.mStencilLoadOp.Value()); } mStencilReadOnly = aOther.mStencilReadOnly; mStencilStoreOp.Reset(); if (aOther.mStencilStoreOp.WasPassed()) { mStencilStoreOp.Construct(aOther.mStencilStoreOp.Value()); } mView = aOther.mView; return *this; } GPURenderPassLayout::GPURenderPassLayout() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPURenderPassLayout::InitIds(JSContext* cx, GPURenderPassLayoutAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->sampleCount_id.init(cx, "sampleCount") || !atomsCache->depthStencilFormat_id.init(cx, "depthStencilFormat") || !atomsCache->colorFormats_id.init(cx, "colorFormats")) { return false; } return true; } bool GPURenderPassLayout::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPURenderPassLayoutAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->colorFormats_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'colorFormats' member of GPURenderPassLayout", "sequence"); return false; } Sequence> &arr = mColorFormats; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } Nullable* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } Nullable& slot = *slotPtr; if (temp.isNullOrUndefined()) { slot.SetNull(); } else { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp, binding_detail::EnumStrings::Values, "GPUTextureFormat", "element of 'colorFormats' member of GPURenderPassLayout", &index)) { return false; } MOZ_ASSERT(index >= 0); slot.SetValue() = static_cast(index); } } } } else { cx.ThrowErrorMessage("'colorFormats' member of GPURenderPassLayout", "sequence"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'colorFormats' member of GPURenderPassLayout"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthStencilFormat_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mDepthStencilFormat.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureFormat", "'depthStencilFormat' member of GPURenderPassLayout", &index)) { return false; } MOZ_ASSERT(index >= 0); (mDepthStencilFormat.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->sampleCount_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'sampleCount' member of GPURenderPassLayout", &mSampleCount)) { return false; } } else { mSampleCount = 1U; } mIsAnyMemberPresent = true; return true; } bool GPURenderPassLayout::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPURenderPassLayout::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPURenderPassLayout& GPURenderPassLayout::operator=(const GPURenderPassLayout& aOther) { GPUObjectDescriptorBase::operator=(aOther); mColorFormats = aOther.mColorFormats; mDepthStencilFormat.Reset(); if (aOther.mDepthStencilFormat.WasPassed()) { mDepthStencilFormat.Construct(aOther.mDepthStencilFormat.Value()); } mSampleCount = aOther.mSampleCount; return *this; } GPUSamplerDescriptor::GPUSamplerDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUSamplerDescriptor::InitIds(JSContext* cx, GPUSamplerDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->mipmapFilter_id.init(cx, "mipmapFilter") || !atomsCache->minFilter_id.init(cx, "minFilter") || !atomsCache->maxAnisotropy_id.init(cx, "maxAnisotropy") || !atomsCache->magFilter_id.init(cx, "magFilter") || !atomsCache->lodMinClamp_id.init(cx, "lodMinClamp") || !atomsCache->lodMaxClamp_id.init(cx, "lodMaxClamp") || !atomsCache->compare_id.init(cx, "compare") || !atomsCache->addressModeW_id.init(cx, "addressModeW") || !atomsCache->addressModeV_id.init(cx, "addressModeV") || !atomsCache->addressModeU_id.init(cx, "addressModeU")) { return false; } return true; } bool GPUSamplerDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUSamplerDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->addressModeU_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUAddressMode", "'addressModeU' member of GPUSamplerDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mAddressModeU = static_cast(index); } } else { mAddressModeU = GPUAddressMode::Clamp_to_edge; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->addressModeV_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUAddressMode", "'addressModeV' member of GPUSamplerDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mAddressModeV = static_cast(index); } } else { mAddressModeV = GPUAddressMode::Clamp_to_edge; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->addressModeW_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUAddressMode", "'addressModeW' member of GPUSamplerDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mAddressModeW = static_cast(index); } } else { mAddressModeW = GPUAddressMode::Clamp_to_edge; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->compare_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mCompare.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUCompareFunction", "'compare' member of GPUSamplerDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); (mCompare.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->lodMaxClamp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'lodMaxClamp' member of GPUSamplerDescriptor", &mLodMaxClamp)) { return false; } else if (!std::isfinite(mLodMaxClamp)) { cx.ThrowErrorMessage("'lodMaxClamp' member of GPUSamplerDescriptor"); return false; } } else { mLodMaxClamp = 32.0F; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->lodMinClamp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'lodMinClamp' member of GPUSamplerDescriptor", &mLodMinClamp)) { return false; } else if (!std::isfinite(mLodMinClamp)) { cx.ThrowErrorMessage("'lodMinClamp' member of GPUSamplerDescriptor"); return false; } } else { mLodMinClamp = 0.0F; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->magFilter_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUFilterMode", "'magFilter' member of GPUSamplerDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mMagFilter = static_cast(index); } } else { mMagFilter = GPUFilterMode::Nearest; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->maxAnisotropy_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'maxAnisotropy' member of GPUSamplerDescriptor", &mMaxAnisotropy)) { return false; } } else { mMaxAnisotropy = 1; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->minFilter_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUFilterMode", "'minFilter' member of GPUSamplerDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mMinFilter = static_cast(index); } } else { mMinFilter = GPUFilterMode::Nearest; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->mipmapFilter_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUMipmapFilterMode", "'mipmapFilter' member of GPUSamplerDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mMipmapFilter = static_cast(index); } } else { mMipmapFilter = GPUMipmapFilterMode::Nearest; } mIsAnyMemberPresent = true; return true; } bool GPUSamplerDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUSamplerDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUSamplerDescriptor& GPUSamplerDescriptor::operator=(const GPUSamplerDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mAddressModeU = aOther.mAddressModeU; mAddressModeV = aOther.mAddressModeV; mAddressModeW = aOther.mAddressModeW; mCompare.Reset(); if (aOther.mCompare.WasPassed()) { mCompare.Construct(aOther.mCompare.Value()); } mLodMaxClamp = aOther.mLodMaxClamp; mLodMinClamp = aOther.mLodMinClamp; mMagFilter = aOther.mMagFilter; mMaxAnisotropy = aOther.mMaxAnisotropy; mMinFilter = aOther.mMinFilter; mMipmapFilter = aOther.mMipmapFilter; return *this; } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUSampler(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsGPUSampler(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUSampler(); tryNext = true; return true; } } } return true; } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUSampler(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUSampler(cx, value, tryNext, passedToJSImpl); } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUTexture(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsGPUTexture(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUTexture(); tryNext = true; return true; } } } return true; } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUTexture(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUTexture(cx, value, tryNext, passedToJSImpl); } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUTextureView(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsGPUTextureView(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUTextureView(); tryNext = true; return true; } } } return true; } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUTextureView(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUTextureView(cx, value, tryNext, passedToJSImpl); } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUBuffer(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsGPUBuffer(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUBuffer(); tryNext = true; return true; } } } return true; } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUBuffer(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUBuffer(cx, value, tryNext, passedToJSImpl); } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUBufferBinding(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot binding_detail::FastGPUBufferBinding& memberSlot = RawSetAsGPUBufferBinding(); if (!IsConvertibleToDictionary(value)) { DestroyGPUBufferBinding(); tryNext = true; return true; } if (!memberSlot.Init(cx, value, "GPUBufferBinding branch of (GPUSampler or GPUTexture or GPUTextureView or GPUBuffer or GPUBufferBinding or GPUExternalTexture)", passedToJSImpl)) { return false; } } return true; } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUBufferBinding(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUBufferBinding(cx, value, tryNext, passedToJSImpl); } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUExternalTexture(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot NonNull& memberSlot = RawSetAsGPUExternalTexture(); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUExternalTexture(); tryNext = true; return true; } } } return true; } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUExternalTexture(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUExternalTexture(cx, value, tryNext, passedToJSImpl); } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToGPUSampler(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToGPUTexture(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToGPUTextureView(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToGPUBuffer(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToGPUExternalTexture(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { done = (failed = !TrySetToGPUBufferBinding(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "GPUSampler, GPUTexture, GPUTextureView, GPUBuffer, GPUExternalTexture, GPUBufferBinding"); return false; } return true; } bool GPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture(OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture&& aOther) : mType(eUninitialized) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eGPUSampler: { mType = eGPUSampler; mValue.mGPUSampler.SetValue(std::move(aOther.mValue.mGPUSampler.Value())); break; } case eGPUTexture: { mType = eGPUTexture; mValue.mGPUTexture.SetValue(std::move(aOther.mValue.mGPUTexture.Value())); break; } case eGPUTextureView: { mType = eGPUTextureView; mValue.mGPUTextureView.SetValue(std::move(aOther.mValue.mGPUTextureView.Value())); break; } case eGPUBuffer: { mType = eGPUBuffer; mValue.mGPUBuffer.SetValue(std::move(aOther.mValue.mGPUBuffer.Value())); break; } case eGPUBufferBinding: { mType = eGPUBufferBinding; mValue.mGPUBufferBinding.SetValue(std::move(aOther.mValue.mGPUBufferBinding.Value())); break; } case eGPUExternalTexture: { mType = eGPUExternalTexture; mValue.mGPUExternalTexture.SetValue(std::move(aOther.mValue.mGPUExternalTexture.Value())); break; } } } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUSampler(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsGPUSampler(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUSampler(); tryNext = true; return true; } } } return true; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUSampler(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUSampler(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::RawSetAsGPUSampler() { if (mType == eGPUSampler) { return mValue.mGPUSampler.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUSampler; return mValue.mGPUSampler.SetValue(); } [[nodiscard]] OwningNonNull& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::SetAsGPUSampler() { if (mType == eGPUSampler) { return mValue.mGPUSampler.Value(); } Uninit(); mType = eGPUSampler; return mValue.mGPUSampler.SetValue(); } void OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::DestroyGPUSampler() { MOZ_RELEASE_ASSERT(IsGPUSampler(), "Wrong type!"); mValue.mGPUSampler.Destroy(); mType = eUninitialized; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUTexture(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsGPUTexture(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUTexture(); tryNext = true; return true; } } } return true; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUTexture(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUTexture(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::RawSetAsGPUTexture() { if (mType == eGPUTexture) { return mValue.mGPUTexture.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUTexture; return mValue.mGPUTexture.SetValue(); } [[nodiscard]] OwningNonNull& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::SetAsGPUTexture() { if (mType == eGPUTexture) { return mValue.mGPUTexture.Value(); } Uninit(); mType = eGPUTexture; return mValue.mGPUTexture.SetValue(); } void OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::DestroyGPUTexture() { MOZ_RELEASE_ASSERT(IsGPUTexture(), "Wrong type!"); mValue.mGPUTexture.Destroy(); mType = eUninitialized; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUTextureView(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsGPUTextureView(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUTextureView(); tryNext = true; return true; } } } return true; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUTextureView(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUTextureView(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::RawSetAsGPUTextureView() { if (mType == eGPUTextureView) { return mValue.mGPUTextureView.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUTextureView; return mValue.mGPUTextureView.SetValue(); } [[nodiscard]] OwningNonNull& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::SetAsGPUTextureView() { if (mType == eGPUTextureView) { return mValue.mGPUTextureView.Value(); } Uninit(); mType = eGPUTextureView; return mValue.mGPUTextureView.SetValue(); } void OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::DestroyGPUTextureView() { MOZ_RELEASE_ASSERT(IsGPUTextureView(), "Wrong type!"); mValue.mGPUTextureView.Destroy(); mType = eUninitialized; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUBuffer(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsGPUBuffer(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUBuffer(); tryNext = true; return true; } } } return true; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUBuffer(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUBuffer(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::RawSetAsGPUBuffer() { if (mType == eGPUBuffer) { return mValue.mGPUBuffer.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUBuffer; return mValue.mGPUBuffer.SetValue(); } [[nodiscard]] OwningNonNull& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::SetAsGPUBuffer() { if (mType == eGPUBuffer) { return mValue.mGPUBuffer.Value(); } Uninit(); mType = eGPUBuffer; return mValue.mGPUBuffer.SetValue(); } void OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::DestroyGPUBuffer() { MOZ_RELEASE_ASSERT(IsGPUBuffer(), "Wrong type!"); mValue.mGPUBuffer.Destroy(); mType = eUninitialized; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUBufferBinding(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot GPUBufferBinding& memberSlot = RawSetAsGPUBufferBinding(); if (!IsConvertibleToDictionary(value)) { DestroyGPUBufferBinding(); tryNext = true; return true; } if (!memberSlot.Init(cx, value, "GPUBufferBinding branch of (GPUSampler or GPUTexture or GPUTextureView or GPUBuffer or GPUBufferBinding or GPUExternalTexture)", passedToJSImpl)) { return false; } } return true; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUBufferBinding(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUBufferBinding(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] GPUBufferBinding& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::RawSetAsGPUBufferBinding() { if (mType == eGPUBufferBinding) { return mValue.mGPUBufferBinding.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUBufferBinding; return mValue.mGPUBufferBinding.SetValue(); } [[nodiscard]] GPUBufferBinding& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::SetAsGPUBufferBinding() { if (mType == eGPUBufferBinding) { return mValue.mGPUBufferBinding.Value(); } Uninit(); mType = eGPUBufferBinding; return mValue.mGPUBufferBinding.SetValue(); } void OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::DestroyGPUBufferBinding() { MOZ_RELEASE_ASSERT(IsGPUBufferBinding(), "Wrong type!"); mValue.mGPUBufferBinding.Destroy(); mType = eUninitialized; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUExternalTexture(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot OwningNonNull& memberSlot = RawSetAsGPUExternalTexture(); static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(value, memberSlot, cx); if (NS_FAILED(rv)) { DestroyGPUExternalTexture(); tryNext = true; return true; } } } return true; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::TrySetToGPUExternalTexture(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUExternalTexture(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] OwningNonNull& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::RawSetAsGPUExternalTexture() { if (mType == eGPUExternalTexture) { return mValue.mGPUExternalTexture.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUExternalTexture; return mValue.mGPUExternalTexture.SetValue(); } [[nodiscard]] OwningNonNull& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::SetAsGPUExternalTexture() { if (mType == eGPUExternalTexture) { return mValue.mGPUExternalTexture.Value(); } Uninit(); mType = eGPUExternalTexture; return mValue.mGPUExternalTexture.SetValue(); } void OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::DestroyGPUExternalTexture() { MOZ_RELEASE_ASSERT(IsGPUExternalTexture(), "Wrong type!"); mValue.mGPUExternalTexture.Destroy(); mType = eUninitialized; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToGPUSampler(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToGPUTexture(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToGPUTextureView(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToGPUBuffer(cx, value, tryNext, passedToJSImpl)) || !tryNext || (failed = !TrySetToGPUExternalTexture(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { done = (failed = !TrySetToGPUBufferBinding(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "GPUSampler, GPUTexture, GPUTextureView, GPUBuffer, GPUExternalTexture, GPUBufferBinding"); return false; } return true; } bool OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } void OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::Uninit() { switch (mType) { case eUninitialized: { break; } case eGPUSampler: { DestroyGPUSampler(); break; } case eGPUTexture: { DestroyGPUTexture(); break; } case eGPUTextureView: { DestroyGPUTextureView(); break; } case eGPUBuffer: { DestroyGPUBuffer(); break; } case eGPUBufferBinding: { DestroyGPUBufferBinding(); break; } case eGPUExternalTexture: { DestroyGPUExternalTexture(); break; } } } OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::operator=(OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture&& aOther) { this->~OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture(); new (this) OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture (std::move(aOther)); return *this; } OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture& OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture::operator=(const OwningGPUSamplerOrGPUTextureOrGPUTextureViewOrGPUBufferOrGPUBufferBindingOrGPUExternalTexture& aOther) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eGPUSampler: { SetAsGPUSampler() = aOther.GetAsGPUSampler(); break; } case eGPUTexture: { SetAsGPUTexture() = aOther.GetAsGPUTexture(); break; } case eGPUTextureView: { SetAsGPUTextureView() = aOther.GetAsGPUTextureView(); break; } case eGPUBuffer: { SetAsGPUBuffer() = aOther.GetAsGPUBuffer(); break; } case eGPUBufferBinding: { SetAsGPUBufferBinding() = aOther.GetAsGPUBufferBinding(); break; } case eGPUExternalTexture: { SetAsGPUExternalTexture() = aOther.GetAsGPUExternalTexture(); break; } } return *this; } GPUShaderModuleCompilationHint::GPUShaderModuleCompilationHint() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUShaderModuleCompilationHint::InitIds(JSContext* cx, GPUShaderModuleCompilationHintAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->layout_id.init(cx, "layout") || !atomsCache->entryPoint_id.init(cx, "entryPoint")) { return false; } return true; } bool GPUShaderModuleCompilationHint::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUShaderModuleCompilationHintAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->entryPoint_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, mEntryPoint)) { return false; } if (!NormalizeUSVString(mEntryPoint)) { JS_ReportOutOfMemory(cx); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'entryPoint' member of GPUShaderModuleCompilationHint"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->layout_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mLayout.Construct(); if (!(mLayout.Value()).Init(cx, temp.ref(), "'layout' member of GPUShaderModuleCompilationHint", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } return true; } bool GPUShaderModuleCompilationHint::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUShaderModuleCompilationHint::TraceDictionary(JSTracer* trc) { } GPUShaderModuleCompilationHint& GPUShaderModuleCompilationHint::operator=(const GPUShaderModuleCompilationHint& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mEntryPoint = aOther.mEntryPoint; mLayout.Reset(); if (aOther.mLayout.WasPassed()) { mLayout.Construct(aOther.mLayout.Value()); } return *this; } GPUTexelCopyBufferInfo::GPUTexelCopyBufferInfo() : GPUTexelCopyBufferLayout(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUTexelCopyBufferInfo::InitIds(JSContext* cx, GPUTexelCopyBufferInfoAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->buffer_id.init(cx, "buffer")) { return false; } return true; } bool GPUTexelCopyBufferInfo::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUTexelCopyBufferInfoAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUTexelCopyBufferLayout::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->buffer_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(temp.ptr(), mBuffer, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("'buffer' member of GPUTexelCopyBufferInfo", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("'buffer' member of GPUTexelCopyBufferInfo"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'buffer' member of GPUTexelCopyBufferInfo"); } return true; } bool GPUTexelCopyBufferInfo::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUTexelCopyBufferInfo::TraceDictionary(JSTracer* trc) { GPUTexelCopyBufferLayout::TraceDictionary(trc); } GPUTexelCopyBufferInfo& GPUTexelCopyBufferInfo::operator=(const GPUTexelCopyBufferInfo& aOther) { GPUTexelCopyBufferLayout::operator=(aOther); mBuffer = aOther.mBuffer; return *this; } GPUTextureViewDescriptor::GPUTextureViewDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUTextureViewDescriptor::InitIds(JSContext* cx, GPUTextureViewDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->usage_id.init(cx, "usage") || !atomsCache->mipLevelCount_id.init(cx, "mipLevelCount") || !atomsCache->format_id.init(cx, "format") || !atomsCache->dimension_id.init(cx, "dimension") || !atomsCache->baseMipLevel_id.init(cx, "baseMipLevel") || !atomsCache->baseArrayLayer_id.init(cx, "baseArrayLayer") || !atomsCache->aspect_id.init(cx, "aspect") || !atomsCache->arrayLayerCount_id.init(cx, "arrayLayerCount")) { return false; } return true; } bool GPUTextureViewDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUTextureViewDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->arrayLayerCount_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mArrayLayerCount.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'arrayLayerCount' member of GPUTextureViewDescriptor", &(mArrayLayerCount.Value()))) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->aspect_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureAspect", "'aspect' member of GPUTextureViewDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mAspect = static_cast(index); } } else { mAspect = GPUTextureAspect::All; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->baseArrayLayer_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'baseArrayLayer' member of GPUTextureViewDescriptor", &mBaseArrayLayer)) { return false; } } else { mBaseArrayLayer = 0U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->baseMipLevel_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'baseMipLevel' member of GPUTextureViewDescriptor", &mBaseMipLevel)) { return false; } } else { mBaseMipLevel = 0U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->dimension_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mDimension.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureViewDimension", "'dimension' member of GPUTextureViewDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); (mDimension.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->format_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mFormat.Construct(); { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureFormat", "'format' member of GPUTextureViewDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); (mFormat.Value()) = static_cast(index); } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->mipLevelCount_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mMipLevelCount.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'mipLevelCount' member of GPUTextureViewDescriptor", &(mMipLevelCount.Value()))) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->usage_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'usage' member of GPUTextureViewDescriptor", &mUsage)) { return false; } } else { mUsage = 0U; } mIsAnyMemberPresent = true; return true; } bool GPUTextureViewDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUTextureViewDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUTextureViewDescriptor& GPUTextureViewDescriptor::operator=(const GPUTextureViewDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mArrayLayerCount.Reset(); if (aOther.mArrayLayerCount.WasPassed()) { mArrayLayerCount.Construct(aOther.mArrayLayerCount.Value()); } mAspect = aOther.mAspect; mBaseArrayLayer = aOther.mBaseArrayLayer; mBaseMipLevel = aOther.mBaseMipLevel; mDimension.Reset(); if (aOther.mDimension.WasPassed()) { mDimension.Construct(aOther.mDimension.Value()); } mFormat.Reset(); if (aOther.mFormat.WasPassed()) { mFormat.Construct(aOther.mFormat.Value()); } mMipLevelCount.Reset(); if (aOther.mMipLevelCount.WasPassed()) { mMipLevelCount.Construct(aOther.mMipLevelCount.Value()); } mUsage = aOther.mUsage; return *this; } GPUVertexBufferLayout::GPUVertexBufferLayout() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUVertexBufferLayout::InitIds(JSContext* cx, GPUVertexBufferLayoutAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->stepMode_id.init(cx, "stepMode") || !atomsCache->attributes_id.init(cx, "attributes") || !atomsCache->arrayStride_id.init(cx, "arrayStride")) { return false; } return true; } bool GPUVertexBufferLayout::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUVertexBufferLayoutAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->arrayStride_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'arrayStride' member of GPUVertexBufferLayout", &mArrayStride)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'arrayStride' member of GPUVertexBufferLayout"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->attributes_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'attributes' member of GPUVertexBufferLayout", "sequence"); return false; } Sequence &arr = mAttributes; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } GPUVertexAttribute* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } GPUVertexAttribute& slot = *slotPtr; if (!slot.Init(cx, temp, "Element of 'attributes' member of GPUVertexBufferLayout", passedToJSImpl)) { return false; } } } else { cx.ThrowErrorMessage("'attributes' member of GPUVertexBufferLayout", "sequence"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'attributes' member of GPUVertexBufferLayout"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stepMode_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUVertexStepMode", "'stepMode' member of GPUVertexBufferLayout", &index)) { return false; } MOZ_ASSERT(index >= 0); mStepMode = static_cast(index); } } else { mStepMode = GPUVertexStepMode::Vertex; } mIsAnyMemberPresent = true; return true; } bool GPUVertexBufferLayout::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUVertexBufferLayout::TraceDictionary(JSTracer* trc) { } GPUVertexBufferLayout& GPUVertexBufferLayout::operator=(const GPUVertexBufferLayout& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mArrayStride = aOther.mArrayStride; mAttributes = aOther.mAttributes; mStepMode = aOther.mStepMode; return *this; } bool RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::TrySetToRangeEnforcedUnsignedLongSequence(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot binding_detail::AutoSequence& memberSlot = RawSetAsRangeEnforcedUnsignedLongSequence(); JS::ForOfIterator iter(cx); if (!iter.init(value, JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { DestroyRangeEnforcedUnsignedLongSequence(); tryNext = true; return true; } binding_detail::AutoSequence &arr = memberSlot; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } uint32_t* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } uint32_t& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of sequence branch of (sequence or GPUExtent3DDict)", &slot)) { return false; } } } return true; } bool RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::TrySetToRangeEnforcedUnsignedLongSequence(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl); } bool RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::TrySetToGPUExtent3DDict(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot binding_detail::FastGPUExtent3DDict& memberSlot = RawSetAsGPUExtent3DDict(); if (!IsConvertibleToDictionary(value)) { DestroyGPUExtent3DDict(); tryNext = true; return true; } if (!memberSlot.Init(cx, value, "GPUExtent3DDict branch of (sequence or GPUExtent3DDict)", passedToJSImpl)) { return false; } } return true; } bool RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::TrySetToGPUExtent3DDict(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUExtent3DDict(cx, value, tryNext, passedToJSImpl); } bool RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { done = (failed = !TrySetToGPUExtent3DDict(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "sequence, GPUExtent3DDict"); return false; } return true; } bool RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict(OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict&& aOther) : mType(eUninitialized) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eRangeEnforcedUnsignedLongSequence: { mType = eRangeEnforcedUnsignedLongSequence; mValue.mRangeEnforcedUnsignedLongSequence.SetValue(std::move(aOther.mValue.mRangeEnforcedUnsignedLongSequence.Value())); break; } case eGPUExtent3DDict: { mType = eGPUExtent3DDict; mValue.mGPUExtent3DDict.SetValue(std::move(aOther.mValue.mGPUExtent3DDict.Value())); break; } } } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::TrySetToRangeEnforcedUnsignedLongSequence(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot Sequence& memberSlot = RawSetAsRangeEnforcedUnsignedLongSequence(); JS::ForOfIterator iter(cx); if (!iter.init(value, JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { DestroyRangeEnforcedUnsignedLongSequence(); tryNext = true; return true; } Sequence &arr = memberSlot; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } uint32_t* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } uint32_t& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of sequence branch of (sequence or GPUExtent3DDict)", &slot)) { return false; } } } return true; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::TrySetToRangeEnforcedUnsignedLongSequence(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] Sequence& OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::RawSetAsRangeEnforcedUnsignedLongSequence() { if (mType == eRangeEnforcedUnsignedLongSequence) { return mValue.mRangeEnforcedUnsignedLongSequence.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eRangeEnforcedUnsignedLongSequence; return mValue.mRangeEnforcedUnsignedLongSequence.SetValue(); } [[nodiscard]] Sequence& OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::SetAsRangeEnforcedUnsignedLongSequence() { if (mType == eRangeEnforcedUnsignedLongSequence) { return mValue.mRangeEnforcedUnsignedLongSequence.Value(); } Uninit(); mType = eRangeEnforcedUnsignedLongSequence; return mValue.mRangeEnforcedUnsignedLongSequence.SetValue(); } void OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::DestroyRangeEnforcedUnsignedLongSequence() { MOZ_RELEASE_ASSERT(IsRangeEnforcedUnsignedLongSequence(), "Wrong type!"); mValue.mRangeEnforcedUnsignedLongSequence.Destroy(); mType = eUninitialized; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::TrySetToGPUExtent3DDict(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot GPUExtent3DDict& memberSlot = RawSetAsGPUExtent3DDict(); if (!IsConvertibleToDictionary(value)) { DestroyGPUExtent3DDict(); tryNext = true; return true; } if (!memberSlot.Init(cx, value, "GPUExtent3DDict branch of (sequence or GPUExtent3DDict)", passedToJSImpl)) { return false; } } return true; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::TrySetToGPUExtent3DDict(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUExtent3DDict(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] GPUExtent3DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::RawSetAsGPUExtent3DDict() { if (mType == eGPUExtent3DDict) { return mValue.mGPUExtent3DDict.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUExtent3DDict; return mValue.mGPUExtent3DDict.SetValue(); } [[nodiscard]] GPUExtent3DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::SetAsGPUExtent3DDict() { if (mType == eGPUExtent3DDict) { return mValue.mGPUExtent3DDict.Value(); } Uninit(); mType = eGPUExtent3DDict; return mValue.mGPUExtent3DDict.SetValue(); } void OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::DestroyGPUExtent3DDict() { MOZ_RELEASE_ASSERT(IsGPUExtent3DDict(), "Wrong type!"); mValue.mGPUExtent3DDict.Destroy(); mType = eUninitialized; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { done = (failed = !TrySetToGPUExtent3DDict(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "sequence, GPUExtent3DDict"); return false; } return true; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } void OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::Uninit() { switch (mType) { case eUninitialized: { break; } case eRangeEnforcedUnsignedLongSequence: { DestroyRangeEnforcedUnsignedLongSequence(); break; } case eGPUExtent3DDict: { DestroyGPUExtent3DDict(); break; } } } OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::operator=(OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict&& aOther) { this->~OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict(); new (this) OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict (std::move(aOther)); return *this; } OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict::operator=(const OwningRangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict& aOther) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eRangeEnforcedUnsignedLongSequence: { SetAsRangeEnforcedUnsignedLongSequence() = aOther.GetAsRangeEnforcedUnsignedLongSequence(); break; } case eGPUExtent3DDict: { SetAsGPUExtent3DDict() = aOther.GetAsGPUExtent3DDict(); break; } } return *this; } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::TrySetToRangeEnforcedUnsignedLongSequence(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot binding_detail::AutoSequence& memberSlot = RawSetAsRangeEnforcedUnsignedLongSequence(); JS::ForOfIterator iter(cx); if (!iter.init(value, JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { DestroyRangeEnforcedUnsignedLongSequence(); tryNext = true; return true; } binding_detail::AutoSequence &arr = memberSlot; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } uint32_t* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } uint32_t& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of sequence branch of (sequence or GPUOrigin2DDict)", &slot)) { return false; } } } return true; } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::TrySetToRangeEnforcedUnsignedLongSequence(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl); } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::TrySetToGPUOrigin2DDict(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot binding_detail::FastGPUOrigin2DDict& memberSlot = RawSetAsGPUOrigin2DDict(); if (!IsConvertibleToDictionary(value)) { DestroyGPUOrigin2DDict(); tryNext = true; return true; } if (!memberSlot.Init(cx, value, "GPUOrigin2DDict branch of (sequence or GPUOrigin2DDict)", passedToJSImpl)) { return false; } } return true; } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::TrySetToGPUOrigin2DDict(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUOrigin2DDict(cx, value, tryNext, passedToJSImpl); } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { done = (failed = !TrySetToGPUOrigin2DDict(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "sequence, GPUOrigin2DDict"); return false; } return true; } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict(OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict&& aOther) : mType(eUninitialized) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eRangeEnforcedUnsignedLongSequence: { mType = eRangeEnforcedUnsignedLongSequence; mValue.mRangeEnforcedUnsignedLongSequence.SetValue(std::move(aOther.mValue.mRangeEnforcedUnsignedLongSequence.Value())); break; } case eGPUOrigin2DDict: { mType = eGPUOrigin2DDict; mValue.mGPUOrigin2DDict.SetValue(std::move(aOther.mValue.mGPUOrigin2DDict.Value())); break; } } } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::TrySetToRangeEnforcedUnsignedLongSequence(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot Sequence& memberSlot = RawSetAsRangeEnforcedUnsignedLongSequence(); JS::ForOfIterator iter(cx); if (!iter.init(value, JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { DestroyRangeEnforcedUnsignedLongSequence(); tryNext = true; return true; } Sequence &arr = memberSlot; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } uint32_t* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } uint32_t& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of sequence branch of (sequence or GPUOrigin2DDict)", &slot)) { return false; } } } return true; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::TrySetToRangeEnforcedUnsignedLongSequence(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] Sequence& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::RawSetAsRangeEnforcedUnsignedLongSequence() { if (mType == eRangeEnforcedUnsignedLongSequence) { return mValue.mRangeEnforcedUnsignedLongSequence.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eRangeEnforcedUnsignedLongSequence; return mValue.mRangeEnforcedUnsignedLongSequence.SetValue(); } [[nodiscard]] Sequence& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::SetAsRangeEnforcedUnsignedLongSequence() { if (mType == eRangeEnforcedUnsignedLongSequence) { return mValue.mRangeEnforcedUnsignedLongSequence.Value(); } Uninit(); mType = eRangeEnforcedUnsignedLongSequence; return mValue.mRangeEnforcedUnsignedLongSequence.SetValue(); } void OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::DestroyRangeEnforcedUnsignedLongSequence() { MOZ_RELEASE_ASSERT(IsRangeEnforcedUnsignedLongSequence(), "Wrong type!"); mValue.mRangeEnforcedUnsignedLongSequence.Destroy(); mType = eUninitialized; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::TrySetToGPUOrigin2DDict(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot GPUOrigin2DDict& memberSlot = RawSetAsGPUOrigin2DDict(); if (!IsConvertibleToDictionary(value)) { DestroyGPUOrigin2DDict(); tryNext = true; return true; } if (!memberSlot.Init(cx, value, "GPUOrigin2DDict branch of (sequence or GPUOrigin2DDict)", passedToJSImpl)) { return false; } } return true; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::TrySetToGPUOrigin2DDict(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUOrigin2DDict(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] GPUOrigin2DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::RawSetAsGPUOrigin2DDict() { if (mType == eGPUOrigin2DDict) { return mValue.mGPUOrigin2DDict.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUOrigin2DDict; return mValue.mGPUOrigin2DDict.SetValue(); } [[nodiscard]] GPUOrigin2DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::SetAsGPUOrigin2DDict() { if (mType == eGPUOrigin2DDict) { return mValue.mGPUOrigin2DDict.Value(); } Uninit(); mType = eGPUOrigin2DDict; return mValue.mGPUOrigin2DDict.SetValue(); } void OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::DestroyGPUOrigin2DDict() { MOZ_RELEASE_ASSERT(IsGPUOrigin2DDict(), "Wrong type!"); mValue.mGPUOrigin2DDict.Destroy(); mType = eUninitialized; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { done = (failed = !TrySetToGPUOrigin2DDict(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "sequence, GPUOrigin2DDict"); return false; } return true; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } void OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::Uninit() { switch (mType) { case eUninitialized: { break; } case eRangeEnforcedUnsignedLongSequence: { DestroyRangeEnforcedUnsignedLongSequence(); break; } case eGPUOrigin2DDict: { DestroyGPUOrigin2DDict(); break; } } } OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::operator=(OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict&& aOther) { this->~OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict(); new (this) OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict (std::move(aOther)); return *this; } OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict::operator=(const OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin2DDict& aOther) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eRangeEnforcedUnsignedLongSequence: { SetAsRangeEnforcedUnsignedLongSequence() = aOther.GetAsRangeEnforcedUnsignedLongSequence(); break; } case eGPUOrigin2DDict: { SetAsGPUOrigin2DDict() = aOther.GetAsGPUOrigin2DDict(); break; } } return *this; } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::TrySetToRangeEnforcedUnsignedLongSequence(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot binding_detail::AutoSequence& memberSlot = RawSetAsRangeEnforcedUnsignedLongSequence(); JS::ForOfIterator iter(cx); if (!iter.init(value, JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { DestroyRangeEnforcedUnsignedLongSequence(); tryNext = true; return true; } binding_detail::AutoSequence &arr = memberSlot; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } uint32_t* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } uint32_t& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of sequence branch of (sequence or GPUOrigin3DDict)", &slot)) { return false; } } } return true; } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::TrySetToRangeEnforcedUnsignedLongSequence(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl); } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::TrySetToGPUOrigin3DDict(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot binding_detail::FastGPUOrigin3DDict& memberSlot = RawSetAsGPUOrigin3DDict(); if (!IsConvertibleToDictionary(value)) { DestroyGPUOrigin3DDict(); tryNext = true; return true; } if (!memberSlot.Init(cx, value, "GPUOrigin3DDict branch of (sequence or GPUOrigin3DDict)", passedToJSImpl)) { return false; } } return true; } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::TrySetToGPUOrigin3DDict(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUOrigin3DDict(cx, value, tryNext, passedToJSImpl); } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { done = (failed = !TrySetToGPUOrigin3DDict(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "sequence, GPUOrigin3DDict"); return false; } return true; } bool RangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict(OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict&& aOther) : mType(eUninitialized) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eRangeEnforcedUnsignedLongSequence: { mType = eRangeEnforcedUnsignedLongSequence; mValue.mRangeEnforcedUnsignedLongSequence.SetValue(std::move(aOther.mValue.mRangeEnforcedUnsignedLongSequence.Value())); break; } case eGPUOrigin3DDict: { mType = eGPUOrigin3DDict; mValue.mGPUOrigin3DDict.SetValue(std::move(aOther.mValue.mGPUOrigin3DDict.Value())); break; } } } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::TrySetToRangeEnforcedUnsignedLongSequence(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot Sequence& memberSlot = RawSetAsRangeEnforcedUnsignedLongSequence(); JS::ForOfIterator iter(cx); if (!iter.init(value, JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { DestroyRangeEnforcedUnsignedLongSequence(); tryNext = true; return true; } Sequence &arr = memberSlot; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } uint32_t* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } uint32_t& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of sequence branch of (sequence or GPUOrigin3DDict)", &slot)) { return false; } } } return true; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::TrySetToRangeEnforcedUnsignedLongSequence(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] Sequence& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::RawSetAsRangeEnforcedUnsignedLongSequence() { if (mType == eRangeEnforcedUnsignedLongSequence) { return mValue.mRangeEnforcedUnsignedLongSequence.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eRangeEnforcedUnsignedLongSequence; return mValue.mRangeEnforcedUnsignedLongSequence.SetValue(); } [[nodiscard]] Sequence& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::SetAsRangeEnforcedUnsignedLongSequence() { if (mType == eRangeEnforcedUnsignedLongSequence) { return mValue.mRangeEnforcedUnsignedLongSequence.Value(); } Uninit(); mType = eRangeEnforcedUnsignedLongSequence; return mValue.mRangeEnforcedUnsignedLongSequence.SetValue(); } void OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::DestroyRangeEnforcedUnsignedLongSequence() { MOZ_RELEASE_ASSERT(IsRangeEnforcedUnsignedLongSequence(), "Wrong type!"); mValue.mRangeEnforcedUnsignedLongSequence.Destroy(); mType = eUninitialized; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::TrySetToGPUOrigin3DDict(BindingCallContext& cx, JS::Handle value, bool& tryNext, bool passedToJSImpl) { tryNext = false; { // scope for memberSlot GPUOrigin3DDict& memberSlot = RawSetAsGPUOrigin3DDict(); if (!IsConvertibleToDictionary(value)) { DestroyGPUOrigin3DDict(); tryNext = true; return true; } if (!memberSlot.Init(cx, value, "GPUOrigin3DDict branch of (sequence or GPUOrigin3DDict)", passedToJSImpl)) { return false; } } return true; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::TrySetToGPUOrigin3DDict(JSContext* cx_, JS::Handle value, bool& tryNext, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return TrySetToGPUOrigin3DDict(cx, value, tryNext, passedToJSImpl); } [[nodiscard]] GPUOrigin3DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::RawSetAsGPUOrigin3DDict() { if (mType == eGPUOrigin3DDict) { return mValue.mGPUOrigin3DDict.Value(); } MOZ_ASSERT(mType == eUninitialized); mType = eGPUOrigin3DDict; return mValue.mGPUOrigin3DDict.SetValue(); } [[nodiscard]] GPUOrigin3DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::SetAsGPUOrigin3DDict() { if (mType == eGPUOrigin3DDict) { return mValue.mGPUOrigin3DDict.Value(); } Uninit(); mType = eGPUOrigin3DDict; return mValue.mGPUOrigin3DDict.SetValue(); } void OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::DestroyGPUOrigin3DDict() { MOZ_RELEASE_ASSERT(IsGPUOrigin3DDict(), "Wrong type!"); mValue.mGPUOrigin3DDict.Destroy(); mType = eUninitialized; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::Init(BindingCallContext& cx, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { MOZ_ASSERT(mType == eUninitialized); bool done = false, failed = false, tryNext; if (value.isObject()) { done = (failed = !TrySetToRangeEnforcedUnsignedLongSequence(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (!done) { done = (failed = !TrySetToGPUOrigin3DDict(cx, value, tryNext, passedToJSImpl)) || !tryNext; } if (failed) { return false; } if (!done) { cx.ThrowErrorMessage(sourceDescription, "sequence, GPUOrigin3DDict"); return false; } return true; } bool OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::Init(JSContext* cx_, JS::Handle value, const char* sourceDescription, bool passedToJSImpl) { BindingCallContext cx(cx_, nullptr); return Init(cx, value, sourceDescription, passedToJSImpl); } void OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::Uninit() { switch (mType) { case eUninitialized: { break; } case eRangeEnforcedUnsignedLongSequence: { DestroyRangeEnforcedUnsignedLongSequence(); break; } case eGPUOrigin3DDict: { DestroyGPUOrigin3DDict(); break; } } } OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::operator=(OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict&& aOther) { this->~OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict(); new (this) OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict (std::move(aOther)); return *this; } OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict& OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict::operator=(const OwningRangeEnforcedUnsignedLongSequenceOrGPUOrigin3DDict& aOther) { switch (aOther.mType) { case eUninitialized: { MOZ_ASSERT(mType == eUninitialized, "We need to destroy ourselves?"); break; } case eRangeEnforcedUnsignedLongSequence: { SetAsRangeEnforcedUnsignedLongSequence() = aOther.GetAsRangeEnforcedUnsignedLongSequence(); break; } case eGPUOrigin3DDict: { SetAsGPUOrigin3DDict() = aOther.GetAsGPUOrigin3DDict(); break; } } return *this; } GPUBindGroupEntry::GPUBindGroupEntry() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUBindGroupEntry::InitIds(JSContext* cx, GPUBindGroupEntryAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->resource_id.init(cx, "resource") || !atomsCache->binding_id.init(cx, "binding")) { return false; } return true; } bool GPUBindGroupEntry::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUBindGroupEntryAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->binding_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'binding' member of GPUBindGroupEntry", &mBinding)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'binding' member of GPUBindGroupEntry"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->resource_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mResource.Init(cx, temp.ref(), "'resource' member of GPUBindGroupEntry", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'resource' member of GPUBindGroupEntry"); } return true; } bool GPUBindGroupEntry::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUBindGroupEntry::TraceDictionary(JSTracer* trc) { } GPUBindGroupEntry& GPUBindGroupEntry::operator=(const GPUBindGroupEntry& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mBinding = aOther.mBinding; mResource = aOther.mResource; return *this; } GPUBindGroupLayoutDescriptor::GPUBindGroupLayoutDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUBindGroupLayoutDescriptor::InitIds(JSContext* cx, GPUBindGroupLayoutDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->entries_id.init(cx, "entries")) { return false; } return true; } bool GPUBindGroupLayoutDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUBindGroupLayoutDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->entries_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'entries' member of GPUBindGroupLayoutDescriptor", "sequence"); return false; } Sequence &arr = mEntries; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } GPUBindGroupLayoutEntry* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } GPUBindGroupLayoutEntry& slot = *slotPtr; if (!slot.Init(cx, temp, "Element of 'entries' member of GPUBindGroupLayoutDescriptor", passedToJSImpl)) { return false; } } } else { cx.ThrowErrorMessage("'entries' member of GPUBindGroupLayoutDescriptor", "sequence"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'entries' member of GPUBindGroupLayoutDescriptor"); } return true; } bool GPUBindGroupLayoutDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUBindGroupLayoutDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUBindGroupLayoutDescriptor& GPUBindGroupLayoutDescriptor::operator=(const GPUBindGroupLayoutDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mEntries = aOther.mEntries; return *this; } GPUColorTargetState::GPUColorTargetState() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUColorTargetState::InitIds(JSContext* cx, GPUColorTargetStateAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->writeMask_id.init(cx, "writeMask") || !atomsCache->format_id.init(cx, "format") || !atomsCache->blend_id.init(cx, "blend")) { return false; } return true; } bool GPUColorTargetState::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUColorTargetStateAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->blend_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mBlend.Construct(); if (!(mBlend.Value()).Init(cx, temp.ref(), "'blend' member of GPUColorTargetState", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->format_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureFormat", "'format' member of GPUColorTargetState", &index)) { return false; } MOZ_ASSERT(index >= 0); mFormat = static_cast(index); } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'format' member of GPUColorTargetState"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->writeMask_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'writeMask' member of GPUColorTargetState", &mWriteMask)) { return false; } } else { mWriteMask = 15U; } mIsAnyMemberPresent = true; return true; } bool GPUColorTargetState::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUColorTargetState::TraceDictionary(JSTracer* trc) { } GPUColorTargetState& GPUColorTargetState::operator=(const GPUColorTargetState& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mBlend.Reset(); if (aOther.mBlend.WasPassed()) { mBlend.Construct(aOther.mBlend.Value()); } mFormat = aOther.mFormat; mWriteMask = aOther.mWriteMask; return *this; } GPUComputePipelineDescriptor::GPUComputePipelineDescriptor() : GPUPipelineDescriptorBase(FastDictionaryInitializer()), mCompute(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUComputePipelineDescriptor::InitIds(JSContext* cx, GPUComputePipelineDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->compute_id.init(cx, "compute")) { return false; } return true; } bool GPUComputePipelineDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUComputePipelineDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUPipelineDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->compute_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mCompute.Init(cx, temp.ref(), "'compute' member of GPUComputePipelineDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'compute' member of GPUComputePipelineDescriptor"); } return true; } bool GPUComputePipelineDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUComputePipelineDescriptor::TraceDictionary(JSTracer* trc) { GPUPipelineDescriptorBase::TraceDictionary(trc); } GPUCopyExternalImageSourceInfo::GPUCopyExternalImageSourceInfo() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUCopyExternalImageSourceInfo::InitIds(JSContext* cx, GPUCopyExternalImageSourceInfoAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->source_id.init(cx, "source") || !atomsCache->origin_id.init(cx, "origin") || !atomsCache->flipY_id.init(cx, "flipY")) { return false; } return true; } bool GPUCopyExternalImageSourceInfo::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUCopyExternalImageSourceInfoAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->flipY_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'flipY' member of GPUCopyExternalImageSourceInfo", &mFlipY)) { return false; } } else { mFlipY = false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->origin_id, temp.ptr())) { return false; } } mOrigin.Uninit(); if (!(!isNull && !temp->isUndefined())) { if (!mOrigin.RawSetAsGPUOrigin2DDict().Init(cx, JS::NullHandleValue, "Member of (sequence or GPUOrigin2DDict)")) { return false; } } else { if (!mOrigin.Init(cx, temp.ref(), "'origin' member of GPUCopyExternalImageSourceInfo", passedToJSImpl)) { return false; } } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->source_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mSource.Init(cx, temp.ref(), "'source' member of GPUCopyExternalImageSourceInfo", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'source' member of GPUCopyExternalImageSourceInfo"); } return true; } bool GPUCopyExternalImageSourceInfo::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUCopyExternalImageSourceInfo::TraceDictionary(JSTracer* trc) { } GPUCopyExternalImageSourceInfo& GPUCopyExternalImageSourceInfo::operator=(const GPUCopyExternalImageSourceInfo& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mFlipY = aOther.mFlipY; mOrigin = aOther.mOrigin; mSource = aOther.mSource; return *this; } GPUDeviceDescriptor::GPUDeviceDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()), mDefaultQueue(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUDeviceDescriptor::InitIds(JSContext* cx, GPUDeviceDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->requiredLimits_id.init(cx, "requiredLimits") || !atomsCache->requiredFeatures_id.init(cx, "requiredFeatures") || !atomsCache->defaultQueue_id.init(cx, "defaultQueue")) { return false; } return true; } bool GPUDeviceDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUDeviceDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->defaultQueue_id, temp.ptr())) { return false; } } if (!mDefaultQueue.Init(cx, (!isNull && !temp->isUndefined()) ? temp.ref() : JS::NullHandleValue, "'defaultQueue' member of GPUDeviceDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->requiredFeatures_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'requiredFeatures' member of GPUDeviceDescriptor", "sequence"); return false; } Sequence &arr = mRequiredFeatures; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } GPUFeatureName* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } GPUFeatureName& slot = *slotPtr; { int index; if (!binding_detail::FindEnumStringIndex(cx, temp, binding_detail::EnumStrings::Values, "GPUFeatureName", "element of 'requiredFeatures' member of GPUDeviceDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); slot = static_cast(index); } } } else { cx.ThrowErrorMessage("'requiredFeatures' member of GPUDeviceDescriptor", "sequence"); return false; } } else { /* mRequiredFeatures array is already empty; nothing to do */ } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->requiredLimits_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mRequiredLimits.Construct(); if (temp.ref().isObject()) { auto& recordEntries = (mRequiredLimits.Value()).Entries(); JS::Rooted recordObj(cx, &temp.ref().toObject()); JS::RootedVector ids(cx); if (!js::GetPropertyKeys(cx, recordObj, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, &ids)) { return false; } if (!recordEntries.SetCapacity(ids.length(), mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } JS::Rooted propNameValue(cx); JS::Rooted temp(cx); JS::Rooted curId(cx); JS::Rooted idVal(cx); // Use a hashset to keep track of ids seen, to avoid // introducing nasty O(N^2) behavior scanning for them all the // time. Ideally we'd use a data structure with O(1) lookup // _and_ ordering for the MozMap, but we don't have one lying // around. nsTHashtable idsSeen; for (size_t i = 0; i < ids.length(); ++i) { curId = ids[i]; JS::Rooted> desc(cx); if (!JS_GetOwnPropertyDescriptorById(cx, recordObj, curId, &desc)) { return false; } if (desc.isNothing() || !desc->enumerable()) { continue; } idVal = js::IdToValue(curId); nsString propName; // This will just throw if idVal is a Symbol, like the spec says // to do. if (!ConvertJSValueToString(cx, idVal, "key of 'requiredLimits' member of GPUDeviceDescriptor", propName)) { return false; } if (!JS_GetPropertyById(cx, recordObj, curId, &temp)) { return false; } Record::EntryType* entry; if (!idsSeen.EnsureInserted(propName)) { // Find the existing entry. auto idx = recordEntries.IndexOf(propName); MOZ_ASSERT(idx != recordEntries.NoIndex, "Why is it not found?"); // Now blow it away to make it look like it was just added // to the array, because it's not obvious that it's // safe to write to its already-initialized mValue via our // normal codegen conversions. For example, the value // could be a union and this would change its type, but // codegen assumes we won't do that. entry = recordEntries.ReconstructElementAt(idx); } else { // Safe to do an infallible append here, because we did a // SetCapacity above to the right capacity. entry = recordEntries.AppendElement(); } entry->mKey = propName; uint64_t& slot = entry->mValue; if (!ValueToPrimitive(cx, temp, "Value in 'requiredLimits' member of GPUDeviceDescriptor", &slot)) { return false; } } } else { cx.ThrowErrorMessage("'requiredLimits' member of GPUDeviceDescriptor"); return false; } mIsAnyMemberPresent = true; } return true; } bool GPUDeviceDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUDeviceDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPURenderBundleEncoderDescriptor::GPURenderBundleEncoderDescriptor() : GPURenderPassLayout(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPURenderBundleEncoderDescriptor::InitIds(JSContext* cx, GPURenderBundleEncoderDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->stencilReadOnly_id.init(cx, "stencilReadOnly") || !atomsCache->depthReadOnly_id.init(cx, "depthReadOnly")) { return false; } return true; } bool GPURenderBundleEncoderDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPURenderBundleEncoderDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPURenderPassLayout::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthReadOnly_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'depthReadOnly' member of GPURenderBundleEncoderDescriptor", &mDepthReadOnly)) { return false; } } else { mDepthReadOnly = false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->stencilReadOnly_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'stencilReadOnly' member of GPURenderBundleEncoderDescriptor", &mStencilReadOnly)) { return false; } } else { mStencilReadOnly = false; } mIsAnyMemberPresent = true; return true; } bool GPURenderBundleEncoderDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPURenderBundleEncoderDescriptor::TraceDictionary(JSTracer* trc) { GPURenderPassLayout::TraceDictionary(trc); } GPURenderBundleEncoderDescriptor& GPURenderBundleEncoderDescriptor::operator=(const GPURenderBundleEncoderDescriptor& aOther) { GPURenderPassLayout::operator=(aOther); mDepthReadOnly = aOther.mDepthReadOnly; mStencilReadOnly = aOther.mStencilReadOnly; return *this; } GPURenderPassColorAttachment::GPURenderPassColorAttachment() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPURenderPassColorAttachment::InitIds(JSContext* cx, GPURenderPassColorAttachmentAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->view_id.init(cx, "view") || !atomsCache->storeOp_id.init(cx, "storeOp") || !atomsCache->resolveTarget_id.init(cx, "resolveTarget") || !atomsCache->loadOp_id.init(cx, "loadOp") || !atomsCache->depthSlice_id.init(cx, "depthSlice") || !atomsCache->clearValue_id.init(cx, "clearValue")) { return false; } return true; } bool GPURenderPassColorAttachment::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPURenderPassColorAttachmentAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->clearValue_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mClearValue.Construct(); if (!(mClearValue.Value()).Init(cx, temp.ref(), "'clearValue' member of GPURenderPassColorAttachment", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthSlice_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mDepthSlice.Construct(); if (!ValueToPrimitive(cx, temp.ref(), "'depthSlice' member of GPURenderPassColorAttachment", &(mDepthSlice.Value()))) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->loadOp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPULoadOp", "'loadOp' member of GPURenderPassColorAttachment", &index)) { return false; } MOZ_ASSERT(index >= 0); mLoadOp = static_cast(index); } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'loadOp' member of GPURenderPassColorAttachment"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->resolveTarget_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mResolveTarget.Construct(); if (!(mResolveTarget.Value()).Init(cx, temp.ref(), "'resolveTarget' member of GPURenderPassColorAttachment", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->storeOp_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUStoreOp", "'storeOp' member of GPURenderPassColorAttachment", &index)) { return false; } MOZ_ASSERT(index >= 0); mStoreOp = static_cast(index); } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'storeOp' member of GPURenderPassColorAttachment"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->view_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mView.Init(cx, temp.ref(), "'view' member of GPURenderPassColorAttachment", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'view' member of GPURenderPassColorAttachment"); } return true; } bool GPURenderPassColorAttachment::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPURenderPassColorAttachment::TraceDictionary(JSTracer* trc) { } GPURenderPassColorAttachment& GPURenderPassColorAttachment::operator=(const GPURenderPassColorAttachment& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mClearValue.Reset(); if (aOther.mClearValue.WasPassed()) { mClearValue.Construct(aOther.mClearValue.Value()); } mDepthSlice.Reset(); if (aOther.mDepthSlice.WasPassed()) { mDepthSlice.Construct(aOther.mDepthSlice.Value()); } mLoadOp = aOther.mLoadOp; mResolveTarget.Reset(); if (aOther.mResolveTarget.WasPassed()) { mResolveTarget.Construct(aOther.mResolveTarget.Value()); } mStoreOp = aOther.mStoreOp; mView = aOther.mView; return *this; } GPUShaderModuleDescriptor::GPUShaderModuleDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUShaderModuleDescriptor::InitIds(JSContext* cx, GPUShaderModuleDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->compilationHints_id.init(cx, "compilationHints") || !atomsCache->code_id.init(cx, "code")) { return false; } return true; } bool GPUShaderModuleDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUShaderModuleDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->code_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ConvertJSValueToString(cx, temp.ref(), eStringify, eStringify, mCode)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'code' member of GPUShaderModuleDescriptor"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->compilationHints_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'compilationHints' member of GPUShaderModuleDescriptor", "sequence"); return false; } Sequence &arr = mCompilationHints; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } GPUShaderModuleCompilationHint* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } GPUShaderModuleCompilationHint& slot = *slotPtr; if (!slot.Init(cx, temp, "Element of 'compilationHints' member of GPUShaderModuleDescriptor", passedToJSImpl)) { return false; } } } else { cx.ThrowErrorMessage("'compilationHints' member of GPUShaderModuleDescriptor", "sequence"); return false; } } else { /* mCompilationHints array is already empty; nothing to do */ } mIsAnyMemberPresent = true; return true; } bool GPUShaderModuleDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUShaderModuleDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUShaderModuleDescriptor& GPUShaderModuleDescriptor::operator=(const GPUShaderModuleDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mCode = aOther.mCode; mCompilationHints = aOther.mCompilationHints; return *this; } GPUTexelCopyTextureInfo::GPUTexelCopyTextureInfo() { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUTexelCopyTextureInfo::InitIds(JSContext* cx, GPUTexelCopyTextureInfoAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->texture_id.init(cx, "texture") || !atomsCache->origin_id.init(cx, "origin") || !atomsCache->mipLevel_id.init(cx, "mipLevel") || !atomsCache->aspect_id.init(cx, "aspect")) { return false; } return true; } bool GPUTexelCopyTextureInfo::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUTexelCopyTextureInfoAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } if (!IsConvertibleToDictionary(val)) { return cx.ThrowErrorMessage(sourceDescription, "dictionary"); } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->aspect_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureAspect", "'aspect' member of GPUTexelCopyTextureInfo", &index)) { return false; } MOZ_ASSERT(index >= 0); mAspect = static_cast(index); } } else { mAspect = GPUTextureAspect::All; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->mipLevel_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'mipLevel' member of GPUTexelCopyTextureInfo", &mMipLevel)) { return false; } } else { mMipLevel = 0U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->origin_id, temp.ptr())) { return false; } } mOrigin.Uninit(); if (!(!isNull && !temp->isUndefined())) { if (!mOrigin.RawSetAsGPUOrigin3DDict().Init(cx, JS::NullHandleValue, "Member of (sequence or GPUOrigin3DDict)")) { return false; } } else { if (!mOrigin.Init(cx, temp.ref(), "'origin' member of GPUTexelCopyTextureInfo", passedToJSImpl)) { return false; } } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->texture_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(temp.ptr(), mTexture, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("'texture' member of GPUTexelCopyTextureInfo", "GPUTexture"); return false; } } } else { cx.ThrowErrorMessage("'texture' member of GPUTexelCopyTextureInfo"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'texture' member of GPUTexelCopyTextureInfo"); } return true; } bool GPUTexelCopyTextureInfo::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUTexelCopyTextureInfo::TraceDictionary(JSTracer* trc) { } GPUTexelCopyTextureInfo& GPUTexelCopyTextureInfo::operator=(const GPUTexelCopyTextureInfo& aOther) { MaybeEmptyDictionaryBase::operator=(aOther); mAspect = aOther.mAspect; mMipLevel = aOther.mMipLevel; mOrigin = aOther.mOrigin; mTexture = aOther.mTexture; return *this; } GPUTextureDescriptor::GPUTextureDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUTextureDescriptor::InitIds(JSContext* cx, GPUTextureDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->viewFormats_id.init(cx, "viewFormats") || !atomsCache->usage_id.init(cx, "usage") || !atomsCache->size_id.init(cx, "size") || !atomsCache->sampleCount_id.init(cx, "sampleCount") || !atomsCache->mipLevelCount_id.init(cx, "mipLevelCount") || !atomsCache->format_id.init(cx, "format") || !atomsCache->dimension_id.init(cx, "dimension")) { return false; } return true; } bool GPUTextureDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUTextureDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->dimension_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureDimension", "'dimension' member of GPUTextureDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mDimension = static_cast(index); } } else { mDimension = GPUTextureDimension::_2d; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->format_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { { int index; if (!binding_detail::FindEnumStringIndex(cx, temp.ref(), binding_detail::EnumStrings::Values, "GPUTextureFormat", "'format' member of GPUTextureDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); mFormat = static_cast(index); } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'format' member of GPUTextureDescriptor"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->mipLevelCount_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'mipLevelCount' member of GPUTextureDescriptor", &mMipLevelCount)) { return false; } } else { mMipLevelCount = 1U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->sampleCount_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'sampleCount' member of GPUTextureDescriptor", &mSampleCount)) { return false; } } else { mSampleCount = 1U; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->size_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mSize.Init(cx, temp.ref(), "'size' member of GPUTextureDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'size' member of GPUTextureDescriptor"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->usage_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'usage' member of GPUTextureDescriptor", &mUsage)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'usage' member of GPUTextureDescriptor"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->viewFormats_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'viewFormats' member of GPUTextureDescriptor", "sequence"); return false; } Sequence &arr = mViewFormats; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } GPUTextureFormat* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } GPUTextureFormat& slot = *slotPtr; { int index; if (!binding_detail::FindEnumStringIndex(cx, temp, binding_detail::EnumStrings::Values, "GPUTextureFormat", "element of 'viewFormats' member of GPUTextureDescriptor", &index)) { return false; } MOZ_ASSERT(index >= 0); slot = static_cast(index); } } } else { cx.ThrowErrorMessage("'viewFormats' member of GPUTextureDescriptor", "sequence"); return false; } } else { /* mViewFormats array is already empty; nothing to do */ } mIsAnyMemberPresent = true; return true; } bool GPUTextureDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUTextureDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUTextureDescriptor& GPUTextureDescriptor::operator=(const GPUTextureDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mDimension = aOther.mDimension; mFormat = aOther.mFormat; mMipLevelCount = aOther.mMipLevelCount; mSampleCount = aOther.mSampleCount; mSize = aOther.mSize; mUsage = aOther.mUsage; mViewFormats = aOther.mViewFormats; return *this; } GPUVertexState::GPUVertexState() : GPUProgrammableStage(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUVertexState::InitIds(JSContext* cx, GPUVertexStateAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->buffers_id.init(cx, "buffers")) { return false; } return true; } bool GPUVertexState::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUVertexStateAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUProgrammableStage::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->buffers_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'buffers' member of GPUVertexState", "sequence"); return false; } Sequence> &arr = mBuffers; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } Nullable* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } Nullable& slot = *slotPtr; if (temp.isNullOrUndefined()) { slot.SetNull(); } else { if (!slot.SetValue().Init(cx, temp, "Element of 'buffers' member of GPUVertexState", passedToJSImpl)) { return false; } } } } else { cx.ThrowErrorMessage("'buffers' member of GPUVertexState", "sequence"); return false; } } else { /* mBuffers array is already empty; nothing to do */ } mIsAnyMemberPresent = true; return true; } bool GPUVertexState::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUVertexState::TraceDictionary(JSTracer* trc) { GPUProgrammableStage::TraceDictionary(trc); } GPUBindGroupDescriptor::GPUBindGroupDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUBindGroupDescriptor::InitIds(JSContext* cx, GPUBindGroupDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->layout_id.init(cx, "layout") || !atomsCache->entries_id.init(cx, "entries")) { return false; } return true; } bool GPUBindGroupDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUBindGroupDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->entries_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'entries' member of GPUBindGroupDescriptor", "sequence"); return false; } Sequence &arr = mEntries; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } GPUBindGroupEntry* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } GPUBindGroupEntry& slot = *slotPtr; if (!slot.Init(cx, temp, "Element of 'entries' member of GPUBindGroupDescriptor", passedToJSImpl)) { return false; } } } else { cx.ThrowErrorMessage("'entries' member of GPUBindGroupDescriptor", "sequence"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'entries' member of GPUBindGroupDescriptor"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->layout_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(temp.ptr(), mLayout, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("'layout' member of GPUBindGroupDescriptor", "GPUBindGroupLayout"); return false; } } } else { cx.ThrowErrorMessage("'layout' member of GPUBindGroupDescriptor"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'layout' member of GPUBindGroupDescriptor"); } return true; } bool GPUBindGroupDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUBindGroupDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPUBindGroupDescriptor& GPUBindGroupDescriptor::operator=(const GPUBindGroupDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mEntries = aOther.mEntries; mLayout = aOther.mLayout; return *this; } GPUCopyExternalImageDestInfo::GPUCopyExternalImageDestInfo() : GPUTexelCopyTextureInfo(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUCopyExternalImageDestInfo::InitIds(JSContext* cx, GPUCopyExternalImageDestInfoAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->premultipliedAlpha_id.init(cx, "premultipliedAlpha")) { return false; } return true; } bool GPUCopyExternalImageDestInfo::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUCopyExternalImageDestInfoAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUTexelCopyTextureInfo::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->premultipliedAlpha_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!ValueToPrimitive(cx, temp.ref(), "'premultipliedAlpha' member of GPUCopyExternalImageDestInfo", &mPremultipliedAlpha)) { return false; } } else { mPremultipliedAlpha = false; } mIsAnyMemberPresent = true; return true; } bool GPUCopyExternalImageDestInfo::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUCopyExternalImageDestInfo::TraceDictionary(JSTracer* trc) { GPUTexelCopyTextureInfo::TraceDictionary(trc); } GPUCopyExternalImageDestInfo& GPUCopyExternalImageDestInfo::operator=(const GPUCopyExternalImageDestInfo& aOther) { GPUTexelCopyTextureInfo::operator=(aOther); mPremultipliedAlpha = aOther.mPremultipliedAlpha; return *this; } GPUFragmentState::GPUFragmentState() : GPUProgrammableStage(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPUFragmentState::InitIds(JSContext* cx, GPUFragmentStateAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->targets_id.init(cx, "targets")) { return false; } return true; } bool GPUFragmentState::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPUFragmentStateAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUProgrammableStage::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->targets_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'targets' member of GPUFragmentState", "sequence"); return false; } Sequence> &arr = mTargets; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } Nullable* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } Nullable& slot = *slotPtr; if (temp.isNullOrUndefined()) { slot.SetNull(); } else { if (!slot.SetValue().Init(cx, temp, "Element of 'targets' member of GPUFragmentState", passedToJSImpl)) { return false; } } } } else { cx.ThrowErrorMessage("'targets' member of GPUFragmentState", "sequence"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'targets' member of GPUFragmentState"); } return true; } bool GPUFragmentState::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPUFragmentState::TraceDictionary(JSTracer* trc) { GPUProgrammableStage::TraceDictionary(trc); } GPURenderPassDescriptor::GPURenderPassDescriptor() : GPUObjectDescriptorBase(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPURenderPassDescriptor::InitIds(JSContext* cx, GPURenderPassDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->timestampWrites_id.init(cx, "timestampWrites") || !atomsCache->occlusionQuerySet_id.init(cx, "occlusionQuerySet") || !atomsCache->depthStencilAttachment_id.init(cx, "depthStencilAttachment") || !atomsCache->colorAttachments_id.init(cx, "colorAttachments")) { return false; } return true; } bool GPURenderPassDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPURenderPassDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUObjectDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->colorAttachments_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (temp.ref().isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(temp.ref(), JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("'colorAttachments' member of GPURenderPassDescriptor", "sequence"); return false; } Sequence> &arr = mColorAttachments; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } Nullable* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } Nullable& slot = *slotPtr; if (temp.isNullOrUndefined()) { slot.SetNull(); } else { if (!slot.SetValue().Init(cx, temp, "Element of 'colorAttachments' member of GPURenderPassDescriptor", passedToJSImpl)) { return false; } } } } else { cx.ThrowErrorMessage("'colorAttachments' member of GPURenderPassDescriptor", "sequence"); return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'colorAttachments' member of GPURenderPassDescriptor"); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthStencilAttachment_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mDepthStencilAttachment.Construct(); if (!(mDepthStencilAttachment.Value()).Init(cx, temp.ref(), "'depthStencilAttachment' member of GPURenderPassDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->occlusionQuerySet_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mOcclusionQuerySet.Construct(); if (temp.ref().isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(temp.ptr(), (mOcclusionQuerySet.Value()), cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("'occlusionQuerySet' member of GPURenderPassDescriptor", "GPUQuerySet"); return false; } } } else { cx.ThrowErrorMessage("'occlusionQuerySet' member of GPURenderPassDescriptor"); return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->timestampWrites_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mTimestampWrites.Construct(); if (!(mTimestampWrites.Value()).Init(cx, temp.ref(), "'timestampWrites' member of GPURenderPassDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } return true; } bool GPURenderPassDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPURenderPassDescriptor::TraceDictionary(JSTracer* trc) { GPUObjectDescriptorBase::TraceDictionary(trc); } GPURenderPassDescriptor& GPURenderPassDescriptor::operator=(const GPURenderPassDescriptor& aOther) { GPUObjectDescriptorBase::operator=(aOther); mColorAttachments = aOther.mColorAttachments; mDepthStencilAttachment.Reset(); if (aOther.mDepthStencilAttachment.WasPassed()) { mDepthStencilAttachment.Construct(aOther.mDepthStencilAttachment.Value()); } mOcclusionQuerySet.Reset(); if (aOther.mOcclusionQuerySet.WasPassed()) { mOcclusionQuerySet.Construct(aOther.mOcclusionQuerySet.Value()); } mTimestampWrites.Reset(); if (aOther.mTimestampWrites.WasPassed()) { mTimestampWrites.Construct(aOther.mTimestampWrites.Value()); } return *this; } GPURenderPipelineDescriptor::GPURenderPipelineDescriptor() : GPUPipelineDescriptorBase(FastDictionaryInitializer()), mMultisample(FastDictionaryInitializer()), mPrimitive(FastDictionaryInitializer()), mVertex(FastDictionaryInitializer()) { // Safe to pass a null context if we pass a null value Init(nullptr, JS::NullHandleValue); } bool GPURenderPipelineDescriptor::InitIds(JSContext* cx, GPURenderPipelineDescriptorAtoms* atomsCache) { MOZ_ASSERT(reinterpret_cast(atomsCache)->isVoid()); // Initialize these in reverse order so that any failure leaves the first one // uninitialized. if (!atomsCache->vertex_id.init(cx, "vertex") || !atomsCache->primitive_id.init(cx, "primitive") || !atomsCache->multisample_id.init(cx, "multisample") || !atomsCache->fragment_id.init(cx, "fragment") || !atomsCache->depthStencil_id.init(cx, "depthStencil")) { return false; } return true; } bool GPURenderPipelineDescriptor::Init(BindingCallContext& cx, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // Passing a null JSContext is OK only if we're initing from null, // Since in that case we will not have to do any property gets // Also evaluate isNullOrUndefined in order to avoid false-positive // checkers by static analysis tools MOZ_ASSERT_IF(!cx, val.isNull() && val.isNullOrUndefined()); GPURenderPipelineDescriptorAtoms* atomsCache = nullptr; if (cx) { atomsCache = GetAtomCache(cx); if (reinterpret_cast(atomsCache)->isVoid() && !InitIds(cx, atomsCache)) { return false; } } // Per spec, we init the parent's members first if (!GPUPipelineDescriptorBase::Init(cx, val)) { return false; } bool isNull = val.isNullOrUndefined(); // We only need these if !isNull, in which case we have |cx|. Maybe > object; Maybe > temp; if (!isNull) { MOZ_ASSERT(cx); object.emplace(cx, &val.toObject()); temp.emplace(cx); } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->depthStencil_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mDepthStencil.Construct(); if (!(mDepthStencil.Value()).Init(cx, temp.ref(), "'depthStencil' member of GPURenderPipelineDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->fragment_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { mFragment.Construct(); if (!(mFragment.Value()).Init(cx, temp.ref(), "'fragment' member of GPURenderPipelineDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->multisample_id, temp.ptr())) { return false; } } if (!mMultisample.Init(cx, (!isNull && !temp->isUndefined()) ? temp.ref() : JS::NullHandleValue, "'multisample' member of GPURenderPipelineDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->primitive_id, temp.ptr())) { return false; } } if (!mPrimitive.Init(cx, (!isNull && !temp->isUndefined()) ? temp.ref() : JS::NullHandleValue, "'primitive' member of GPURenderPipelineDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; if (!isNull) { if (!JS_GetPropertyById(cx, *object, atomsCache->vertex_id, temp.ptr())) { return false; } } if (!isNull && !temp->isUndefined()) { if (!mVertex.Init(cx, temp.ref(), "'vertex' member of GPURenderPipelineDescriptor", passedToJSImpl)) { return false; } mIsAnyMemberPresent = true; } else if (cx) { // Don't error out if we have no cx. In that // situation the caller is default-constructing us and we'll // just assume they know what they're doing. return cx.ThrowErrorMessage("'vertex' member of GPURenderPipelineDescriptor"); } return true; } bool GPURenderPipelineDescriptor::Init(JSContext* cx_, JS::Handle val, const char* sourceDescription, bool passedToJSImpl) { // We don't want to use sourceDescription for our context here; // that's not really what it's formatted for. BindingCallContext cx(cx_, nullptr); return Init(cx, val, sourceDescription, passedToJSImpl); } void GPURenderPipelineDescriptor::TraceDictionary(JSTracer* trc) { GPUPipelineDescriptorBase::TraceDictionary(trc); } namespace GPU_Binding { MOZ_CAN_RUN_SCRIPT static bool requestAdapter(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPU.requestAdapter"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPU", "requestAdapter", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); binding_detail::FastGPURequestAdapterOptions arg0; if (!arg0.Init(cx, (args.hasDefined(0)) ? args[0] : JS::NullHandleValue, "Argument 1", false)) { return false; } FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->RequestAdapter(Constify(arg0), rv))); if (rv.MaybeSetPendingException(cx, "GPU.requestAdapter")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool requestAdapter_promiseWrapper(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { bool ok = requestAdapter(cx, obj, void_self, args); if (ok) { return true; } return ConvertExceptionToPromise(cx, args.rval()); } static const JSJitInfo requestAdapter_methodinfo = { { (JSJitGetterOp)requestAdapter_promiseWrapper }, { prototypes::id::GPU }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool getPreferredCanvasFormat(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPU", "getPreferredCanvasFormat", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); GPUTextureFormat result(MOZ_KnownLive(self)->GetPreferredCanvasFormat()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo getPreferredCanvasFormat_methodinfo = { { (JSJitGetterOp)getPreferredCanvasFormat }, { prototypes::id::GPU }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_wgslLanguageFeatures(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPU", "wgslLanguageFeatures", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); auto result(StrongOrRawPtr(MOZ_KnownLive(self)->WgslLanguageFeatures())); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo wgslLanguageFeatures_getterinfo = { { get_wgslLanguageFeatures }, { prototypes::id::GPU }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasNone, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ true, /* isMovable. Not relevant for setters. */ true, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::Instance* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("requestAdapter", (GenericMethod), reinterpret_cast(&requestAdapter_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("getPreferredCanvasFormat", (GenericMethod), reinterpret_cast(&getPreferredCanvasFormat_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("wgslLanguageFeatures", JSPROP_ENUMERATE, GenericGetter, &wgslLanguageFeatures_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[3]; static PropertyInfo sNativeProperties_propertyInfos[3]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 3, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[2] } } }; static_assert(3 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPU, constructors::id::GPU, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPU, true, 0, "GPU", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPU, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPU", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPU, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::Instance* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPU); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPU); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPU", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPU, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPU, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPU_Binding namespace GPUAdapter_Binding { MOZ_CAN_RUN_SCRIPT static bool get_features(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapter", "features", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); auto result(StrongOrRawPtr(MOZ_KnownLive(self)->Features())); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo features_getterinfo = { { get_features }, { prototypes::id::GPUAdapter }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasNone, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ true, /* isMovable. Not relevant for setters. */ true, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_limits(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapter", "limits", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); auto result(StrongOrRawPtr(MOZ_KnownLive(self)->Limits())); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo limits_getterinfo = { { get_limits }, { prototypes::id::GPUAdapter }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasNone, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ true, /* isMovable. Not relevant for setters. */ true, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_info(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapter", "info", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); auto result(StrongOrRawPtr(MOZ_KnownLive(self)->Info())); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo info_getterinfo = { { get_info }, { prototypes::id::GPUAdapter }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasNone, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ true, /* isMovable. Not relevant for setters. */ true, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool requestDevice(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUAdapter.requestDevice"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapter", "requestDevice", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); binding_detail::FastGPUDeviceDescriptor arg0; if (!arg0.Init(cx, (args.hasDefined(0)) ? args[0] : JS::NullHandleValue, "Argument 1", false)) { return false; } FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->RequestDevice(Constify(arg0), rv))); if (rv.MaybeSetPendingException(cx, "GPUAdapter.requestDevice")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool requestDevice_promiseWrapper(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { bool ok = requestDevice(cx, obj, void_self, args); if (ok) { return true; } return ConvertExceptionToPromise(cx, args.rval()); } static const JSJitInfo requestDevice_methodinfo = { { (JSJitGetterOp)requestDevice_promiseWrapper }, { prototypes::id::GPUAdapter }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_missingFeatures(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapter", "missingFeatures", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint64_t result(MOZ_KnownLive(self)->MissingFeatures()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().set(JS::NumberValue(double(result))); return true; } static const JSJitInfo missingFeatures_getterinfo = { { get_missingFeatures }, { prototypes::id::GPUAdapter }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::Adapter* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("requestDevice", (GenericMethod), reinterpret_cast(&requestDevice_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("features", JSPROP_ENUMERATE, GenericGetter, &features_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("limits", JSPROP_ENUMERATE, GenericGetter, &limits_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("info", JSPROP_ENUMERATE, GenericGetter, &info_getterinfo, nullptr, nullptr), JS_PS_END, JSPropertySpec::nativeAccessors("missingFeatures", JSPROP_ENUMERATE, GenericGetter, &missingFeatures_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const PrefableDisablers sAttributes_disablers4 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), &nsRFPService::IsSystemPrincipalOrAboutFingerprintingProtection }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { &sAttributes_disablers4, &sAttributes_specs[4] }, { nullptr, nullptr } }; static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(3 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[5]; static PropertyInfo sNativeProperties_propertyInfos[5]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 5, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[1] } } }; static_assert(5 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUAdapter, constructors::id::GPUAdapter, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUAdapter, true, 0, "GPUAdapter", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUAdapterPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUAdapter, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUAdapter", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUAdapter, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::Adapter* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUAdapter); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUAdapter); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUAdapter", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUAdapter, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUAdapter, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUAdapter_Binding namespace GPUAdapterInfo_Binding { MOZ_CAN_RUN_SCRIPT static bool get_vendor(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "vendor", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetVendor(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetVendor(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo vendor_getterinfo = { { get_vendor }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_architecture(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "architecture", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetArchitecture(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetArchitecture(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo architecture_getterinfo = { { get_architecture }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_device(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "device", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetDevice(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetDevice(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo device_getterinfo = { { get_device }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_description(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "description", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetDescription(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetDescription(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo description_getterinfo = { { get_description }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_subgroupMinSize(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "subgroupMinSize", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->SubgroupMinSize()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo subgroupMinSize_getterinfo = { { get_subgroupMinSize }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_subgroupMaxSize(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "subgroupMaxSize", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->SubgroupMaxSize()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo subgroupMaxSize_getterinfo = { { get_subgroupMaxSize }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_isFallbackAdapter(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "isFallbackAdapter", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); bool result(MOZ_KnownLive(self)->IsFallbackAdapter()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setBoolean(result); return true; } static const JSJitInfo isFallbackAdapter_getterinfo = { { get_isFallbackAdapter }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_BOOLEAN, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_wgpuName(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "wgpuName", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetWgpuName(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetWgpuName(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo wgpuName_getterinfo = { { get_wgpuName }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_wgpuVendor(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "wgpuVendor", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->WgpuVendor()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo wgpuVendor_getterinfo = { { get_wgpuVendor }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_wgpuDevice(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "wgpuDevice", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->WgpuDevice()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo wgpuDevice_getterinfo = { { get_wgpuDevice }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_wgpuDeviceType(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "wgpuDeviceType", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetWgpuDeviceType(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetWgpuDeviceType(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo wgpuDeviceType_getterinfo = { { get_wgpuDeviceType }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_wgpuDriver(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "wgpuDriver", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetWgpuDriver(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetWgpuDriver(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo wgpuDriver_getterinfo = { { get_wgpuDriver }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_wgpuDriverInfo(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "wgpuDriverInfo", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetWgpuDriverInfo(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetWgpuDriverInfo(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo wgpuDriverInfo_getterinfo = { { get_wgpuDriverInfo }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_wgpuBackend(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUAdapterInfo", "wgpuBackend", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetWgpuBackend(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetWgpuBackend(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo wgpuBackend_getterinfo = { { get_wgpuBackend }, { prototypes::id::GPUAdapterInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::AdapterInfo* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("vendor", JSPROP_ENUMERATE, GenericGetter, &vendor_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("architecture", JSPROP_ENUMERATE, GenericGetter, &architecture_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("device", JSPROP_ENUMERATE, GenericGetter, &device_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("description", JSPROP_ENUMERATE, GenericGetter, &description_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("subgroupMinSize", JSPROP_ENUMERATE, GenericGetter, &subgroupMinSize_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("subgroupMaxSize", JSPROP_ENUMERATE, GenericGetter, &subgroupMaxSize_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("isFallbackAdapter", JSPROP_ENUMERATE, GenericGetter, &isFallbackAdapter_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(7 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sChromeAttributes_specs[] = { JSPropertySpec::nativeAccessors("wgpuName", JSPROP_ENUMERATE, GenericGetter, &wgpuName_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("wgpuVendor", JSPROP_ENUMERATE, GenericGetter, &wgpuVendor_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("wgpuDevice", JSPROP_ENUMERATE, GenericGetter, &wgpuDevice_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("wgpuDeviceType", JSPROP_ENUMERATE, GenericGetter, &wgpuDeviceType_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("wgpuDriver", JSPROP_ENUMERATE, GenericGetter, &wgpuDriver_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("wgpuDriverInfo", JSPROP_ENUMERATE, GenericGetter, &wgpuDriverInfo_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("wgpuBackend", JSPROP_ENUMERATE, GenericGetter, &wgpuBackend_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sChromeAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sChromeAttributes[] = { { &sChromeAttributes_disablers0, &sChromeAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(7 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[7]; static PropertyInfo sNativeProperties_propertyInfos[7]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 7, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(7 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); static uint16_t sChromeOnlyNativeProperties_sortedPropertyIndices[7]; static PropertyInfo sChromeOnlyNativeProperties_propertyInfos[7]; static const NativePropertiesN<1> sChromeOnlyNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sChromeAttributes */, false, 0, false, 0, false, 0, -1, 7, sChromeOnlyNativeProperties_sortedPropertyIndices, { { sChromeAttributes, &sChromeOnlyNativeProperties_propertyInfos[0] } } }; static_assert(7 < 1ull << (CHAR_BIT * sizeof(sChromeOnlyNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), sChromeOnlyNativeProperties.Upcast(), &sNativePropertiesInited }, prototypes::id::GPUAdapterInfo, constructors::id::GPUAdapterInfo, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUAdapterInfo, true, 0, "GPUAdapterInfo", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUAdapterInfoPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUAdapterInfo, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUAdapterInfo", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUAdapterInfo, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::AdapterInfo* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUAdapterInfo); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUAdapterInfo); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), sChromeOnlyNativeProperties.Upcast(), "GPUAdapterInfo", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUAdapterInfo, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUAdapterInfo, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUAdapterInfo_Binding namespace GPUBindGroup_Binding { MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBindGroup", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBindGroup", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUBindGroup }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUBindGroup }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::BindGroup* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUBindGroup, constructors::id::GPUBindGroup, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUBindGroup, true, 0, "GPUBindGroup", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUBindGroupPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUBindGroup, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUBindGroup", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUBindGroup, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::BindGroup* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUBindGroup); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUBindGroup); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUBindGroup", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUBindGroup, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUBindGroup, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUBindGroup_Binding namespace GPUBindGroupLayout_Binding { MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBindGroupLayout", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBindGroupLayout", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUBindGroupLayout }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUBindGroupLayout }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::BindGroupLayout* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUBindGroupLayout, constructors::id::GPUBindGroupLayout, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUBindGroupLayout, true, 0, "GPUBindGroupLayout", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUBindGroupLayoutPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUBindGroupLayout, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUBindGroupLayout", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUBindGroupLayout, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::BindGroupLayout* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUBindGroupLayout); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUBindGroupLayout); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUBindGroupLayout", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUBindGroupLayout, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUBindGroupLayout, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUBindGroupLayout_Binding namespace GPUBuffer_Binding { MOZ_CAN_RUN_SCRIPT static bool get_size(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBuffer", "size", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint64_t result(MOZ_KnownLive(self)->Size()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().set(JS::NumberValue(double(result))); return true; } static const JSJitInfo size_getterinfo = { { get_size }, { prototypes::id::GPUBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_usage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBuffer", "usage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->Usage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo usage_getterinfo = { { get_usage }, { prototypes::id::GPUBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_mapState(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBuffer", "mapState", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); GPUBufferMapState result(MOZ_KnownLive(self)->MapState()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo mapState_getterinfo = { { get_mapState }, { prototypes::id::GPUBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool mapAsync(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUBuffer.mapAsync"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBuffer", "mapAsync", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUBuffer.mapAsync", 1)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } uint64_t arg1; if (args.hasDefined(1)) { if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } } else { arg1 = 0ULL; } Optional arg2; if (args.hasDefined(2)) { arg2.Construct(); if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2.Value())) { return false; } } FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->MapAsync(arg0, arg1, Constify(arg2), rv))); if (rv.MaybeSetPendingException(cx, "GPUBuffer.mapAsync")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool mapAsync_promiseWrapper(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { bool ok = mapAsync(cx, obj, void_self, args); if (ok) { return true; } return ConvertExceptionToPromise(cx, args.rval()); } static const JSJitInfo mapAsync_methodinfo = { { (JSJitGetterOp)mapAsync_promiseWrapper }, { prototypes::id::GPUBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool getMappedRange(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUBuffer.getMappedRange"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBuffer", "getMappedRange", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint64_t arg0; if (args.hasDefined(0)) { if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } } else { arg0 = 0ULL; } Optional arg1; if (args.hasDefined(1)) { arg1.Construct(); if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1.Value())) { return false; } } FastErrorResult rv; JS::Rooted result(cx); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetMappedRange(cx, arg0, Constify(arg1), &result, rv))>, "Should be returning void here"); MOZ_KnownLive(self)->GetMappedRange(cx, arg0, Constify(arg1), &result, rv); if (rv.MaybeSetPendingException(cx, "GPUBuffer.getMappedRange")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); JS::ExposeObjectToActiveJS(result); args.rval().setObject(*result); if (!MaybeWrapNonDOMObjectValue(cx, args.rval())) { return false; } return true; } static const JSJitInfo getMappedRange_methodinfo = { { (JSJitGetterOp)getMappedRange }, { prototypes::id::GPUBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool unmap(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBuffer", "unmap", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vUnmap(cx, rv))>, "Should be returning void here"); MOZ_KnownLive(self)->Unmap(cx, rv); if (rv.MaybeSetPendingException(cx, "GPUBuffer.unmap")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo unmap_methodinfo = { { (JSJitGetterOp)unmap }, { prototypes::id::GPUBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool destroy(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBuffer", "destroy", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDestroy(cx, rv))>, "Should be returning void here"); MOZ_KnownLive(self)->Destroy(cx, rv); if (rv.MaybeSetPendingException(cx, "GPUBuffer.destroy")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo destroy_methodinfo = { { (JSJitGetterOp)destroy }, { prototypes::id::GPUBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBuffer", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUBuffer", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::Buffer* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("mapAsync", (GenericMethod), reinterpret_cast(&mapAsync_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("getMappedRange", (GenericMethod), reinterpret_cast(&getMappedRange_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("unmap", (GenericMethod), reinterpret_cast(&unmap_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("destroy", (GenericMethod), reinterpret_cast(&destroy_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(4 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("size", JSPROP_ENUMERATE, GenericGetter, &size_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("usage", JSPROP_ENUMERATE, GenericGetter, &usage_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("mapState", JSPROP_ENUMERATE, GenericGetter, &mapState_getterinfo, nullptr, nullptr), JS_PS_END, JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, &sAttributes_specs[4] }, { nullptr, nullptr } }; static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(3 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[8]; static PropertyInfo sNativeProperties_propertyInfos[8]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 8, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[4] } } }; static_assert(8 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUBuffer, constructors::id::GPUBuffer, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUBuffer, true, 0, "GPUBuffer", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUBufferPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUBuffer, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUBuffer", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUBuffer, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::Buffer* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUBuffer); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUBuffer); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUBuffer", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUBuffer, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUBuffer, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUBuffer_Binding namespace GPUBufferUsage_Binding { MOZ_GLOBINIT static const ConstantSpec sConstants_specs[] = { { "MAP_READ", JS::NumberValue(1U) }, { "MAP_WRITE", JS::NumberValue(2U) }, { "COPY_SRC", JS::NumberValue(4U) }, { "COPY_DST", JS::NumberValue(8U) }, { "INDEX", JS::NumberValue(16U) }, { "VERTEX", JS::NumberValue(32U) }, { "UNIFORM", JS::NumberValue(64U) }, { "STORAGE", JS::NumberValue(128U) }, { "INDIRECT", JS::NumberValue(256U) }, { "QUERY_RESOLVE", JS::NumberValue(512U) }, { 0, JS::UndefinedValue() } }; static const PrefableDisablers sConstants_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sConstants[] = { { &sConstants_disablers0, &sConstants_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(10 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[10]; static PropertyInfo sNativeProperties_propertyInfos[10]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, true, 0 /* sConstants */, -1, 10, sNativeProperties_sortedPropertyIndices, { { sConstants, &sNativeProperties_propertyInfos[0] } } }; static_assert(10 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::_ID_Count, constructors::id::GPUBufferUsage, &DefaultXrayExpandoObjectClass }; static const DOMIfaceAndProtoJSClass sNamespaceObjectClass = { { "GPUBufferUsage", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS, JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eNamespace, prototypes::id::_ID_Count, 0, &sNativePropertyHooks, // This isn't strictly following the spec (see // https://console.spec.whatwg.org/#ref-for-dfn-namespace-object), // but should be ok for Xrays. JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Rooted constructorProto(aCx, JS::GetRealmObjectPrototype(aCx)); if (!constructorProto) { return; } JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUBufferUsage); dom::CreateNamespaceObject(aCx, aGlobal, constructorProto, sNamespaceObjectClass, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUBufferUsage", ShouldExpose(aCx, aGlobal, aDefineOnGlobal)); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUBufferUsage, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUBufferUsage_Binding namespace GPUCanvasContext_Binding { MOZ_CAN_RUN_SCRIPT static bool get_canvas(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCanvasContext", "canvas", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); OwningHTMLCanvasElementOrOffscreenCanvas result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetCanvas(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetCanvas(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!result.ToJSVal(cx, obj, args.rval())) { return false; } return true; } static const JSJitInfo canvas_getterinfo = { { get_canvas }, { prototypes::id::GPUCanvasContext }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool configure(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUCanvasContext.configure"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCanvasContext", "configure", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUCanvasContext.configure", 1)) { return false; } binding_detail::FastGPUCanvasConfiguration arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vConfigure(Constify(arg0), rv))>, "Should be returning void here"); MOZ_KnownLive(self)->Configure(Constify(arg0), rv); if (rv.MaybeSetPendingException(cx, "GPUCanvasContext.configure")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo configure_methodinfo = { { (JSJitGetterOp)configure }, { prototypes::id::GPUCanvasContext }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool unconfigure(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCanvasContext", "unconfigure", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vUnconfigure())>, "Should be returning void here"); MOZ_KnownLive(self)->Unconfigure(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo unconfigure_methodinfo = { { (JSJitGetterOp)unconfigure }, { prototypes::id::GPUCanvasContext }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool getConfiguration(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCanvasContext", "getConfiguration", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); Nullable result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetConfiguration(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetConfiguration(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (result.IsNull()) { args.rval().setNull(); return true; } if (!result.Value().ToObjectInternal(cx, args.rval())) { return false; } return true; } static const JSJitInfo getConfiguration_methodinfo = { { (JSJitGetterOp)getConfiguration }, { prototypes::id::GPUCanvasContext }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNKNOWN, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool getCurrentTexture(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCanvasContext", "getCurrentTexture", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->GetCurrentTexture(rv))); if (rv.MaybeSetPendingException(cx, "GPUCanvasContext.getCurrentTexture")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo getCurrentTexture_methodinfo = { { (JSJitGetterOp)getCurrentTexture }, { prototypes::id::GPUCanvasContext }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::CanvasContext* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("configure", (GenericMethod), reinterpret_cast(&configure_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("unconfigure", (GenericMethod), reinterpret_cast(&unconfigure_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("getConfiguration", (GenericMethod), reinterpret_cast(&getConfiguration_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("getCurrentTexture", (GenericMethod), reinterpret_cast(&getCurrentTexture_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(4 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("canvas", JSPROP_ENUMERATE, GenericGetter, &canvas_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[5]; static PropertyInfo sNativeProperties_propertyInfos[5]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 5, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[4] } } }; static_assert(5 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUCanvasContext, constructors::id::GPUCanvasContext, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUCanvasContext, true, 0, "GPUCanvasContext", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUCanvasContextPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUCanvasContext, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUCanvasContext", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUCanvasContext, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::CanvasContext* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUCanvasContext); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUCanvasContext); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUCanvasContext", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUCanvasContext, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUCanvasContext, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUCanvasContext_Binding namespace GPUColorWrite_Binding { MOZ_GLOBINIT static const ConstantSpec sConstants_specs[] = { { "RED", JS::NumberValue(1U) }, { "GREEN", JS::NumberValue(2U) }, { "BLUE", JS::NumberValue(4U) }, { "ALPHA", JS::NumberValue(8U) }, { "ALL", JS::NumberValue(15U) }, { 0, JS::UndefinedValue() } }; static const PrefableDisablers sConstants_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sConstants[] = { { &sConstants_disablers0, &sConstants_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(5 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[5]; static PropertyInfo sNativeProperties_propertyInfos[5]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, true, 0 /* sConstants */, -1, 5, sNativeProperties_sortedPropertyIndices, { { sConstants, &sNativeProperties_propertyInfos[0] } } }; static_assert(5 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::_ID_Count, constructors::id::GPUColorWrite, &DefaultXrayExpandoObjectClass }; static const DOMIfaceAndProtoJSClass sNamespaceObjectClass = { { "GPUColorWrite", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS, JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eNamespace, prototypes::id::_ID_Count, 0, &sNativePropertyHooks, // This isn't strictly following the spec (see // https://console.spec.whatwg.org/#ref-for-dfn-namespace-object), // but should be ok for Xrays. JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Rooted constructorProto(aCx, JS::GetRealmObjectPrototype(aCx)); if (!constructorProto) { return; } JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUColorWrite); dom::CreateNamespaceObject(aCx, aGlobal, constructorProto, sNamespaceObjectClass, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUColorWrite", ShouldExpose(aCx, aGlobal, aDefineOnGlobal)); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUColorWrite, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUColorWrite_Binding namespace GPUCommandBuffer_Binding { MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandBuffer", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandBuffer", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUCommandBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUCommandBuffer }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::CommandBuffer* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUCommandBuffer, constructors::id::GPUCommandBuffer, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUCommandBuffer, true, 0, "GPUCommandBuffer", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUCommandBufferPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUCommandBuffer, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUCommandBuffer", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUCommandBuffer, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::CommandBuffer* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUCommandBuffer); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUCommandBuffer); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUCommandBuffer", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUCommandBuffer, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUCommandBuffer, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUCommandBuffer_Binding namespace GPUCommandEncoder_Binding { MOZ_CAN_RUN_SCRIPT static bool beginRenderPass(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUCommandEncoder.beginRenderPass"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "beginRenderPass", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUCommandEncoder.beginRenderPass", 1)) { return false; } binding_detail::FastGPURenderPassDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->BeginRenderPass(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo beginRenderPass_methodinfo = { { (JSJitGetterOp)beginRenderPass }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool beginComputePass(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUCommandEncoder.beginComputePass"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "beginComputePass", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); binding_detail::FastGPUComputePassDescriptor arg0; if (!arg0.Init(cx, (args.hasDefined(0)) ? args[0] : JS::NullHandleValue, "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->BeginComputePass(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo beginComputePass_methodinfo = { { (JSJitGetterOp)beginComputePass }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool copyBufferToBuffer(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUCommandEncoder.copyBufferToBuffer"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "copyBufferToBuffer", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); unsigned argcount = std::min(args.length(), 5u); switch (argcount) { case 2: { [[fallthrough]]; } case 3: { NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } NonNull arg1; if (args[1].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[1], arg1, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 2", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 2"); return false; } Optional arg2; if (args.hasDefined(2)) { arg2.Construct(); if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2.Value())) { return false; } } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vCopyBufferToBuffer(MOZ_KnownLive(NonNullHelper(arg0)), MOZ_KnownLive(NonNullHelper(arg1)), Constify(arg2)))>, "Should be returning void here"); MOZ_KnownLive(self)->CopyBufferToBuffer(MOZ_KnownLive(NonNullHelper(arg0)), MOZ_KnownLive(NonNullHelper(arg1)), Constify(arg2)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; break; } case 4: { [[fallthrough]]; } case 5: { NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } uint64_t arg1; if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } NonNull arg2; if (args[2].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[2], arg2, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 3", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 3"); return false; } uint64_t arg3; if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } Optional arg4; if (args.hasDefined(4)) { arg4.Construct(); if (!ValueToPrimitive(cx, args[4], "Argument 5", &arg4.Value())) { return false; } } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vCopyBufferToBuffer(MOZ_KnownLive(NonNullHelper(arg0)), arg1, MOZ_KnownLive(NonNullHelper(arg2)), arg3, Constify(arg4)))>, "Should be returning void here"); MOZ_KnownLive(self)->CopyBufferToBuffer(MOZ_KnownLive(NonNullHelper(arg0)), arg1, MOZ_KnownLive(NonNullHelper(arg2)), arg3, Constify(arg4)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; break; } default: { // Using nsPrintfCString here would require including that // header. Let's not worry about it. nsAutoCString argCountStr; argCountStr.AppendPrintf("%u", args.length()); return cx.ThrowErrorMessage(argCountStr.get()); } } MOZ_CRASH("We have an always-returning default case"); return false; } static const JSJitInfo copyBufferToBuffer_methodinfo = { { (JSJitGetterOp)copyBufferToBuffer }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool copyBufferToTexture(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUCommandEncoder.copyBufferToTexture"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "copyBufferToTexture", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUCommandEncoder.copyBufferToTexture", 3)) { return false; } binding_detail::FastGPUTexelCopyBufferInfo arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } binding_detail::FastGPUTexelCopyTextureInfo arg1; if (!arg1.Init(cx, args[1], "Argument 2", false)) { return false; } RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict arg2; if (!arg2.Init(cx, args[2], "Argument 3", false)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vCopyBufferToTexture(Constify(arg0), Constify(arg1), Constify(arg2)))>, "Should be returning void here"); MOZ_KnownLive(self)->CopyBufferToTexture(Constify(arg0), Constify(arg1), Constify(arg2)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo copyBufferToTexture_methodinfo = { { (JSJitGetterOp)copyBufferToTexture }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool copyTextureToBuffer(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUCommandEncoder.copyTextureToBuffer"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "copyTextureToBuffer", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUCommandEncoder.copyTextureToBuffer", 3)) { return false; } binding_detail::FastGPUTexelCopyTextureInfo arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } binding_detail::FastGPUTexelCopyBufferInfo arg1; if (!arg1.Init(cx, args[1], "Argument 2", false)) { return false; } RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict arg2; if (!arg2.Init(cx, args[2], "Argument 3", false)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vCopyTextureToBuffer(Constify(arg0), Constify(arg1), Constify(arg2)))>, "Should be returning void here"); MOZ_KnownLive(self)->CopyTextureToBuffer(Constify(arg0), Constify(arg1), Constify(arg2)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo copyTextureToBuffer_methodinfo = { { (JSJitGetterOp)copyTextureToBuffer }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool copyTextureToTexture(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUCommandEncoder.copyTextureToTexture"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "copyTextureToTexture", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUCommandEncoder.copyTextureToTexture", 3)) { return false; } binding_detail::FastGPUTexelCopyTextureInfo arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } binding_detail::FastGPUTexelCopyTextureInfo arg1; if (!arg1.Init(cx, args[1], "Argument 2", false)) { return false; } RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict arg2; if (!arg2.Init(cx, args[2], "Argument 3", false)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vCopyTextureToTexture(Constify(arg0), Constify(arg1), Constify(arg2)))>, "Should be returning void here"); MOZ_KnownLive(self)->CopyTextureToTexture(Constify(arg0), Constify(arg1), Constify(arg2)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo copyTextureToTexture_methodinfo = { { (JSJitGetterOp)copyTextureToTexture }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool clearBuffer(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUCommandEncoder.clearBuffer"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "clearBuffer", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUCommandEncoder.clearBuffer", 1)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } uint64_t arg1; if (args.hasDefined(1)) { if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } } else { arg1 = 0ULL; } Optional arg2; if (args.hasDefined(2)) { arg2.Construct(); if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2.Value())) { return false; } } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vClearBuffer(MOZ_KnownLive(NonNullHelper(arg0)), arg1, Constify(arg2)))>, "Should be returning void here"); MOZ_KnownLive(self)->ClearBuffer(MOZ_KnownLive(NonNullHelper(arg0)), arg1, Constify(arg2)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo clearBuffer_methodinfo = { { (JSJitGetterOp)clearBuffer }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool resolveQuerySet(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUCommandEncoder.resolveQuerySet"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "resolveQuerySet", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUCommandEncoder.resolveQuerySet", 5)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUQuerySet"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } uint32_t arg1; if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } uint32_t arg2; if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } NonNull arg3; if (args[3].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[3], arg3, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 4", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 4"); return false; } uint64_t arg4; if (!ValueToPrimitive(cx, args[4], "Argument 5", &arg4)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vResolveQuerySet(MOZ_KnownLive(NonNullHelper(arg0)), arg1, arg2, MOZ_KnownLive(NonNullHelper(arg3)), arg4))>, "Should be returning void here"); MOZ_KnownLive(self)->ResolveQuerySet(MOZ_KnownLive(NonNullHelper(arg0)), arg1, arg2, MOZ_KnownLive(NonNullHelper(arg3)), arg4); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo resolveQuerySet_methodinfo = { { (JSJitGetterOp)resolveQuerySet }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool finish(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUCommandEncoder.finish"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "finish", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); binding_detail::FastGPUCommandBufferDescriptor arg0; if (!arg0.Init(cx, (args.hasDefined(0)) ? args[0] : JS::NullHandleValue, "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->Finish(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo finish_methodinfo = { { (JSJitGetterOp)finish }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool pushDebugGroup(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "pushDebugGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUCommandEncoder.pushDebugGroup", 1)) { return false; } nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vPushDebugGroup(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->PushDebugGroup(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo pushDebugGroup_methodinfo = { { (JSJitGetterOp)pushDebugGroup }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool popDebugGroup(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "popDebugGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vPopDebugGroup())>, "Should be returning void here"); MOZ_KnownLive(self)->PopDebugGroup(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo popDebugGroup_methodinfo = { { (JSJitGetterOp)popDebugGroup }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool insertDebugMarker(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "insertDebugMarker", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUCommandEncoder.insertDebugMarker", 1)) { return false; } nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vInsertDebugMarker(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->InsertDebugMarker(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo insertDebugMarker_methodinfo = { { (JSJitGetterOp)insertDebugMarker }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCommandEncoder", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUCommandEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::CommandEncoder* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("beginRenderPass", (GenericMethod), reinterpret_cast(&beginRenderPass_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("beginComputePass", (GenericMethod), reinterpret_cast(&beginComputePass_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("copyBufferToBuffer", (GenericMethod), reinterpret_cast(©BufferToBuffer_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("copyBufferToTexture", (GenericMethod), reinterpret_cast(©BufferToTexture_methodinfo), 3, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("copyTextureToBuffer", (GenericMethod), reinterpret_cast(©TextureToBuffer_methodinfo), 3, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("copyTextureToTexture", (GenericMethod), reinterpret_cast(©TextureToTexture_methodinfo), 3, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("clearBuffer", (GenericMethod), reinterpret_cast(&clearBuffer_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("resolveQuerySet", (GenericMethod), reinterpret_cast(&resolveQuerySet_methodinfo), 5, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("finish", (GenericMethod), reinterpret_cast(&finish_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END, JS_FNSPEC("pushDebugGroup", (GenericMethod), reinterpret_cast(&pushDebugGroup_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("popDebugGroup", (GenericMethod), reinterpret_cast(&popDebugGroup_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("insertDebugMarker", (GenericMethod), reinterpret_cast(&insertDebugMarker_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, &sMethods_specs[10] }, { nullptr, nullptr } }; static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(9 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[13]; static PropertyInfo sNativeProperties_propertyInfos[13]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 13, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[12] } } }; static_assert(13 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUCommandEncoder, constructors::id::GPUCommandEncoder, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUCommandEncoder, true, 0, "GPUCommandEncoder", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUCommandEncoderPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUCommandEncoder, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUCommandEncoder", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUCommandEncoder, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::CommandEncoder* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUCommandEncoder); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUCommandEncoder); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUCommandEncoder", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUCommandEncoder, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUCommandEncoder, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUCommandEncoder_Binding namespace GPUCompilationInfo_Binding { MOZ_CAN_RUN_SCRIPT static bool get_messages(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCompilationInfo", "messages", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // Have to either root across the getter call or reget after. bool isXray; JS::Rooted slotStorage(cx, GetCachedSlotStorageObject(cx, obj, &isXray)); if (!slotStorage) { return false; } const size_t slotIndex = isXray ? (DOM_EXPANDO_RESERVED_SLOTS + 0) : (DOM_INSTANCE_RESERVED_SLOTS + 0); MOZ_ASSERT(slotIndex < JSCLASS_RESERVED_SLOTS(JS::GetClass(slotStorage))); { // Scope for cachedVal JS::Value cachedVal = JS::GetNativeObjectReservedSlot(slotStorage, slotIndex); if (!cachedVal.isUndefined()) { args.rval().set(cachedVal); // The cached value is in the compartment of slotStorage, // so wrap into the caller compartment as needed. return MaybeWrapNonDOMObjectValue(cx, args.rval()); } } nsTArray> result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetMessages(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetMessages(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); { JS::Rooted conversionScope(cx, isXray ? JS::CurrentGlobalOrNull(cx) : slotStorage); JSAutoRealm ar(cx, conversionScope); do { // block we break out of when done wrapping uint32_t length = result.Length(); JS::Rooted returnArray(cx, JS::NewArrayObject(cx, length)); if (!returnArray) { return false; } // Scope for 'tmp' { JS::Rooted tmp(cx); for (uint32_t sequenceIdx0 = 0; sequenceIdx0 < length; ++sequenceIdx0) { // Control block to let us common up the JS_DefineElement calls when there // are different ways to succeed at wrapping the object. do { if (!GetOrCreateDOMReflector(cx, result[sequenceIdx0], &tmp)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } break; } while (false); if (!JS_DefineElement(cx, returnArray, sequenceIdx0, tmp, JSPROP_ENUMERATE)) { return false; } } } args.rval().setObject(*returnArray); break; } while (false); JS::Rooted rvalObj(cx, &args.rval().toObject()); if (!JS_FreezeObject(cx, rvalObj)) { return false; } } { // And now store things in the realm of our slotStorage. JSAutoRealm ar(cx, slotStorage); // Make a copy so that we don't do unnecessary wrapping on args.rval(). JS::Rooted storedVal(cx, args.rval()); if (!MaybeWrapNonDOMObjectValue(cx, &storedVal)) { return false; } JS::SetNativeObjectReservedSlot(slotStorage, slotIndex, storedVal); if (!isXray) { // In the Xray case we don't need to do this, because getting the // expando object already preserved our wrapper. PreserveWrapper(self); } } // And now make sure args.rval() is in the caller realm. return MaybeWrapNonDOMObjectValue(cx, args.rval()); } static const JSJitInfo messages_getterinfo = { { get_messages }, { prototypes::id::GPUCompilationInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasDOMSets, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ true, /* isMovable. Not relevant for setters. */ true, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ true, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ (DOM_INSTANCE_RESERVED_SLOTS + 0) /* Reserved slot index, if we're stored in a slot, else 0. */ }; static_assert((DOM_INSTANCE_RESERVED_SLOTS + 0) <= JSJitInfo::maxSlotIndex, "We won't fit"); static_assert((DOM_INSTANCE_RESERVED_SLOTS + 0) < 2, "There is no slot for us"); static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::CompilationInfo* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("messages", JSPROP_ENUMERATE, GenericGetter, &messages_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); // This may allocate too many slots, because we only really need // slots for our non-interface-typed members that we cache. But // allocating slots only for those would make the slot index // computations much more complicated, so let's do this the simple // way for now. DEFINE_XRAY_EXPANDO_CLASS_WITH_OPS(static, sXrayExpandoObjectClass, 1, &xpc::XrayExpandoObjectClassOps); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUCompilationInfo, constructors::id::GPUCompilationInfo, &sXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUCompilationInfo, true, 0, "GPUCompilationInfo", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUCompilationInfoPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUCompilationInfo, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUCompilationInfo", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUCompilationInfo, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(2 >= 2, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::CompilationInfo* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void ClearCachedMessagesValue(mozilla::webgpu::CompilationInfo* aObject) { JSObject* obj; obj = aObject->GetWrapper(); if (!obj) { return; } JS::SetNativeObjectReservedSlot(obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), JS::UndefinedValue()); ClearXrayExpandoSlots(RootingCx(), obj, (DOM_EXPANDO_RESERVED_SLOTS + 0)); } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUCompilationInfo); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUCompilationInfo); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUCompilationInfo", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUCompilationInfo, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUCompilationInfo, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUCompilationInfo_Binding namespace GPUCompilationMessage_Binding { MOZ_CAN_RUN_SCRIPT static bool get_message(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCompilationMessage", "message", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetMessage(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetMessage(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo message_getterinfo = { { get_message }, { prototypes::id::GPUCompilationMessage }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_type(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCompilationMessage", "type", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); GPUCompilationMessageType result(MOZ_KnownLive(self)->Type()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo type_getterinfo = { { get_type }, { prototypes::id::GPUCompilationMessage }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_lineNum(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCompilationMessage", "lineNum", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint64_t result(MOZ_KnownLive(self)->LineNum()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().set(JS::NumberValue(double(result))); return true; } static const JSJitInfo lineNum_getterinfo = { { get_lineNum }, { prototypes::id::GPUCompilationMessage }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_linePos(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCompilationMessage", "linePos", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint64_t result(MOZ_KnownLive(self)->LinePos()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().set(JS::NumberValue(double(result))); return true; } static const JSJitInfo linePos_getterinfo = { { get_linePos }, { prototypes::id::GPUCompilationMessage }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_offset(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCompilationMessage", "offset", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint64_t result(MOZ_KnownLive(self)->Offset()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().set(JS::NumberValue(double(result))); return true; } static const JSJitInfo offset_getterinfo = { { get_offset }, { prototypes::id::GPUCompilationMessage }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_length(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUCompilationMessage", "length", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint64_t result(MOZ_KnownLive(self)->Length()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().set(JS::NumberValue(double(result))); return true; } static const JSJitInfo length_getterinfo = { { get_length }, { prototypes::id::GPUCompilationMessage }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::CompilationMessage* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("message", JSPROP_ENUMERATE, GenericGetter, &message_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("type", JSPROP_ENUMERATE, GenericGetter, &type_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("lineNum", JSPROP_ENUMERATE, GenericGetter, &lineNum_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("linePos", JSPROP_ENUMERATE, GenericGetter, &linePos_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("offset", JSPROP_ENUMERATE, GenericGetter, &offset_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("length", JSPROP_ENUMERATE, GenericGetter, &length_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(6 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[6]; static PropertyInfo sNativeProperties_propertyInfos[6]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 6, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(6 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUCompilationMessage, constructors::id::GPUCompilationMessage, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUCompilationMessage, true, 0, "GPUCompilationMessage", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUCompilationMessagePrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUCompilationMessage, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUCompilationMessage", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUCompilationMessage, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::CompilationMessage* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUCompilationMessage); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUCompilationMessage); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUCompilationMessage", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUCompilationMessage, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUCompilationMessage, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUCompilationMessage_Binding namespace GPUComputePassEncoder_Binding { MOZ_CAN_RUN_SCRIPT static bool setPipeline(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUComputePassEncoder.setPipeline"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePassEncoder", "setPipeline", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUComputePassEncoder.setPipeline", 1)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUComputePipeline"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetPipeline(MOZ_KnownLive(NonNullHelper(arg0))))>, "Should be returning void here"); MOZ_KnownLive(self)->SetPipeline(MOZ_KnownLive(NonNullHelper(arg0))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setPipeline_methodinfo = { { (JSJitGetterOp)setPipeline }, { prototypes::id::GPUComputePassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool dispatchWorkgroups(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUComputePassEncoder.dispatchWorkgroups"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePassEncoder", "dispatchWorkgroups", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUComputePassEncoder.dispatchWorkgroups", 1)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } uint32_t arg1; if (args.hasDefined(1)) { if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } } else { arg1 = 1U; } uint32_t arg2; if (args.hasDefined(2)) { if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } } else { arg2 = 1U; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDispatchWorkgroups(arg0, arg1, arg2))>, "Should be returning void here"); MOZ_KnownLive(self)->DispatchWorkgroups(arg0, arg1, arg2); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo dispatchWorkgroups_methodinfo = { { (JSJitGetterOp)dispatchWorkgroups }, { prototypes::id::GPUComputePassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool dispatchWorkgroupsIndirect(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUComputePassEncoder.dispatchWorkgroupsIndirect"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePassEncoder", "dispatchWorkgroupsIndirect", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUComputePassEncoder.dispatchWorkgroupsIndirect", 2)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } uint64_t arg1; if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDispatchWorkgroupsIndirect(MOZ_KnownLive(NonNullHelper(arg0)), arg1))>, "Should be returning void here"); MOZ_KnownLive(self)->DispatchWorkgroupsIndirect(MOZ_KnownLive(NonNullHelper(arg0)), arg1); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo dispatchWorkgroupsIndirect_methodinfo = { { (JSJitGetterOp)dispatchWorkgroupsIndirect }, { prototypes::id::GPUComputePassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool end(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePassEncoder", "end", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vEnd())>, "Should be returning void here"); MOZ_KnownLive(self)->End(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo end_methodinfo = { { (JSJitGetterOp)end }, { prototypes::id::GPUComputePassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setBindGroup(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUComputePassEncoder.setBindGroup"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePassEncoder", "setBindGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); unsigned argcount = std::min(args.length(), 5u); switch (argcount) { case 2: { [[fallthrough]]; } case 3: { uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } mozilla::webgpu::BindGroup* arg1; if (args[1].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[1], arg1, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 2", "GPUBindGroup"); return false; } } } else if (args[1].isNullOrUndefined()) { arg1 = nullptr; } else { cx.ThrowErrorMessage("Argument 2"); return false; } binding_detail::AutoSequence arg2; if (args.hasDefined(2)) { if (args[2].isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(args[2], JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("Argument 3", "sequence"); return false; } binding_detail::AutoSequence &arr = arg2; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } uint32_t* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } uint32_t& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of argument 3", &slot)) { return false; } } } else { cx.ThrowErrorMessage("Argument 3", "sequence"); return false; } } else { /* arg2 array is already empty; nothing to do */ } FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), rv))>, "Should be returning void here"); MOZ_KnownLive(self)->SetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), rv); if (rv.MaybeSetPendingException(cx, "GPUComputePassEncoder.setBindGroup")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; break; } case 5: { uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } mozilla::webgpu::BindGroup* arg1; if (args[1].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[1], arg1, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 2", "GPUBindGroup"); return false; } } } else if (args[1].isNullOrUndefined()) { arg1 = nullptr; } else { cx.ThrowErrorMessage("Argument 2"); return false; } RootedSpiderMonkeyInterface arg2(cx); if (args[2].isObject()) { if (!arg2.Init(&args[2].toObject())) { cx.ThrowErrorMessage("Argument 3", "Uint32Array"); return false; } if (JS::IsLargeArrayBufferView(arg2.Obj())) { cx.ThrowErrorMessage("Argument 3"); return false; } if (JS::IsResizableArrayBufferView(arg2.Obj())) { cx.ThrowErrorMessage("Argument 3"); return false; } if (JS::IsImmutableArrayBufferView(arg2.Obj())) { cx.ThrowErrorMessage("Argument 3"); return false; } } else { cx.ThrowErrorMessage("Argument 3"); return false; } uint64_t arg3; if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } uint32_t arg4; if (!ValueToPrimitive(cx, args[4], "Argument 5", &arg4)) { return false; } FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), arg3, arg4, rv))>, "Should be returning void here"); MOZ_KnownLive(self)->SetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), arg3, arg4, rv); if (rv.MaybeSetPendingException(cx, "GPUComputePassEncoder.setBindGroup")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; break; } default: { // Using nsPrintfCString here would require including that // header. Let's not worry about it. nsAutoCString argCountStr; argCountStr.AppendPrintf("%u", args.length()); return cx.ThrowErrorMessage(argCountStr.get()); } } MOZ_CRASH("We have an always-returning default case"); return false; } static const JSJitInfo setBindGroup_methodinfo = { { (JSJitGetterOp)setBindGroup }, { prototypes::id::GPUComputePassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool pushDebugGroup(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePassEncoder", "pushDebugGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUComputePassEncoder.pushDebugGroup", 1)) { return false; } nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vPushDebugGroup(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->PushDebugGroup(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo pushDebugGroup_methodinfo = { { (JSJitGetterOp)pushDebugGroup }, { prototypes::id::GPUComputePassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool popDebugGroup(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePassEncoder", "popDebugGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vPopDebugGroup())>, "Should be returning void here"); MOZ_KnownLive(self)->PopDebugGroup(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo popDebugGroup_methodinfo = { { (JSJitGetterOp)popDebugGroup }, { prototypes::id::GPUComputePassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool insertDebugMarker(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePassEncoder", "insertDebugMarker", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUComputePassEncoder.insertDebugMarker", 1)) { return false; } nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vInsertDebugMarker(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->InsertDebugMarker(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo insertDebugMarker_methodinfo = { { (JSJitGetterOp)insertDebugMarker }, { prototypes::id::GPUComputePassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePassEncoder", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePassEncoder", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUComputePassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUComputePassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::ComputePassEncoder* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("setPipeline", (GenericMethod), reinterpret_cast(&setPipeline_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("dispatchWorkgroups", (GenericMethod), reinterpret_cast(&dispatchWorkgroups_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("dispatchWorkgroupsIndirect", (GenericMethod), reinterpret_cast(&dispatchWorkgroupsIndirect_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("end", (GenericMethod), reinterpret_cast(&end_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END, JS_FNSPEC("setBindGroup", (GenericMethod), reinterpret_cast(&setBindGroup_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("pushDebugGroup", (GenericMethod), reinterpret_cast(&pushDebugGroup_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("popDebugGroup", (GenericMethod), reinterpret_cast(&popDebugGroup_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("insertDebugMarker", (GenericMethod), reinterpret_cast(&insertDebugMarker_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, &sMethods_specs[5] }, { nullptr, nullptr } }; static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(4 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[9]; static PropertyInfo sNativeProperties_propertyInfos[9]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 9, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[8] } } }; static_assert(9 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUComputePassEncoder, constructors::id::GPUComputePassEncoder, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUComputePassEncoder, true, 0, "GPUComputePassEncoder", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUComputePassEncoderPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUComputePassEncoder, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUComputePassEncoder", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUComputePassEncoder, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::ComputePassEncoder* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUComputePassEncoder); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUComputePassEncoder); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUComputePassEncoder", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUComputePassEncoder, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUComputePassEncoder, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUComputePassEncoder_Binding namespace GPUComputePipeline_Binding { MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePipeline", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePipeline", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUComputePipeline }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUComputePipeline }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool getBindGroupLayout(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUComputePipeline", "getBindGroupLayout", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUComputePipeline.getBindGroupLayout", 1)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->GetBindGroupLayout(arg0))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo getBindGroupLayout_methodinfo = { { (JSJitGetterOp)getBindGroupLayout }, { prototypes::id::GPUComputePipeline }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::ComputePipeline* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("getBindGroupLayout", (GenericMethod), reinterpret_cast(&getBindGroupLayout_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const Prefable sMethods[] = { { nullptr, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[2]; static PropertyInfo sNativeProperties_propertyInfos[2]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 2, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[1] } } }; static_assert(2 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUComputePipeline, constructors::id::GPUComputePipeline, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUComputePipeline, true, 0, "GPUComputePipeline", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUComputePipelinePrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUComputePipeline, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUComputePipeline", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUComputePipeline, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::ComputePipeline* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUComputePipeline); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUComputePipeline); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUComputePipeline", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUComputePipeline, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUComputePipeline, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUComputePipeline_Binding namespace GPUDevice_Binding { static_assert(IsRefcounted::value == IsRefcounted::value, "Can't inherit from an interface with a different ownership model."); MOZ_CAN_RUN_SCRIPT static bool get_features(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "features", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); auto result(StrongOrRawPtr(MOZ_KnownLive(self)->Features())); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo features_getterinfo = { { get_features }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasNone, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ true, /* isMovable. Not relevant for setters. */ true, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_limits(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "limits", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); auto result(StrongOrRawPtr(MOZ_KnownLive(self)->Limits())); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo limits_getterinfo = { { get_limits }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasNone, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ true, /* isMovable. Not relevant for setters. */ true, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_adapterInfo(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "adapterInfo", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); auto result(StrongOrRawPtr(MOZ_KnownLive(self)->GetAdapterInfo())); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo adapterInfo_getterinfo = { { get_adapterInfo }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasNone, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ true, /* isMovable. Not relevant for setters. */ true, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_queue(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "queue", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); auto result(StrongOrRawPtr(MOZ_KnownLive(self)->GetQueue())); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo queue_getterinfo = { { get_queue }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasNone, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ true, /* isMovable. Not relevant for setters. */ true, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool destroy(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "destroy", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDestroy())>, "Should be returning void here"); MOZ_KnownLive(self)->Destroy(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo destroy_methodinfo = { { (JSJitGetterOp)destroy }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createBuffer(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createBuffer"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createBuffer", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createBuffer", 1)) { return false; } binding_detail::FastGPUBufferDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateBuffer(Constify(arg0), rv))); if (rv.MaybeSetPendingException(cx, "GPUDevice.createBuffer")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createBuffer_methodinfo = { { (JSJitGetterOp)createBuffer }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createTexture(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createTexture"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createTexture", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createTexture", 1)) { return false; } binding_detail::FastGPUTextureDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateTexture(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createTexture_methodinfo = { { (JSJitGetterOp)createTexture }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool importExternalTexture(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.importExternalTexture"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "importExternalTexture", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.importExternalTexture", 1)) { return false; } binding_detail::FastGPUExternalTextureDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->ImportExternalTexture(Constify(arg0), rv))); if (rv.MaybeSetPendingException(cx, "GPUDevice.importExternalTexture")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo importExternalTexture_methodinfo = { { (JSJitGetterOp)importExternalTexture }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createSampler(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createSampler"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createSampler", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); binding_detail::FastGPUSamplerDescriptor arg0; if (!arg0.Init(cx, (args.hasDefined(0)) ? args[0] : JS::NullHandleValue, "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateSampler(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createSampler_methodinfo = { { (JSJitGetterOp)createSampler }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createBindGroupLayout(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createBindGroupLayout"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createBindGroupLayout", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createBindGroupLayout", 1)) { return false; } binding_detail::FastGPUBindGroupLayoutDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateBindGroupLayout(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createBindGroupLayout_methodinfo = { { (JSJitGetterOp)createBindGroupLayout }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createPipelineLayout(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createPipelineLayout"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createPipelineLayout", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createPipelineLayout", 1)) { return false; } binding_detail::FastGPUPipelineLayoutDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreatePipelineLayout(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createPipelineLayout_methodinfo = { { (JSJitGetterOp)createPipelineLayout }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createBindGroup(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createBindGroup"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createBindGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createBindGroup", 1)) { return false; } binding_detail::FastGPUBindGroupDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateBindGroup(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createBindGroup_methodinfo = { { (JSJitGetterOp)createBindGroup }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createShaderModule(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createShaderModule"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createShaderModule", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createShaderModule", 1)) { return false; } binding_detail::FastGPUShaderModuleDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateShaderModule(Constify(arg0), rv))); if (rv.MaybeSetPendingException(cx, "GPUDevice.createShaderModule")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createShaderModule_methodinfo = { { (JSJitGetterOp)createShaderModule }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createComputePipeline(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createComputePipeline"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createComputePipeline", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createComputePipeline", 1)) { return false; } binding_detail::FastGPUComputePipelineDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateComputePipeline(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createComputePipeline_methodinfo = { { (JSJitGetterOp)createComputePipeline }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createRenderPipeline(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createRenderPipeline"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createRenderPipeline", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createRenderPipeline", 1)) { return false; } binding_detail::FastGPURenderPipelineDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateRenderPipeline(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createRenderPipeline_methodinfo = { { (JSJitGetterOp)createRenderPipeline }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createComputePipelineAsync(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createComputePipelineAsync"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createComputePipelineAsync", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createComputePipelineAsync", 1)) { return false; } binding_detail::FastGPUComputePipelineDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateComputePipelineAsync(Constify(arg0), rv))); if (rv.MaybeSetPendingException(cx, "GPUDevice.createComputePipelineAsync")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool createComputePipelineAsync_promiseWrapper(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { bool ok = createComputePipelineAsync(cx, obj, void_self, args); if (ok) { return true; } return ConvertExceptionToPromise(cx, args.rval()); } static const JSJitInfo createComputePipelineAsync_methodinfo = { { (JSJitGetterOp)createComputePipelineAsync_promiseWrapper }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createRenderPipelineAsync(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createRenderPipelineAsync"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createRenderPipelineAsync", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createRenderPipelineAsync", 1)) { return false; } binding_detail::FastGPURenderPipelineDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateRenderPipelineAsync(Constify(arg0), rv))); if (rv.MaybeSetPendingException(cx, "GPUDevice.createRenderPipelineAsync")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool createRenderPipelineAsync_promiseWrapper(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { bool ok = createRenderPipelineAsync(cx, obj, void_self, args); if (ok) { return true; } return ConvertExceptionToPromise(cx, args.rval()); } static const JSJitInfo createRenderPipelineAsync_methodinfo = { { (JSJitGetterOp)createRenderPipelineAsync_promiseWrapper }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createCommandEncoder(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createCommandEncoder"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createCommandEncoder", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); binding_detail::FastGPUCommandEncoderDescriptor arg0; if (!arg0.Init(cx, (args.hasDefined(0)) ? args[0] : JS::NullHandleValue, "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateCommandEncoder(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createCommandEncoder_methodinfo = { { (JSJitGetterOp)createCommandEncoder }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createRenderBundleEncoder(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createRenderBundleEncoder"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createRenderBundleEncoder", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createRenderBundleEncoder", 1)) { return false; } binding_detail::FastGPURenderBundleEncoderDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateRenderBundleEncoder(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createRenderBundleEncoder_methodinfo = { { (JSJitGetterOp)createRenderBundleEncoder }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool createQuerySet(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.createQuerySet"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "createQuerySet", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.createQuerySet", 1)) { return false; } binding_detail::FastGPUQuerySetDescriptor arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateQuerySet(Constify(arg0), rv))); if (rv.MaybeSetPendingException(cx, "GPUDevice.createQuerySet")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createQuerySet_methodinfo = { { (JSJitGetterOp)createQuerySet }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_lost(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "lost", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->GetLost(rv))); if (rv.MaybeSetPendingException(cx, "GPUDevice.lost getter")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool get_lost_promiseWrapper(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { bool ok = get_lost(cx, obj, void_self, args); if (ok) { return true; } return ConvertExceptionToPromise(cx, args.rval()); } static const JSJitInfo lost_getterinfo = { { get_lost_promiseWrapper }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool pushErrorScope(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUDevice.pushErrorScope"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "pushErrorScope", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUDevice.pushErrorScope", 1)) { return false; } GPUErrorFilter arg0; { int index; if (!binding_detail::FindEnumStringIndex(cx, args[0], binding_detail::EnumStrings::Values, "GPUErrorFilter", "argument 1", &index)) { return false; } MOZ_ASSERT(index >= 0); arg0 = static_cast(index); } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vPushErrorScope(arg0))>, "Should be returning void here"); MOZ_KnownLive(self)->PushErrorScope(arg0); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo pushErrorScope_methodinfo = { { (JSJitGetterOp)pushErrorScope }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool popErrorScope(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "popErrorScope", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->PopErrorScope(rv))); if (rv.MaybeSetPendingException(cx, "GPUDevice.popErrorScope")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool popErrorScope_promiseWrapper(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { bool ok = popErrorScope(cx, obj, void_self, args); if (ok) { return true; } return ConvertExceptionToPromise(cx, args.rval()); } static const JSJitInfo popErrorScope_methodinfo = { { (JSJitGetterOp)popErrorScope_promiseWrapper }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_onuncapturederror(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "onuncapturederror", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); RefPtr result(MOZ_KnownLive(self)->GetOnuncapturederror()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (result) { args.rval().setObjectOrNull(GetCallbackFromCallbackObject(cx, result)); if (!MaybeWrapObjectOrNullValue(cx, args.rval())) { return false; } return true; } else { args.rval().setNull(); return true; } } MOZ_CAN_RUN_SCRIPT static bool set_onuncapturederror(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "onuncapturederror", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); RootedCallback> arg0(cx); if (args[0].isObject()) { { // scope for tempRoot and tempGlobalRoot if needed arg0 = new binding_detail::FastEventHandlerNonNull(&args[0].toObject(), JS::CurrentGlobalOrNull(cx)); } } else { arg0 = nullptr; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetOnuncapturederror(MOZ_KnownLive(Constify(arg0))))>, "Should be returning void here"); MOZ_KnownLive(self)->SetOnuncapturederror(MOZ_KnownLive(Constify(arg0))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo onuncapturederror_getterinfo = { { get_onuncapturederror }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNKNOWN, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo onuncapturederror_setterinfo = { { (JSJitGetterOp)set_onuncapturederror }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDevice", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUDevice }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::Device* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("destroy", (GenericMethod), reinterpret_cast(&destroy_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createBuffer", (GenericMethod), reinterpret_cast(&createBuffer_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createTexture", (GenericMethod), reinterpret_cast(&createTexture_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FS_END, JS_FNSPEC("importExternalTexture", (GenericMethod), reinterpret_cast(&importExternalTexture_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FS_END, JS_FNSPEC("createSampler", (GenericMethod), reinterpret_cast(&createSampler_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createBindGroupLayout", (GenericMethod), reinterpret_cast(&createBindGroupLayout_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createPipelineLayout", (GenericMethod), reinterpret_cast(&createPipelineLayout_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createBindGroup", (GenericMethod), reinterpret_cast(&createBindGroup_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createShaderModule", (GenericMethod), reinterpret_cast(&createShaderModule_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createComputePipeline", (GenericMethod), reinterpret_cast(&createComputePipeline_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createRenderPipeline", (GenericMethod), reinterpret_cast(&createRenderPipeline_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createComputePipelineAsync", (GenericMethod), reinterpret_cast(&createComputePipelineAsync_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createRenderPipelineAsync", (GenericMethod), reinterpret_cast(&createRenderPipelineAsync_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createCommandEncoder", (GenericMethod), reinterpret_cast(&createCommandEncoder_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createRenderBundleEncoder", (GenericMethod), reinterpret_cast(&createRenderBundleEncoder_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("createQuerySet", (GenericMethod), reinterpret_cast(&createQuerySet_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("pushErrorScope", (GenericMethod), reinterpret_cast(&pushErrorScope_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("popErrorScope", (GenericMethod), reinterpret_cast(&popErrorScope_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const PrefableDisablers sMethods_disablers4 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), &mozilla::webgpu::Instance::ExternalTexturePrefEnabled }; static const PrefableDisablers sMethods_disablers6 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { &sMethods_disablers4, &sMethods_specs[4] }, { &sMethods_disablers6, &sMethods_specs[6] }, { nullptr, nullptr } }; static_assert(3 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(14 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("features", JSPROP_ENUMERATE, GenericGetter, &features_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("limits", JSPROP_ENUMERATE, GenericGetter, &limits_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("adapterInfo", JSPROP_ENUMERATE, GenericGetter, &adapterInfo_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("queue", JSPROP_ENUMERATE, GenericGetter, &queue_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("lost", JSPROP_ENUMERATE, GenericGetter, &lost_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("onuncapturederror", JSPROP_ENUMERATE, GenericGetter, &onuncapturederror_getterinfo, GenericSetter, &onuncapturederror_setterinfo), JS_PS_END, JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, &sAttributes_specs[7] }, { nullptr, nullptr } }; static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(6 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[25]; static PropertyInfo sNativeProperties_propertyInfos[25]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 25, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[18] } } }; static_assert(25 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUDevice, constructors::id::GPUDevice, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, EventTarget_Binding::GetConstructorObjectHandle, PrototypeTraits::Depth, prototypes::id::GPUDevice, true, 0, "GPUDevice", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUDevicePrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUDevice, PrototypeTraits::Depth, &sNativePropertyHooks, EventTarget_Binding::GetProtoObject }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUDevice", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::EventTarget, prototypes::id::GPUDevice, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::Device* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(static_cast(aObject) == reinterpret_cast(aObject), "Multiple inheritance for mozilla::dom::EventTarget is broken."); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUDevice); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUDevice); JS::Handle parentProto(EventTarget_Binding::GetProtoObjectHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(EventTarget_Binding::GetConstructorObjectHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUDevice", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUDevice, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUDevice, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUDevice_Binding namespace GPUDeviceLostInfo_Binding { MOZ_CAN_RUN_SCRIPT static bool get_reason(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDeviceLostInfo", "reason", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); GPUDeviceLostReason result(MOZ_KnownLive(self)->Reason()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo reason_getterinfo = { { get_reason }, { prototypes::id::GPUDeviceLostInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_message(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUDeviceLostInfo", "message", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetMessage(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetMessage(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo message_getterinfo = { { get_message }, { prototypes::id::GPUDeviceLostInfo }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::DeviceLostInfo* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("reason", JSPROP_ENUMERATE, GenericGetter, &reason_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("message", JSPROP_ENUMERATE, GenericGetter, &message_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[2]; static PropertyInfo sNativeProperties_propertyInfos[2]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 2, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(2 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUDeviceLostInfo, constructors::id::GPUDeviceLostInfo, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUDeviceLostInfo, true, 0, "GPUDeviceLostInfo", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUDeviceLostInfoPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUDeviceLostInfo, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUDeviceLostInfo", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUDeviceLostInfo, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::DeviceLostInfo* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUDeviceLostInfo); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUDeviceLostInfo); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUDeviceLostInfo", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUDeviceLostInfo, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUDeviceLostInfo, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUDeviceLostInfo_Binding namespace GPUError_Binding { MOZ_CAN_RUN_SCRIPT static bool get_message(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUError", "message", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetMessage(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetMessage(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo message_getterinfo = { { get_message }, { prototypes::id::GPUError }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("message", JSPROP_ENUMERATE, GenericGetter, &message_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUError, constructors::id::GPUError, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUError, true, 0, "GPUError", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUErrorPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUError, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUError); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUError); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUError", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUError, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JSObject* GetProtoObject(JSContext* aCx) { return GetProtoObjectHandle(aCx); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUError, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUError_Binding namespace GPUExternalTexture_Binding { MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUExternalTexture", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUExternalTexture", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUExternalTexture }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUExternalTexture }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::ExternalTexture* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUExternalTexture, constructors::id::GPUExternalTexture, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUExternalTexture, true, 0, "GPUExternalTexture", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUExternalTexturePrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUExternalTexture, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUExternalTexture", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUExternalTexture, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::ExternalTexture* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUExternalTexture); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUExternalTexture); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUExternalTexture", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUExternalTexture, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUExternalTexture, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUExternalTexture_Binding namespace GPUInternalError_Binding { static_assert(IsRefcounted::value == IsRefcounted::value, "Can't inherit from an interface with a different ownership model."); static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::InternalError* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { nullptr, nullptr, &sNativePropertiesInited }, prototypes::id::GPUInternalError, constructors::id::GPUInternalError, &DefaultXrayExpandoObjectClass }; static bool _constructor(JSContext* cx, unsigned argc, JS::Value* vp) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUInternalError", "constructor", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::Rooted obj(cx, &args.callee()); if (!args.isConstructing()) { return ThrowConstructorWithoutNew(cx, "GPUInternalError"); } JS::Rooted desiredProto(cx); if (!GetDesiredProto(cx, args, prototypes::id::GPUInternalError, CreateInterfaceObjects, &desiredProto)) { return false; } if (!args.requireAtLeast(cx, "GPUInternalError constructor", 1)) { return false; } GlobalObject global(cx, obj); if (global.Failed()) { return false; } bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } Maybe ar; if (objIsXray) { // Since our object is an Xray, we can just CheckedUnwrapStatic: // we know Xrays have no dynamic unwrap behavior. obj = js::CheckedUnwrapStatic(obj); if (!obj) { return false; } ar.emplace(cx, obj); if (!JS_WrapObject(cx, &desiredProto)) { return false; } } FastErrorResult rv; auto result(StrongOrRawPtr(mozilla::webgpu::InternalError::Constructor(global, NonNullHelper(Constify(arg0)), rv))); if (rv.MaybeSetPendingException(cx, "GPUInternalError constructor")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); static_assert(!std::is_pointer_v, "NewObject implies that we need to keep the object alive with a strong reference."); if (!GetOrCreateDOMReflector(cx, result, args.rval(), desiredProto)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const DOMInterfaceInfo sInterfaceObjectInfo = { { _constructor, &sNativePropertyHooks }, GPUError_Binding::GetConstructorObjectHandle, PrototypeTraits::Depth, prototypes::id::GPUInternalError, true, 1, "GPUInternalError", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUInternalErrorPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUInternalError, PrototypeTraits::Depth, &sNativePropertyHooks, GPUError_Binding::GetProtoObject }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUInternalError", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUError, prototypes::id::GPUInternalError, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::InternalError* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(static_cast(aObject) == reinterpret_cast(aObject), "Multiple inheritance for mozilla::webgpu::Error is broken."); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUInternalError); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUInternalError); JS::Handle parentProto(GPUError_Binding::GetProtoObjectHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(GPUError_Binding::GetConstructorObjectHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 1, false, Span{}, interfaceCache, nullptr, nullptr, "GPUInternalError", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUInternalError, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUInternalError, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUInternalError_Binding namespace GPUMapMode_Binding { MOZ_GLOBINIT static const ConstantSpec sConstants_specs[] = { { "READ", JS::NumberValue(1U) }, { "WRITE", JS::NumberValue(2U) }, { 0, JS::UndefinedValue() } }; static const PrefableDisablers sConstants_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sConstants[] = { { &sConstants_disablers0, &sConstants_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[2]; static PropertyInfo sNativeProperties_propertyInfos[2]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, true, 0 /* sConstants */, -1, 2, sNativeProperties_sortedPropertyIndices, { { sConstants, &sNativeProperties_propertyInfos[0] } } }; static_assert(2 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::_ID_Count, constructors::id::GPUMapMode, &DefaultXrayExpandoObjectClass }; static const DOMIfaceAndProtoJSClass sNamespaceObjectClass = { { "GPUMapMode", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS, JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eNamespace, prototypes::id::_ID_Count, 0, &sNativePropertyHooks, // This isn't strictly following the spec (see // https://console.spec.whatwg.org/#ref-for-dfn-namespace-object), // but should be ok for Xrays. JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Rooted constructorProto(aCx, JS::GetRealmObjectPrototype(aCx)); if (!constructorProto) { return; } JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUMapMode); dom::CreateNamespaceObject(aCx, aGlobal, constructorProto, sNamespaceObjectClass, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUMapMode", ShouldExpose(aCx, aGlobal, aDefineOnGlobal)); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUMapMode, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUMapMode_Binding namespace GPUOutOfMemoryError_Binding { static_assert(IsRefcounted::value == IsRefcounted::value, "Can't inherit from an interface with a different ownership model."); static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::OutOfMemoryError* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { nullptr, nullptr, &sNativePropertiesInited }, prototypes::id::GPUOutOfMemoryError, constructors::id::GPUOutOfMemoryError, &DefaultXrayExpandoObjectClass }; static bool _constructor(JSContext* cx, unsigned argc, JS::Value* vp) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUOutOfMemoryError", "constructor", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::Rooted obj(cx, &args.callee()); if (!args.isConstructing()) { return ThrowConstructorWithoutNew(cx, "GPUOutOfMemoryError"); } JS::Rooted desiredProto(cx); if (!GetDesiredProto(cx, args, prototypes::id::GPUOutOfMemoryError, CreateInterfaceObjects, &desiredProto)) { return false; } if (!args.requireAtLeast(cx, "GPUOutOfMemoryError constructor", 1)) { return false; } GlobalObject global(cx, obj); if (global.Failed()) { return false; } bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } Maybe ar; if (objIsXray) { // Since our object is an Xray, we can just CheckedUnwrapStatic: // we know Xrays have no dynamic unwrap behavior. obj = js::CheckedUnwrapStatic(obj); if (!obj) { return false; } ar.emplace(cx, obj); if (!JS_WrapObject(cx, &desiredProto)) { return false; } } FastErrorResult rv; auto result(StrongOrRawPtr(mozilla::webgpu::OutOfMemoryError::Constructor(global, NonNullHelper(Constify(arg0)), rv))); if (rv.MaybeSetPendingException(cx, "GPUOutOfMemoryError constructor")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); static_assert(!std::is_pointer_v, "NewObject implies that we need to keep the object alive with a strong reference."); if (!GetOrCreateDOMReflector(cx, result, args.rval(), desiredProto)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const DOMInterfaceInfo sInterfaceObjectInfo = { { _constructor, &sNativePropertyHooks }, GPUError_Binding::GetConstructorObjectHandle, PrototypeTraits::Depth, prototypes::id::GPUOutOfMemoryError, true, 1, "GPUOutOfMemoryError", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUOutOfMemoryErrorPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUOutOfMemoryError, PrototypeTraits::Depth, &sNativePropertyHooks, GPUError_Binding::GetProtoObject }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUOutOfMemoryError", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUError, prototypes::id::GPUOutOfMemoryError, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::OutOfMemoryError* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(static_cast(aObject) == reinterpret_cast(aObject), "Multiple inheritance for mozilla::webgpu::Error is broken."); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUOutOfMemoryError); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUOutOfMemoryError); JS::Handle parentProto(GPUError_Binding::GetProtoObjectHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(GPUError_Binding::GetConstructorObjectHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 1, false, Span{}, interfaceCache, nullptr, nullptr, "GPUOutOfMemoryError", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUOutOfMemoryError, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUOutOfMemoryError, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUOutOfMemoryError_Binding namespace GPUPipelineError_Binding { static_assert(IsRefcounted::value == IsRefcounted::value, "Can't inherit from an interface with a different ownership model."); MOZ_CAN_RUN_SCRIPT static bool get_reason(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUPipelineError", "reason", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); GPUPipelineErrorReason result(MOZ_KnownLive(self)->Reason()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo reason_getterinfo = { { get_reason }, { prototypes::id::GPUPipelineError }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::PipelineError* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("reason", JSPROP_ENUMERATE, GenericGetter, &reason_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUPipelineError, constructors::id::GPUPipelineError, &DefaultXrayExpandoObjectClass }; static bool _constructor(JSContext* cx_, unsigned argc, JS::Value* vp) { BindingCallContext cx(cx_, "GPUPipelineError constructor"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUPipelineError", "constructor", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::Rooted obj(cx, &args.callee()); if (!args.isConstructing()) { return ThrowConstructorWithoutNew(cx, "GPUPipelineError"); } JS::Rooted desiredProto(cx); if (!GetDesiredProto(cx, args, prototypes::id::GPUPipelineError, CreateInterfaceObjects, &desiredProto)) { return false; } if (!args.requireAtLeast(cx, "GPUPipelineError constructor", 2)) { return false; } GlobalObject global(cx, obj); if (global.Failed()) { return false; } bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj); nsAutoString arg0; if (args.hasDefined(0)) { if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } } else { arg0.AssignLiteral(u""); } binding_detail::FastGPUPipelineErrorInit arg1; if (!arg1.Init(cx, args[1], "Argument 2", false)) { return false; } Maybe ar; if (objIsXray) { // Since our object is an Xray, we can just CheckedUnwrapStatic: // we know Xrays have no dynamic unwrap behavior. obj = js::CheckedUnwrapStatic(obj); if (!obj) { return false; } ar.emplace(cx, obj); if (!JS_WrapObject(cx, &desiredProto)) { return false; } } auto result(StrongOrRawPtr(mozilla::webgpu::PipelineError::Constructor(global, NonNullHelper(Constify(arg0)), Constify(arg1)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); static_assert(!std::is_pointer_v, "NewObject implies that we need to keep the object alive with a strong reference."); if (!GetOrCreateDOMReflector(cx, result, args.rval(), desiredProto)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const DOMInterfaceInfo sInterfaceObjectInfo = { { _constructor, &sNativePropertyHooks }, DOMException_Binding::GetConstructorObjectHandle, PrototypeTraits::Depth, prototypes::id::GPUPipelineError, true, 2, "GPUPipelineError", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUPipelineErrorPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUPipelineError, PrototypeTraits::Depth, &sNativePropertyHooks, DOMException_Binding::GetProtoObject }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUPipelineError", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::DOMException, prototypes::id::GPUPipelineError, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::PipelineError* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(static_cast(aObject) == reinterpret_cast(aObject), "Multiple inheritance for mozilla::dom::DOMException is broken."); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUPipelineError); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUPipelineError); JS::Handle parentProto(DOMException_Binding::GetProtoObjectHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(DOMException_Binding::GetConstructorObjectHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 2, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUPipelineError", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUPipelineError, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUPipelineError, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUPipelineError_Binding namespace GPUPipelineLayout_Binding { MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUPipelineLayout", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUPipelineLayout", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUPipelineLayout }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUPipelineLayout }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::PipelineLayout* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUPipelineLayout, constructors::id::GPUPipelineLayout, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUPipelineLayout, true, 0, "GPUPipelineLayout", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUPipelineLayoutPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUPipelineLayout, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUPipelineLayout", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUPipelineLayout, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::PipelineLayout* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUPipelineLayout); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUPipelineLayout); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUPipelineLayout", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUPipelineLayout, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUPipelineLayout, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUPipelineLayout_Binding namespace GPUQuerySet_Binding { MOZ_CAN_RUN_SCRIPT static bool destroy(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQuerySet", "destroy", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDestroy())>, "Should be returning void here"); MOZ_KnownLive(self)->Destroy(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo destroy_methodinfo = { { (JSJitGetterOp)destroy }, { prototypes::id::GPUQuerySet }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_type(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQuerySet", "type", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); GPUQueryType result(MOZ_KnownLive(self)->Type()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo type_getterinfo = { { get_type }, { prototypes::id::GPUQuerySet }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_count(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQuerySet", "count", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->Count()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo count_getterinfo = { { get_count }, { prototypes::id::GPUQuerySet }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQuerySet", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQuerySet", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUQuerySet }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUQuerySet }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::QuerySet* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("destroy", (GenericMethod), reinterpret_cast(&destroy_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("type", JSPROP_ENUMERATE, GenericGetter, &type_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("count", JSPROP_ENUMERATE, GenericGetter, &count_getterinfo, nullptr, nullptr), JS_PS_END, JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, &sAttributes_specs[3] }, { nullptr, nullptr } }; static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[4]; static PropertyInfo sNativeProperties_propertyInfos[4]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 4, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[1] } } }; static_assert(4 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUQuerySet, constructors::id::GPUQuerySet, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUQuerySet, true, 0, "GPUQuerySet", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUQuerySetPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUQuerySet, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUQuerySet", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUQuerySet, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::QuerySet* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUQuerySet); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUQuerySet); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUQuerySet", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUQuerySet, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUQuerySet, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUQuerySet_Binding namespace GPUQueue_Binding { MOZ_CAN_RUN_SCRIPT static bool submit(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUQueue.submit"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQueue", "submit", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUQueue.submit", 1)) { return false; } binding_detail::AutoSequence> arg0; if (args[0].isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(args[0], JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("Argument 1", "sequence"); return false; } binding_detail::AutoSequence> &arr = arg0; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } OwningNonNull* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } OwningNonNull& slot = *slotPtr; if (temp.isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(&temp, slot, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Element of argument 1", "GPUCommandBuffer"); return false; } } } else { cx.ThrowErrorMessage("Element of argument 1"); return false; } } } else { cx.ThrowErrorMessage("Argument 1", "sequence"); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSubmit(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->Submit(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo submit_methodinfo = { { (JSJitGetterOp)submit }, { prototypes::id::GPUQueue }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool onSubmittedWorkDone(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQueue", "onSubmittedWorkDone", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->OnSubmittedWorkDone(rv))); if (rv.MaybeSetPendingException(cx, "GPUQueue.onSubmittedWorkDone")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool onSubmittedWorkDone_promiseWrapper(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { bool ok = onSubmittedWorkDone(cx, obj, void_self, args); if (ok) { return true; } return ConvertExceptionToPromise(cx, args.rval()); } static const JSJitInfo onSubmittedWorkDone_methodinfo = { { (JSJitGetterOp)onSubmittedWorkDone_promiseWrapper }, { prototypes::id::GPUQueue }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool writeBuffer(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUQueue.writeBuffer"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQueue", "writeBuffer", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUQueue.writeBuffer", 3)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } uint64_t arg1; if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } MaybeSharedArrayBufferOrMaybeSharedArrayBufferView arg2; if (!arg2.Init(cx, args[2], "Argument 3", false)) { return false; } uint64_t arg3; if (args.hasDefined(3)) { if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } } else { arg3 = 0ULL; } Optional arg4; if (args.hasDefined(4)) { arg4.Construct(); if (!ValueToPrimitive(cx, args[4], "Argument 5", &arg4.Value())) { return false; } } FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vWriteBuffer(MOZ_KnownLive(NonNullHelper(arg0)), arg1, Constify(arg2), arg3, Constify(arg4), rv))>, "Should be returning void here"); MOZ_KnownLive(self)->WriteBuffer(MOZ_KnownLive(NonNullHelper(arg0)), arg1, Constify(arg2), arg3, Constify(arg4), rv); if (rv.MaybeSetPendingException(cx, "GPUQueue.writeBuffer")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo writeBuffer_methodinfo = { { (JSJitGetterOp)writeBuffer }, { prototypes::id::GPUQueue }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool writeTexture(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUQueue.writeTexture"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQueue", "writeTexture", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUQueue.writeTexture", 4)) { return false; } binding_detail::FastGPUTexelCopyTextureInfo arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } MaybeSharedArrayBufferOrMaybeSharedArrayBufferView arg1; if (!arg1.Init(cx, args[1], "Argument 2", false)) { return false; } binding_detail::FastGPUTexelCopyBufferLayout arg2; if (!arg2.Init(cx, args[2], "Argument 3", false)) { return false; } RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict arg3; if (!arg3.Init(cx, args[3], "Argument 4", false)) { return false; } FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vWriteTexture(Constify(arg0), Constify(arg1), Constify(arg2), Constify(arg3), rv))>, "Should be returning void here"); MOZ_KnownLive(self)->WriteTexture(Constify(arg0), Constify(arg1), Constify(arg2), Constify(arg3), rv); if (rv.MaybeSetPendingException(cx, "GPUQueue.writeTexture")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo writeTexture_methodinfo = { { (JSJitGetterOp)writeTexture }, { prototypes::id::GPUQueue }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool copyExternalImageToTexture(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUQueue.copyExternalImageToTexture"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQueue", "copyExternalImageToTexture", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPUQueue.copyExternalImageToTexture", 3)) { return false; } binding_detail::FastGPUCopyExternalImageSourceInfo arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } binding_detail::FastGPUCopyExternalImageDestInfo arg1; if (!arg1.Init(cx, args[1], "Argument 2", false)) { return false; } RangeEnforcedUnsignedLongSequenceOrGPUExtent3DDict arg2; if (!arg2.Init(cx, args[2], "Argument 3", false)) { return false; } FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vCopyExternalImageToTexture(Constify(arg0), Constify(arg1), Constify(arg2), rv))>, "Should be returning void here"); MOZ_KnownLive(self)->CopyExternalImageToTexture(Constify(arg0), Constify(arg1), Constify(arg2), rv); if (rv.MaybeSetPendingException(cx, "GPUQueue.copyExternalImageToTexture")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo copyExternalImageToTexture_methodinfo = { { (JSJitGetterOp)copyExternalImageToTexture }, { prototypes::id::GPUQueue }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQueue", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUQueue", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUQueue }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUQueue }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::Queue* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("submit", (GenericMethod), reinterpret_cast(&submit_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("onSubmittedWorkDone", (GenericMethod), reinterpret_cast(&onSubmittedWorkDone_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("writeBuffer", (GenericMethod), reinterpret_cast(&writeBuffer_methodinfo), 3, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("writeTexture", (GenericMethod), reinterpret_cast(&writeTexture_methodinfo), 4, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("copyExternalImageToTexture", (GenericMethod), reinterpret_cast(©ExternalImageToTexture_methodinfo), 3, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(5 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[6]; static PropertyInfo sNativeProperties_propertyInfos[6]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 6, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[5] } } }; static_assert(6 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUQueue, constructors::id::GPUQueue, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUQueue, true, 0, "GPUQueue", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUQueuePrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUQueue, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUQueue", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUQueue, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::Queue* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUQueue); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUQueue); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUQueue", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUQueue, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUQueue, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUQueue_Binding namespace GPURenderBundle_Binding { MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundle", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundle", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPURenderBundle }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPURenderBundle }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::RenderBundle* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPURenderBundle, constructors::id::GPURenderBundle, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPURenderBundle, true, 0, "GPURenderBundle", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPURenderBundlePrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPURenderBundle, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPURenderBundle", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPURenderBundle, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::RenderBundle* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPURenderBundle); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPURenderBundle); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPURenderBundle", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPURenderBundle, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPURenderBundle, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPURenderBundle_Binding namespace GPURenderBundleEncoder_Binding { MOZ_CAN_RUN_SCRIPT static bool finish(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderBundleEncoder.finish"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "finish", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); binding_detail::FastGPURenderBundleDescriptor arg0; if (!arg0.Init(cx, (args.hasDefined(0)) ? args[0] : JS::NullHandleValue, "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->Finish(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo finish_methodinfo = { { (JSJitGetterOp)finish }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setBindGroup(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderBundleEncoder.setBindGroup"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "setBindGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); unsigned argcount = std::min(args.length(), 5u); switch (argcount) { case 2: { [[fallthrough]]; } case 3: { uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } mozilla::webgpu::BindGroup* arg1; if (args[1].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[1], arg1, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 2", "GPUBindGroup"); return false; } } } else if (args[1].isNullOrUndefined()) { arg1 = nullptr; } else { cx.ThrowErrorMessage("Argument 2"); return false; } binding_detail::AutoSequence arg2; if (args.hasDefined(2)) { if (args[2].isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(args[2], JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("Argument 3", "sequence"); return false; } binding_detail::AutoSequence &arr = arg2; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } uint32_t* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } uint32_t& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of argument 3", &slot)) { return false; } } } else { cx.ThrowErrorMessage("Argument 3", "sequence"); return false; } } else { /* arg2 array is already empty; nothing to do */ } FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), rv))>, "Should be returning void here"); MOZ_KnownLive(self)->SetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), rv); if (rv.MaybeSetPendingException(cx, "GPURenderBundleEncoder.setBindGroup")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; break; } case 5: { uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } mozilla::webgpu::BindGroup* arg1; if (args[1].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[1], arg1, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 2", "GPUBindGroup"); return false; } } } else if (args[1].isNullOrUndefined()) { arg1 = nullptr; } else { cx.ThrowErrorMessage("Argument 2"); return false; } RootedSpiderMonkeyInterface arg2(cx); if (args[2].isObject()) { if (!arg2.Init(&args[2].toObject())) { cx.ThrowErrorMessage("Argument 3", "Uint32Array"); return false; } if (JS::IsLargeArrayBufferView(arg2.Obj())) { cx.ThrowErrorMessage("Argument 3"); return false; } if (JS::IsResizableArrayBufferView(arg2.Obj())) { cx.ThrowErrorMessage("Argument 3"); return false; } if (JS::IsImmutableArrayBufferView(arg2.Obj())) { cx.ThrowErrorMessage("Argument 3"); return false; } } else { cx.ThrowErrorMessage("Argument 3"); return false; } uint64_t arg3; if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } uint32_t arg4; if (!ValueToPrimitive(cx, args[4], "Argument 5", &arg4)) { return false; } FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), arg3, arg4, rv))>, "Should be returning void here"); MOZ_KnownLive(self)->SetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), arg3, arg4, rv); if (rv.MaybeSetPendingException(cx, "GPURenderBundleEncoder.setBindGroup")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; break; } default: { // Using nsPrintfCString here would require including that // header. Let's not worry about it. nsAutoCString argCountStr; argCountStr.AppendPrintf("%u", args.length()); return cx.ThrowErrorMessage(argCountStr.get()); } } MOZ_CRASH("We have an always-returning default case"); return false; } static const JSJitInfo setBindGroup_methodinfo = { { (JSJitGetterOp)setBindGroup }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool pushDebugGroup(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "pushDebugGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderBundleEncoder.pushDebugGroup", 1)) { return false; } nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vPushDebugGroup(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->PushDebugGroup(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo pushDebugGroup_methodinfo = { { (JSJitGetterOp)pushDebugGroup }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool popDebugGroup(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "popDebugGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vPopDebugGroup())>, "Should be returning void here"); MOZ_KnownLive(self)->PopDebugGroup(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo popDebugGroup_methodinfo = { { (JSJitGetterOp)popDebugGroup }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool insertDebugMarker(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "insertDebugMarker", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderBundleEncoder.insertDebugMarker", 1)) { return false; } nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vInsertDebugMarker(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->InsertDebugMarker(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo insertDebugMarker_methodinfo = { { (JSJitGetterOp)insertDebugMarker }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setPipeline(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderBundleEncoder.setPipeline"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "setPipeline", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderBundleEncoder.setPipeline", 1)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPURenderPipeline"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetPipeline(MOZ_KnownLive(NonNullHelper(arg0))))>, "Should be returning void here"); MOZ_KnownLive(self)->SetPipeline(MOZ_KnownLive(NonNullHelper(arg0))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setPipeline_methodinfo = { { (JSJitGetterOp)setPipeline }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setIndexBuffer(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderBundleEncoder.setIndexBuffer"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "setIndexBuffer", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderBundleEncoder.setIndexBuffer", 2)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } GPUIndexFormat arg1; { int index; if (!binding_detail::FindEnumStringIndex(cx, args[1], binding_detail::EnumStrings::Values, "GPUIndexFormat", "argument 2", &index)) { return false; } MOZ_ASSERT(index >= 0); arg1 = static_cast(index); } uint64_t arg2; if (args.hasDefined(2)) { if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } } else { arg2 = 0ULL; } Optional arg3; if (args.hasDefined(3)) { arg3.Construct(); if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3.Value())) { return false; } } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetIndexBuffer(MOZ_KnownLive(NonNullHelper(arg0)), arg1, arg2, Constify(arg3)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetIndexBuffer(MOZ_KnownLive(NonNullHelper(arg0)), arg1, arg2, Constify(arg3)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setIndexBuffer_methodinfo = { { (JSJitGetterOp)setIndexBuffer }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setVertexBuffer(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderBundleEncoder.setVertexBuffer"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "setVertexBuffer", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderBundleEncoder.setVertexBuffer", 2)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } mozilla::webgpu::Buffer* arg1; if (args[1].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[1], arg1, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 2", "GPUBuffer"); return false; } } } else if (args[1].isNullOrUndefined()) { arg1 = nullptr; } else { cx.ThrowErrorMessage("Argument 2"); return false; } uint64_t arg2; if (args.hasDefined(2)) { if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } } else { arg2 = 0ULL; } Optional arg3; if (args.hasDefined(3)) { arg3.Construct(); if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3.Value())) { return false; } } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetVertexBuffer(arg0, MOZ_KnownLive(Constify(arg1)), arg2, Constify(arg3)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetVertexBuffer(arg0, MOZ_KnownLive(Constify(arg1)), arg2, Constify(arg3)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setVertexBuffer_methodinfo = { { (JSJitGetterOp)setVertexBuffer }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool draw(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderBundleEncoder.draw"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "draw", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderBundleEncoder.draw", 1)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } uint32_t arg1; if (args.hasDefined(1)) { if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } } else { arg1 = 1U; } uint32_t arg2; if (args.hasDefined(2)) { if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } } else { arg2 = 0U; } uint32_t arg3; if (args.hasDefined(3)) { if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } } else { arg3 = 0U; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDraw(arg0, arg1, arg2, arg3))>, "Should be returning void here"); MOZ_KnownLive(self)->Draw(arg0, arg1, arg2, arg3); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo draw_methodinfo = { { (JSJitGetterOp)draw }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool drawIndexed(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderBundleEncoder.drawIndexed"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "drawIndexed", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderBundleEncoder.drawIndexed", 1)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } uint32_t arg1; if (args.hasDefined(1)) { if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } } else { arg1 = 1U; } uint32_t arg2; if (args.hasDefined(2)) { if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } } else { arg2 = 0U; } int32_t arg3; if (args.hasDefined(3)) { if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } } else { arg3 = 0; } uint32_t arg4; if (args.hasDefined(4)) { if (!ValueToPrimitive(cx, args[4], "Argument 5", &arg4)) { return false; } } else { arg4 = 0U; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDrawIndexed(arg0, arg1, arg2, arg3, arg4))>, "Should be returning void here"); MOZ_KnownLive(self)->DrawIndexed(arg0, arg1, arg2, arg3, arg4); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo drawIndexed_methodinfo = { { (JSJitGetterOp)drawIndexed }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool drawIndirect(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderBundleEncoder.drawIndirect"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "drawIndirect", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderBundleEncoder.drawIndirect", 2)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } uint64_t arg1; if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDrawIndirect(MOZ_KnownLive(NonNullHelper(arg0)), arg1))>, "Should be returning void here"); MOZ_KnownLive(self)->DrawIndirect(MOZ_KnownLive(NonNullHelper(arg0)), arg1); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo drawIndirect_methodinfo = { { (JSJitGetterOp)drawIndirect }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool drawIndexedIndirect(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderBundleEncoder.drawIndexedIndirect"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderBundleEncoder", "drawIndexedIndirect", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderBundleEncoder.drawIndexedIndirect", 2)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } uint64_t arg1; if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDrawIndexedIndirect(MOZ_KnownLive(NonNullHelper(arg0)), arg1))>, "Should be returning void here"); MOZ_KnownLive(self)->DrawIndexedIndirect(MOZ_KnownLive(NonNullHelper(arg0)), arg1); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo drawIndexedIndirect_methodinfo = { { (JSJitGetterOp)drawIndexedIndirect }, { prototypes::id::GPURenderBundleEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::RenderBundleEncoder* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("finish", (GenericMethod), reinterpret_cast(&finish_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END, JS_FNSPEC("setBindGroup", (GenericMethod), reinterpret_cast(&setBindGroup_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("pushDebugGroup", (GenericMethod), reinterpret_cast(&pushDebugGroup_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("popDebugGroup", (GenericMethod), reinterpret_cast(&popDebugGroup_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("insertDebugMarker", (GenericMethod), reinterpret_cast(&insertDebugMarker_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("setPipeline", (GenericMethod), reinterpret_cast(&setPipeline_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("setIndexBuffer", (GenericMethod), reinterpret_cast(&setIndexBuffer_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("setVertexBuffer", (GenericMethod), reinterpret_cast(&setVertexBuffer_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("draw", (GenericMethod), reinterpret_cast(&draw_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("drawIndexed", (GenericMethod), reinterpret_cast(&drawIndexed_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("drawIndirect", (GenericMethod), reinterpret_cast(&drawIndirect_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("drawIndexedIndirect", (GenericMethod), reinterpret_cast(&drawIndexedIndirect_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, &sMethods_specs[2] }, { nullptr, nullptr } }; static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(11 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[13]; static PropertyInfo sNativeProperties_propertyInfos[13]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 13, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[12] } } }; static_assert(13 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPURenderBundleEncoder, constructors::id::GPURenderBundleEncoder, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPURenderBundleEncoder, true, 0, "GPURenderBundleEncoder", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPURenderBundleEncoderPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPURenderBundleEncoder, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPURenderBundleEncoder", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPURenderBundleEncoder, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::RenderBundleEncoder* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPURenderBundleEncoder); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPURenderBundleEncoder); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPURenderBundleEncoder", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPURenderBundleEncoder, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPURenderBundleEncoder, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPURenderBundleEncoder_Binding namespace GPURenderPassEncoder_Binding { MOZ_CAN_RUN_SCRIPT static bool setViewport(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.setViewport"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "setViewport", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.setViewport", 6)) { return false; } float arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } else if (!std::isfinite(arg0)) { cx.ThrowErrorMessage("Argument 1"); return false; } float arg1; if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } else if (!std::isfinite(arg1)) { cx.ThrowErrorMessage("Argument 2"); return false; } float arg2; if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } else if (!std::isfinite(arg2)) { cx.ThrowErrorMessage("Argument 3"); return false; } float arg3; if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } else if (!std::isfinite(arg3)) { cx.ThrowErrorMessage("Argument 4"); return false; } float arg4; if (!ValueToPrimitive(cx, args[4], "Argument 5", &arg4)) { return false; } else if (!std::isfinite(arg4)) { cx.ThrowErrorMessage("Argument 5"); return false; } float arg5; if (!ValueToPrimitive(cx, args[5], "Argument 6", &arg5)) { return false; } else if (!std::isfinite(arg5)) { cx.ThrowErrorMessage("Argument 6"); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetViewport(arg0, arg1, arg2, arg3, arg4, arg5))>, "Should be returning void here"); MOZ_KnownLive(self)->SetViewport(arg0, arg1, arg2, arg3, arg4, arg5); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setViewport_methodinfo = { { (JSJitGetterOp)setViewport }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setScissorRect(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.setScissorRect"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "setScissorRect", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.setScissorRect", 4)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } uint32_t arg1; if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } uint32_t arg2; if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } uint32_t arg3; if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetScissorRect(arg0, arg1, arg2, arg3))>, "Should be returning void here"); MOZ_KnownLive(self)->SetScissorRect(arg0, arg1, arg2, arg3); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setScissorRect_methodinfo = { { (JSJitGetterOp)setScissorRect }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setBlendConstant(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.setBlendConstant"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "setBlendConstant", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.setBlendConstant", 1)) { return false; } DoubleSequenceOrGPUColorDict arg0; if (!arg0.Init(cx, args[0], "Argument 1", false)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetBlendConstant(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetBlendConstant(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setBlendConstant_methodinfo = { { (JSJitGetterOp)setBlendConstant }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setStencilReference(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.setStencilReference"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "setStencilReference", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.setStencilReference", 1)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetStencilReference(arg0))>, "Should be returning void here"); MOZ_KnownLive(self)->SetStencilReference(arg0); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setStencilReference_methodinfo = { { (JSJitGetterOp)setStencilReference }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool beginOcclusionQuery(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.beginOcclusionQuery"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "beginOcclusionQuery", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.beginOcclusionQuery", 1)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vBeginOcclusionQuery(arg0))>, "Should be returning void here"); MOZ_KnownLive(self)->BeginOcclusionQuery(arg0); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo beginOcclusionQuery_methodinfo = { { (JSJitGetterOp)beginOcclusionQuery }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool endOcclusionQuery(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "endOcclusionQuery", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vEndOcclusionQuery())>, "Should be returning void here"); MOZ_KnownLive(self)->EndOcclusionQuery(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo endOcclusionQuery_methodinfo = { { (JSJitGetterOp)endOcclusionQuery }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool executeBundles(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.executeBundles"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "executeBundles", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.executeBundles", 1)) { return false; } binding_detail::AutoSequence> arg0; if (args[0].isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(args[0], JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("Argument 1", "sequence"); return false; } binding_detail::AutoSequence> &arr = arg0; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } OwningNonNull* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } OwningNonNull& slot = *slotPtr; if (temp.isObject()) { static_assert(IsRefcounted::value, "We can only store refcounted classes."); { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(&temp, slot, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Element of argument 1", "GPURenderBundle"); return false; } } } else { cx.ThrowErrorMessage("Element of argument 1"); return false; } } } else { cx.ThrowErrorMessage("Argument 1", "sequence"); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vExecuteBundles(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->ExecuteBundles(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo executeBundles_methodinfo = { { (JSJitGetterOp)executeBundles }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool end(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "end", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vEnd())>, "Should be returning void here"); MOZ_KnownLive(self)->End(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo end_methodinfo = { { (JSJitGetterOp)end }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setBindGroup(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.setBindGroup"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "setBindGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); unsigned argcount = std::min(args.length(), 5u); switch (argcount) { case 2: { [[fallthrough]]; } case 3: { uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } mozilla::webgpu::BindGroup* arg1; if (args[1].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[1], arg1, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 2", "GPUBindGroup"); return false; } } } else if (args[1].isNullOrUndefined()) { arg1 = nullptr; } else { cx.ThrowErrorMessage("Argument 2"); return false; } binding_detail::AutoSequence arg2; if (args.hasDefined(2)) { if (args[2].isObject()) { JS::ForOfIterator iter(cx); if (!iter.init(args[2], JS::ForOfIterator::AllowNonIterable)) { return false; } if (!iter.valueIsIterable()) { cx.ThrowErrorMessage("Argument 3", "sequence"); return false; } binding_detail::AutoSequence &arr = arg2; if (mozilla::Maybe sizeHint = iter.sizeHint()) { if (!arr.SetCapacity(*sizeHint, mozilla::fallible)) { JS_ReportOutOfMemory(cx); return false; } } JS::Rooted temp(cx); while (true) { bool done; if (!iter.next(&temp, &done)) { return false; } if (done) { break; } uint32_t* slotPtr = arr.AppendElement(mozilla::fallible); if (!slotPtr) { JS_ReportOutOfMemory(cx); return false; } uint32_t& slot = *slotPtr; if (!ValueToPrimitive(cx, temp, "Element of argument 3", &slot)) { return false; } } } else { cx.ThrowErrorMessage("Argument 3", "sequence"); return false; } } else { /* arg2 array is already empty; nothing to do */ } FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), rv))>, "Should be returning void here"); MOZ_KnownLive(self)->SetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), rv); if (rv.MaybeSetPendingException(cx, "GPURenderPassEncoder.setBindGroup")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; break; } case 5: { uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } mozilla::webgpu::BindGroup* arg1; if (args[1].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[1], arg1, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 2", "GPUBindGroup"); return false; } } } else if (args[1].isNullOrUndefined()) { arg1 = nullptr; } else { cx.ThrowErrorMessage("Argument 2"); return false; } RootedSpiderMonkeyInterface arg2(cx); if (args[2].isObject()) { if (!arg2.Init(&args[2].toObject())) { cx.ThrowErrorMessage("Argument 3", "Uint32Array"); return false; } if (JS::IsLargeArrayBufferView(arg2.Obj())) { cx.ThrowErrorMessage("Argument 3"); return false; } if (JS::IsResizableArrayBufferView(arg2.Obj())) { cx.ThrowErrorMessage("Argument 3"); return false; } if (JS::IsImmutableArrayBufferView(arg2.Obj())) { cx.ThrowErrorMessage("Argument 3"); return false; } } else { cx.ThrowErrorMessage("Argument 3"); return false; } uint64_t arg3; if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } uint32_t arg4; if (!ValueToPrimitive(cx, args[4], "Argument 5", &arg4)) { return false; } FastErrorResult rv; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), arg3, arg4, rv))>, "Should be returning void here"); MOZ_KnownLive(self)->SetBindGroup(arg0, MOZ_KnownLive(Constify(arg1)), Constify(arg2), arg3, arg4, rv); if (rv.MaybeSetPendingException(cx, "GPURenderPassEncoder.setBindGroup")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; break; } default: { // Using nsPrintfCString here would require including that // header. Let's not worry about it. nsAutoCString argCountStr; argCountStr.AppendPrintf("%u", args.length()); return cx.ThrowErrorMessage(argCountStr.get()); } } MOZ_CRASH("We have an always-returning default case"); return false; } static const JSJitInfo setBindGroup_methodinfo = { { (JSJitGetterOp)setBindGroup }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool pushDebugGroup(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "pushDebugGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.pushDebugGroup", 1)) { return false; } nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vPushDebugGroup(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->PushDebugGroup(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo pushDebugGroup_methodinfo = { { (JSJitGetterOp)pushDebugGroup }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool popDebugGroup(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "popDebugGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vPopDebugGroup())>, "Should be returning void here"); MOZ_KnownLive(self)->PopDebugGroup(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo popDebugGroup_methodinfo = { { (JSJitGetterOp)popDebugGroup }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool insertDebugMarker(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "insertDebugMarker", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.insertDebugMarker", 1)) { return false; } nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vInsertDebugMarker(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->InsertDebugMarker(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo insertDebugMarker_methodinfo = { { (JSJitGetterOp)insertDebugMarker }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setPipeline(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.setPipeline"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "setPipeline", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.setPipeline", 1)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPURenderPipeline"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetPipeline(MOZ_KnownLive(NonNullHelper(arg0))))>, "Should be returning void here"); MOZ_KnownLive(self)->SetPipeline(MOZ_KnownLive(NonNullHelper(arg0))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setPipeline_methodinfo = { { (JSJitGetterOp)setPipeline }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setIndexBuffer(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.setIndexBuffer"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "setIndexBuffer", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.setIndexBuffer", 2)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } GPUIndexFormat arg1; { int index; if (!binding_detail::FindEnumStringIndex(cx, args[1], binding_detail::EnumStrings::Values, "GPUIndexFormat", "argument 2", &index)) { return false; } MOZ_ASSERT(index >= 0); arg1 = static_cast(index); } uint64_t arg2; if (args.hasDefined(2)) { if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } } else { arg2 = 0ULL; } Optional arg3; if (args.hasDefined(3)) { arg3.Construct(); if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3.Value())) { return false; } } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetIndexBuffer(MOZ_KnownLive(NonNullHelper(arg0)), arg1, arg2, Constify(arg3)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetIndexBuffer(MOZ_KnownLive(NonNullHelper(arg0)), arg1, arg2, Constify(arg3)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setIndexBuffer_methodinfo = { { (JSJitGetterOp)setIndexBuffer }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool setVertexBuffer(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.setVertexBuffer"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "setVertexBuffer", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.setVertexBuffer", 2)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } mozilla::webgpu::Buffer* arg1; if (args[1].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[1], arg1, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 2", "GPUBuffer"); return false; } } } else if (args[1].isNullOrUndefined()) { arg1 = nullptr; } else { cx.ThrowErrorMessage("Argument 2"); return false; } uint64_t arg2; if (args.hasDefined(2)) { if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } } else { arg2 = 0ULL; } Optional arg3; if (args.hasDefined(3)) { arg3.Construct(); if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3.Value())) { return false; } } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetVertexBuffer(arg0, MOZ_KnownLive(Constify(arg1)), arg2, Constify(arg3)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetVertexBuffer(arg0, MOZ_KnownLive(Constify(arg1)), arg2, Constify(arg3)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo setVertexBuffer_methodinfo = { { (JSJitGetterOp)setVertexBuffer }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool draw(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.draw"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "draw", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.draw", 1)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } uint32_t arg1; if (args.hasDefined(1)) { if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } } else { arg1 = 1U; } uint32_t arg2; if (args.hasDefined(2)) { if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } } else { arg2 = 0U; } uint32_t arg3; if (args.hasDefined(3)) { if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } } else { arg3 = 0U; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDraw(arg0, arg1, arg2, arg3))>, "Should be returning void here"); MOZ_KnownLive(self)->Draw(arg0, arg1, arg2, arg3); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo draw_methodinfo = { { (JSJitGetterOp)draw }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool drawIndexed(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.drawIndexed"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "drawIndexed", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.drawIndexed", 1)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } uint32_t arg1; if (args.hasDefined(1)) { if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } } else { arg1 = 1U; } uint32_t arg2; if (args.hasDefined(2)) { if (!ValueToPrimitive(cx, args[2], "Argument 3", &arg2)) { return false; } } else { arg2 = 0U; } int32_t arg3; if (args.hasDefined(3)) { if (!ValueToPrimitive(cx, args[3], "Argument 4", &arg3)) { return false; } } else { arg3 = 0; } uint32_t arg4; if (args.hasDefined(4)) { if (!ValueToPrimitive(cx, args[4], "Argument 5", &arg4)) { return false; } } else { arg4 = 0U; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDrawIndexed(arg0, arg1, arg2, arg3, arg4))>, "Should be returning void here"); MOZ_KnownLive(self)->DrawIndexed(arg0, arg1, arg2, arg3, arg4); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo drawIndexed_methodinfo = { { (JSJitGetterOp)drawIndexed }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool drawIndirect(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.drawIndirect"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "drawIndirect", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.drawIndirect", 2)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } uint64_t arg1; if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDrawIndirect(MOZ_KnownLive(NonNullHelper(arg0)), arg1))>, "Should be returning void here"); MOZ_KnownLive(self)->DrawIndirect(MOZ_KnownLive(NonNullHelper(arg0)), arg1); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo drawIndirect_methodinfo = { { (JSJitGetterOp)drawIndirect }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool drawIndexedIndirect(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPURenderPassEncoder.drawIndexedIndirect"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPassEncoder", "drawIndexedIndirect", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPassEncoder.drawIndexedIndirect", 2)) { return false; } NonNull arg0; if (args[0].isObject()) { { // Our JSContext should be in the right global to do unwrapping in. nsresult rv = UnwrapObject(args[0], arg0, cx); if (NS_FAILED(rv)) { cx.ThrowErrorMessage("Argument 1", "GPUBuffer"); return false; } } } else { cx.ThrowErrorMessage("Argument 1"); return false; } uint64_t arg1; if (!ValueToPrimitive(cx, args[1], "Argument 2", &arg1)) { return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDrawIndexedIndirect(MOZ_KnownLive(NonNullHelper(arg0)), arg1))>, "Should be returning void here"); MOZ_KnownLive(self)->DrawIndexedIndirect(MOZ_KnownLive(NonNullHelper(arg0)), arg1); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo drawIndexedIndirect_methodinfo = { { (JSJitGetterOp)drawIndexedIndirect }, { prototypes::id::GPURenderPassEncoder }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::RenderPassEncoder* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("setViewport", (GenericMethod), reinterpret_cast(&setViewport_methodinfo), 6, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("setScissorRect", (GenericMethod), reinterpret_cast(&setScissorRect_methodinfo), 4, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("setBlendConstant", (GenericMethod), reinterpret_cast(&setBlendConstant_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("setStencilReference", (GenericMethod), reinterpret_cast(&setStencilReference_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("beginOcclusionQuery", (GenericMethod), reinterpret_cast(&beginOcclusionQuery_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("endOcclusionQuery", (GenericMethod), reinterpret_cast(&endOcclusionQuery_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("executeBundles", (GenericMethod), reinterpret_cast(&executeBundles_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("end", (GenericMethod), reinterpret_cast(&end_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END, JS_FNSPEC("setBindGroup", (GenericMethod), reinterpret_cast(&setBindGroup_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("pushDebugGroup", (GenericMethod), reinterpret_cast(&pushDebugGroup_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("popDebugGroup", (GenericMethod), reinterpret_cast(&popDebugGroup_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("insertDebugMarker", (GenericMethod), reinterpret_cast(&insertDebugMarker_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("setPipeline", (GenericMethod), reinterpret_cast(&setPipeline_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("setIndexBuffer", (GenericMethod), reinterpret_cast(&setIndexBuffer_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("setVertexBuffer", (GenericMethod), reinterpret_cast(&setVertexBuffer_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("draw", (GenericMethod), reinterpret_cast(&draw_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("drawIndexed", (GenericMethod), reinterpret_cast(&drawIndexed_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("drawIndirect", (GenericMethod), reinterpret_cast(&drawIndirect_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("drawIndexedIndirect", (GenericMethod), reinterpret_cast(&drawIndexedIndirect_methodinfo), 2, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, &sMethods_specs[9] }, { nullptr, nullptr } }; static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(11 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[20]; static PropertyInfo sNativeProperties_propertyInfos[20]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 20, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[19] } } }; static_assert(20 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPURenderPassEncoder, constructors::id::GPURenderPassEncoder, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPURenderPassEncoder, true, 0, "GPURenderPassEncoder", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPURenderPassEncoderPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPURenderPassEncoder, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPURenderPassEncoder", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPURenderPassEncoder, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::RenderPassEncoder* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPURenderPassEncoder); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPURenderPassEncoder); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPURenderPassEncoder", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPURenderPassEncoder, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPURenderPassEncoder, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPURenderPassEncoder_Binding namespace GPURenderPipeline_Binding { MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPipeline", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPipeline", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPURenderPipeline }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPURenderPipeline }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool getBindGroupLayout(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPURenderPipeline", "getBindGroupLayout", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); if (!args.requireAtLeast(cx, "GPURenderPipeline.getBindGroupLayout", 1)) { return false; } uint32_t arg0; if (!ValueToPrimitive(cx, args[0], "Argument 1", &arg0)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->GetBindGroupLayout(arg0))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo getBindGroupLayout_methodinfo = { { (JSJitGetterOp)getBindGroupLayout }, { prototypes::id::GPURenderPipeline }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::RenderPipeline* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("getBindGroupLayout", (GenericMethod), reinterpret_cast(&getBindGroupLayout_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const Prefable sMethods[] = { { nullptr, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[2]; static PropertyInfo sNativeProperties_propertyInfos[2]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 2, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[1] } } }; static_assert(2 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPURenderPipeline, constructors::id::GPURenderPipeline, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPURenderPipeline, true, 0, "GPURenderPipeline", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPURenderPipelinePrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPURenderPipeline, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPURenderPipeline", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPURenderPipeline, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::RenderPipeline* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPURenderPipeline); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPURenderPipeline); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPURenderPipeline", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPURenderPipeline, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPURenderPipeline, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPURenderPipeline_Binding namespace GPUSampler_Binding { MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSampler", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSampler", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUSampler }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUSampler }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::Sampler* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUSampler, constructors::id::GPUSampler, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUSampler, true, 0, "GPUSampler", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUSamplerPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUSampler, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUSampler", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUSampler, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::Sampler* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUSampler); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUSampler); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUSampler", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUSampler, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUSampler, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUSampler_Binding namespace GPUShaderModule_Binding { MOZ_CAN_RUN_SCRIPT static bool getCompilationInfo(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUShaderModule", "getCompilationInfo", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); FastErrorResult rv; auto result(StrongOrRawPtr(MOZ_KnownLive(self)->GetCompilationInfo(rv))); if (rv.MaybeSetPendingException(cx, "GPUShaderModule.getCompilationInfo")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool getCompilationInfo_promiseWrapper(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { bool ok = getCompilationInfo(cx, obj, void_self, args); if (ok) { return true; } return ConvertExceptionToPromise(cx, args.rval()); } static const JSJitInfo getCompilationInfo_methodinfo = { { (JSJitGetterOp)getCompilationInfo_promiseWrapper }, { prototypes::id::GPUShaderModule }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUShaderModule", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUShaderModule", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUShaderModule }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUShaderModule }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::ShaderModule* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("getCompilationInfo", (GenericMethod), reinterpret_cast(&getCompilationInfo_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[2]; static PropertyInfo sNativeProperties_propertyInfos[2]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 2, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[1] } } }; static_assert(2 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUShaderModule, constructors::id::GPUShaderModule, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUShaderModule, true, 0, "GPUShaderModule", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUShaderModulePrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUShaderModule, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUShaderModule", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUShaderModule, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::ShaderModule* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUShaderModule); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUShaderModule); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUShaderModule", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUShaderModule, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUShaderModule, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUShaderModule_Binding namespace GPUShaderStage_Binding { MOZ_GLOBINIT static const ConstantSpec sConstants_specs[] = { { "VERTEX", JS::NumberValue(1U) }, { "FRAGMENT", JS::NumberValue(2U) }, { "COMPUTE", JS::NumberValue(4U) }, { 0, JS::UndefinedValue() } }; static const PrefableDisablers sConstants_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sConstants[] = { { &sConstants_disablers0, &sConstants_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(3 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[3]; static PropertyInfo sNativeProperties_propertyInfos[3]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, true, 0 /* sConstants */, -1, 3, sNativeProperties_sortedPropertyIndices, { { sConstants, &sNativeProperties_propertyInfos[0] } } }; static_assert(3 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::_ID_Count, constructors::id::GPUShaderStage, &DefaultXrayExpandoObjectClass }; static const DOMIfaceAndProtoJSClass sNamespaceObjectClass = { { "GPUShaderStage", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS, JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eNamespace, prototypes::id::_ID_Count, 0, &sNativePropertyHooks, // This isn't strictly following the spec (see // https://console.spec.whatwg.org/#ref-for-dfn-namespace-object), // but should be ok for Xrays. JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Rooted constructorProto(aCx, JS::GetRealmObjectPrototype(aCx)); if (!constructorProto) { return; } JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUShaderStage); dom::CreateNamespaceObject(aCx, aGlobal, constructorProto, sNamespaceObjectClass, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUShaderStage", ShouldExpose(aCx, aGlobal, aDefineOnGlobal)); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUShaderStage, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUShaderStage_Binding namespace GPUSupportedFeatures_Binding { namespace SetlikeHelpers { void Clear(mozilla::webgpu::SupportedFeatures* self, ErrorResult& aRv) { MOZ_ASSERT(self); AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because // all we want is to wrap into _some_ scope and then unwrap to find // the reflector, and wrapping has no side-effects. JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible); if (!scope) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } JSAutoRealm tempRealm(cx, scope); JS::Rooted v(cx); if(!ToJSValue(cx, self, &v)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } // This is a reflector, but due to trying to name things // similarly across method generators, it's called obj here. JS::Rooted obj(cx); obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false); JSAutoRealm reflectorRealm(cx, obj); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } if (created) { PreserveWrapper(self); } if (!JS::SetClear(cx, backingObj)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } } bool Delete(mozilla::webgpu::SupportedFeatures* self, const nsAString& aKey, ErrorResult& aRv) { MOZ_ASSERT(self); AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because // all we want is to wrap into _some_ scope and then unwrap to find // the reflector, and wrapping has no side-effects. JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible); if (!scope) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } JSAutoRealm tempRealm(cx, scope); JS::Rooted v(cx); if(!ToJSValue(cx, self, &v)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } // This is a reflector, but due to trying to name things // similarly across method generators, it's called obj here. JS::Rooted obj(cx); obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false); JSAutoRealm reflectorRealm(cx, obj); JS::RootedVector argv(cx); if (!argv.resize(1)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } do { if (!xpc::NonVoidStringToJsval(cx, aKey, argv[0])) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } break; } while (false); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } if (created) { PreserveWrapper(self); } bool retVal; if (!JS::SetDelete(cx, backingObj, argv[0], &retVal)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } return retVal; } bool Has(mozilla::webgpu::SupportedFeatures* self, const nsAString& aKey, ErrorResult& aRv) { MOZ_ASSERT(self); AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because // all we want is to wrap into _some_ scope and then unwrap to find // the reflector, and wrapping has no side-effects. JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible); if (!scope) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } JSAutoRealm tempRealm(cx, scope); JS::Rooted v(cx); if(!ToJSValue(cx, self, &v)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } // This is a reflector, but due to trying to name things // similarly across method generators, it's called obj here. JS::Rooted obj(cx); obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false); JSAutoRealm reflectorRealm(cx, obj); JS::RootedVector argv(cx); if (!argv.resize(1)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } do { if (!xpc::NonVoidStringToJsval(cx, aKey, argv[0])) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } break; } while (false); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } if (created) { PreserveWrapper(self); } bool retVal; if (!JS::SetHas(cx, backingObj, argv[0], &retVal)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } return retVal; } void Add(mozilla::webgpu::SupportedFeatures* self, const nsAString& aKey, ErrorResult& aRv) { MOZ_ASSERT(self); AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because // all we want is to wrap into _some_ scope and then unwrap to find // the reflector, and wrapping has no side-effects. JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible); if (!scope) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } JSAutoRealm tempRealm(cx, scope); JS::Rooted v(cx); if(!ToJSValue(cx, self, &v)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } // This is a reflector, but due to trying to name things // similarly across method generators, it's called obj here. JS::Rooted obj(cx); obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false); JSAutoRealm reflectorRealm(cx, obj); JS::RootedVector argv(cx); if (!argv.resize(1)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } do { if (!xpc::NonVoidStringToJsval(cx, aKey, argv[0])) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } break; } while (false); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } if (created) { PreserveWrapper(self); } if (!JS::SetAdd(cx, backingObj, argv[0])) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } } } // namespace SetlikeHelpers MOZ_CAN_RUN_SCRIPT static bool get_size(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedFeatures", "size", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } uint32_t result = JS::SetSize(cx, backingObj); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo size_getterinfo = { { get_size }, { prototypes::id::GPUSupportedFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool entries(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedFeatures", "entries", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change // after bug 1023984 is fixed. if (xpc::WrapperFactory::IsXrayWrapper(obj)) { JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported."); return false; } JS::Rooted result(cx); JS::Rooted v(cx); if (!JS::SetEntries(cx, backingObj, &v)) { return false; } result = &v.toObject(); JS::ExposeObjectToActiveJS(result); args.rval().setObject(*result); if (!MaybeWrapObjectValue(cx, args.rval())) { return false; } return true; } static const JSJitInfo::ArgType entries_methodinfo_argTypes[] = { JSJitInfo::ArgTypeListEnd }; static const JSTypedMethodJitInfo entries_methodinfo = { { { (JSJitGetterOp)entries }, { prototypes::id::GPUSupportedFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ true, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }, entries_methodinfo_argTypes }; MOZ_CAN_RUN_SCRIPT static bool keys(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedFeatures", "keys", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change // after bug 1023984 is fixed. if (xpc::WrapperFactory::IsXrayWrapper(obj)) { JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported."); return false; } JS::Rooted result(cx); JS::Rooted v(cx); if (!JS::SetKeys(cx, backingObj, &v)) { return false; } result = &v.toObject(); JS::ExposeObjectToActiveJS(result); args.rval().setObject(*result); if (!MaybeWrapObjectValue(cx, args.rval())) { return false; } return true; } static const JSJitInfo::ArgType keys_methodinfo_argTypes[] = { JSJitInfo::ArgTypeListEnd }; static const JSTypedMethodJitInfo keys_methodinfo = { { { (JSJitGetterOp)keys }, { prototypes::id::GPUSupportedFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ true, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }, keys_methodinfo_argTypes }; MOZ_CAN_RUN_SCRIPT static bool values(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedFeatures", "values", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change // after bug 1023984 is fixed. if (xpc::WrapperFactory::IsXrayWrapper(obj)) { JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported."); return false; } JS::Rooted result(cx); JS::Rooted v(cx); if (!JS::SetValues(cx, backingObj, &v)) { return false; } result = &v.toObject(); JS::ExposeObjectToActiveJS(result); args.rval().setObject(*result); if (!MaybeWrapObjectValue(cx, args.rval())) { return false; } return true; } static const JSJitInfo::ArgType values_methodinfo_argTypes[] = { JSJitInfo::ArgTypeListEnd }; static const JSTypedMethodJitInfo values_methodinfo = { { { (JSJitGetterOp)values }, { prototypes::id::GPUSupportedFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ true, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }, values_methodinfo_argTypes }; MOZ_CAN_RUN_SCRIPT static bool forEach(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUSupportedFeatures.forEach"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedFeatures", "forEach", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); JS::Rooted arg0(cx); if (args.get(0).isObject()) { arg0 = &args.get(0).toObject(); } else { cx.ThrowErrorMessage("Argument 1"); return false; } JS::Rooted arg1(cx); if (args.hasDefined(1)) { arg1 = args.get(1); } else { arg1 = JS::UndefinedValue(); } JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } // Create a wrapper function. JSFunction* func = js::NewFunctionWithReserved(cx, ForEachHandler, 3, 0, nullptr); if (!func) { return false; } JS::Rooted funcObj(cx, JS_GetFunctionObject(func)); JS::Rooted funcVal(cx, JS::ObjectValue(*funcObj)); js::SetFunctionNativeReserved(funcObj, FOREACH_CALLBACK_SLOT, JS::ObjectValue(*arg0)); js::SetFunctionNativeReserved(funcObj, FOREACH_MAPLIKEORSETLIKEOBJ_SLOT, JS::ObjectValue(*obj)); if (!JS::SetForEach(cx, backingObj, funcVal, arg1)) { return false; } args.rval().setUndefined(); return true; } static const JSJitInfo forEach_methodinfo = { { (JSJitGetterOp)forEach }, { prototypes::id::GPUSupportedFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool has(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedFeatures", "has", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args.get(0), eStringify, eStringify, arg0)) { return false; } JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } JS::Rooted arg0Val(cx); if (!ToJSValue(cx, arg0, &arg0Val)) { return false; } bool result; if (!JS::SetHas(cx, backingObj, arg0Val, &result)) { return false; } args.rval().setBoolean(result); return true; } static const JSJitInfo::ArgType has_methodinfo_argTypes[] = { JSJitInfo::String, JSJitInfo::ArgTypeListEnd }; static const JSTypedMethodJitInfo has_methodinfo = { { { (JSJitGetterOp)has }, { prototypes::id::GPUSupportedFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasDOMSets, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_BOOLEAN, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ true, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }, has_methodinfo_argTypes }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::SupportedFeatures* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("entries", (GenericMethod), reinterpret_cast(&entries_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("keys", (GenericMethod), reinterpret_cast(&keys_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("values", (GenericMethod), reinterpret_cast(&values_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("forEach", (GenericMethod), reinterpret_cast(&forEach_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("has", (GenericMethod), reinterpret_cast(&has_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const Prefable sMethods[] = { { nullptr, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(5 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("size", JSPROP_ENUMERATE, GenericGetter, &size_getterinfo, nullptr, nullptr), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[6]; static PropertyInfo sNativeProperties_propertyInfos[6]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, 2, 6, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[5] } } }; static_assert(2 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.iteratorAliasMethodIndex) - 1), "We have an iterator alias index that is oversized"); static_assert(6 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); // This may allocate too many slots, because we only really need // slots for our non-interface-typed members that we cache. But // allocating slots only for those would make the slot index // computations much more complicated, so let's do this the simple // way for now. DEFINE_XRAY_EXPANDO_CLASS_WITH_OPS(static, sXrayExpandoObjectClass, 1, &xpc::XrayExpandoObjectClassOps); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUSupportedFeatures, constructors::id::GPUSupportedFeatures, &sXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUSupportedFeatures, true, 0, "GPUSupportedFeatures", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUSupportedFeaturesPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUSupportedFeatures, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUSupportedFeatures", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUSupportedFeatures, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(2 >= 2, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::SupportedFeatures* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUSupportedFeatures); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUSupportedFeatures); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUSupportedFeatures", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); JS::AssertObjectIsNotGray(*protoCache); JS::Handle proto = JS::Handle::fromMarkedLocation(protoCache->unsafeAddress()); if (!proto) { *protoCache = nullptr; if (interfaceCache) { *interfaceCache = nullptr; } return; } // Set up aliases on the interface prototype object we just created. JS::Rooted aliasedVal(aCx); if (!JS_GetProperty(aCx, proto, "values", &aliasedVal)) { *protoCache = nullptr; if (interfaceCache) { *interfaceCache = nullptr; } return; } JS::Rooted iteratorId(aCx, JS::GetWellKnownSymbolKey(aCx, JS::SymbolCode::iterator)); if (!JS_DefinePropertyById(aCx, proto, iteratorId, aliasedVal, 0)) { *protoCache = nullptr; if (interfaceCache) { *interfaceCache = nullptr; } return; } } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUSupportedFeatures, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUSupportedFeatures, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUSupportedFeatures_Binding namespace GPUSupportedLimits_Binding { MOZ_CAN_RUN_SCRIPT static bool get_maxTextureDimension1D(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxTextureDimension1D", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxTextureDimension1D()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxTextureDimension1D_getterinfo = { { get_maxTextureDimension1D }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxTextureDimension2D(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxTextureDimension2D", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxTextureDimension2D()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxTextureDimension2D_getterinfo = { { get_maxTextureDimension2D }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxTextureDimension3D(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxTextureDimension3D", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxTextureDimension3D()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxTextureDimension3D_getterinfo = { { get_maxTextureDimension3D }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxTextureArrayLayers(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxTextureArrayLayers", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxTextureArrayLayers()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxTextureArrayLayers_getterinfo = { { get_maxTextureArrayLayers }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxBindGroups(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxBindGroups", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxBindGroups()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxBindGroups_getterinfo = { { get_maxBindGroups }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxBindGroupsPlusVertexBuffers(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxBindGroupsPlusVertexBuffers", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxBindGroupsPlusVertexBuffers()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxBindGroupsPlusVertexBuffers_getterinfo = { { get_maxBindGroupsPlusVertexBuffers }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxBindingsPerBindGroup(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxBindingsPerBindGroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxBindingsPerBindGroup()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxBindingsPerBindGroup_getterinfo = { { get_maxBindingsPerBindGroup }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxDynamicUniformBuffersPerPipelineLayout(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxDynamicUniformBuffersPerPipelineLayout", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxDynamicUniformBuffersPerPipelineLayout()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxDynamicUniformBuffersPerPipelineLayout_getterinfo = { { get_maxDynamicUniformBuffersPerPipelineLayout }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxDynamicStorageBuffersPerPipelineLayout(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxDynamicStorageBuffersPerPipelineLayout", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxDynamicStorageBuffersPerPipelineLayout()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxDynamicStorageBuffersPerPipelineLayout_getterinfo = { { get_maxDynamicStorageBuffersPerPipelineLayout }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxSampledTexturesPerShaderStage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxSampledTexturesPerShaderStage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxSampledTexturesPerShaderStage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxSampledTexturesPerShaderStage_getterinfo = { { get_maxSampledTexturesPerShaderStage }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxSamplersPerShaderStage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxSamplersPerShaderStage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxSamplersPerShaderStage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxSamplersPerShaderStage_getterinfo = { { get_maxSamplersPerShaderStage }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxStorageBuffersInVertexStage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxStorageBuffersInVertexStage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxStorageBuffersInVertexStage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxStorageBuffersInVertexStage_getterinfo = { { get_maxStorageBuffersInVertexStage }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxStorageBuffersInFragmentStage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxStorageBuffersInFragmentStage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxStorageBuffersInFragmentStage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxStorageBuffersInFragmentStage_getterinfo = { { get_maxStorageBuffersInFragmentStage }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxStorageBuffersPerShaderStage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxStorageBuffersPerShaderStage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxStorageBuffersPerShaderStage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxStorageBuffersPerShaderStage_getterinfo = { { get_maxStorageBuffersPerShaderStage }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxStorageTexturesInVertexStage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxStorageTexturesInVertexStage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxStorageTexturesInVertexStage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxStorageTexturesInVertexStage_getterinfo = { { get_maxStorageTexturesInVertexStage }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxStorageTexturesInFragmentStage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxStorageTexturesInFragmentStage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxStorageTexturesInFragmentStage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxStorageTexturesInFragmentStage_getterinfo = { { get_maxStorageTexturesInFragmentStage }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxStorageTexturesPerShaderStage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxStorageTexturesPerShaderStage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxStorageTexturesPerShaderStage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxStorageTexturesPerShaderStage_getterinfo = { { get_maxStorageTexturesPerShaderStage }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxUniformBuffersPerShaderStage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxUniformBuffersPerShaderStage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxUniformBuffersPerShaderStage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxUniformBuffersPerShaderStage_getterinfo = { { get_maxUniformBuffersPerShaderStage }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxUniformBufferBindingSize(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxUniformBufferBindingSize", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint64_t result(MOZ_KnownLive(self)->MaxUniformBufferBindingSize()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().set(JS::NumberValue(double(result))); return true; } static const JSJitInfo maxUniformBufferBindingSize_getterinfo = { { get_maxUniformBufferBindingSize }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxStorageBufferBindingSize(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxStorageBufferBindingSize", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint64_t result(MOZ_KnownLive(self)->MaxStorageBufferBindingSize()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().set(JS::NumberValue(double(result))); return true; } static const JSJitInfo maxStorageBufferBindingSize_getterinfo = { { get_maxStorageBufferBindingSize }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_minUniformBufferOffsetAlignment(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "minUniformBufferOffsetAlignment", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MinUniformBufferOffsetAlignment()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo minUniformBufferOffsetAlignment_getterinfo = { { get_minUniformBufferOffsetAlignment }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_minStorageBufferOffsetAlignment(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "minStorageBufferOffsetAlignment", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MinStorageBufferOffsetAlignment()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo minStorageBufferOffsetAlignment_getterinfo = { { get_minStorageBufferOffsetAlignment }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxVertexBuffers(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxVertexBuffers", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxVertexBuffers()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxVertexBuffers_getterinfo = { { get_maxVertexBuffers }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxBufferSize(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxBufferSize", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint64_t result(MOZ_KnownLive(self)->MaxBufferSize()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().set(JS::NumberValue(double(result))); return true; } static const JSJitInfo maxBufferSize_getterinfo = { { get_maxBufferSize }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxVertexAttributes(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxVertexAttributes", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxVertexAttributes()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxVertexAttributes_getterinfo = { { get_maxVertexAttributes }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxVertexBufferArrayStride(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxVertexBufferArrayStride", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxVertexBufferArrayStride()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxVertexBufferArrayStride_getterinfo = { { get_maxVertexBufferArrayStride }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxInterStageShaderVariables(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxInterStageShaderVariables", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxInterStageShaderVariables()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxInterStageShaderVariables_getterinfo = { { get_maxInterStageShaderVariables }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxColorAttachments(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxColorAttachments", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxColorAttachments()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxColorAttachments_getterinfo = { { get_maxColorAttachments }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxColorAttachmentBytesPerSample(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxColorAttachmentBytesPerSample", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxColorAttachmentBytesPerSample()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxColorAttachmentBytesPerSample_getterinfo = { { get_maxColorAttachmentBytesPerSample }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxComputeWorkgroupStorageSize(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxComputeWorkgroupStorageSize", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxComputeWorkgroupStorageSize()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxComputeWorkgroupStorageSize_getterinfo = { { get_maxComputeWorkgroupStorageSize }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxComputeInvocationsPerWorkgroup(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxComputeInvocationsPerWorkgroup", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxComputeInvocationsPerWorkgroup()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxComputeInvocationsPerWorkgroup_getterinfo = { { get_maxComputeInvocationsPerWorkgroup }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxComputeWorkgroupSizeX(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxComputeWorkgroupSizeX", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxComputeWorkgroupSizeX()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxComputeWorkgroupSizeX_getterinfo = { { get_maxComputeWorkgroupSizeX }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxComputeWorkgroupSizeY(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxComputeWorkgroupSizeY", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxComputeWorkgroupSizeY()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxComputeWorkgroupSizeY_getterinfo = { { get_maxComputeWorkgroupSizeY }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxComputeWorkgroupSizeZ(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxComputeWorkgroupSizeZ", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxComputeWorkgroupSizeZ()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxComputeWorkgroupSizeZ_getterinfo = { { get_maxComputeWorkgroupSizeZ }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_maxComputeWorkgroupsPerDimension(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUSupportedLimits", "maxComputeWorkgroupsPerDimension", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MaxComputeWorkgroupsPerDimension()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo maxComputeWorkgroupsPerDimension_getterinfo = { { get_maxComputeWorkgroupsPerDimension }, { prototypes::id::GPUSupportedLimits }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::SupportedLimits* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("maxTextureDimension1D", JSPROP_ENUMERATE, GenericGetter, &maxTextureDimension1D_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxTextureDimension2D", JSPROP_ENUMERATE, GenericGetter, &maxTextureDimension2D_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxTextureDimension3D", JSPROP_ENUMERATE, GenericGetter, &maxTextureDimension3D_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxTextureArrayLayers", JSPROP_ENUMERATE, GenericGetter, &maxTextureArrayLayers_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxBindGroups", JSPROP_ENUMERATE, GenericGetter, &maxBindGroups_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxBindGroupsPlusVertexBuffers", JSPROP_ENUMERATE, GenericGetter, &maxBindGroupsPlusVertexBuffers_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxBindingsPerBindGroup", JSPROP_ENUMERATE, GenericGetter, &maxBindingsPerBindGroup_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxDynamicUniformBuffersPerPipelineLayout", JSPROP_ENUMERATE, GenericGetter, &maxDynamicUniformBuffersPerPipelineLayout_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxDynamicStorageBuffersPerPipelineLayout", JSPROP_ENUMERATE, GenericGetter, &maxDynamicStorageBuffersPerPipelineLayout_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxSampledTexturesPerShaderStage", JSPROP_ENUMERATE, GenericGetter, &maxSampledTexturesPerShaderStage_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxSamplersPerShaderStage", JSPROP_ENUMERATE, GenericGetter, &maxSamplersPerShaderStage_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxStorageBuffersInVertexStage", JSPROP_ENUMERATE, GenericGetter, &maxStorageBuffersInVertexStage_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxStorageBuffersInFragmentStage", JSPROP_ENUMERATE, GenericGetter, &maxStorageBuffersInFragmentStage_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxStorageBuffersPerShaderStage", JSPROP_ENUMERATE, GenericGetter, &maxStorageBuffersPerShaderStage_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxStorageTexturesInVertexStage", JSPROP_ENUMERATE, GenericGetter, &maxStorageTexturesInVertexStage_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxStorageTexturesInFragmentStage", JSPROP_ENUMERATE, GenericGetter, &maxStorageTexturesInFragmentStage_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxStorageTexturesPerShaderStage", JSPROP_ENUMERATE, GenericGetter, &maxStorageTexturesPerShaderStage_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxUniformBuffersPerShaderStage", JSPROP_ENUMERATE, GenericGetter, &maxUniformBuffersPerShaderStage_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxUniformBufferBindingSize", JSPROP_ENUMERATE, GenericGetter, &maxUniformBufferBindingSize_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxStorageBufferBindingSize", JSPROP_ENUMERATE, GenericGetter, &maxStorageBufferBindingSize_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("minUniformBufferOffsetAlignment", JSPROP_ENUMERATE, GenericGetter, &minUniformBufferOffsetAlignment_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("minStorageBufferOffsetAlignment", JSPROP_ENUMERATE, GenericGetter, &minStorageBufferOffsetAlignment_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxVertexBuffers", JSPROP_ENUMERATE, GenericGetter, &maxVertexBuffers_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxBufferSize", JSPROP_ENUMERATE, GenericGetter, &maxBufferSize_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxVertexAttributes", JSPROP_ENUMERATE, GenericGetter, &maxVertexAttributes_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxVertexBufferArrayStride", JSPROP_ENUMERATE, GenericGetter, &maxVertexBufferArrayStride_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxInterStageShaderVariables", JSPROP_ENUMERATE, GenericGetter, &maxInterStageShaderVariables_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxColorAttachments", JSPROP_ENUMERATE, GenericGetter, &maxColorAttachments_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxColorAttachmentBytesPerSample", JSPROP_ENUMERATE, GenericGetter, &maxColorAttachmentBytesPerSample_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxComputeWorkgroupStorageSize", JSPROP_ENUMERATE, GenericGetter, &maxComputeWorkgroupStorageSize_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxComputeInvocationsPerWorkgroup", JSPROP_ENUMERATE, GenericGetter, &maxComputeInvocationsPerWorkgroup_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxComputeWorkgroupSizeX", JSPROP_ENUMERATE, GenericGetter, &maxComputeWorkgroupSizeX_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxComputeWorkgroupSizeY", JSPROP_ENUMERATE, GenericGetter, &maxComputeWorkgroupSizeY_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxComputeWorkgroupSizeZ", JSPROP_ENUMERATE, GenericGetter, &maxComputeWorkgroupSizeZ_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("maxComputeWorkgroupsPerDimension", JSPROP_ENUMERATE, GenericGetter, &maxComputeWorkgroupsPerDimension_getterinfo, nullptr, nullptr), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(35 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[35]; static PropertyInfo sNativeProperties_propertyInfos[35]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 35, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(35 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUSupportedLimits, constructors::id::GPUSupportedLimits, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUSupportedLimits, true, 0, "GPUSupportedLimits", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUSupportedLimitsPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUSupportedLimits, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUSupportedLimits", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUSupportedLimits, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::SupportedLimits* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUSupportedLimits); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUSupportedLimits); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUSupportedLimits", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUSupportedLimits, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUSupportedLimits, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUSupportedLimits_Binding namespace GPUTexture_Binding { MOZ_CAN_RUN_SCRIPT static bool createView(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "GPUTexture.createView"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "createView", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); binding_detail::FastGPUTextureViewDescriptor arg0; if (!arg0.Init(cx, (args.hasDefined(0)) ? args[0] : JS::NullHandleValue, "Argument 1", false)) { return false; } auto result(StrongOrRawPtr(MOZ_KnownLive(self)->CreateView(Constify(arg0)))); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!GetOrCreateDOMReflector(cx, result, args.rval())) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const JSJitInfo createView_methodinfo = { { (JSJitGetterOp)createView }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool destroy(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "destroy", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); // NOTE: This assert does NOT call the function. static_assert(std::is_void_vDestroy())>, "Should be returning void here"); MOZ_KnownLive(self)->Destroy(); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setUndefined(); return true; } static const JSJitInfo destroy_methodinfo = { { (JSJitGetterOp)destroy }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_width(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "width", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->Width()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo width_getterinfo = { { get_width }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_height(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "height", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->Height()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo height_getterinfo = { { get_height }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_depthOrArrayLayers(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "depthOrArrayLayers", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->DepthOrArrayLayers()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo depthOrArrayLayers_getterinfo = { { get_depthOrArrayLayers }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_mipLevelCount(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "mipLevelCount", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->MipLevelCount()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo mipLevelCount_getterinfo = { { get_mipLevelCount }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_sampleCount(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "sampleCount", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->SampleCount()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo sampleCount_getterinfo = { { get_sampleCount }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_dimension(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "dimension", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); GPUTextureDimension result(MOZ_KnownLive(self)->Dimension()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo dimension_getterinfo = { { get_dimension }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_format(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "format", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); GPUTextureFormat result(MOZ_KnownLive(self)->Format()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!ToJSValue(cx, result, args.rval())) { return false; } return true; } static const JSJitInfo format_getterinfo = { { get_format }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_usage(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "usage", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); uint32_t result(MOZ_KnownLive(self)->Usage()); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo usage_getterinfo = { { get_usage }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTexture", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUTexture }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::Texture* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("createView", (GenericMethod), reinterpret_cast(&createView_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("destroy", (GenericMethod), reinterpret_cast(&destroy_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const PrefableDisablers sMethods_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sMethods[] = { { &sMethods_disablers0, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("width", JSPROP_ENUMERATE, GenericGetter, &width_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("height", JSPROP_ENUMERATE, GenericGetter, &height_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("depthOrArrayLayers", JSPROP_ENUMERATE, GenericGetter, &depthOrArrayLayers_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("mipLevelCount", JSPROP_ENUMERATE, GenericGetter, &mipLevelCount_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("sampleCount", JSPROP_ENUMERATE, GenericGetter, &sampleCount_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("dimension", JSPROP_ENUMERATE, GenericGetter, &dimension_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("format", JSPROP_ENUMERATE, GenericGetter, &format_getterinfo, nullptr, nullptr), JSPropertySpec::nativeAccessors("usage", JSPROP_ENUMERATE, GenericGetter, &usage_getterinfo, nullptr, nullptr), JS_PS_END, JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const PrefableDisablers sAttributes_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sAttributes[] = { { &sAttributes_disablers0, &sAttributes_specs[0] }, { nullptr, &sAttributes_specs[9] }, { nullptr, nullptr } }; static_assert(2 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(8 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[11]; static PropertyInfo sNativeProperties_propertyInfos[11]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, -1, 11, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[2] } } }; static_assert(11 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUTexture, constructors::id::GPUTexture, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUTexture, true, 0, "GPUTexture", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUTexturePrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUTexture, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUTexture", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUTexture, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::Texture* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUTexture); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUTexture); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUTexture", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUTexture, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUTexture, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUTexture_Binding namespace GPUTextureUsage_Binding { MOZ_GLOBINIT static const ConstantSpec sConstants_specs[] = { { "COPY_SRC", JS::NumberValue(1U) }, { "COPY_DST", JS::NumberValue(2U) }, { "TEXTURE_BINDING", JS::NumberValue(4U) }, { "STORAGE_BINDING", JS::NumberValue(8U) }, { "RENDER_ATTACHMENT", JS::NumberValue(16U) }, { "TRANSIENT_ATTACHMENT", JS::NumberValue(32U) }, { 0, JS::UndefinedValue() } }; static const PrefableDisablers sConstants_disablers0 = { WebIDLPrefIndex::NoPref, 0, true, OriginTrial(0), nullptr }; static const Prefable sConstants[] = { { &sConstants_disablers0, &sConstants_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(6 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[6]; static PropertyInfo sNativeProperties_propertyInfos[6]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, true, 0 /* sConstants */, -1, 6, sNativeProperties_sortedPropertyIndices, { { sConstants, &sNativeProperties_propertyInfos[0] } } }; static_assert(6 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::_ID_Count, constructors::id::GPUTextureUsage, &DefaultXrayExpandoObjectClass }; static const DOMIfaceAndProtoJSClass sNamespaceObjectClass = { { "GPUTextureUsage", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS, JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eNamespace, prototypes::id::_ID_Count, 0, &sNativePropertyHooks, // This isn't strictly following the spec (see // https://console.spec.whatwg.org/#ref-for-dfn-namespace-object), // but should be ok for Xrays. JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Rooted constructorProto(aCx, JS::GetRealmObjectPrototype(aCx)); if (!constructorProto) { return; } JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUTextureUsage); dom::CreateNamespaceObject(aCx, aGlobal, constructorProto, sNamespaceObjectClass, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUTextureUsage", ShouldExpose(aCx, aGlobal, aDefineOnGlobal)); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUTextureUsage, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUTextureUsage_Binding namespace GPUTextureView_Binding { MOZ_CAN_RUN_SCRIPT static bool get_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTextureView", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); DOMString result; // NOTE: This assert does NOT call the function. static_assert(std::is_void_vGetLabel(result))>, "Should be returning void here"); MOZ_KnownLive(self)->GetLabel(result); MOZ_ASSERT(!JS_IsExceptionPending(cx)); if (!xpc::NonVoidStringToJsval(cx, result, args.rval())) { return false; } return true; } MOZ_CAN_RUN_SCRIPT static bool set_label(JSContext* cx, JS::Handle obj, void* void_self, JSJitSetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUTextureView", "label", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_SETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } if (!NormalizeUSVString(arg0)) { JS_ReportOutOfMemory(cx); return false; } // NOTE: This assert does NOT call the function. static_assert(std::is_void_vSetLabel(Constify(arg0)))>, "Should be returning void here"); MOZ_KnownLive(self)->SetLabel(Constify(arg0)); MOZ_ASSERT(!JS_IsExceptionPending(cx)); return true; } static const JSJitInfo label_getterinfo = { { get_label }, { prototypes::id::GPUTextureView }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_STRING, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static const JSJitInfo label_setterinfo = { { (JSJitGetterOp)set_label }, { prototypes::id::GPUTextureView }, { PrototypeTraits::Depth }, JSJitInfo::Setter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::TextureView* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("label", JSPROP_ENUMERATE, GenericGetter, &label_getterinfo, GenericSetter, &label_setterinfo), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[1]; static PropertyInfo sNativeProperties_propertyInfos[1]; static const NativePropertiesN<1> sNativeProperties = { false, 0, false, 0, false, 0, true, 0 /* sAttributes */, false, 0, false, 0, false, 0, -1, 1, sNativeProperties_sortedPropertyIndices, { { sAttributes, &sNativeProperties_propertyInfos[0] } } }; static_assert(1 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::GPUTextureView, constructors::id::GPUTextureView, &DefaultXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::GPUTextureView, true, 0, "GPUTextureView", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUTextureViewPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUTextureView, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUTextureView", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUTextureView, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::TextureView* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUTextureView); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUTextureView); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "GPUTextureView", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUTextureView, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUTextureView, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUTextureView_Binding namespace GPUValidationError_Binding { static_assert(IsRefcounted::value == IsRefcounted::value, "Can't inherit from an interface with a different ownership model."); static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::ValidationError* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { nullptr, nullptr, &sNativePropertiesInited }, prototypes::id::GPUValidationError, constructors::id::GPUValidationError, &DefaultXrayExpandoObjectClass }; static bool _constructor(JSContext* cx, unsigned argc, JS::Value* vp) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "GPUValidationError", "constructor", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::Rooted obj(cx, &args.callee()); if (!args.isConstructing()) { return ThrowConstructorWithoutNew(cx, "GPUValidationError"); } JS::Rooted desiredProto(cx); if (!GetDesiredProto(cx, args, prototypes::id::GPUValidationError, CreateInterfaceObjects, &desiredProto)) { return false; } if (!args.requireAtLeast(cx, "GPUValidationError constructor", 1)) { return false; } GlobalObject global(cx, obj); if (global.Failed()) { return false; } bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj); nsAutoString arg0; if (!ConvertJSValueToString(cx, args[0], eStringify, eStringify, arg0)) { return false; } Maybe ar; if (objIsXray) { // Since our object is an Xray, we can just CheckedUnwrapStatic: // we know Xrays have no dynamic unwrap behavior. obj = js::CheckedUnwrapStatic(obj); if (!obj) { return false; } ar.emplace(cx, obj); if (!JS_WrapObject(cx, &desiredProto)) { return false; } } FastErrorResult rv; auto result(StrongOrRawPtr(mozilla::webgpu::ValidationError::Constructor(global, NonNullHelper(Constify(arg0)), rv))); if (rv.MaybeSetPendingException(cx, "GPUValidationError constructor")) [[unlikely]] { return false; } MOZ_ASSERT(!JS_IsExceptionPending(cx)); static_assert(!std::is_pointer_v, "NewObject implies that we need to keep the object alive with a strong reference."); if (!GetOrCreateDOMReflector(cx, result, args.rval(), desiredProto)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); return false; } return true; } static const DOMInterfaceInfo sInterfaceObjectInfo = { { _constructor, &sNativePropertyHooks }, GPUError_Binding::GetConstructorObjectHandle, PrototypeTraits::Depth, prototypes::id::GPUValidationError, true, 1, "GPUValidationError", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "GPUValidationErrorPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::GPUValidationError, PrototypeTraits::Depth, &sNativePropertyHooks, GPUError_Binding::GetProtoObject }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "GPUValidationError", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::GPUError, prototypes::id::GPUValidationError, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(1 >= 1, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::ValidationError* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(static_cast(aObject) == reinterpret_cast(aObject), "Multiple inheritance for mozilla::webgpu::Error is broken."); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::GPUValidationError); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::GPUValidationError); JS::Handle parentProto(GPUError_Binding::GetProtoObjectHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(GPUError_Binding::GetConstructorObjectHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 1, false, Span{}, interfaceCache, nullptr, nullptr, "GPUValidationError", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::GPUValidationError, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::GPUValidationError, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace GPUValidationError_Binding namespace WGSLLanguageFeatures_Binding { namespace SetlikeHelpers { void Clear(mozilla::webgpu::WGSLLanguageFeatures* self, ErrorResult& aRv) { MOZ_ASSERT(self); AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because // all we want is to wrap into _some_ scope and then unwrap to find // the reflector, and wrapping has no side-effects. JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible); if (!scope) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } JSAutoRealm tempRealm(cx, scope); JS::Rooted v(cx); if(!ToJSValue(cx, self, &v)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } // This is a reflector, but due to trying to name things // similarly across method generators, it's called obj here. JS::Rooted obj(cx); obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false); JSAutoRealm reflectorRealm(cx, obj); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } if (created) { PreserveWrapper(self); } if (!JS::SetClear(cx, backingObj)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } } bool Delete(mozilla::webgpu::WGSLLanguageFeatures* self, const nsAString& aKey, ErrorResult& aRv) { MOZ_ASSERT(self); AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because // all we want is to wrap into _some_ scope and then unwrap to find // the reflector, and wrapping has no side-effects. JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible); if (!scope) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } JSAutoRealm tempRealm(cx, scope); JS::Rooted v(cx); if(!ToJSValue(cx, self, &v)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } // This is a reflector, but due to trying to name things // similarly across method generators, it's called obj here. JS::Rooted obj(cx); obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false); JSAutoRealm reflectorRealm(cx, obj); JS::RootedVector argv(cx); if (!argv.resize(1)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } do { if (!xpc::NonVoidStringToJsval(cx, aKey, argv[0])) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } break; } while (false); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } if (created) { PreserveWrapper(self); } bool retVal; if (!JS::SetDelete(cx, backingObj, argv[0], &retVal)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } return retVal; } bool Has(mozilla::webgpu::WGSLLanguageFeatures* self, const nsAString& aKey, ErrorResult& aRv) { MOZ_ASSERT(self); AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because // all we want is to wrap into _some_ scope and then unwrap to find // the reflector, and wrapping has no side-effects. JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible); if (!scope) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } JSAutoRealm tempRealm(cx, scope); JS::Rooted v(cx); if(!ToJSValue(cx, self, &v)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } // This is a reflector, but due to trying to name things // similarly across method generators, it's called obj here. JS::Rooted obj(cx); obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false); JSAutoRealm reflectorRealm(cx, obj); JS::RootedVector argv(cx); if (!argv.resize(1)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } do { if (!xpc::NonVoidStringToJsval(cx, aKey, argv[0])) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } break; } while (false); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } if (created) { PreserveWrapper(self); } bool retVal; if (!JS::SetHas(cx, backingObj, argv[0], &retVal)) { aRv.Throw(NS_ERROR_UNEXPECTED); return bool(0); } return retVal; } void Add(mozilla::webgpu::WGSLLanguageFeatures* self, const nsAString& aKey, ErrorResult& aRv) { MOZ_ASSERT(self); AutoJSAPI jsapi; jsapi.Init(); JSContext* cx = jsapi.cx(); // It's safe to use UnprivilegedJunkScopeOrWorkerGlobal here because // all we want is to wrap into _some_ scope and then unwrap to find // the reflector, and wrapping has no side-effects. JSObject* scope = UnprivilegedJunkScopeOrWorkerGlobal(fallible); if (!scope) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } JSAutoRealm tempRealm(cx, scope); JS::Rooted v(cx); if(!ToJSValue(cx, self, &v)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } // This is a reflector, but due to trying to name things // similarly across method generators, it's called obj here. JS::Rooted obj(cx); obj = js::UncheckedUnwrap(&v.toObject(), /* stopAtWindowProxy = */ false); JSAutoRealm reflectorRealm(cx, obj); JS::RootedVector argv(cx); if (!argv.resize(1)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } do { if (!xpc::NonVoidStringToJsval(cx, aKey, argv[0])) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } break; } while (false); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } if (created) { PreserveWrapper(self); } if (!JS::SetAdd(cx, backingObj, argv[0])) { aRv.Throw(NS_ERROR_UNEXPECTED); return; } } } // namespace SetlikeHelpers MOZ_CAN_RUN_SCRIPT static bool get_size(JSContext* cx, JS::Handle obj, void* void_self, JSJitGetterCallArgs args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "WGSLLanguageFeatures", "size", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_GETTER) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } uint32_t result = JS::SetSize(cx, backingObj); MOZ_ASSERT(!JS_IsExceptionPending(cx)); args.rval().setNumber(result); return true; } static const JSJitInfo size_getterinfo = { { get_size }, { prototypes::id::WGSLLanguageFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Getter, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_DOUBLE, /* returnType. Not relevant for setters. */ true, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool entries(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "WGSLLanguageFeatures", "entries", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change // after bug 1023984 is fixed. if (xpc::WrapperFactory::IsXrayWrapper(obj)) { JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported."); return false; } JS::Rooted result(cx); JS::Rooted v(cx); if (!JS::SetEntries(cx, backingObj, &v)) { return false; } result = &v.toObject(); JS::ExposeObjectToActiveJS(result); args.rval().setObject(*result); if (!MaybeWrapObjectValue(cx, args.rval())) { return false; } return true; } static const JSJitInfo::ArgType entries_methodinfo_argTypes[] = { JSJitInfo::ArgTypeListEnd }; static const JSTypedMethodJitInfo entries_methodinfo = { { { (JSJitGetterOp)entries }, { prototypes::id::WGSLLanguageFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ true, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }, entries_methodinfo_argTypes }; MOZ_CAN_RUN_SCRIPT static bool keys(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "WGSLLanguageFeatures", "keys", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change // after bug 1023984 is fixed. if (xpc::WrapperFactory::IsXrayWrapper(obj)) { JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported."); return false; } JS::Rooted result(cx); JS::Rooted v(cx); if (!JS::SetKeys(cx, backingObj, &v)) { return false; } result = &v.toObject(); JS::ExposeObjectToActiveJS(result); args.rval().setObject(*result); if (!MaybeWrapObjectValue(cx, args.rval())) { return false; } return true; } static const JSJitInfo::ArgType keys_methodinfo_argTypes[] = { JSJitInfo::ArgTypeListEnd }; static const JSTypedMethodJitInfo keys_methodinfo = { { { (JSJitGetterOp)keys }, { prototypes::id::WGSLLanguageFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ true, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }, keys_methodinfo_argTypes }; MOZ_CAN_RUN_SCRIPT static bool values(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "WGSLLanguageFeatures", "values", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } // TODO (Bug 1173651): Xrays currently cannot wrap iterators. Change // after bug 1023984 is fixed. if (xpc::WrapperFactory::IsXrayWrapper(obj)) { JS_ReportErrorASCII(cx, "Xray wrapping of iterators not supported."); return false; } JS::Rooted result(cx); JS::Rooted v(cx); if (!JS::SetValues(cx, backingObj, &v)) { return false; } result = &v.toObject(); JS::ExposeObjectToActiveJS(result); args.rval().setObject(*result); if (!MaybeWrapObjectValue(cx, args.rval())) { return false; } return true; } static const JSJitInfo::ArgType values_methodinfo_argTypes[] = { JSJitInfo::ArgTypeListEnd }; static const JSTypedMethodJitInfo values_methodinfo = { { { (JSJitGetterOp)values }, { prototypes::id::WGSLLanguageFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_OBJECT, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ true, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }, values_methodinfo_argTypes }; MOZ_CAN_RUN_SCRIPT static bool forEach(JSContext* cx_, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { BindingCallContext cx(cx_, "WGSLLanguageFeatures.forEach"); AUTO_PROFILER_LABEL_DYNAMIC_FAST( "WGSLLanguageFeatures", "forEach", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); JS::Rooted arg0(cx); if (args.get(0).isObject()) { arg0 = &args.get(0).toObject(); } else { cx.ThrowErrorMessage("Argument 1"); return false; } JS::Rooted arg1(cx); if (args.hasDefined(1)) { arg1 = args.get(1); } else { arg1 = JS::UndefinedValue(); } JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } // Create a wrapper function. JSFunction* func = js::NewFunctionWithReserved(cx, ForEachHandler, 3, 0, nullptr); if (!func) { return false; } JS::Rooted funcObj(cx, JS_GetFunctionObject(func)); JS::Rooted funcVal(cx, JS::ObjectValue(*funcObj)); js::SetFunctionNativeReserved(funcObj, FOREACH_CALLBACK_SLOT, JS::ObjectValue(*arg0)); js::SetFunctionNativeReserved(funcObj, FOREACH_MAPLIKEORSETLIKEOBJ_SLOT, JS::ObjectValue(*obj)); if (!JS::SetForEach(cx, backingObj, funcVal, arg1)) { return false; } args.rval().setUndefined(); return true; } static const JSJitInfo forEach_methodinfo = { { (JSJitGetterOp)forEach }, { prototypes::id::WGSLLanguageFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasEverything, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_UNDEFINED, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ false, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }; MOZ_CAN_RUN_SCRIPT static bool has(JSContext* cx, JS::Handle obj, void* void_self, const JSJitMethodCallArgs& args) { AUTO_PROFILER_LABEL_DYNAMIC_FAST( "WGSLLanguageFeatures", "has", DOM, cx, uint32_t(js::ProfilingStackFrame::Flags::STRING_TEMPLATE_METHOD) | uint32_t(js::ProfilingStackFrame::Flags::RELEVANT_FOR_JS)); auto* self = static_cast(void_self); nsAutoString arg0; if (!ConvertJSValueToString(cx, args.get(0), eStringify, eStringify, arg0)) { return false; } JS::Rooted backingObj(cx); bool created = false; if (!GetSetlikeBackingObject(cx, obj, (DOM_INSTANCE_RESERVED_SLOTS + 0), &backingObj, &created)) { return false; } if (created) { PreserveWrapper(self); } JS::Rooted arg0Val(cx); if (!ToJSValue(cx, arg0, &arg0Val)) { return false; } bool result; if (!JS::SetHas(cx, backingObj, arg0Val, &result)) { return false; } args.rval().setBoolean(result); return true; } static const JSJitInfo::ArgType has_methodinfo_argTypes[] = { JSJitInfo::String, JSJitInfo::ArgTypeListEnd }; static const JSTypedMethodJitInfo has_methodinfo = { { { (JSJitGetterOp)has }, { prototypes::id::WGSLLanguageFeatures }, { PrototypeTraits::Depth }, JSJitInfo::Method, JSJitInfo::AliasDOMSets, /* aliasSet. Not relevant for setters. */ JSVAL_TYPE_BOOLEAN, /* returnType. Not relevant for setters. */ false, /* isInfallible. False in setters. */ false, /* isMovable. Not relevant for setters. */ false, /* isEliminatable. Not relevant for setters. */ false, /* isAlwaysInSlot. Only relevant for getters. */ false, /* isLazilyCachedInSlot. Only relevant for getters. */ true, /* isTypedMethod. Only relevant for methods. */ 0 /* Reserved slot index, if we're stored in a slot, else 0. */ }, has_methodinfo_argTypes }; static void _finalize(JS::GCContext* gcx, JSObject* obj) { mozilla::webgpu::WGSLLanguageFeatures* self = UnwrapPossiblyNotInitializedDOMObject(obj); if (self) { JS::SetNativeObjectReservedSlot(obj, DOM_OBJECT_SLOT, JS::UndefinedValue()); ClearWrapper(self, self, obj); if (size_t mallocBytes = BindingJSObjectMallocBytes(self)) { JS::RemoveAssociatedMemory(obj, mallocBytes, JS::MemoryUse::DOMBinding); } AddForDeferredFinalization(self); } } MOZ_GLOBINIT static const JSFunctionSpec sMethods_specs[] = { JS_FNSPEC("entries", (GenericMethod), reinterpret_cast(&entries_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("keys", (GenericMethod), reinterpret_cast(&keys_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("values", (GenericMethod), reinterpret_cast(&values_methodinfo), 0, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("forEach", (GenericMethod), reinterpret_cast(&forEach_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FNSPEC("has", (GenericMethod), reinterpret_cast(&has_methodinfo), 1, JSPROP_ENUMERATE, nullptr), JS_FS_END }; static const Prefable sMethods[] = { { nullptr, &sMethods_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(5 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); MOZ_GLOBINIT static const JSPropertySpec sAttributes_specs[] = { JSPropertySpec::nativeAccessors("size", JSPROP_ENUMERATE, GenericGetter, &size_getterinfo, nullptr, nullptr), JS_PS_END }; static const Prefable sAttributes[] = { { nullptr, &sAttributes_specs[0] }, { nullptr, nullptr } }; static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_PREF_INDEX, "We have a prefable index that is >= (1 << NUM_BITS_PROPERTY_INFO_PREF_INDEX)"); static_assert(1 <= 1ull << NUM_BITS_PROPERTY_INFO_SPEC_INDEX, "We have a spec index that is >= (1 << NUM_BITS_PROPERTY_INFO_SPEC_INDEX)"); static uint16_t sNativeProperties_sortedPropertyIndices[6]; static PropertyInfo sNativeProperties_propertyInfos[6]; static const NativePropertiesN<2> sNativeProperties = { false, 0, false, 0, true, 0 /* sMethods */, true, 1 /* sAttributes */, false, 0, false, 0, false, 0, 2, 6, sNativeProperties_sortedPropertyIndices, { { sMethods, &sNativeProperties_propertyInfos[0] }, { sAttributes, &sNativeProperties_propertyInfos[5] } } }; static_assert(2 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.iteratorAliasMethodIndex) - 1), "We have an iterator alias index that is oversized"); static_assert(6 < 1ull << (CHAR_BIT * sizeof(sNativeProperties.propertyInfoCount)), "We have a property info count that is oversized"); // This may allocate too many slots, because we only really need // slots for our non-interface-typed members that we cache. But // allocating slots only for those would make the slot index // computations much more complicated, so let's do this the simple // way for now. DEFINE_XRAY_EXPANDO_CLASS_WITH_OPS(static, sXrayExpandoObjectClass, 1, &xpc::XrayExpandoObjectClassOps); bool sNativePropertiesInited = false; const NativePropertyHooks sNativePropertyHooks = { nullptr, { sNativeProperties.Upcast(), nullptr, &sNativePropertiesInited }, prototypes::id::WGSLLanguageFeatures, constructors::id::WGSLLanguageFeatures, &sXrayExpandoObjectClass }; static const DOMInterfaceInfo sInterfaceObjectInfo = { { ThrowingConstructor, &sNativePropertyHooks }, JS::GetRealmFunctionPrototypeHandle, PrototypeTraits::Depth, prototypes::id::WGSLLanguageFeatures, true, 0, "WGSLLanguageFeatures", }; static const DOMIfaceAndProtoJSClass sPrototypeClass = { { "WGSLLanguageFeaturesPrototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(DOM_INTERFACE_PROTO_SLOTS_BASE), JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS }, eInterfacePrototype, prototypes::id::WGSLLanguageFeatures, PrototypeTraits::Depth, &sNativePropertyHooks, JS::GetRealmObjectPrototype }; bool ConstructorEnabled(JSContext* aCx, JS::Handle aObj) { return mozilla::webgpu::Instance::PrefEnabled(aCx, aObj) && mozilla::dom::IsSecureContextOrObjectIsFromSecureContext(aCx, aObj); } static JS::Handle GetProtoObjectHandle(JSContext* aCx); static const JSClassOps sClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* enumerate */ nullptr, /* newEnumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ _finalize, /* finalize */ nullptr, /* call */ nullptr, /* construct */ nullptr, /* trace */ }; static const DOMJSClass sClass = { { "WGSLLanguageFeatures", JSCLASS_IS_DOMJSCLASS | JSCLASS_FOREGROUND_FINALIZE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_PRESERVES_WRAPPER, &sClassOps, JS_NULL_CLASS_SPEC, &NativeTypeHelpers::sClassExtension, JS_NULL_OBJECT_OPS }, { prototypes::id::WGSLLanguageFeatures, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count, prototypes::id::_ID_Count }, std::is_base_of_v, &sNativePropertyHooks, GetProtoObjectHandle, GetCCParticipant::Get(), nullptr, NativeTypeHelpers::GetWrapperCache }; static_assert(1 == DOM_INSTANCE_RESERVED_SLOTS, "Must have the right minimal number of reserved slots."); static_assert(2 >= 2, "Must have enough reserved slots."); bool Wrap(JSContext* aCx, mozilla::webgpu::WGSLLanguageFeatures* aObject, nsWrapperCache* aCache, JS::Handle aGivenProto, JS::MutableHandle aReflector) { static_assert(!std::is_base_of_v, "Shouldn't have wrappercached things that are not refcounted."); static_assert(std::is_same_v); MOZ_ASSERT(ToSupportsIsCorrect(aObject)); MOZ_ASSERT_IF(aGivenProto, js::IsObjectInContextCompartment(aGivenProto, aCx)); MOZ_ASSERT(!aCache->GetWrapper(), "You should probably not be using Wrap() directly; use " "GetOrCreateDOMReflector instead"); MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), "nsISupports must be on our primary inheritance chain"); // If the wrapper cache contains a dead reflector then finalize that // now, ensuring that the finalizer for the old reflector always // runs before the new reflector is created and attached. This // avoids the awkward situation where there are multiple reflector // objects that contain pointers to the same native. if (JSObject* oldReflector = aCache->GetWrapperMaybeDead()) { _finalize(nullptr /* unused */, oldReflector); MOZ_ASSERT(!aCache->GetWrapperMaybeDead()); } JS::Rooted global(aCx, FindAssociatedGlobal(aCx, aObject->GetParentObject())); if (!global) { return false; } MOZ_ASSERT(JS_IsGlobalObject(global)); JS::AssertObjectIsNotGray(global); // That might have ended up wrapping us already, due to the wonders // of XBL. Check for that, and bail out as needed. aReflector.set(aCache->GetWrapper()); if (aReflector) { #ifdef DEBUG AssertReflectorHasGivenProto(aCx, aReflector, aGivenProto); #endif // DEBUG return true; } JSAutoRealm ar(aCx, global); JS::Handle canonicalProto = GetProtoObjectHandle(aCx); if (!canonicalProto) { return false; } JS::Rooted proto(aCx); if (aGivenProto) { proto = aGivenProto; // Unfortunately, while aGivenProto was in the compartment of aCx // coming in, we changed compartments to that of "parent" so may need // to wrap the proto here. if (js::GetContextCompartment(aCx) != JS::GetCompartment(proto)) { if (!JS_WrapObject(aCx, &proto)) { return false; } } } else { proto = canonicalProto; } BindingJSObjectCreator creator(aCx); creator.CreateObject(aCx, sClass.ToJSClass(), proto, aObject, aReflector); if (!aReflector) { return false; } aCache->SetWrapper(aReflector); creator.InitializationSucceeded(); MOZ_ASSERT(aCache->GetWrapperPreserveColor() && aCache->GetWrapperPreserveColor() == aReflector); // If proto != canonicalProto, we have to preserve our wrapper; // otherwise we won't be able to properly recreate it later, since // we won't know what proto to use. Note that we don't check // aGivenProto here, since it's entirely possible (and even // somewhat common) to have a non-null aGivenProto which is the // same as canonicalProto. if (proto != canonicalProto) { PreserveWrapper(aObject); } return true; } void CreateInterfaceObjects(JSContext* aCx, JS::Handle aGlobal, ProtoAndIfaceCache& aProtoAndIfaceCache, DefineInterfaceProperty aDefineOnGlobal) { JS::Heap* protoCache = &aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::WGSLLanguageFeatures); JS::Heap* interfaceCache = &aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::WGSLLanguageFeatures); JS::Handle parentProto(JS::GetRealmObjectPrototypeHandle(aCx)); if (!parentProto) { return; } JS::Handle constructorProto(JS::GetRealmFunctionPrototypeHandle(aCx)); if (!constructorProto) { return; } dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, &sPrototypeClass, protoCache, constructorProto, &sInterfaceObjectInfo, 0, false, Span{}, interfaceCache, sNativeProperties.Upcast(), nullptr, "WGSLLanguageFeatures", ShouldExpose(aCx, aGlobal, aDefineOnGlobal), nullptr, false, nullptr); JS::AssertObjectIsNotGray(*protoCache); JS::Handle proto = JS::Handle::fromMarkedLocation(protoCache->unsafeAddress()); if (!proto) { *protoCache = nullptr; if (interfaceCache) { *interfaceCache = nullptr; } return; } // Set up aliases on the interface prototype object we just created. JS::Rooted aliasedVal(aCx); if (!JS_GetProperty(aCx, proto, "values", &aliasedVal)) { *protoCache = nullptr; if (interfaceCache) { *interfaceCache = nullptr; } return; } JS::Rooted iteratorId(aCx, JS::GetWellKnownSymbolKey(aCx, JS::SymbolCode::iterator)); if (!JS_DefinePropertyById(aCx, proto, iteratorId, aliasedVal, 0)) { *protoCache = nullptr; if (interfaceCache) { *interfaceCache = nullptr; } return; } } static JS::Handle GetProtoObjectHandle(JSContext* aCx) { /* Get the interface prototype object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, prototypes::id::WGSLLanguageFeatures, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } JS::Handle GetConstructorObjectHandle(JSContext* aCx) { /* Get the interface object for this class. This will create the object as needed. */ return GetPerInterfaceObjectHandle(aCx, constructors::id::WGSLLanguageFeatures, &CreateInterfaceObjects, DefineInterfaceProperty::CheckExposure); } } // namespace WGSLLanguageFeatures_Binding } // namespace dom } // namespace mozilla