Dawn.node, make C++ class inheritance reflected in JavaScript
This makes the webgpu:idl,inheritance tests pass for
GPUValidationError, GPUOutMemoryError, and GPUInternalError
pass the test that they inherit from GPUError
Bug: 419128706
Change-Id: Ib56a6403bef7f677e9f5f740193770012de30ad4
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/243274
Commit-Queue: Gregg Tavares <gman@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/node/interop/Core.cpp b/src/dawn/node/interop/Core.cpp
index 710c9e6..26a2946 100644
--- a/src/dawn/node/interop/Core.cpp
+++ b/src/dawn/node/interop/Core.cpp
@@ -206,4 +206,30 @@
return o;
}
+// Chain the prototype of derivedClassConstructor to the prototype of baseClassValue
+// by calling the JavaScript function Object.setPrototypeOf
+void ChainPrototype(Napi::Value baseClassValue, Napi::Function derivedClassConstructor) {
+ // Look up our base constructor
+ Napi::Function baseClassConstructor = baseClassValue.As<Napi::Function>();
+
+ // Look up base prototype
+ Napi::Value baseClassPrototypeValue = baseClassConstructor.Get("prototype");
+ Napi::Object baseClassPrototype = baseClassPrototypeValue.As<Napi::Object>();
+
+ // Lookup our prototype
+ Napi::Object derivedPrototype = derivedClassConstructor.Get("prototype").As<Napi::Object>();
+
+ Napi::Object global = derivedClassConstructor.Env().Global();
+ Napi::Function setProtoType =
+ global.Get("Object").ToObject().Get("setPrototypeOf").As<Napi::Function>();
+
+ // Makes Derived super() call Base constructor
+ // JS = Object.setPrototypeOf(Derived, Base);
+ setProtoType.Call({derivedClassConstructor, baseClassConstructor});
+
+ // Make derived.someMethod call base.someMethod if someMethod does not exist on Derived.
+ // JS = Object.setPrototypeOf(Derived.constructor, Base.constructor)
+ setProtoType.Call({derivedPrototype, baseClassPrototype});
+}
+
} // namespace wgpu::interop
diff --git a/src/dawn/node/interop/Core.h b/src/dawn/node/interop/Core.h
index eb07517..64a7528 100644
--- a/src/dawn/node/interop/Core.h
+++ b/src/dawn/node/interop/Core.h
@@ -829,6 +829,8 @@
return deferred.Promise();
}
+void ChainPrototype(Napi::Value baseClassValue, Napi::Function derivedClassConstructor);
+
} // namespace wgpu::interop
#endif // SRC_DAWN_NODE_INTEROP_CORE_H_
diff --git a/src/dawn/node/interop/WebGPU.cpp.tmpl b/src/dawn/node/interop/WebGPU.cpp.tmpl
index 0122640..93900ff 100644
--- a/src/dawn/node/interop/WebGPU.cpp.tmpl
+++ b/src/dawn/node/interop/WebGPU.cpp.tmpl
@@ -96,7 +96,16 @@
Wrappers(Napi::Env env) {
{{- range $ := .Declarations}}
{{- if IsInterfaceOrNamespace $}}
+{{- if and (IsInterface $) ($.Inherits)}}
+ {
+ // It's an interface and it inherits from another class, pass the class it inherits
+ // from to its Class factory
+ Napi::Value baseClassValue = {{$.Inherits}}_ctor.Value();
+ {{$.Name}}_ctor = Napi::Persistent(W{{$.Name}}::Class(env, baseClassValue));
+ }
+{{- else}}
{{$.Name}}_ctor = Napi::Persistent(W{{$.Name}}::Class(env));
+{{- end}}
{{- end}}
{{- end}}
}
@@ -158,8 +167,14 @@
{{- if IsInterface $}}
std::unique_ptr<{{$.Name}}> impl;
{{- end}}
+{{- if and (IsInterface $) ($.Inherits) }}
+ // This class inherits from another, require the class factory to
+ // receive the base class so it can setup inheritance.
+ static Napi::Function Class(Napi::Env env, Napi::Value baseClassValue) {
+{{- else}}
static Napi::Function Class(Napi::Env env) {
- return DefineClass(env, "{{$.Name}}", {
+{{- end}}
+ auto func = DefineClass(env, "{{$.Name}}", {
{{ if $s := SetlikeOf $}}
InstanceMethod("has", &W{{$.Name}}::has),
InstanceMethod("keys", &W{{$.Name}}::keys),
@@ -180,6 +195,12 @@
StaticValue("{{$c.Name}}", ToJS(env, {{$.Name}}::{{$c.Name}}), napi_default_jsproperty),
{{- end}}
});
+
+{{- if and (IsInterface $) ($.Inherits)}}
+ // It inherits from another class, setup the prototype chain.
+ ChainPrototype(baseClassValue, func);
+{{- end}}
+ return func;
}
W{{$.Name}}(const Napi::CallbackInfo& info) : ObjectWrap(info) {}