@@ -37,6 +37,13 @@ static const ProtocolDescriptor *getComparableDescriptor() {
37
37
return descriptor;
38
38
}
39
39
40
+ static const ProtocolDescriptor *getHashableDescriptor () {
41
+ auto descriptor = SWIFT_LAZY_CONSTANT (
42
+ reinterpret_cast <const ProtocolDescriptor *>(
43
+ dlsym (RTLD_DEFAULT, " $sSHMp" )));
44
+ return descriptor;
45
+ }
46
+
40
47
static const WitnessTable *conformsToProtocol (const Metadata *type,
41
48
const ProtocolDescriptor *protocol) {
42
49
using Fn = const WitnessTable *(const Metadata *, const ProtocolDescriptor *);
@@ -449,3 +456,130 @@ bool swift::_swift_tupleComparable_greaterThan(OpaqueValue *tuple1,
449
456
// each other.
450
457
return false ;
451
458
}
459
+
460
+ // ===----------------------------------------------------------------------===//
461
+ // Tuple Hashable Conformance
462
+ // ===----------------------------------------------------------------------===//
463
+
464
+ #define TUPLE_HASHABLE_WT SYMBOL (" _swift_tupleHashable_wt" )
465
+
466
+ // Define the conformance descriptor for tuple Hashable. We do this in
467
+ // assembly to work around relative reference issues.
468
+ __asm(
469
+ " .section __DATA,__data\n "
470
+ " .globl " TUPLE_HASHABLE_CONF " \n "
471
+ " .p2align 2\n "
472
+ TUPLE_HASHABLE_CONF " :\n "
473
+ // This is an indirectable relative reference to the Hashable protocol
474
+ // descriptor. However, this is 0 here because the compatibility libraries
475
+ // can't have a dependency on libswiftCore (which is where Hashable lives).
476
+ " .long 0\n "
477
+ // 769 is the MetadataKind::Tuple
478
+ " .long 769\n "
479
+ // This is a direct relative reference to the witness table defined below.
480
+ " .long ((" TUPLE_HASHABLE_WT " ) - (" TUPLE_HASHABLE_CONF " )) - 8\n "
481
+ // 32 are the ConformanceFlags with the type reference bit set to MetadataKind.
482
+ " .long 32\n "
483
+ );
484
+
485
+ extern const ProtocolConformanceDescriptor _swift_tupleHashable_conf;
486
+
487
+ // Due to the fact that the compatibility libraries can't have a hard
488
+ // dependency to libswiftCore (which is where the Hashable protocol desciptor
489
+ // lives), we have to manually implant this before calling any user code.
490
+ __attribute__ ((constructor))
491
+ void _emplaceTupleHashableDescriptor() {
492
+ auto tupleHashableConf = const_cast <int32_t *>(
493
+ reinterpret_cast <const int32_t *>(&_swift_tupleHashable_conf));
494
+ auto hashable = getHashableDescriptor ();
495
+
496
+ // This is an indirectable pointer.
497
+ *tupleHashableConf = intptr_t (hashable) - intptr_t (tupleHashableConf);
498
+ }
499
+
500
+ // The base Equatable protocol is itself a requirement, thus the requirement
501
+ // count is 4 (Equatable + hashValue + hash(into:) + _rawHashValue) and the
502
+ // witness is the tuple Equatable table.
503
+ SWIFT_RUNTIME_EXPORT
504
+ _WitnessTable<4 > _swift_tupleHashable_wt = {
505
+ &_swift_tupleHashable_conf,
506
+ {
507
+ reinterpret_cast <const void *>(&_swift_tupleEquatable_wt),
508
+ reinterpret_cast <void *>(_swift_tupleHashable_hashValue),
509
+ reinterpret_cast <void *>(_swift_tupleHashable_hash),
510
+ nullptr
511
+ }
512
+ };
513
+
514
+ static void *get_rawHashValueDefaultImplFunc () {
515
+ auto impl = SWIFT_LAZY_CONSTANT (
516
+ dlsym (RTLD_DEFAULT, " $sSHsE13_rawHashValue4seedS2i_tF" ));
517
+ return impl;
518
+ }
519
+
520
+ // Due to the fact that the compatibility libraries can't have a hard
521
+ // dependency to libswiftCore (which is where the _rawHashValue default impl
522
+ // lives), we have to manually implant this before calling any user code.
523
+ __attribute__ ((constructor))
524
+ void _emplaceTupleHashable_rawHashValueDefaultImpl() {
525
+ _swift_tupleHashable_wt.Witnesses [3 ] = get_rawHashValueDefaultImplFunc ();
526
+ }
527
+
528
+ using HashValueFn = SWIFT_CC(swift) intptr_t (OpaqueValue *value, Metadata *Self,
529
+ void *witnessTable);
530
+ using HasherCombineFn = SWIFT_CC(swift) void (OpaqueValue *value,
531
+ const Metadata *Self,
532
+ const WitnessTable *witnessTable,
533
+ SWIFT_CONTEXT OpaqueValue *hasher);
534
+
535
+ static HashValueFn *get_hashValueFunc () {
536
+ auto descriptor = SWIFT_LAZY_CONSTANT (
537
+ reinterpret_cast <HashValueFn *>(
538
+ dlsym (RTLD_DEFAULT, STR (SWIFT_HASHVALUE_FUNC))));
539
+ return descriptor;
540
+ }
541
+
542
+ static HasherCombineFn *getHashCombineFunc () {
543
+ auto descriptor = SWIFT_LAZY_CONSTANT (
544
+ reinterpret_cast <HasherCombineFn *>(
545
+ dlsym (RTLD_DEFAULT, STR (SWIFT_HASHER_COMBINE_FUNC))));
546
+ return descriptor;
547
+ }
548
+
549
+ SWIFT_RUNTIME_EXPORT SWIFT_CC (swift)
550
+ intptr_t swift::_swift_tupleHashable_hashValue(SWIFT_CONTEXT OpaqueValue *tuple,
551
+ Metadata *Self, void *witnessTable) {
552
+ auto _hashValue = get_hashValueFunc ();
553
+ return _hashValue (tuple, Self, witnessTable);
554
+ }
555
+
556
+ SWIFT_RUNTIME_EXPORT SWIFT_CC (swift)
557
+ void swift::_swift_tupleHashable_hash(OpaqueValue *hasher,
558
+ SWIFT_CONTEXT OpaqueValue *tuple,
559
+ Metadata *Self, void *witnessTable) {
560
+ auto tupleTy = cast<TupleTypeMetadata>(Self);
561
+
562
+ // Loop through all elements and hash them into the Hasher.
563
+ for (size_t i = 0 ; i != tupleTy->NumElements ; i += 1 ) {
564
+ auto elt = tupleTy->getElement (i);
565
+
566
+ // Ensure we actually have a conformance to Hashable for this element type.
567
+ auto hashable = getHashableDescriptor ();
568
+ auto conformance = conformsToProtocol (elt.Type , hashable);
569
+
570
+ // If we don't have a conformance then something somewhere messed up in
571
+ // deciding that this tuple type was Hashable...??
572
+ if (!conformance)
573
+ swift_unreachable (" Tuple hasing requires that all elements be Hashable." );
574
+
575
+ // Get the element value from the tuple.
576
+ auto value = reinterpret_cast <OpaqueValue *>(
577
+ reinterpret_cast <char *>(tuple) + elt.Offset );
578
+
579
+ auto hasherCombine = getHashCombineFunc ();
580
+
581
+ // Call the combine function on the hasher for this element value and we're
582
+ // done!
583
+ hasherCombine (value, elt.Type , conformance, hasher);
584
+ }
585
+ }
0 commit comments