> On Sep 6, 2017, at 4:31 PM, Joe Groff <jgr...@apple.com> wrote:
> 
> 
>> On Sep 6, 2017, at 2:28 PM, Andrew Trick <atr...@apple.com> wrote:
>> 
>> 
>>>> On Sep 6, 2017, at 1:12 PM, Joe Groff via swift-evolution 
>>>> <swift-evolution@swift.org> wrote:
>>>> 
>>>> 
>>>> On Sep 6, 2017, at 1:06 PM, Taylor Swift <kelvin1...@gmail.com> wrote:
>>>> 
>>>> 
>>>> 
>>>>> On Wed, Sep 6, 2017 at 12:41 PM, Joe Groff via swift-evolution 
>>>>> <swift-evolution@swift.org> wrote:
>>>>> Currently, memory is deallocated by an instance method on 
>>>>> UnsafeMutablePointer, deallocate(count:). Like much of the Swift pointer 
>>>>> API, performing this operation on a buffer pointer requires extracting 
>>>>> baseAddress! and count. It is very common for the allocation code above 
>>>>> to be immediately followed by:
>>>>> 
>>>>> defer
>>>>> 
>>>>> {
>>>>>   buffer.
>>>>> baseAddress?.deallocate(capacity: buffer.count
>>>>> )
>>>>> }
>>>>> 
>>>>> This method is extremely problematic because nearly all users, on first 
>>>>> seeing the signature of deallocate(capacity:), will naturally conclude 
>>>>> from the capacity label that deallocate(capacity:) is equivalent to some 
>>>>> kind of realloc()that can only shrink the buffer. However this is not the 
>>>>> actual behavior — deallocate(capacity:) actually ignores the capacity 
>>>>> argument and just calls free() on self. The current API is not only 
>>>>> awkward and suboptimal, it is misleading. You can write perfectly legal 
>>>>> Swift code that shouldn’t segfault, but still can, for example
>>>>> 
>>>>> var ptr = UnsafeMutablePointer<UInt8>.allocate(capacity: 1000000
>>>>> )
>>>>> ptr.
>>>>> initialize(to: 13, count: 1000000
>>>>> )
>>>>> ptr.
>>>>> deallocate(capacity: 500000) // deallocate the second half of the memory 
>>>>> block
>>>>> ptr[0] // segmentation fault
>>>>> where the first 500000 addresses should still be valid if the 
>>>>> documentation is to be read literally.
>>>> 
>>>> The fact that the Swift runtime currently uses malloc/free is an 
>>>> implementation detail. Tracking deallocation size is a very useful 
>>>> optimization for better allocator backends, and C++ underwent an ABI break 
>>>> to make it so that sized delete can be supported. Maybe we can change the 
>>>> name to `deallocate(allocatedCapacity:)` to make it clear that it isn't 
>>>> resizing the memory, and/or make the capacity argument optional so that 
>>>> you can pay for the overhead of the allocator deriving the size if it's 
>>>> inconvenient for the calling code to carry the size around, but we 
>>>> shouldn't remove the functionality altogether.
>>>> 
>>>> -Joe
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution@swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>> 
>>>> The idea is to get the house in order by removing all parameters from 
>>>> deallocate(), since that’s what it really does right now. Then, in the 
>>>> future, if Swift gets a more sophisticated allocator backend, a new method 
>>>> like deallocate(capacity:) or reallocate(toCapacity:) could be added 
>>>> without conflicting with the currently named deallocate(capacity:). 
>>>> However, using the function signature to pretend that it does something it 
>>>> can’t actually do right now is extremely dangerous.
>>> 
>>> I don't think that's a good idea in this case, because it's not unlikely we 
>>> would explore an optimized allocator soon after ABI stability, and 
>>> retrofitting these interfaces in a future version of Swift would put a 
>>> deployment target limit on when they can be used, and mean that a lot of 
>>> user code would need to be retrofitted to carry allocated capacities where 
>>> needed to see any benefit.
>>> 
>>> -Joe
>> 
>> The fact that we’re using malloc and free is already part of the ABI because 
>> old libraries need to be able to deallocate memory allocated by newer 
>> libraries.
> 
> The compiler doesn't ever generate calls directly to malloc and free, and the 
> runtime entry points we do use already take size and alignment on both 
> allocation and deallocation.
> 
>> Within the standard library we could make use of some new deallocation fast 
>> path in the future without worrying about backward deployment.
>> 
>> Outside of the standard library, clients will get the benefits of whatever 
>> allocator is available on their deployed platform because we now encourage 
>> them to use UnsafeBufferPointer.deallocate(). We can change the 
>> implementation inside UnsafeBufferPointer all we want, as long as it’s still 
>> malloc-compatible.
>> 
>> I’m sure we’ll want to provide a better allocation/deallocation API in the 
>> future for systems programmers based on move-only types. That will already 
>> be deployment-limited.
>> 
>> Absolute worst case, we introduce a sized UnsafePointer.deallocate in the 
>> future. Any new code outside the stdlib that wants the performance advantage 
>> would either need to
>> - trivially wrap deallocation using UnsafeBufferPointer
>> - create a trivial UnsafePointer.deallocate thunk under an availability flag
> 
> Since we already have sized deallocate, why would we take it away? If the 
> name is misleading, we can change the name.
> 
> -Joe

Exactly, we are changing the name to `deallocate()`. As for the old 
`deallocate(capacity:)` method that *needs* to be removed because it is 
actively harmful. As I’ve explained it’s not enough to just drop in a sized 
backend later as an “implementation detail” because it’s not an implementation 
detail, you’re changing the fundamental behavior of that method.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to