Skip to content

Instantly share code, notes, and snippets.

SE-0184 Part 1: Unsafe[Mutable][Raw][Buffer]Pointer: add missing methods, adjust existing labels for clarity, and remove deallocation size

Here I've listed the changes from SE-0184 that have been reviewed by the core team and are no longer considered controversial. Let's call this SE-1084 Part 1. The diff below summarizes SE-1084 Part 1 vs. Swift 4. The core team requests have been incorporated, and are annotated as "Amended" comments. The amendments are minor and almost exclusively revise the original Swift 3 API rather than calling into question anything newly introduced by SE-0184. Consequently, there's no need for those to go back to swift-evolution. The remainder of SE-0184, part 2, will introduce changes to the slice API in conjunction with the buffer API, so does need to go back to swift-evolution as a new proposal.

Analyzing dispatch performance

When it comes to resilient performance we need to prioritize future flexibility and ABI simplicity over perceived performance advantages. Being able to react to future performance issues that arise with specific apps is far more important than benchmarking. Time not spent implementing complex ABI mechanisms is time that will be spent optimizing more critical performance areas.

It's easy to say we should simply measure performance and let the data

SE-0184 Part 2 (recomend splitting into a follow-up proposal): Buffer Full vs. Partial Initialization.

Buffer Memory State

struct UnsafeMutableBufferPointer<Element> 
{
    func initialize<S : Sequence>(from: S) -> (S.Iterator, Index) where S.Element == Element

// Amended: Remove the `at` label on all buffer APIs. Only support full initialization/assignment/deinitialization.

Exclusivity Enforcement in Swift 5

The Swift 5 release enables runtime checking of "Exclusive Access to Memory" by default in Release builds. Previously, these runtime checks were only enabled in Debug builds. In this post, I'll explain what this change means for Swift developers and why it is essential to Swift's strategy for safety and performance.

Background

SIL Opaque Values

Introduction

A SIL type is either loadable or address-only. A loadable type is one whose object size and layout can be determined by the compiler and whose values are not "pinned" to a memory address. Types are most commonly address-only because their layout is opaque by abstraction. Generic type parameters are address-only because their concrete type not statically identified. Resilient types are

@atrick
atrick / 2022-04-iterative-reachability.md
Last active May 5, 2022 01:06
Iterative Backward Reachability

Iterative Backward Reachability

This should replace the current non-iterative Reachability. The current non-iterative algorithm would only make sense when uses are post-dominating and we change it to propagate in DFS RPO order. But this algorithm should very seldom need to iterate anyway. So we should probably use it instead.

Input:

  • dominating def

  • uses (gens) - during initialization only

@atrick
atrick / 2022-07-borrowed-value.md
Last active July 27, 2022 01:04
BorrowedValue pre-pitch

BorrowedValue pitch

Introduction

Adding control over value ownership to Swift requires the coordination of multiple language features. This proposal focuses on the specific problem of composing aggregates from "shared" values. A "shared borrow" provides read-only access to a value within a designated scope. This allows APIs to view the contents of a value without taking ownership of it.

Let's define "shared borrowing" as initializing a non-owned variable with the value from another variable without making a copy. To be concise, we'll just call this "borrowing" from here on. Consider passing an argument to a non-consuming parameter (this is the default ownership convention):

func nonConsuming<T>(t: T)

Constrain implicit raw pointer conversion to trivial values

Introduction

Swift supports implicit inout conversion to unsafe pointers. A mutable variable can be passed inout to a function that receives an unsafe pointer to the value. According to the normal rules for pointer conversion, this naturally extends to raw pointers. Raw pointers allow the pointer-taking function to operate directly on the value's bytes.

func readBytes(_ pointer: UnsafeRawPointer) {
  assert(pointer.load(as: UInt16.self) == 0xaaaa)
}