Skip to content

Commit ca4a9f9

Browse files
Merge pull request #4643 from swiftwasm/main
[pull] swiftwasm from main
2 parents b607743 + 2d2a56f commit ca4a9f9

33 files changed

+151
-16
lines changed

docs/OpenBSD.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Getting started with Swift on OpenBSD
22

3-
Swift builds and runs on OpenBSD (tested on 6.8), with some special considerations.
3+
Swift builds and runs on OpenBSD, with some special considerations. This document was last tested on OpenBSD 7.1, but may also work on later versions.
44

55
## Preparing
66

77
The following packages are required to build Swift. You can install these via `pkg_add`:
88

99
```shell
10-
$ doas pkg_add bash cmake e2fsprogs git icu4c ninja py-six python3
10+
$ doas pkg_add bash cmake e2fsprogs git icu4c ninja py3-six python3
1111
```
1212

1313
Because LLVM is built as part of building Swift and does not include some of the patches to handle the OpenBSD library naming convention, you will need to create some symlinks:
@@ -23,10 +23,10 @@ $ doas ln -s /usr/lib/libpthread.so.26.1 /usr/lib/libpthread.so
2323

2424
*Note: you may need to update the version numbers if necessary.*
2525

26-
Also link `~/bin/python` to the `python2.7` binary:
26+
Also link `~/bin/python` to the `python3` binary:
2727

2828
```shell
29-
$ doas ln -s /usr/local/bin/python2.7 ~/bin/python
29+
$ ln -s /usr/local/bin/python3 ~/bin/python
3030
```
3131

3232
Since the build requires significant amounts of memory at certain points, you may need to ensure that the user you are using to build Swift has the appropriate limits set. Using the `staff` group in `login.conf` and ensuring the shell limits are raised is recommended.
@@ -50,14 +50,16 @@ Download the sources with the [Getting Started](/docs/HowToGuides/GettingStarted
5050
"aliases": [ "main", "swift/main" ],
5151
"repos": {
5252
"cmark": "main",
53-
"llvm-project": "swift/main",
53+
"llvm-project": "stable/20211026",
5454
"swift": "main"
5555
}
5656
}
5757
}
5858
}
5959
```
6060

61+
*Note: you may need to check `utils/update_checkout/update-checkout-config.json` for the correct LLVM stable branch to build against.*
62+
6163
## Building
6264

6365
Once the sources have completed downloading, you can use the standard `build-script` mechanism to start building Swift. However, some options are required to be set to successfully build Swift.
@@ -66,23 +68,26 @@ These options are:
6668
* `--skip-build-clang-tools-extra` and `--skip-build-compiler-rt`: to ensure LLVM builds cleanly,
6769
* `--extra-cmake-options=`
6870
* `-DCMAKE_DISABLE_FIND_PACKAGE_Backtrace=TRUE,-DCMAKE_DISABLE_FIND_PACKAGE_LibXml2=TRUE,-DLLVM_VERSION_SUFFIX=''`: to ensure LLVM builds cleanly,
69-
* `-DSWIFT_BUILD_SOURCEKIT=OFF,-DSWIFT_BUILD_SYNTAXPARSERLIB=OFF,-DSWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY=OFF`: to ensure Swift does not attempt to build libdispatch, which is not yet supported on OpenBSD,
71+
* `-DSWIFT_ENABLE_DISPATCH=FALSE,-DSWIFT_BUILD_SOURCEKIT=OFF,-DSWIFT_BUILD_SYNTAXPARSERLIB=OFF,-DSWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY=OFF,-DSWIFT_IMPLICIT_CONCURRENCY_IMPORT=OFF,-DSWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED=OFF`: to ensure Swift does not attempt to build libdispatch, which is not yet supported on OpenBSD,
7072
* `-DSWIFT_USE_LINKER=lld`: to specify that `lld` should be used over `gold`,
7173
* `-DCMAKE_INSTALL_DIR=/usr/local"`: to set the correct platform install directory.
7274

7375
In full, the minimal set of flags to supply to `build-script` looks like:
7476
```shell
7577
$ ./utils/build-script \
78+
--release \
7679
--skip-build-clang-tools-extra \
7780
--skip-build-compiler-rt \
7881
--extra-cmake-options="\
7982
-DCMAKE_DISABLE_FIND_PACKAGE_Backtrace=TRUE,\
8083
-DCMAKE_DISABLE_FIND_PACKAGE_LibXml2=TRUE,\
8184
-DLLVM_VERSION_SUFFIX='',\
85+
-DSWIFT_ENABLE_DISPATCH=OFF,\
8286
-DSWIFT_BUILD_SOURCEKIT=OFF,\
8387
-DSWIFT_BUILD_SYNTAXPARSERLIB=OFF,\
8488
-DSWIFT_ENABLE_EXPERIMENTAL_CONCURRENCY=OFF,\
8589
-DSWIFT_IMPLICIT_CONCURRENCY_IMPORT=OFF,\
90+
-DSWIFT_ENABLE_EXPERIMENTAL_DISTRIBUTED=OFF,\
8691
-DSWIFT_USE_LINKER=lld,\
8792
-DCMAKE_INSTALL_DIR=/usr/local"
8893
```

docs/SIL.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3745,6 +3745,8 @@ store_borrow
37453745

37463746
Stores the value ``%0`` to a stack location ``%1``, which must be an
37473747
``alloc_stack $T``.
3748+
The stack location must not be modified by other instructions than
3749+
``store_borrow``.
37483750
The stored value is alive until the ``dealloc_stack`` or until another
37493751
``store_borrow`` overwrites the value. During the its lifetime, the stored
37503752
value must not be modified or destroyed.

lib/SIL/Verifier/LoadBorrowImmutabilityChecker.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,9 +363,9 @@ bool LoadBorrowImmutabilityAnalysis::isImmutable(LoadBorrowInst *lbi) {
363363
// cases to try and exhaustively identify if those writes overlap with our
364364
// load_borrow.
365365
SmallVector<Operand *, 8> endBorrowUses;
366-
transform(lbi->getUsersOfType<EndBorrowInst>(),
367-
std::back_inserter(endBorrowUses),
368-
[](EndBorrowInst *ebi) { return &ebi->getAllOperands()[0]; });
366+
visitTransitiveEndBorrows(lbi, [&](EndBorrowInst *endBorrow) {
367+
endBorrowUses.push_back(&endBorrow->getOperandRef());
368+
});
369369

370370
switch (accessPath.getStorage().getKind()) {
371371
case AccessStorage::Nested: {

lib/SIL/Verifier/MemoryLifetimeVerifier.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ class MemoryLifetimeVerifier {
8989
/// Register the destination address of a store_borrow as borrowed location.
9090
void registerStoreBorrowLocation(SILValue addr);
9191

92+
/// Registers all store_borrow instructions in a block.
93+
void registerStoreBorrowsInBlock(SILBasicBlock *block);
94+
9295
/// Handles locations of the predecessor's terminator, which are only valid
9396
/// in \p block.
9497
/// Example: @out results of try_apply. They are only valid in the
@@ -286,6 +289,13 @@ void MemoryLifetimeVerifier::registerStoreBorrowLocation(SILValue addr) {
286289
}
287290
}
288291

292+
void MemoryLifetimeVerifier::registerStoreBorrowsInBlock(SILBasicBlock *block) {
293+
for (SILInstruction &inst : *block) {
294+
if (auto *sbi = dyn_cast<StoreBorrowInst>(&inst))
295+
registerStoreBorrowLocation(sbi->getDest());
296+
}
297+
}
298+
289299
void MemoryLifetimeVerifier::initDataflow(BitDataflow &dataFlow) {
290300
// Initialize the entry and exit sets to all-bits-set. Except for the function
291301
// entry.
@@ -579,7 +589,6 @@ void MemoryLifetimeVerifier::checkBlock(SILBasicBlock *block, Bits &bits) {
579589
case SILInstructionKind::StoreBorrowInst: {
580590
SILValue destAddr = cast<StoreBorrowInst>(&I)->getDest();
581591
locations.setBits(bits, destAddr);
582-
registerStoreBorrowLocation(destAddr);
583592
break;
584593
}
585594
case SILInstructionKind::CopyAddrInst: {
@@ -764,6 +773,7 @@ void MemoryLifetimeVerifier::verify() {
764773
locations.handleSingleBlockLocations([this](SILBasicBlock *block) {
765774
storeBorrowLocations.clear();
766775
Bits bits(locations.getNumLocations());
776+
registerStoreBorrowsInBlock(block);
767777
checkBlock(block, bits);
768778
});
769779
}

lib/Threading/Pthreads.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ void swift::threading_impl::once_slow(once_t &predicate, void (*fn)(void *),
7171

7272
pthread_mutex_lock(&onceMutex);
7373
while (predicate.load(std::memory_order_acquire) >= (std::int64_t)0) {
74-
pthread_cond_wait(&onceCond);
74+
pthread_cond_wait(&onceCond, &onceMutex);
7575
}
7676
pthread_mutex_unlock(&onceMutex);
7777
}

stdlib/public/Concurrency/Task.cpp

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask,
113113

114114
auto queueHead = fragment->waitQueue.load(std::memory_order_acquire);
115115
bool contextInitialized = false;
116+
auto escalatedPriority = JobPriority::Unspecified;
116117
while (true) {
117118
switch (queueHead.getStatus()) {
118119
case Status::Error:
@@ -145,6 +146,47 @@ FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask,
145146
waitingTask->flagAsSuspended();
146147
}
147148

149+
// Escalate the blocking task to the priority of the waiting task.
150+
// FIXME: Also record that the waiting task is now waiting on the
151+
// blocking task so that escalators of the waiting task can propagate
152+
// the escalation to the blocking task.
153+
//
154+
// Recording this dependency is tricky because we need escalators
155+
// to be able to escalate without worrying about the blocking task
156+
// concurrently finishing, resuming the escalated task, and being
157+
// invalidated. So we're not doing that yet. In the meantime, we
158+
// do the best-effort alternative of escalating the blocking task
159+
// as a one-time deal to the current priority of the waiting task.
160+
// If the waiting task is escalated after this point, the priority
161+
// will not be escalated, but that's inevitable in the absence of
162+
// propagation during escalation.
163+
//
164+
// We have to do the escalation before we successfully enqueue the
165+
// waiting task on the blocking task's wait queue, because as soon as
166+
// we do, this thread is no longer blocking the resumption of the
167+
// waiting task, and so both the blocking task (which is retained
168+
// during the wait only from the waiting task's perspective) and the
169+
// waiting task (which can simply terminate) must be treat as
170+
// invalidated from this thread's perspective.
171+
//
172+
// When we do fix this bug to record the dependency, we will have to
173+
// do it before this escalation of the blocking task so that there
174+
// isn't a race where an escalation of the waiting task can fail
175+
// to propagate to the blocking task. The correct priority to
176+
// escalate to is the priority we observe when we successfully record
177+
// the dependency; any later escalations will automatically propagate.
178+
//
179+
// If the blocking task finishes while we're doing this escalation,
180+
// the escalation will be innocuous. The wasted effort is acceptable;
181+
// programmers should be encouraged to give tasks that will block
182+
// other tasks the correct priority to begin with.
183+
auto waitingStatus =
184+
waitingTask->_private()._status().load(std::memory_order_relaxed);
185+
if (waitingStatus.getStoredPriority() > escalatedPriority) {
186+
swift_task_escalate(this, waitingStatus.getStoredPriority());
187+
escalatedPriority = waitingStatus.getStoredPriority();
188+
}
189+
148190
// Put the waiting task at the beginning of the wait queue.
149191
waitingTask->getNextWaitingTask() = queueHead.getTask();
150192
auto newQueueHead = WaitQueueItem::get(Status::Executing, waitingTask);
@@ -153,11 +195,6 @@ FutureFragment::Status AsyncTask::waitFuture(AsyncTask *waitingTask,
153195
/*success*/ std::memory_order_release,
154196
/*failure*/ std::memory_order_acquire)) {
155197

156-
// Escalate the priority of this task based on the priority
157-
// of the waiting task.
158-
auto status = waitingTask->_private()._status().load(std::memory_order_relaxed);
159-
swift_task_escalate(this, status.getStoredPriority());
160-
161198
_swift_task_clearCurrent();
162199
return FutureFragment::Status::Executing;
163200
}

stdlib/public/stubs/Random.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939

4040
#endif
4141

42+
#if __has_include(<unistd.h>)
43+
#include <unistd.h>
44+
#endif
45+
4246
#include <stdlib.h>
4347
#include <unistd.h>
4448

test/SILOptimizer/load_borrow_verify.sil renamed to test/SIL/OwnershipVerifier/load_borrow_verify.sil

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,23 @@ bb0(%0 : @owned $K):
153153
return %r : $()
154154
}
155155

156+
sil @use_guaranteed : $@convention(thin) (@guaranteed K) -> ()
157+
158+
sil [ossa] @test_write_reborrow : $@convention(thin) (@owned K, @owned K) -> () {
159+
bb0(%0 : @owned $K, %1 : @owned $K):
160+
%stk = alloc_stack [lexical] $K
161+
store %0 to [init] %stk : $*K
162+
%ld1 = load_borrow %stk : $*K
163+
br bb2(%ld1 : $K)
164+
165+
bb2(%ld : @guaranteed $K):
166+
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed K) -> ()
167+
%4 = apply %3(%ld) : $@convention(thin) (@guaranteed K) -> ()
168+
end_borrow %ld : $K
169+
store %1 to [assign] %stk : $*K
170+
destroy_addr %stk : $*K
171+
dealloc_stack %stk : $*K
172+
%6 = tuple ()
173+
return %6 : $()
174+
}
175+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %target-sil-opt %s -verify-continue-on-failure=true -o /dev/null 2>&1 | %FileCheck %s
2+
3+
class Klass {}
4+
5+
sil @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
6+
7+
// Write: store {{.*}} [assign] {{.*}}
8+
// CHECK: Begin Error in function test_write_reborrow
9+
// CHECK: SIL verification failed: Found load borrow that is invalidated by a local write?!: loadBorrowImmutabilityAnalysis.isImmutable(LBI)
10+
// CHECK: End Error in function test_write_reborrow
11+
sil [ossa] @test_write_reborrow : $@convention(thin) (@owned Klass, @owned Klass) -> () {
12+
bb0(%0 : @owned $Klass, %1 : @owned $Klass):
13+
%stk = alloc_stack [lexical] $Klass
14+
store %0 to [init] %stk : $*Klass
15+
%ld1 = load_borrow %stk : $*Klass
16+
br bb2(%ld1 : $Klass)
17+
18+
bb2(%ld : @guaranteed $Klass):
19+
store %1 to [assign] %stk : $*Klass
20+
%3 = function_ref @use_guaranteed : $@convention(thin) (@guaranteed Klass) -> ()
21+
%4 = apply %3(%ld) : $@convention(thin) (@guaranteed Klass) -> ()
22+
end_borrow %ld : $Klass
23+
destroy_addr %stk : $*Klass
24+
dealloc_stack %stk : $*Klass
25+
%6 = tuple ()
26+
return %6 : $()
27+
}

test/SIL/memory_lifetime_failures.sil

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,36 @@ bb0(%0 : @guaranteed $Optional<T>):
361361
return %res : $()
362362
}
363363

364+
// CHECK: SIL memory lifetime failure in @test_store_borrow_single_block: store-borrow location cannot be written
365+
sil [ossa] @test_store_borrow_single_block : $@convention(thin) (@guaranteed T) -> () {
366+
bb0(%0 : @guaranteed $T):
367+
%stk = alloc_stack $T
368+
%copy = copy_value %0 : $T
369+
store %copy to [init] %stk : $*T
370+
%ld = load [take] %stk : $*T
371+
destroy_value %ld : $T
372+
store_borrow %0 to %stk : $*T
373+
dealloc_stack %stk : $*T
374+
%8 = tuple ()
375+
return %8 : $()
376+
}
377+
378+
// CHECK: SIL memory lifetime failure in @test_store_borrow_multi_block: store-borrow location cannot be written
379+
sil [ossa] @test_store_borrow_multi_block : $@convention(thin) (@guaranteed T) -> () {
380+
bb0(%0 : @guaranteed $T):
381+
%stk = alloc_stack $T
382+
%copy = copy_value %0 : $T
383+
store %copy to [init] %stk : $*T
384+
%ld = load [take] %stk : $*T
385+
destroy_value %ld : $T
386+
br bb1
387+
bb1:
388+
store_borrow %0 to %stk : $*T
389+
dealloc_stack %stk : $*T
390+
%8 = tuple ()
391+
return %8 : $()
392+
}
393+
364394
// CHECK: SIL memory lifetime failure in @test_cast_br_take_always: memory is not initialized, but should be
365395
sil [ossa] @test_cast_br_take_always : $@convention(thin) <U, V> (@in U) -> () {
366396
bb0(%0 : $*U):

0 commit comments

Comments
 (0)