Skip to content

Commit b277d57

Browse files
authored
[embind] Allow pointers for properties with a getter and setter function. (#24239)
When using separate getter and setter functions for class properties the setter function did not have policies applied to it. This caused setters with raw pointers to fail. For now, use the supplied return value policy to allow pointers. In the future we should probably add separate polices for arguments, but that will be a much bigger change. Note: I've added a lot more testing for properties and return value polices. This has highlighted a few issues where we seem to be creating extra copies. Fixes: #24225
1 parent 12bda01 commit b277d57

File tree

2 files changed

+100
-10
lines changed

2 files changed

+100
-10
lines changed

system/include/emscripten/bind.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -1927,7 +1927,6 @@ class class_ {
19271927
typename = typename std::enable_if<!internal::isPolicy<Setter>::value>::type>
19281928
EMSCRIPTEN_ALWAYS_INLINE const class_& property(const char* fieldName, Getter getter, Setter setter, Policies...) const {
19291929
using namespace internal;
1930-
using ReturnPolicy = GetReturnValuePolicy<PropertyType, Policies...>::tag;
19311930

19321931
typedef GetterPolicy<
19331932
typename std::conditional<std::is_same<PropertyType, internal::DeduceArgumentsTag>::value,
@@ -1939,17 +1938,24 @@ class class_ {
19391938
FunctionTag<Setter, PropertyType>>::type> SP;
19401939

19411940

1941+
using ReturnPolicy = GetReturnValuePolicy<typename GP::ReturnType, Policies...>::tag;
19421942
auto gter = &GP::template get<ClassType, ReturnPolicy>;
19431943
auto ster = &SP::template set<ClassType>;
19441944

1945+
typename WithPolicies<Policies...>::template ArgTypeList<typename GP::ReturnType> returnType;
1946+
// XXX: This currently applies all the polices (including return value polices) to the
1947+
// setter function argument to allow pointers. Using return value polices doesn't really
1948+
// make sense on an argument, but we don't have separate argument policies yet.
1949+
typename WithPolicies<Policies...>::template ArgTypeList<typename SP::ArgumentType> argType;
1950+
19451951
_embind_register_class_property(
19461952
TypeID<ClassType>::get(),
19471953
fieldName,
1948-
TypeID<typename GP::ReturnType>::get(),
1954+
returnType.getTypes()[0],
19491955
getSignature(gter),
19501956
reinterpret_cast<GenericFunction>(gter),
19511957
GP::getContext(getter),
1952-
TypeID<typename SP::ArgumentType>::get(),
1958+
argType.getTypes()[0],
19531959
getSignature(ster),
19541960
reinterpret_cast<GenericFunction>(ster),
19551961
SP::getContext(setter));

test/embind/test_return_value_policy.cpp

+91-7
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@ struct ValueHolder {
108108
void setPtr(Value* v) {
109109
valuePtr = v;
110110
}
111+
Value* getPtrConst() const {
112+
return valuePtr;
113+
}
111114
static Value* staticGetPtr() {
112115
static Value v;
113116
return &v;
@@ -265,6 +268,7 @@ int main() {
265268

266269
console.log("valueHolder.valueReference");
267270
valueProp = valueHolder.valueReference;
271+
assert(valueProp instanceof Module.Value);
268272
// Check that both references are updated.
269273
valueProp.setName("reference");
270274
valueProp = valueHolder.valueReference;
@@ -295,6 +299,72 @@ int main() {
295299
Module.assertDestructed(1);
296300
Module.assertAllCountsZero();
297301

302+
console.log("valueHolder.getterValueDefault");
303+
valueProp = valueHolder.getterValueDefault;
304+
assert(valueProp instanceof Module.Value);
305+
valueProp.delete();
306+
// TODO: Investigate if this can be made to only create one copy. The getter
307+
// wrapper appears to create an extra copy.
308+
Module.assertCopy(2);
309+
Module.assertDestructed(2);
310+
Module.assertAllCountsZero();
311+
312+
console.log("valueHolder.getterValueTakeOwnership");
313+
valueProp = valueHolder.getterValueTakeOwnership;
314+
assert(valueProp instanceof Module.Value);
315+
valueProp.delete();
316+
// TODO: Investigate if the copy can be removed.
317+
Module.assertCopy(1);
318+
Module.assertMove(1);
319+
Module.assertDestructed(2);
320+
Module.assertAllCountsZero();
321+
322+
console.log("valueHolder.getterValuePtrTakeOwnership");
323+
valueProp = valueHolder.getterValuePtrTakeOwnership;
324+
assert(valueProp instanceof Module.Value);
325+
Module.assertAllCountsZero();
326+
327+
console.log("valueHolder.getterValuePtrReference");
328+
valueProp = valueHolder.getterValuePtrReference;
329+
assert(valueProp instanceof Module.Value);
330+
Module.assertAllCountsZero();
331+
332+
console.log("valueHolder.getterSetterValueDefault");
333+
valueProp = valueHolder.getterSetterValueDefault;
334+
assert(valueProp instanceof Module.Value);
335+
valueProp.delete();
336+
// TODO: Investigate if this can be made to only create one copy. The getter
337+
// wrapper appears to create an extra copy.
338+
Module.assertCopy(2);
339+
Module.assertDestructed(2);
340+
Module.assertAllCountsZero();
341+
342+
console.log("valueHolder.getterSetterValueTakeOwnership");
343+
valueProp = valueHolder.getterSetterValueTakeOwnership;
344+
assert(valueProp instanceof Module.Value);
345+
valueProp.delete();
346+
// TODO: Investigate if the copy can be removed.
347+
Module.assertCopy(1);
348+
Module.assertMove(1);
349+
Module.assertDestructed(2);
350+
Module.assertAllCountsZero();
351+
352+
console.log("valueHolder.getterSetterPtrReference");
353+
valueHolder.initializeValuePtr();
354+
valueProp = valueHolder.getterSetterPtrReference;
355+
assert(valueProp instanceof Module.Value);
356+
Module.assertDefault(1);
357+
Module.assertAllCountsZero();
358+
359+
console.log("valueHolder.getterSetterPtrTakeOwnership");
360+
valueHolder.initializeValuePtr();
361+
valueProp = valueHolder.getterSetterPtrTakeOwnership;
362+
assert(valueProp instanceof Module.Value);
363+
valueProp.delete();
364+
Module.assertDefault(1);
365+
Module.assertDestructed(1);
366+
Module.assertAllCountsZero();
367+
298368
valueHolder.delete();
299369
);
300370
}
@@ -341,16 +411,30 @@ EMSCRIPTEN_BINDINGS(xxx) {
341411
.property("valueTakeOwnership", &ValueHolder::value, return_value_policy::take_ownership())
342412

343413
// Test binding raw pointers with the various methods.
414+
// Skip the test for default since that is forbidden.
344415
.property("valuePtrReference", &ValueHolder::valuePtr, return_value_policy::reference())
345416
.property("valuePtrTakeOwnership", &ValueHolder::valuePtr, return_value_policy::take_ownership())
346417

347-
// Check that compiling with getter and setter methods works as expected.
348-
// These are only tested for compilation since they use the same underlying
349-
// mechanisms as the other property bindings.
350-
// Getter only.
351-
.property("getterValue", &ValueHolder::get, return_value_policy::reference())
352-
// Getter and setter.
353-
.property("getterSetterValue", &ValueHolder::get, &ValueHolder::set, return_value_policy::reference())
418+
// Getter method only with value.
419+
.property("getterValueDefault", &ValueHolder::get)
420+
// Skip the test for rvp::reference since that is forbidden.
421+
.property("getterValueTakeOwnership", &ValueHolder::get, return_value_policy::take_ownership())
422+
423+
// Getter method only with pointer.
424+
// Skip the test for default since that is not allowed.
425+
.property("getterValuePtrReference", &ValueHolder::getPtrConst, return_value_policy::reference())
426+
.property("getterValuePtrTakeOwnership", &ValueHolder::getPtrConst, return_value_policy::take_ownership())
427+
428+
// Getter and setter with value.
429+
.property("getterSetterValueDefault", &ValueHolder::get, &ValueHolder::set)
430+
// Skip the test for rvp::reference since that is forbidden.
431+
.property("getterSetterValueTakeOwnership", &ValueHolder::get, &ValueHolder::set, return_value_policy::take_ownership())
432+
433+
// Getter and setter with pointer.
434+
// Skip the test for default since that is not allowed.
435+
.property("getterSetterPtrReference", &ValueHolder::getPtrConst, &ValueHolder::setPtr, return_value_policy::reference())
436+
.property("getterSetterPtrTakeOwnership", &ValueHolder::getPtrConst, &ValueHolder::setPtr, return_value_policy::take_ownership())
437+
354438
// std::function getter.
355439
.property("getterPtrWithStdFunctionReference", std::function<const Value*(const ValueHolder&)>(&value_holder), return_value_policy::reference())
356440
;

0 commit comments

Comments
 (0)