From ca23830127a2123100e52e644302e23143d8369a Mon Sep 17 00:00:00 2001 From: JustOff Date: Wed, 13 Mar 2019 20:19:53 +0200 Subject: Implement the spec provision for handling repeated keys in records by updating the existing value --- dom/bindings/Codegen.py | 44 +++++++++++++++++++++++++++++++++++--------- dom/bindings/Record.h | 11 +++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 4e6248e49..e32d16a48 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -4791,13 +4791,16 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, }) keyType = recordKeyType(recordType) - if recordType.keyType.isDOMString(): - keyConversionFunction = "ConvertJSValueToString" - elif recordType.keyType.isUSVString(): - keyConversionFunction = "ConvertJSValueToUSVString" - else: - assert recordType.keyType.isByteString() + if recordType.keyType.isByteString(): keyConversionFunction = "ConvertJSValueToByteString" + hashKeyType = "nsCStringHashKey" + else: + hashKeyType = "nsStringHashKey" + if recordType.keyType.isDOMString(): + keyConversionFunction = "ConvertJSValueToString" + else: + assert recordType.keyType.isUSVString() + keyConversionFunction = "ConvertJSValueToUSVString" templateBody = fill( """ @@ -4819,6 +4822,12 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, JS::Rooted temp(cx); JS::Rooted curId(cx); JS::Rooted idVal(cx); + // Use a hashset to keep track of ids seen, to avoid + // introducing nasty O(N^2) behavior scanning for them all the + // time. Ideally we'd use a data structure with O(1) lookup + // _and_ ordering for the MozMap, but we don't have one lying + // around. + nsTHashtable<${hashKeyType}> idsSeen; for (size_t i = 0; i < ids.length(); ++i) { curId = ids[i]; @@ -4845,9 +4854,25 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, $*{exceptionCode} } - // Safe to do an infallible append here, because we did a - // SetCapacity above to the right capacity. - ${typeName}::EntryType* entry = recordEntries.AppendElement(); + ${typeName}::EntryType* entry; + if (idsSeen.Contains(propName)) { + // Find the existing entry. + auto idx = recordEntries.IndexOf(propName); + MOZ_ASSERT(idx != recordEntries.NoIndex, + "Why is it not found?"); + // Now blow it away to make it look like it was just added + // to the array, because it's not obvious that it's + // safe to write to its already-initialized mValue via our + // normal codegen conversions. For example, the value + // could be a union and this would change its type, but + // codegen assumes we won't do that. + entry = recordEntries.ReconstructElementAt(idx); + } else { + // Safe to do an infallible append here, because we did a + // SetCapacity above to the right capacity. + entry = recordEntries.AppendElement(); + idsSeen.PutEntry(propName); + } entry->mKey = propName; ${valueType}& slot = entry->mValue; $*{valueConversion} @@ -4855,6 +4880,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, """, exceptionCode=exceptionCode, recordRef=recordRef, + hashKeyType=hashKeyType, keyType=keyType, keyConversionFunction=keyConversionFunction, typeName=typeName, diff --git a/dom/bindings/Record.h b/dom/bindings/Record.h index b7f7b01b0..d6ab31699 100644 --- a/dom/bindings/Record.h +++ b/dom/bindings/Record.h @@ -77,4 +77,15 @@ private: } // namespace dom } // namespace mozilla +template +class nsDefaultComparator, K> +{ +public: + bool Equals(const mozilla::dom::binding_detail::RecordEntry& aEntry, + const K& aKey) const + { + return aEntry.mKey == aKey; + } +}; + #endif // mozilla_dom_Record_h -- cgit v1.2.3