Skip to content

Commit

Permalink
Use generated structures instead of NSDictionary to serialize members…
Browse files Browse the repository at this point in the history
… of ObjC classes

https://bugs.webkit.org/show_bug.cgi?id=269438
rdar://122994790

Reviewed by Brady Eidson.

This makes it so that we don't need to expand what an NSDictionary can contain in order
to increase the number of ObjC classes that are serialized using generated serialization.

This also makes it so we don't need "webkit_secure_coding" in SerializedTypeInfo.cpp,
so all the metadata has the same form.

We can also simplify CoreIPCDictionary to just a vector of key/value pairs.

If a type is not declared as optional with a question mark in the serialization.in file,
then we debug assert on the encoding side if it is missing and we fail to decode on the
decoding side if it is missing.

* Source/WebKit/Scripts/generate-serializers.py:
(SerializedType.__init__):
(SerializedType.name_declaration_for_serialized_type_info):
(SerializedType.members_for_serialized_type_info):
(MemberVariable.value_without_question_mark):
(MemberVariable):
(MemberVariable.ns_type_enum_value):
(MemberVariable.array_contents):
(MemberVariable.dictionary_contents):
(MemberVariable.has_container_contents):
(MemberVariable.ns_type):
(MemberVariable.dictionary_type):
(MemberVariable.value_is_optional):
(check_type_members):
(check_type_members.is):
(encode_type):
(decode_type):
(construct_type):
(generate_impl):
(generate_one_serialized_type_info):
(generate_serialized_type_info):
(parse_serialized_types):
(generate_webkit_secure_coding_impl):
(generate_webkit_secure_coding_impl.is):
(generate_webkit_secure_coding_header):
(generate_one_dictionary_member_validation): Deleted.
* Source/WebKit/Scripts/webkit/tests/GeneratedWebKitSecureCoding.cpp:
(WebKit::dictionaryFromVector):
(WebKit::dictionaryFromOptionalVector):
(WebKit::vectorFromDictionary):
(WebKit::optionalVectorFromDictionary):
(WebKit::arrayFromVector):
(WebKit::arrayFromOptionalVector):
(WebKit::vectorFromArray):
(WebKit::optionalVectorFromArray):
(WebKit::CoreIPCAVOutputContext::CoreIPCAVOutputContext):
(WebKit::CoreIPCAVOutputContext::toID const):
(WebKit::CoreIPCNSSomeFoundationType::CoreIPCNSSomeFoundationType):
(WebKit::CoreIPCNSSomeFoundationType::toID const):
(WebKit::CoreIPCDDScannerResult::CoreIPCDDScannerResult):
(WebKit::CoreIPCDDScannerResult::toID const):
(WebKit::CoreIPCAVOutputContext::isValidDictionary): Deleted.
(WebKit::CoreIPCNSSomeFoundationType::isValidDictionary): Deleted.
(WebKit::CoreIPCDDScannerResult::isValidDictionary): Deleted.
* Source/WebKit/Scripts/webkit/tests/GeneratedWebKitSecureCoding.h:
(WebKit::CoreIPCAVOutputContext::CoreIPCAVOutputContext):
(WebKit::CoreIPCNSSomeFoundationType::CoreIPCNSSomeFoundationType):
(WebKit::CoreIPCDDScannerResult::CoreIPCDDScannerResult):
* Source/WebKit/Scripts/webkit/tests/SerializedTypeInfo.cpp:
(WebKit::allSerializedTypes):
* Source/WebKit/Scripts/webkit/tests/WebKitPlatformGeneratedSerializers.cpp:
(IPC::ArgumentCoder<WebKit::CoreIPCAVOutputContext>::encode):
(IPC::ArgumentCoder<WebKit::CoreIPCAVOutputContext>::decode):
(IPC::ArgumentCoder<WebKit::CoreIPCNSSomeFoundationType>::encode):
(IPC::ArgumentCoder<WebKit::CoreIPCNSSomeFoundationType>::decode):
(IPC::ArgumentCoder<WebKit::CoreIPCDDScannerResult>::encode):
(IPC::ArgumentCoder<WebKit::CoreIPCDDScannerResult>::decode):
* Source/WebKit/Shared/Cocoa/ArgumentCodersCocoa.h:
* Source/WebKit/Shared/Cocoa/ArgumentCodersCocoa.mm:
(IPC::getClass<PKSecureElementPass>):
* Source/WebKit/Shared/Cocoa/CoreIPCDictionary.h:
* Source/WebKit/Shared/Cocoa/CoreIPCDictionary.mm:
(WebKit::CoreIPCDictionary::CoreIPCDictionary):
(WebKit::CoreIPCDictionary::toID const):
(WebKit::CoreIPCDictionary::keyHasValueOfType const): Deleted.
(WebKit::CoreIPCDictionary::keyIsMissingOrHasValueOfType const): Deleted.
(WebKit::CoreIPCDictionary::collectionValuesAreOfType const): Deleted.
(WebKit::CoreIPCDictionary::createNSDictionaryIfNeeded const): Deleted.
* Source/WebKit/Shared/Cocoa/CoreIPCDictionary.serialization.in:
* Source/WebKit/Shared/Cocoa/CoreIPCPassKit.serialization.in:

Canonical link: https://commits.webkit.org/274799@main
  • Loading branch information
achristensen07 committed Feb 16, 2024
1 parent 4e839b3 commit dc84002
Show file tree
Hide file tree
Showing 15 changed files with 708 additions and 366 deletions.
319 changes: 247 additions & 72 deletions Source/WebKit/Scripts/generate-serializers.py

Large diffs are not rendered by default.

268 changes: 208 additions & 60 deletions Source/WebKit/Scripts/webkit/tests/GeneratedWebKitSecureCoding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,114 +45,262 @@ static RetainPtr<NSDictionary> dictionaryForWebKitSecureCodingType(id object)
return [archiver accumulatedDictionary];
}

template<typename T> static RetainPtr<NSDictionary> dictionaryFromVector(const Vector<std::pair<String, RetainPtr<T>>>& vector)
{
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:vector.size()];
for (auto& pair : vector)
dictionary[pair.first] = pair.second;
return dictionary;
}

template<typename T> static RetainPtr<NSDictionary> dictionaryFromOptionalVector(const std::optional<Vector<std::pair<String, RetainPtr<T>>>>& vector)
{
if (!vector)
return nil;
return dictionaryFromVector<T>(*vector);
}

template<typename T> static Vector<std::pair<String, RetainPtr<T>>> vectorFromDictionary(NSDictionary *dictionary)
{
if (![dictionary isKindOfClass:NSDictionary.class])
return { };
__block Vector<std::pair<String, RetainPtr<T>>> result;
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL*){
if ([key isKindOfClass:NSString.class] && [value isKindOfClass:IPC::getClass<T>()])
result.append((NSString *)key, (T)value);
}];
return result;
}

template<typename T> static std::optional<Vector<std::pair<String, RetainPtr<T>>>> optionalVectorFromDictionary(NSDictionary *dictionary)
{
if (![dictionary isKindOfClass:NSDictionary.class])
return std::nullopt;
return vectorFromDictionary<T>(dictionary);
}

template<typename T> static RetainPtr<NSArray> arrayFromVector(const Vector<RetainPtr<T>>& vector)
{
return createNSArray(vector, [] (auto& t) {
return t.get();
});
}

template<typename T> static RetainPtr<NSArray> arrayFromOptionalVector(const std::optional<Vector<RetainPtr<T>>>& vector)
{
if (!vector)
return nil;
return arrayFromVector<T>(*vector);
}

template<typename T> static Vector<RetainPtr<T>> vectorFromArray(NSArray *array)
{
if (![array isKindOfClass:NSArray.class])
return { };
Vector<RetainPtr<T>> result;
for (id element in array) {
if ([element isKindOfClass:IPC::getClass<T>()])
result.append((T *)element);
}
return result;
}

template<typename T> static std::optional<Vector<RetainPtr<T>>> optionalVectorFromArray(NSArray *array)
{
if (![array isKindOfClass:NSArray.class])
return std::nullopt;
return vectorFromArray<T>(array);
}

#if USE(AVFOUNDATION)
CoreIPCAVOutputContext::CoreIPCAVOutputContext(AVOutputContext *object)
: m_propertyList(dictionaryForWebKitSecureCodingType(object))
CoreIPCAVOutputContext::CoreIPCAVOutputContext(
RetainPtr<NSString>&& AVOutputContextSerializationKeyContextID,
RetainPtr<NSString>&& AVOutputContextSerializationKeyContextType
)
: m_AVOutputContextSerializationKeyContextID(WTFMove(AVOutputContextSerializationKeyContextID))
, m_AVOutputContextSerializationKeyContextType(WTFMove(AVOutputContextSerializationKeyContextType))
{
}

bool CoreIPCAVOutputContext::isValidDictionary(CoreIPCDictionary& dictionary)
CoreIPCAVOutputContext::CoreIPCAVOutputContext(AVOutputContext *object)
{
if (!dictionary.keyHasValueOfType("AVOutputContextSerializationKeyContextID"_s, IPC::NSType::String))
return false;
auto dictionary = dictionaryForWebKitSecureCodingType(object);
m_AVOutputContextSerializationKeyContextID = (NSString *)[dictionary objectForKey:@"AVOutputContextSerializationKeyContextID"];
if (!m_AVOutputContextSerializationKeyContextID || IPC::typeFromObject(m_AVOutputContextSerializationKeyContextID.get()) != IPC::NSType::String) {
m_AVOutputContextSerializationKeyContextID = nullptr;
}

if (!dictionary.keyHasValueOfType("AVOutputContextSerializationKeyContextType"_s, IPC::NSType::String))
return false;
m_AVOutputContextSerializationKeyContextType = (NSString *)[dictionary objectForKey:@"AVOutputContextSerializationKeyContextType"];
if (!m_AVOutputContextSerializationKeyContextType || IPC::typeFromObject(m_AVOutputContextSerializationKeyContextType.get()) != IPC::NSType::String) {
m_AVOutputContextSerializationKeyContextType = nullptr;
}

return true;
}

RetainPtr<id> CoreIPCAVOutputContext::toID() const
{
auto propertyList = [NSMutableDictionary dictionaryWithCapacity:2];
if (m_AVOutputContextSerializationKeyContextID)
propertyList[@"AVOutputContextSerializationKeyContextID"] = m_AVOutputContextSerializationKeyContextID.get();
if (m_AVOutputContextSerializationKeyContextType)
propertyList[@"AVOutputContextSerializationKeyContextType"] = m_AVOutputContextSerializationKeyContextType.get();
if (![PAL::getAVOutputContextClass() instancesRespondToSelector:@selector(_initWithWebKitPropertyListData:)]) {
auto unarchiver = adoptNS([[WKKeyedCoder alloc] initWithDictionary:m_propertyList.toID().get()]);
auto unarchiver = adoptNS([[WKKeyedCoder alloc] initWithDictionary:propertyList]);
return adoptNS([[PAL::getAVOutputContextClass() alloc] initWithCoder:unarchiver.get()]);
}
return adoptNS([[PAL::getAVOutputContextClass() alloc] _initWithWebKitPropertyListData:m_propertyList.toID().get()]);
return adoptNS([[PAL::getAVOutputContextClass() alloc] _initWithWebKitPropertyListData:propertyList]);
}
#endif // USE(AVFOUNDATION)

CoreIPCNSSomeFoundationType::CoreIPCNSSomeFoundationType(NSSomeFoundationType *object)
: m_propertyList([object _webKitPropertyListData])
CoreIPCNSSomeFoundationType::CoreIPCNSSomeFoundationType(
RetainPtr<NSString>&& StringKey,
RetainPtr<NSNumber>&& NumberKey,
RetainPtr<NSNumber>&& OptionalNumberKey,
RetainPtr<NSArray>&& ArrayKey,
RetainPtr<NSArray>&& OptionalArrayKey,
RetainPtr<NSDictionary>&& DictionaryKey,
RetainPtr<NSDictionary>&& OptionalDictionaryKey
)
: m_StringKey(WTFMove(StringKey))
, m_NumberKey(WTFMove(NumberKey))
, m_OptionalNumberKey(WTFMove(OptionalNumberKey))
, m_ArrayKey(WTFMove(ArrayKey))
, m_OptionalArrayKey(WTFMove(OptionalArrayKey))
, m_DictionaryKey(WTFMove(DictionaryKey))
, m_OptionalDictionaryKey(WTFMove(OptionalDictionaryKey))
{
}

bool CoreIPCNSSomeFoundationType::isValidDictionary(CoreIPCDictionary& dictionary)
CoreIPCNSSomeFoundationType::CoreIPCNSSomeFoundationType(NSSomeFoundationType *object)
{
if (!dictionary.keyHasValueOfType("StringKey"_s, IPC::NSType::String))
return false;
auto dictionary = dictionaryForWebKitSecureCodingType(object);
m_StringKey = (NSString *)[dictionary objectForKey:@"StringKey"];
if (!m_StringKey || IPC::typeFromObject(m_StringKey.get()) != IPC::NSType::String) {
m_StringKey = nullptr;
}

if (!dictionary.keyHasValueOfType("NumberKey"_s, IPC::NSType::Number))
return false;
m_NumberKey = (NSNumber *)[dictionary objectForKey:@"NumberKey"];
if (!m_NumberKey || IPC::typeFromObject(m_NumberKey.get()) != IPC::NSType::Number) {
m_NumberKey = nullptr;
}

if (!dictionary.keyIsMissingOrHasValueOfType("OptionalNumberKey"_s, IPC::NSType::Number))
return false;
m_OptionalNumberKey = (NSNumber *)[dictionary objectForKey:@"OptionalNumberKey"];
if (m_OptionalNumberKey && IPC::typeFromObject(m_OptionalNumberKey.get()) != IPC::NSType::Number) {
m_OptionalNumberKey = nullptr;
}

if (!dictionary.keyHasValueOfType("ArrayKey"_s, IPC::NSType::Array))
return false;
m_ArrayKey = (NSArray *)[dictionary objectForKey:@"ArrayKey"];
if (!m_ArrayKey || IPC::typeFromObject(m_ArrayKey.get()) != IPC::NSType::Array) {
m_ArrayKey = nullptr;
}

if (!dictionary.keyIsMissingOrHasValueOfType("OptionalArrayKey"_s, IPC::NSType::Array))
return false;
m_OptionalArrayKey = (NSArray *)[dictionary objectForKey:@"OptionalArrayKey"];
if (m_OptionalArrayKey && IPC::typeFromObject(m_OptionalArrayKey.get()) != IPC::NSType::Array) {
m_OptionalArrayKey = nullptr;
}

if (!dictionary.keyHasValueOfType("DictionaryKey"_s, IPC::NSType::Dictionary))
return false;
m_DictionaryKey = (NSDictionary *)[dictionary objectForKey:@"DictionaryKey"];
if (!m_DictionaryKey || IPC::typeFromObject(m_DictionaryKey.get()) != IPC::NSType::Dictionary) {
m_DictionaryKey = nullptr;
}

if (!dictionary.keyIsMissingOrHasValueOfType("OptionalDictionaryKey"_s, IPC::NSType::Dictionary))
return false;
m_OptionalDictionaryKey = (NSDictionary *)[dictionary objectForKey:@"OptionalDictionaryKey"];
if (m_OptionalDictionaryKey && IPC::typeFromObject(m_OptionalDictionaryKey.get()) != IPC::NSType::Dictionary) {
m_OptionalDictionaryKey = nullptr;
}

return true;
}

RetainPtr<id> CoreIPCNSSomeFoundationType::toID() const
{
auto propertyList = [NSMutableDictionary dictionaryWithCapacity:7];
if (m_StringKey)
propertyList[@"StringKey"] = m_StringKey.get();
if (m_NumberKey)
propertyList[@"NumberKey"] = m_NumberKey.get();
if (m_OptionalNumberKey)
propertyList[@"OptionalNumberKey"] = m_OptionalNumberKey.get();
if (m_ArrayKey)
propertyList[@"ArrayKey"] = m_ArrayKey.get();
if (m_OptionalArrayKey)
propertyList[@"OptionalArrayKey"] = m_OptionalArrayKey.get();
if (m_DictionaryKey)
propertyList[@"DictionaryKey"] = m_DictionaryKey.get();
if (m_OptionalDictionaryKey)
propertyList[@"OptionalDictionaryKey"] = m_OptionalDictionaryKey.get();
RELEASE_ASSERT([NSSomeFoundationType instancesRespondToSelector:@selector(_initWithWebKitPropertyListData:)]);
return adoptNS([[NSSomeFoundationType alloc] _initWithWebKitPropertyListData:m_propertyList.toID().get()]);
return adoptNS([[NSSomeFoundationType alloc] _initWithWebKitPropertyListData:propertyList]);
}

#if ENABLE(DATA_DETECTION)
CoreIPCDDScannerResult::CoreIPCDDScannerResult(DDScannerResult *object)
: m_propertyList([object _webKitPropertyListData])
CoreIPCDDScannerResult::CoreIPCDDScannerResult(
RetainPtr<NSString>&& StringKey,
RetainPtr<NSNumber>&& NumberKey,
RetainPtr<NSNumber>&& OptionalNumberKey,
Vector<RetainPtr<DDScannerResult>>&& ArrayKey,
std::optional<Vector<RetainPtr<DDScannerResult>>>&& OptionalArrayKey,
Vector<std::pair<String, RetainPtr<Number>>>&& DictionaryKey,
std::optional<Vector<std::pair<String, RetainPtr<DDScannerResult>>>>&& OptionalDictionaryKey,
Vector<RetainPtr<NSData>>&& DataArrayKey,
Vector<RetainPtr<SecTrustRef>>&& SecTrustArrayKey
)
: m_StringKey(WTFMove(StringKey))
, m_NumberKey(WTFMove(NumberKey))
, m_OptionalNumberKey(WTFMove(OptionalNumberKey))
, m_ArrayKey(WTFMove(ArrayKey))
, m_OptionalArrayKey(WTFMove(OptionalArrayKey))
, m_DictionaryKey(WTFMove(DictionaryKey))
, m_OptionalDictionaryKey(WTFMove(OptionalDictionaryKey))
, m_DataArrayKey(WTFMove(DataArrayKey))
, m_SecTrustArrayKey(WTFMove(SecTrustArrayKey))
{
}

bool CoreIPCDDScannerResult::isValidDictionary(CoreIPCDictionary& dictionary)
CoreIPCDDScannerResult::CoreIPCDDScannerResult(DDScannerResult *object)
{
if (!dictionary.keyHasValueOfType("StringKey"_s, IPC::NSType::String))
return false;

if (!dictionary.keyHasValueOfType("NumberKey"_s, IPC::NSType::Number))
return false;

if (!dictionary.keyIsMissingOrHasValueOfType("OptionalNumberKey"_s, IPC::NSType::Number))
return false;

if (!dictionary.keyHasValueOfType("ArrayKey"_s, IPC::NSType::Array))
return false;
if (!dictionary.collectionValuesAreOfType("ArrayKey"_s, IPC::NSType::DDScannerResult))
return false;

if (!dictionary.keyIsMissingOrHasValueOfType("OptionalArrayKey"_s, IPC::NSType::Array))
return false;
if (!dictionary.collectionValuesAreOfType("OptionalArrayKey"_s, IPC::NSType::DDScannerResult))
return false;
auto dictionary = dictionaryForWebKitSecureCodingType(object);
m_StringKey = (NSString *)[dictionary objectForKey:@"StringKey"];
if (!m_StringKey || IPC::typeFromObject(m_StringKey.get()) != IPC::NSType::String) {
m_StringKey = nullptr;
}

if (!dictionary.keyHasValueOfType("DictionaryKey"_s, IPC::NSType::Dictionary))
return false;
if (!dictionary.collectionValuesAreOfType("DictionaryKey"_s, IPC::NSType::String, IPC::NSType::Number))
return false;
m_NumberKey = (NSNumber *)[dictionary objectForKey:@"NumberKey"];
if (!m_NumberKey || IPC::typeFromObject(m_NumberKey.get()) != IPC::NSType::Number) {
m_NumberKey = nullptr;
}

if (!dictionary.keyIsMissingOrHasValueOfType("OptionalDictionaryKey"_s, IPC::NSType::Dictionary))
return false;
if (!dictionary.collectionValuesAreOfType("OptionalDictionaryKey"_s, IPC::NSType::String, IPC::NSType::DDScannerResult))
return false;
m_OptionalNumberKey = (NSNumber *)[dictionary objectForKey:@"OptionalNumberKey"];
if (m_OptionalNumberKey && IPC::typeFromObject(m_OptionalNumberKey.get()) != IPC::NSType::Number) {
m_OptionalNumberKey = nullptr;
}

return true;
m_ArrayKey = vectorFromArray<DDScannerResult>((NSArray *)[dictionary objectForKey:@"ArrayKey"]);
m_OptionalArrayKey = optionalVectorFromArray<DDScannerResult>((NSArray *)[dictionary objectForKey:@"OptionalArrayKey"]);
m_DictionaryKey = vectorFromDictionary<Number>((NSDictionary *)[dictionary objectForKey:@"DictionaryKey"]);
m_OptionalDictionaryKey = optionalVectorFromDictionary<DDScannerResult>((NSDictionary *)[dictionary objectForKey:@"OptionalDictionaryKey"]);
m_DataArrayKey = vectorFromArray<NSData>((NSArray *)[dictionary objectForKey:@"DataArrayKey"]);
m_SecTrustArrayKey = vectorFromArray<SecTrustRef>((NSArray *)[dictionary objectForKey:@"SecTrustArrayKey"]);
}

RetainPtr<id> CoreIPCDDScannerResult::toID() const
{
auto propertyList = [NSMutableDictionary dictionaryWithCapacity:9];
if (m_StringKey)
propertyList[@"StringKey"] = m_StringKey.get();
if (m_NumberKey)
propertyList[@"NumberKey"] = m_NumberKey.get();
if (m_OptionalNumberKey)
propertyList[@"OptionalNumberKey"] = m_OptionalNumberKey.get();
propertyList[@"ArrayKey"] = arrayFromVector(m_ArrayKey).get();
if (auto array = arrayFromOptionalVector(m_OptionalArrayKey))
propertyList[@"OptionalArrayKey"] = array.get();
propertyList[@"DictionaryKey"] = dictionaryFromVector(m_DictionaryKey).get();
if (auto dictionary = dictionaryFromOptionalVector(m_OptionalDictionaryKey))
propertyList[@"OptionalDictionaryKey"] = dictionary.get();
propertyList[@"DataArrayKey"] = arrayFromVector(m_DataArrayKey).get();
propertyList[@"SecTrustArrayKey"] = arrayFromVector(m_SecTrustArrayKey).get();
RELEASE_ASSERT([PAL::getDDScannerResultClass() instancesRespondToSelector:@selector(_initWithWebKitPropertyListData:)]);
return adoptNS([[PAL::getDDScannerResultClass() alloc] _initWithWebKitPropertyListData:m_propertyList.toID().get()]);
return adoptNS([[PAL::getDDScannerResultClass() alloc] _initWithWebKitPropertyListData:propertyList]);
}
#endif // ENABLE(DATA_DETECTION)

Expand Down
Loading

0 comments on commit dc84002

Please sign in to comment.