@@ -608,3 +608,203 @@ bool swift::_swift_tupleComparable_greaterThan(OpaqueValue *tuple1,
608
608
// each other.
609
609
return false ;
610
610
}
611
+
612
+ // ===----------------------------------------------------------------------===//
613
+ // Tuple Hashable Conformance
614
+ // ===----------------------------------------------------------------------===//
615
+
616
+ #if defined(__ELF__)
617
+ // Create a GOT equivalent for the Hashable reference.
618
+ __asm (
619
+ " .type got." HASHABLE_DESCRIPTOR_SYMBOL " , @object\n "
620
+ " .section .data.rel.ro\n "
621
+ " .p2align 3\n "
622
+ " got." HASHABLE_DESCRIPTOR_SYMBOL " :\n "
623
+ " .quad (" HASHABLE_DESCRIPTOR_SYMBOL " )\n "
624
+ " .size got." HASHABLE_DESCRIPTOR_SYMBOL " , 8\n "
625
+ );
626
+
627
+ // Create a GOT equivalent for the Hashable base conformance to Equatable.
628
+ __asm (
629
+ " .type got." HASHABLE_BASE_CONFORMANCE_DESCRIPTOR " , @object\n "
630
+ " .p2align 3\n "
631
+ " got." HASHABLE_BASE_CONFORMANCE_DESCRIPTOR " :\n "
632
+ " .quad (" HASHABLE_BASE_CONFORMANCE_DESCRIPTOR " )\n "
633
+ " .size got." HASHABLE_BASE_CONFORMANCE_DESCRIPTOR " , 8\n "
634
+ );
635
+
636
+ // Create a GOT equivalent for the Hashable.hashValue method descriptor.
637
+ __asm (
638
+ " .type got." HASHABLE_HASHVALUE_METHOD_DESCRIPTOR " , @object\n "
639
+ " .p2align 3\n "
640
+ " got." HASHABLE_HASHVALUE_METHOD_DESCRIPTOR " :\n "
641
+ " .quad (" HASHABLE_HASHVALUE_METHOD_DESCRIPTOR " )\n "
642
+ " .size got." HASHABLE_HASHVALUE_METHOD_DESCRIPTOR " , 8\n "
643
+ );
644
+
645
+ // Create a GOT equivalent for the Hashable.hash(into:) method descriptor.
646
+ __asm (
647
+ " .type got." HASHABLE_HASH_METHOD_DESCRIPTOR " , @object\n "
648
+ " .p2align 3\n "
649
+ " got." HASHABLE_HASH_METHOD_DESCRIPTOR " :\n "
650
+ " .quad (" HASHABLE_HASH_METHOD_DESCRIPTOR " )\n "
651
+ " .size got." HASHABLE_HASH_METHOD_DESCRIPTOR " , 8\n "
652
+ );
653
+
654
+ // Create a GOT equivalent for the Hashable._rawHashValue method descriptor.
655
+ __asm (
656
+ " .type got." HASHABLE_RAWHASHVALUE_METHOD_DESCRIPTOR " , @object\n "
657
+ " .p2align 3\n "
658
+ " got." HASHABLE_RAWHASHVALUE_METHOD_DESCRIPTOR " :\n "
659
+ " .quad (" HASHABLE_RAWHASHVALUE_METHOD_DESCRIPTOR " )\n "
660
+ " .size got." HASHABLE_RAWHASHVALUE_METHOD_DESCRIPTOR " , 8\n "
661
+ );
662
+ #endif
663
+
664
+ // Define the conformance descriptor for tuple Hashable. We do this in
665
+ // assembly to work around relative reference issues.
666
+ __asm (
667
+ #if defined(__ELF__)
668
+ " .type __swift_tupleHashable_private, @object\n "
669
+ " .local __swift_tupleHashable_private\n "
670
+ " .comm __swift_tupleHashable_private, 128, 16\n "
671
+ " .protected " TUPLE_HASHABLE_CONF " \n "
672
+ " .type " TUPLE_HASHABLE_CONF " , @object\n "
673
+ " .section .rodata\n "
674
+ #elif defined(__MACH__)
675
+ " .zerofill __DATA, __bss, __swift_tupleHashable_private, 128, 4\n "
676
+ " .section __TEXT, __const\n "
677
+ #endif
678
+ " .globl " TUPLE_HASHABLE_CONF " \n "
679
+ " .p2align 2\n "
680
+ TUPLE_HASHABLE_CONF " :\n "
681
+ #if defined(__ELF__)
682
+ // This is an indirectable relative reference to the GOT equivalent for the
683
+ // Hashable protocol descriptor, hence why we add 1 to indicate indirect.
684
+ " .long (got." HASHABLE_DESCRIPTOR_SYMBOL " - \
685
+ (" TUPLE_HASHABLE_CONF " )) + 1\n "
686
+ #elif defined(__MACH__)
687
+ " .long " HASHABLE_DESCRIPTOR_SYMBOL " @GOTPCREL + 5\n "
688
+ #endif
689
+ // 769 is the MetadataKind::Tuple
690
+ " .long 769\n "
691
+ // This indicates that we have no witness table pattern. We use a generic
692
+ // witness table for builtin conformances.
693
+ " .long 0\n "
694
+ // 196640 are the ConformanceFlags with the type reference bit set to
695
+ // MetadataKind, the has resilient witness bit, and the generic witness table
696
+ // bit.
697
+ " .long 196640\n "
698
+ // This 4 is the ResilientWitnessesHeader indicating we have 4 resilient
699
+ // witnesses.
700
+ " .long 4\n "
701
+ #if defined(__ELF__)
702
+ // This is an indirectable relative reference to the GOT equivalent for the
703
+ // Hashable base conformance for Equatable, hence why we add 1 to indicate
704
+ // indirect.
705
+ " .long ((got." HASHABLE_BASE_CONFORMANCE_DESCRIPTOR " - \
706
+ (" TUPLE_HASHABLE_CONF " )) - 20) + 1\n "
707
+ #elif defined(__MACH__)
708
+ " .long " HASHABLE_BASE_CONFORMANCE_DESCRIPTOR " @GOTPCREL + 5\n "
709
+ #endif
710
+ // This is a direct relative reference to the associated conformance for
711
+ // Equatable defined above in assembly. NOTE: We intentionally use the
712
+ // Comparable implementation for this because the implementation is the same
713
+ // for both Hashable and Comparable. Both want to grab the Equatable table
714
+ // from its elements whose witness table is located in the same place for both
715
+ // protocols. NOTE: This is minus 23 because the associated conformance
716
+ // structure is 1 aligned.
717
+ " .long ((\" " TUPLE_COMPARABLE_ASSOCIATEDCONFORMANCE " \" ) - \
718
+ (" TUPLE_HASHABLE_CONF " )) - 23\n "
719
+ #if defined(__ELF__)
720
+ // This is an indirectable relative reference to the GOT equivalent for the
721
+ // Hashable.hashValue method descriptor, hence why we add 1 to indicate
722
+ // indirect.
723
+ " .long ((got." HASHABLE_HASHVALUE_METHOD_DESCRIPTOR " - \
724
+ (" TUPLE_HASHABLE_CONF " )) - 28) + 1\n "
725
+ #elif defined(__MACH__)
726
+ " .long " HASHABLE_HASHVALUE_METHOD_DESCRIPTOR " @GOTPCREL + 5\n "
727
+ #endif
728
+ // This is a direct relative reference to the hashValue witness defined below.
729
+ " .long ((" TUPLE_HASHABLE_HASHVALUE " ) - (" TUPLE_HASHABLE_CONF " )) - 32\n "
730
+ #if defined(__ELF__)
731
+ // This is an indirectable relative reference to the GOT equivalent for the
732
+ // Hashable.hash(into:) method descriptor, hence why we add 1 to indicate
733
+ // indirect.
734
+ " .long ((got." HASHABLE_HASH_METHOD_DESCRIPTOR " - \
735
+ (" TUPLE_HASHABLE_CONF " )) - 36) + 1\n "
736
+ #elif defined(__MACH__)
737
+ " .long " HASHABLE_HASH_METHOD_DESCRIPTOR " @GOTPCREL + 5\n "
738
+ #endif
739
+ // This is a direct relative reference to the hash(into:) witness defined below.
740
+ " .long ((" TUPLE_HASHABLE_HASH " ) - (" TUPLE_HASHABLE_CONF " )) - 40\n "
741
+ #if defined(__ELF__)
742
+ // This is an indirectable relative reference to the GOT equivalent for the
743
+ // Hashable._rawHashValue method descriptor, hence why we add 1 to indicate
744
+ // indirect.
745
+ " .long ((got." HASHABLE_RAWHASHVALUE_METHOD_DESCRIPTOR " - \
746
+ (" TUPLE_HASHABLE_CONF " )) - 44) + 1\n "
747
+ #elif defined(__MACH__)
748
+ " .long " HASHABLE_RAWHASHVALUE_METHOD_DESCRIPTOR " @GOTPCREL + 5\n "
749
+ #endif
750
+ // This 0 indicates that we are requesting the default implementation for the
751
+ // _rawHashValue getter.
752
+ " .long 0\n "
753
+ // The witness table size in words.
754
+ " .short 0\n "
755
+ // The witness table private size in words & requires instantiation.
756
+ " .short 1\n "
757
+ // The witness table instantiator function.
758
+ " .long 0\n "
759
+ // This is a direct relative reference to the private data for the
760
+ // conformance.
761
+ " .long (__swift_tupleHashable_private - (" TUPLE_HASHABLE_CONF " )) - 60\n "
762
+ #if defined(__ELF__)
763
+ " .size " TUPLE_HASHABLE_CONF " , 64\n "
764
+ #endif
765
+ );
766
+
767
+ // These are all function values that we reinterpret later.
768
+ extern void *SWIFT_HASHVALUE_FUNC;
769
+ extern void *SWIFT_HASHER_COMBINE_FUNC;
770
+
771
+ using HashValueFn = SWIFT_CC(swift) intptr_t (OpaqueValue *value, Metadata *Self,
772
+ void *witnessTable);
773
+ using HasherCombineFn = SWIFT_CC(swift) void (OpaqueValue *value,
774
+ const Metadata *Self,
775
+ const WitnessTable *witnessTable,
776
+ SWIFT_CONTEXT OpaqueValue *hasher);
777
+
778
+ SWIFT_RUNTIME_EXPORT SWIFT_CC (swift)
779
+ intptr_t _swift_tupleHashable_hashValue(SWIFT_CONTEXT OpaqueValue *tuple,
780
+ Metadata *Self, void *witnessTable) {
781
+ auto _hashValue = reinterpret_cast <HashValueFn *>(&SWIFT_HASHVALUE_FUNC);
782
+ return _hashValue (tuple, Self, witnessTable);
783
+ }
784
+
785
+ SWIFT_RUNTIME_EXPORT SWIFT_CC (swift)
786
+ void _swift_tupleHashable_hash(OpaqueValue *hasher,
787
+ SWIFT_CONTEXT OpaqueValue *tuple,
788
+ Metadata *Self, void *witnessTable) {
789
+ auto tupleTy = cast<TupleTypeMetadata>(Self);
790
+ auto table = reinterpret_cast <void **>(witnessTable);
791
+
792
+ // Loop through all elements and hash them into the Hasher.
793
+ for (size_t i = 0 ; i != tupleTy->NumElements ; i += 1 ) {
794
+ auto elt = tupleTy->getElement (i);
795
+
796
+ // Get the element conformance from the private data in the witness table.
797
+ auto conformance = reinterpret_cast <const WitnessTable *>(table[-1 - i]);
798
+
799
+ // Get the element value from the tuple.
800
+ auto value = reinterpret_cast <OpaqueValue *>(
801
+ reinterpret_cast <char *>(tuple) + elt.Offset );
802
+
803
+ auto hasherCombine =
804
+ reinterpret_cast <HasherCombineFn *>(&SWIFT_HASHER_COMBINE_FUNC);
805
+
806
+ // Call the combine function on the hasher for this element value and we're
807
+ // done!
808
+ hasherCombine (value, elt.Type , conformance, hasher);
809
+ }
810
+ }
0 commit comments