Bug 238001 - [WebGPU] Remove the double pointer indirection in front of all objects
Summary: [WebGPU] Remove the double pointer indirection in front of all objects
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: New Bugs (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Myles C. Maxfield
URL:
Keywords: InRadar
: 237921 (view as bug list)
Depends on:
Blocks:
 
Reported: 2022-03-16 22:48 PDT by Myles C. Maxfield
Modified: 2022-03-22 14:33 PDT (History)
4 users (show)

See Also:


Attachments
Patch (47.41 KB, patch)
2022-03-16 23:15 PDT, Myles C. Maxfield
no flags Details | Formatted Diff | Diff
Patch (58.05 KB, patch)
2022-03-21 19:17 PDT, Myles C. Maxfield
ews-feeder: commit-queue-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Myles C. Maxfield 2022-03-16 22:48:51 PDT
[WebGPU] Remove the double pointer indirection in front of all objects
Comment 1 Myles C. Maxfield 2022-03-16 23:15:14 PDT
Created attachment 454933 [details]
Patch
Comment 2 Myles C. Maxfield 2022-03-16 23:19:54 PDT
*** Bug 237921 has been marked as a duplicate of this bug. ***
Comment 3 Kimmo Kinnunen 2022-03-17 00:51:02 PDT
Comment on attachment 454933 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=454933&action=review

> Source/WebGPU/ChangeLog:18
> +

Unfortunately you have to invert the relationship.

Now you have reasoning of:
"WGPUBufferImpl has the same layout as WebGPU::Buffer. This means I can take hunk of data pointed by WGPUBufferImpl* and treat it as WebGPU::Buffer".

This is invalid reasoning. You can imagine a compiler that knows everything. It will know that the program never creates a single WGPUBufferImpl. This means it will remove all code that accesses data through WGPUBufferImpls, as that simply cannot happen, as there are never instances of such.

So when you have code like:
void wgpuAdapterRelease(WGPUAdapter adapter)
{
    adapter->deref();
}

The code will be removed, because WGPUAdapterImpl is never instantiated, so that ->deref() call cannot ever be made.


This is the same scenario as having:
struct Kimmo {
  int a;
};
struct Myles {
  int a;
}

Myles* m = getMyles();

Kimmo* k = static_cast<Kimmo*>(m);
printf("%d", k->a);



struct WGPUBufferImpl : public WebGPU::Buffer;

// This is UB, WebGPU::Buffer is not WGPUBufferImpl.
WGPUBufferImpl* wgpuobj = static_cast<WGPUBufferImp *>(new WebGPU::Buffer());

// This is UB, WebGPU::Buffer is not float.
float* wgpuobj = static_cast<float*>(new WebGPU::Buffer());


E.g. you have to have something where WGPUBufferImpl is instantiated.

Since you instantiate WebGPU::Buffer instances, you need to have

struct WGPUBufferImpl {};
class WebGPU::Buffer : public WGPUBufferImpl {};

This way you can downcast:

WGPUBufferImpl* wgpuobj = new  WebGPU::Buffer();

// This is defined, since wgpuobject points to a real WebGPU::Buffer.
static_cast<WebGPU::Buffer*>(wgpuobj)->doSomethingBuffery();

So going back:

WebGPU::Adapter* fromAPI(WGPUAdapter adapter)
{
    // This static cast is DEFINED, IFF adapter was created from a pointer that pointed to WebGPU::Adapter. 
    return static_cast<WebGPU::Adapter*>(adapter);
}

void wgpuAdapterRelease(WGPUAdapter adapter)
{
    fromAPI(adapter)->deref();
}



The minimal type punning is achieved when:
-Input downcasts
- Output is natural subtype conversion

if you:
-  don't want empty base clasess
- void* types in the api

Then you need to type pun to opaque struct ptrs in the output.

> Source/WebGPU/WebGPU/CommandEncoder.mm:363
> +    return static_cast<WGPUComputePassEncoder>(WebGPU::fromAPI(commandEncoder).beginComputePass(*descriptor).leakRef());

So this is incorrect type punning, leading to UB.

There is never an instance of WGPUComputePassEncoder in this program. So the (all knowing) compiler knows this and can remove all code that ever references these codes, as they never can execute. If they would execute, they'd be UB. 

You have to invert the inheritance, unfortunately.


so you write this code as

    return WebGPU::releaseToAPI(WebGPU::fromAPI(commandEncoder).beginComputePass(*descriptor));


WGPUComputePassEncoder releaseToAPI(RefPtr<WebGPU::ComputePassEncoder>&& e)
{
     return e.leakRef();
}
Comment 4 Kimmo Kinnunen 2022-03-17 01:34:49 PDT
if you:
- don't want empty base clasess
- don't want void* types in the api

Then you need to type pun to opaque struct ptrs in the output.

So you have plain-old opaque struct api:

typedef struct WGPUBuffer WGPUBuffer; 
// struct WGPUBuffer opaque, never defined.
class WebGPU::Buffer {};

WGPUBuffer* releaseToAPI(RefPtr<WebGPU::Buffer>&& e)
{
     return reinterpret_cast<WGPUBuffer*>(e.leakRef());
}


WebGPU::Buffer& fromAPI(WGPUBuffer* b)
{
   return *reinterpret_cast<WebGPU::Buffer*>(b);
}

Strictly that should be UB too, but at least that's just something everybody lives with, I suppose.
Comment 5 Myles C. Maxfield 2022-03-21 19:17:14 PDT
Created attachment 455317 [details]
Patch
Comment 6 EWS 2022-03-22 12:05:35 PDT
Committed r291687 (248729@main): <https://commits.webkit.org/248729@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 455317 [details].
Comment 7 Radar WebKit Bug Importer 2022-03-22 12:06:17 PDT
<rdar://problem/90651490>