dawn_node: Implement the [SameObject] IDL attribute
This is done by moving the set up of these attributes to the place where the wrapper objects are created, by doing: jsObject.DefineProperty("foo", impl->getOnceFoo()); Three alternatives that weren't chosen are: - Caching a weak reference to the member's Napi::Value on the wrapper struct, and recreate it only as needed. This is good because it doesn't risk using the value after it is GCed, but it can result in multiple calls to the getters, which could be unexpected (for example for GPUDevice.lost in a follow-up CL). - Caching a persistent reference to the member's Napi::Value on the wrapper struct. This calls the getter once and doesn't risk using the value after it is GCed. However if Javascript does something like `myGPUDevice.limits.device = myGPUDevice`, a cycle is created that the GC doesn't have visibility into, and that can't be collected. (the origin of the edge of the reference graph that persistent references make is unknown to the GC). - Caching the member on a hidden variable of the JS object. I didn't find a way to do this. The closest would have been to do jsObject[Symbol(...)] = cachedValue but even symbols can be retrieved with Object.getOwnPropertySymbols. Bug: dawn:1123 Fixed: dawn:1144 Change-Id: I1bc82dd9d10be95bf2bdca73bdfb843bc556d2df Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/85361 Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
76517cfc32
commit
ecc3fe6f0f
|
@ -135,7 +135,6 @@ namespace wgpu::binding {
|
|||
}
|
||||
|
||||
interop::Interface<interop::GPUQueue> GPUDevice::getQueue(Napi::Env env) {
|
||||
// TODO(crbug.com/dawn/1144): Should probably return the same Queue JS object.
|
||||
return interop::GPUQueue::Create<GPUQueue>(env, device_.GetQueue(), async_);
|
||||
}
|
||||
|
||||
|
|
|
@ -149,9 +149,11 @@ Wrappers* Wrappers::instance = nullptr;
|
|||
InstanceMethod("{{$m.Name}}", &W{{$.Name}}::{{$m.Name}}),
|
||||
{{- end}}
|
||||
{{- range $a := AttributesOf $}}
|
||||
{{- if not (HasAnnotation $a "SameObject")}}
|
||||
InstanceAccessor("{{$a.Name}}", &W{{$.Name}}::get{{Title $a.Name}},
|
||||
{{- if $a.Readonly}} nullptr{{else}} &W{{$.Name}}::set{{Title $a.Name}}{{end -}}
|
||||
),
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- range $c := ConstantsOf $}}
|
||||
StaticValue("{{$c.Name}}", ToJS(env, {{$.Name}}::{{$c.Name}}), napi_default_jsproperty),
|
||||
|
@ -219,6 +221,7 @@ Wrappers* Wrappers::instance = nullptr;
|
|||
{{- end}}
|
||||
|
||||
{{- range $a := AttributesOf $}}
|
||||
{{- if not (HasAnnotation $a "SameObject")}}
|
||||
Napi::Value get{{Title $a.Name}}(const Napi::CallbackInfo& info) {
|
||||
return ToJS(info.Env(), impl->get{{Title $a.Name}}(info.Env()));
|
||||
}
|
||||
|
@ -233,7 +236,8 @@ Wrappers* Wrappers::instance = nullptr;
|
|||
Napi::Error::New(info.Env(), res.error).ThrowAsJavaScriptException();
|
||||
}
|
||||
}
|
||||
{{- end }}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
};
|
||||
{{end}}
|
||||
|
@ -331,6 +335,16 @@ Interface<{{$.Name}}> {{$.Name}}::Bind(Napi::Env env, std::unique_ptr<{{$.Name}}
|
|||
auto object = wrappers->{{$.Name}}_ctor.New({});
|
||||
auto* wrapper = Wrappers::W{{$.Name}}::Unwrap(object);
|
||||
wrapper->impl = std::move(impl);
|
||||
|
||||
{{- /*Add the [SameObject] members as read-only property on the JS object.*/ -}}
|
||||
{{- range $a := AttributesOf $}}
|
||||
{{- if HasAnnotation $a "SameObject"}}
|
||||
object.DefineProperty(Napi::PropertyDescriptor::Value(
|
||||
"{{$a.Name}}", ToJS(env, wrapper->impl->get{{Title $a.Name}}(env))
|
||||
));
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
|
||||
return Interface<{{$.Name}}>(object);
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ func run() error {
|
|||
"ConstantsOf": constantsOf,
|
||||
"EnumEntryName": enumEntryName,
|
||||
"Eval": g.eval,
|
||||
"HasAnnotation": hasAnnotation,
|
||||
"Include": g.include,
|
||||
"IsBasicLiteral": is(ast.BasicLiteral{}),
|
||||
"IsConstructor": isConstructor,
|
||||
|
@ -493,6 +494,22 @@ func enumEntryName(s string) string {
|
|||
return "k" + strings.ReplaceAll(pascalCase(strings.Trim(s, `"`)), "-", "")
|
||||
}
|
||||
|
||||
func findAnnotation(list []*ast.Annotation, name string) *ast.Annotation {
|
||||
for _, annotation := range list {
|
||||
if annotation.Name == name {
|
||||
return annotation
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasAnnotation(obj interface{}, name string) bool {
|
||||
if member, ok := obj.(*ast.Member); ok {
|
||||
return findAnnotation(member.Annotations, name) != nil
|
||||
}
|
||||
panic("Unhandled AST node type in hasAnnotation")
|
||||
}
|
||||
|
||||
// Method describes a WebIDL interface method
|
||||
type Method struct {
|
||||
// Name of the method
|
||||
|
|
Loading…
Reference in New Issue