summaryrefslogtreecommitdiffstats
path: root/dom/bindings
diff options
context:
space:
mode:
Diffstat (limited to 'dom/bindings')
-rw-r--r--dom/bindings/Codegen.py44
-rw-r--r--dom/bindings/Record.h11
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<JS::Value> temp(cx);
JS::Rooted<jsid> curId(cx);
JS::Rooted<JS::Value> 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<typename K, typename V>
+class nsDefaultComparator<mozilla::dom::binding_detail::RecordEntry<K, V>, K>
+{
+public:
+ bool Equals(const mozilla::dom::binding_detail::RecordEntry<K, V>& aEntry,
+ const K& aKey) const
+ {
+ return aEntry.mKey == aKey;
+ }
+};
+
#endif // mozilla_dom_Record_h