Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use SipHash-1-3 for all hashing, through a resilient hashing interface #14913

Merged
merged 5 commits into from
Mar 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3593,8 +3593,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,

SILValue hashCode;

// TODO: Combine hashes of the indexes. There isn't a great hash combining
// interface in the standard library to do this yet.
// TODO: Combine hashes of the indexes using an inout _Hasher
{
auto &index = indexes[0];

Expand Down
10 changes: 10 additions & 0 deletions stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,15 @@ struct PersistentState {
static var runNoTestsWasCalled: Bool = false
static var ranSomething: Bool = false
static var complaintInstalled = false
static var hashingKeyOverridden = false

static func overrideHashingKey() {
if !hashingKeyOverridden {
// FIXME(hasher): This has to run before creating the first Set/Dictionary
_Hasher._secretKey = (0, 0)
hashingKeyOverridden = true
}
}

static func complainIfNothingRuns() {
if !complaintInstalled {
Expand Down Expand Up @@ -1200,6 +1209,7 @@ func stopTrackingObjects(_: UnsafePointer<CChar>) -> Int

public final class TestSuite {
public init(_ name: String) {
PersistentState.overrideHashingKey()
self.name = name
_precondition(
_testNameToIndex[name] == nil,
Expand Down
12 changes: 12 additions & 0 deletions stdlib/public/core/AnyHashable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ internal protocol _AnyHashableBox {
/// no comparison is possible. Otherwise, contains the result of `==`.
func _isEqual(to: _AnyHashableBox) -> Bool?
var _hashValue: Int { get }
func _hash(_into hasher: inout _Hasher)

var _base: Any { get }
func _downCastConditional<T>(into result: UnsafeMutablePointer<T>) -> Bool
Expand Down Expand Up @@ -93,6 +94,12 @@ internal struct _ConcreteHashableBox<Base : Hashable> : _AnyHashableBox {
return _baseHashable.hashValue
}

@_inlineable // FIXME(sil-serialize-all)
@_versioned // FIXME(sil-serialize-all)
func _hash(_into hasher: inout _Hasher) {
_baseHashable._hash(into: &hasher)
}

@_inlineable // FIXME(sil-serialize-all)
@_versioned // FIXME(sil-serialize-all)
internal var _base: Any {
Expand Down Expand Up @@ -295,6 +302,11 @@ extension AnyHashable : Hashable {
public var hashValue: Int {
return _box._hashValue
}

@_inlineable // FIXME(sil-serialize-all)
public func _hash(into hasher: inout _Hasher) {
_box._hash(_into: &hasher)
}
}

extension AnyHashable : CustomStringConvertible {
Expand Down
8 changes: 6 additions & 2 deletions stdlib/public/core/Bool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,13 @@ extension Bool : Equatable, Hashable {
/// invocations of the same program. Do not persist the hash value across
/// program runs.
@_inlineable // FIXME(sil-serialize-all)
@_transparent
public var hashValue: Int {
return self ? 1 : 0
return _hashValue(for: self)
}

@_inlineable // FIXME(sil-serialize-all)
public func _hash(into hasher: inout _Hasher) {
hasher.append((self ? 1 : 0) as UInt8)
}

@_inlineable // FIXME(sil-serialize-all)
Expand Down
7 changes: 6 additions & 1 deletion stdlib/public/core/CTypes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,12 @@ extension OpaquePointer: Hashable {
/// program runs.
@_inlineable // FIXME(sil-serialize-all)
public var hashValue: Int {
return Int(Builtin.ptrtoint_Word(_rawValue))
return _hashValue(for: self)
}

@_inlineable // FIXME(sil-serialize-all)
public func _hash(into hasher: inout _Hasher) {
hasher.append(Int(Builtin.ptrtoint_Word(_rawValue)))
}
}

Expand Down
11 changes: 7 additions & 4 deletions stdlib/public/core/DoubleWidth.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,13 @@ extension DoubleWidth : Comparable {
extension DoubleWidth : Hashable {
@_inlineable // FIXME(sil-serialize-all)
public var hashValue: Int {
var result = 0
result = _combineHashValues(result, _storage.high.hashValue)
result = _combineHashValues(result, _storage.low.hashValue)
return result
return _hashValue(for: self)
}

@_inlineable // FIXME(sil-serialize-all)
public func _hash(into hasher: inout _Hasher) {
hasher.append(low)
hasher.append(high)
}
}

Expand Down
4 changes: 4 additions & 0 deletions stdlib/public/core/DropWhile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ extension LazyDropWhileCollection.Index: Hashable where Base.Index: Hashable {
public var hashValue: Int {
return base.hashValue
}

public func _hash(into hasher: inout _Hasher) {
hasher.append(base)
}
}

extension LazyDropWhileCollection: Collection {
Expand Down
9 changes: 8 additions & 1 deletion stdlib/public/core/Flatten.swift
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,14 @@ extension FlattenCollection.Index : Comparable {
extension FlattenCollection.Index : Hashable
where Base.Index : Hashable, Base.Element.Index : Hashable {
public var hashValue: Int {
return _combineHashValues(_inner?.hashValue ?? 0, _outer.hashValue)
return _hashValue(for: self)
}

public func _hash(into hasher: inout _Hasher) {
hasher.append(_outer)
if let inner = _inner {
hasher.append(inner)
}
}
}

Expand Down
29 changes: 14 additions & 15 deletions stdlib/public/core/FloatingPointTypes.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -1524,26 +1524,25 @@ extension ${Self} : Hashable {
/// your program. Do not save hash values to use during a future execution.
@_inlineable // FIXME(sil-serialize-all)
public var hashValue: Int {
return _hashValue(for: self)
}

@_inlineable // FIXME(sil-serialize-all)
public func _hash(into hasher: inout _Hasher) {
var v = self
if isZero {
// To satisfy the axiom that equality implies hash equality, we need to
// finesse the hash value of -0.0 to match +0.0.
return 0
} else {
%if bits <= word_bits:
return Int(bitPattern: UInt(bitPattern))
%elif bits == 64: # Double -> 32-bit Int
return Int(truncatingIfNeeded: bitPattern &>> 32) ^
Int(truncatingIfNeeded: bitPattern)
%elif word_bits == 32: # Float80 -> 32-bit Int
return Int(truncatingIfNeeded: significandBitPattern &>> 32) ^
Int(truncatingIfNeeded: significandBitPattern) ^
Int(_representation.signAndExponent)
%else: # Float80 -> 64-bit Int
return Int(bitPattern: UInt(significandBitPattern)) ^
Int(_representation.signAndExponent)
%end
v = 0
}
%if bits == 80:
hasher.append(v._representation.signAndExponent)
hasher.append(v.significandBitPattern)
%else:
hasher.append(v.bitPattern)
%end
}

}

extension ${Self} {
Expand Down
19 changes: 18 additions & 1 deletion stdlib/public/core/Hashable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,24 @@ public protocol Hashable : Equatable {
/// Hash values are not guaranteed to be equal across different executions of
/// your program. Do not save hash values to use during a future execution.
var hashValue: Int { get }

/// Feed bits to be hashed into the hash function represented by `hasher`.
func _hash(into hasher: inout _Hasher)
}

extension Hashable {
@inline(__always)
public func _hash(into hasher: inout _Hasher) {
hasher.append(self.hashValue)
}
}

// Called by synthesized `hashValue` implementations.
@inline(__always)
public func _hashValue<H: Hashable>(for value: H) -> Int {
var hasher = _Hasher()
hasher.append(value)
return hasher.finalize()
}

// Called by the SwiftValue implementation.
Expand All @@ -126,4 +144,3 @@ internal func Hashable_hashValue_indirect<T : Hashable>(
) -> Int {
return value.pointee.hashValue
}

13 changes: 9 additions & 4 deletions stdlib/public/core/HashedCollections.swift.gyb
Original file line number Diff line number Diff line change
Expand Up @@ -792,11 +792,16 @@ extension Set : Hashable {
@_inlineable // FIXME(sil-serialize-all)
public var hashValue: Int {
// FIXME(ABI)#177: <rdar://problem/18915294> Cache Set<T> hashValue
var result: Int = _mixInt(0)
return _hashValue(for: self)
}

@_inlineable // FIXME(sil-serialize-all)
public func _hash(into hasher: inout _Hasher) {
var hash = 0
for member in self {
result ^= _mixInt(member.hashValue)
hash ^= _hashValue(for: member)
}
return result
hasher.append(hash)
}
}

Expand Down Expand Up @@ -3985,7 +3990,7 @@ extension _Native${Self}Buffer
@_versioned
@inline(__always) // For performance reasons.
internal func _bucket(_ k: Key) -> Int {
return _squeezeHashValue(k.hashValue, bucketCount)
return _hashValue(for: k) & _bucketMask
}

@_inlineable // FIXME(sil-serialize-all)
Expand Down
Loading