A lot of time (when it's not every time) I got the following error when I try to print objects on lldb. Is there some build/debug configuration to change or is this an error inside lldb?
(lldb) po userLevel
error: warning: Stopped in an Objective-C method, but 'self' isn't available; pretending we are in a generic context
error: use of undeclared identifier 'userLevel'
error: 1 errors parsing expression
I build with llvm and do not strip debug symbols.
Edit: Here is the backtrace:
(lldb) bt
* thread #1: tid = 0x1c03, 0x001169c5 FanCake-Beta`-[KWUserLevelController addPoints:](, _cmd=0x0029187b, points=15) + 179 at KWUserLevelController.m:53, stop reason = step over
frame #0: 0x001169c5 FanCake-Beta`-[KWUserLevelController addPoints:](, _cmd=0x0029187b, points=15) + 179 at KWUserLevelController.m:53
frame #1: 0x00112172 FanCake-Beta`-[KWEventRealTimeControllergameEngine:hostedGame:didSucceedIn:withScore:](self=0x0b9d7740, _cmd=0x0027a2a7, engine=0x1be5af40, game=0x1be5a850, completionTime=3.59473554800206, score=0) + 421 at KWEventRealTimeController.m:647
frame #2: 0x0007189a FanCake-Beta`__35-[KMCatchEmGameEngine animateStep6]_block_invoke197(, finished='\x01') + 257 at KMCatchEmGameEngine.m:214
frame #3: 0x01990df6 UIKit`-[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 223
frame #4: 0x01983d66 UIKit`-[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 237
frame #5: 0x01983f04 UIKit`-[UIViewAnimationState animationDidStop:finished:] + 68
frame #6: 0x017587d8 QuartzCore`CA::Layer::run_animation_callbacks(void*) + 284
frame #7: 0x03634014 libdispatch.dylib`_dispatch_client_callout + 14
frame #8: 0x036247d5 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 296
frame #9: 0x04737af5 CoreFoundation`__CFRunLoopRun + 1925
frame #10: 0x04736f44 CoreFoundation`CFRunLoopRunSpecific + 276
frame #11: 0x04736e1b CoreFoundation`CFRunLoopRunInMode + 123
frame #12: 0x040367e3 GraphicsServices`GSEventRunModal + 88
frame #13: 0x04036668 GraphicsServices`GSEventRun + 104
frame #14: 0x01945ffc UIKit`UIApplicationMain + 1211
frame #15: 0x000039a8 FanCake-Beta`main(argc=1, argv=0xbffff354) + 94 at main.m:13
frame #16: 0x00002dc5 FanCake-Beta`start + 53
Edit 2: Same thing when I try to print local vars
(lldb) po currentUser
error: variable not available
If I put some NSLog() in the code, the correct value is printing. But not with the po command.
I usually get this error when I have compiler optimization turned on. The compiler will generate code which does not necessarily follow your code logic flow.
Go to your project in the navigator -> Target -> Build settings -> Search for optimization level -> expand optimization level -> select the debug line -> change to none in both columns of your project and target.
Hope this helps.
I was having this problem and it went away when I edited my scheme and set the Run build to Debug. I had set it to AdHoc for testing Push Notifications and that apparently makes LLDB unhappy.
Because it's optimized away. Let's use an example:
void f(int self) {
// Here, "self" is live:Its value is used in the call to NSLog()
NSLog(#"I am %d",self);
// Here, "self" is dead: Its value is never used.
// I could do self=0 or self=self*self and nobody would know.
// An optimizing compiler will typically optimize it away.
// It might still be on the stack (in the parameters passed to NSLog())
// but the compiler shouldn't assume this.
NSLog(#"Another function call: %d", 1);
// If "self" was on the stack, it will probably now have been overwritten.
}
Compilers do a lot of things to make your code faster/smaller; forgetting about variables which are no longer needed is a very common optimization.
As already said in this other question:
In Build Settings, setting Precompile Prefix Header to NO fixed it for me.
Related
There was an article on the internet about embedding manually built Racket libs into an iOS application. Disregarding the fact that such a possibility is more fun than useful, I've followed instructions and (ta-dah) been able to create a working example (to my surprise!).
Anyway, I was quite more eager to repeat a trick with the macOS Xcode project. There is Racket.framework included in Racket distribution and it works well with gcc (and -framework option) but from Xcode's perspective of view this framework doesn't have valid structure and xcodetools are not able to link to it or moreover codesign.
So I've decided to follow iOS instructions from the article but for macOS. I've built macOS Racket libraries (librktio, libracket and libmzgc) using ./configure without specifying host and
just make
make cgc && make install-cgc
(NB: in the end result was same for both).
I've created interop C source:
#include "scheme.h"
#include "interop.h"
#include "racketmac.c" // <- this is my rkt module made with raco ctool
static int init(Scheme_Env *e, int argc, char *argv[]) {
declare_modules(e);
return 0;
}
int init_racket() {
return scheme_main_setup(1, init, 0, NULL);
}
and header:
#ifndef Interop_h
#define Interop_h
int init_racket(void);
#endif /* Interop_h */
, then added "interop.h" to bridging header and C function call from Swift like:
import Cocoa
final public class RacketInteractor: NSObject {
public override init() {
super.init()
init_racket()
}
}
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var interactor: RacketInteractor!
func applicationDidFinishLaunching(_ aNotification: Notification) {
interactor = RacketInteractor()
}
// ...
}
Project, macOS Cocoa application, is build-able and runnable. But call of init_racket every single time results in EXC_BAD_ACCESS. Studying stack trace has given me understanding that scheme interpreter is trying to emit "out of memory" error (look for frame #5):
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x10ad2153d)
frame #0: 0x000000010ad2153d
* frame #1: 0x0000000100102814 RacketMapApp`scheme_native_stack_trace at jitstack.c:215:7 [opt]
frame #2: 0x0000000100058f7b RacketMapApp`continuation_marks(p=0x000000010a3b1250, _cont=0x0000000000000000, econt=0x0000000000000000, mc=<unavailable>, prompt_tag=0x000000010a4001d0, who="continuation-marks", just_chain=0) at fun.c:7906:10 [opt]
frame #3: 0x000000010002d565 RacketMapApp`do_raise(arg=0x000000010ac49028, need_debug=1, eb=180654120) at error.c:4606:13 [opt]
frame #4: 0x0000000100028f8a RacketMapApp`scheme_raise_exn(id=17) at error.c:4402:3 [opt]
frame #5: 0x000000010002c4f7 RacketMapApp`scheme_raise_out_of_memory(where=<unavailable>, msg=<unavailable>) at error.c:2541:3 [opt]
frame #6: 0x00000001001a02af RacketMapApp`scheme_malloc_code [inlined] malloc_page(size=<unavailable>) at salloc.c:1047:5 [opt]
frame #7: 0x00000001001a0271 RacketMapApp`scheme_malloc_code(size=35320) at salloc.c:1156 [opt]
frame #8: 0x00000001001035ef RacketMapApp`scheme_generate_one(old_jitter=0x0000000000000000, generate=(RacketMapApp`scheme_do_generate_common at jitcommon.c:3576), data=0x0000000000000000, gcable=0, save_ptr=0x0000000000000000, ndata=0x0000000000000000) at jitstate.c:256:18 [opt]
frame #9: 0x000000010008f593 RacketMapApp`create_native_lambda(lam=0x000000010ac5b348, clear_code_after_jit=1, case_lam=0x0000000000000000) at jit.c:4127:5 [opt]
frame #10: 0x0000000100101f4b RacketMapApp`scheme_jit_closure(code=0x000000010ac5b308, context=0x0000000000000000) at jitprep.c:558:13 [opt]
frame #11: 0x0000000100101abe RacketMapApp`jit_expr(expr=0x000000010a2e3c68) at jitprep.c:0 [opt]
frame #12: 0x0000000100101cd9 RacketMapApp`jit_expr [inlined] define_values_jit(data=<unavailable>) at jitprep.c:301:12 [opt]
frame #13: 0x0000000100101c82 RacketMapApp`jit_expr(expr=0x000000010ac48fe8) at jitprep.c:651 [opt]
frame #14: 0x00000001001020ce RacketMapApp`scheme_jit_linklet(linklet=0x000000010a4bfb88, step=<unavailable>) at jitprep.c:704:9 [opt]
frame #15: 0x00000001001088f4 RacketMapApp`instantiate_linklet_k at linklet.c:0 [opt]
frame #16: 0x000000010004ffd9 RacketMapApp`scheme_top_level_do_worker(k=(RacketMapApp`instantiate_linklet_k at linklet.c:1325), eb=<unavailable>, new_thread=0) at fun.c:1314:11 [opt]
frame #17: 0x000000010002450f RacketMapApp`scheme_basic_env [inlined] place_instance_init(stack_base=<unavailable>, initial_main_os_thread=1) at env.c:501:3 [opt]
frame #18: 0x000000010002436b RacketMapApp`scheme_basic_env at env.c:214 [opt]
frame #19: 0x000000010019f7f8 RacketMapApp`scheme_main_setup [inlined] call_with_basic(data=<unavailable>) at salloc.c:178:16 [opt]
frame #20: 0x000000010019f7f3 RacketMapApp`scheme_main_setup [inlined] do_main_stack_setup(no_auto_statics=<unavailable>, data=<unavailable>) at salloc.c:203 [opt]
frame #21: 0x000000010019f7c3 RacketMapApp`scheme_main_setup [inlined] scheme_main_stack_setup(no_auto_statics=<unavailable>, data=<unavailable>) at salloc.c:337 [opt]
frame #22: 0x000000010019f758 RacketMapApp`scheme_main_setup(no_auto_statics=<unavailable>, _main=(RacketMapApp`init at interop.c:14), argc=0, argv=0x0000000000000000) at salloc.c:187 [opt]
frame #23: 0x00000001000017fb RacketMapApp`#objc RacketInteractor.init() [inlined] RacketMapApp.RacketInteractor.init() -> RacketMapApp.RacketInteractor at RacketInteractor.swift:19:9 [opt]
frame #24: 0x00000001000017bc RacketMapApp`#objc RacketInteractor.init() at <compiler-generated>:15 [opt]
frame #25: 0x00000001000024ed RacketMapApp`#objc AppDelegate.applicationDidFinishLaunching(_:) [inlined] RacketMapApp.RacketInteractor.__allocating_init() -> RacketMapApp.RacketInteractor at <compiler-generated>:0 [opt]
frame #26: 0x00000001000024e2 RacketMapApp`#objc AppDelegate.applicationDidFinishLaunching(_:) [inlined] RacketMapApp.AppDelegate.applicationDidFinishLaunching(self=0x0000600000004320) -> () at AppDelegate.swift:17 [opt]
frame #27: 0x00000001000024e2 RacketMapApp`#objc AppDelegate.applicationDidFinishLaunching(_:) at <compiler-generated>:16 [opt]
frame #28: 0x00007fff3443135f CoreFoundation`__CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
frame #29: 0x00007fff344312f3 CoreFoundation`___CFXRegistrationPost1_block_invoke + 63
frame #30: 0x00007fff34431268 CoreFoundation`_CFXRegistrationPost1 + 372
frame #31: 0x00007fff34430ebe CoreFoundation`___CFXNotificationPost_block_invoke + 97
frame #32: 0x00007fff344007e2 CoreFoundation`-[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1575
frame #33: 0x00007fff343ffc82 CoreFoundation`_CFXNotificationPost + 1351
frame #34: 0x00007fff36a85a02 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 59
frame #35: 0x00007fff3160b2ff AppKit`-[NSApplication _postDidFinishNotification] + 312
frame #36: 0x00007fff3160b042 AppKit`-[NSApplication _sendFinishLaunchingNotification] + 208
frame #37: 0x00007fff31608103 AppKit`-[NSApplication(NSAppleEventHandling) _handleAEOpenEvent:] + 549
frame #38: 0x00007fff31607d49 AppKit`-[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] + 688
frame #39: 0x00007fff36ab1226 Foundation`-[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] + 308
frame #40: 0x00007fff36ab1090 Foundation`_NSAppleEventManagerGenericHandler + 98
frame #41: 0x00007fff357b5092 AE`___lldb_unnamed_symbol77$$AE + 2172
frame #42: 0x00007fff357b47b9 AE`___lldb_unnamed_symbol76$$AE + 41
frame #43: 0x00007fff357aca27 AE`aeProcessAppleEvent + 449
frame #44: 0x00007fff32fa22b8 HIToolbox`AEProcessAppleEvent + 54
frame #45: 0x00007fff3160215c AppKit`_DPSNextEvent + 1670
frame #46: 0x00007fff31600690 AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1352
frame #47: 0x00007fff315f23ae AppKit`-[NSApplication run] + 658
frame #48: 0x00007fff315c4775 AppKit`NSApplicationMain + 777
frame #49: 0x0000000100001a29 RacketMapApp`main at AppDelegate.swift:12:7 [opt]
frame #50: 0x00007fff6ba967fd libdyld.dylib`start + 1
frame #51: 0x00007fff6ba967fd libdyld.dylib`start + 1
I tried to create static lib with Interop sources and add it to the Xcode project with the same result.
At the same moment, created librktio, libracket and libmzgc are totally OK to be used with gcc cli. So I'm confused because I even don't know how to debug such error properly. Maybe I need to tweak some Xcode build options? Why iOS-ready libraries are working fine while macOS-ready ones aren't? Is there an easier way to embed Racket into the Xcode macOS project (through generating it via CMake, for example)?
EDIT: When building racket3m version, crash message is more clear, for example:
"WARNING: couldn't protect 16384 bytes of page 0x10a350000(os/kern) protection failure"
It's like syscalls for memory allocations just don't give enough resources, and this is weird.
"WARNING: couldn't protect 16384 bytes of page 0x10a350000(os/kern) protection failure"
Occurs when your app is missing the "Allow Unsigned Executable Memory" entitlement. Make sure your app has that and the "Allow JIT" entitlement.
But once you get past that, you'll run into Racket 3m's GC write barrier, which I briefly touch upon in the article. For that to work in debug mode, you'll have to register a signal handler in lldb to pass the expected SIGSEGV when it occurs. Unfortunately, there's an LLDB bug and this doesn't work on arm, but it may work on x86-64.
I am currently trying to learn swift and while I was coding some dummy stuff, I noticed the xcode is skipping some lines and sometimes stops on weird lines . my env: macos sierra,xcode Version 8.2.1 (8C1002)
since xcode is skipping some lines , I thought the problem is from code optimisation , then I switched to terminal to debug, below is the input&output
I compiled using
swiftc -g -Onone *.swift
then
load it with lldb
lldb main
set breakpoint on lint 18 as shown below and process run with "r"
17 do {
-> 18 try StaticM.teststatic2()
19 print (1)
20 }catch {
21
(lldb) thread step-in
Process 963 stopped
* thread #1: tid = 0x86e1, 0x0000000100001f6a main`static StaticM.teststatic2(self=main.StaticM, $error=Error # 0x00007fff5fbffac0) throws -> () + 26 at staticExt.swift:13, queue = 'com.apple.main-thread', stop reason = step in
frame #0: 0x0000000100001f6a main`static StaticM.teststatic2(self=main.StaticM, $error=Error # 0x00007fff5fbffac0) throws -> () + 26 at staticExt.swift:13
10 public extension StaticM {
11 #discardableResult
12 public static func teststatic2() throws {
-> 13 var asdf=2;
14 let sdfgsdfg=2;
15 print(sdfgsdfg);
16 print (asdf);
(lldb) n
Process 963 stopped
* thread #1: tid = 0x86e1, 0x0000000100001f72 main`static StaticM.teststatic2(self=main.StaticM, $error=Error # 0x00007fff5fbffac0) throws -> () + 34 at staticExt.swift:15, queue = 'com.apple.main-thread', stop reason = step over
frame #0: 0x0000000100001f72 main`static StaticM.teststatic2(self=main.StaticM, $error=Error # 0x00007fff5fbffac0) throws -> () + 34 at staticExt.swift:15
12 public static func teststatic2() throws {
13 var asdf=2;
14 let sdfgsdfg=2;
-> 15 print(sdfgsdfg);
16 print (asdf);
17 asdf += 1;
18 }
(lldb) process continue
Process 963 resuming
2
2
1
Process 963 exited with status = 0 (0x00000000)
(lldb)
question is , after I go to next line using "n" in lldb, why lldb skips line 14 of staticExt.swift and jumps straight to line 15 ?
also , sometimes when trying to debug some other program, I click on "step-in" in xcode, it stops on the declaration line of the func instead of first line in the code block, I clicked stepover , it goes back to the caller func line instead of executing the first line of that func.
in all,programe works , but why lldb jumps even with -Onone and -g ?
could you please let me where can I find more info ?
thank you very much.
Swift's basic types (Int's, Strings, etc.) are formally somewhat heavy-weight - for instance in your example:
(lldb) expr --raw -- asdf
(Swift.Int) $R0 = {
_value = 3
}
To make performance acceptable even though this is true, the swift compiler "unboxes" these types in common operations and applies other "optimization-like" tricks to make all this go faster. Since this is such a pervasive feature of swift, it does so even at -Onone, to make performance of unoptimized code acceptable. And once the optimizer starts getting involved, it sometimes can't help itself and will do more work than maybe it should at -Onone.
In this case, because the first variable is a "let" of an Int, swiftc knows it can just directly insert the value into the arguments when it goes to call print, so it doesn't need to make up a variable. If you change the let to a var then code will actually be generated for that line, and the line will get its own line table entry.
If you know how to read assembly code, you can look at the mixed disassembly to see this in action.
In lldb:
(lldb) dis -m -f
will give you mixed disassembly of the current frame.
I am wondering how Swift's sort function is implemented. Which sorting algorithm does it use—is it a mergesort, quicksort, or something completely different? What are the timing/complexity guarantees provided by this function?
I can't find any indication of how it is implemented either online or in the official documentation.
Update 2: As we can see in Sort.swift, sort() now uses a “modified timsort” in Swift 5. Timsort is a
... hybrid stable sorting algorithm, derived from merge sort and insertion sort ...
In the worst case, Timsort takes O(n log n) comparisons to sort an array of n elements. In the best case, which occurs when the input is already sorted, it runs in linear time, meaning that it is an adaptive sorting algorithm.
This means that sort() happens to be a stable sort in Swift 5, but that is still an implementation detail. The MutableCollection.sort documentation states that
The sorting algorithm is not guaranteed to be stable. A stable sort preserves the relative order of elements that compare equal.
See also Is sort() stable in Swift 5? in the Swift forum:
The algorithm was only recently made stable in preparation for a proposal to make it guaranteed as such.
Update: Swift is open source now, and in
https://github.com/apple/swift/blob/master/stdlib/public/core/Sort.swift
one can see that sorting a collection is done using introsort
with a maximum recursion depth of 2*floor(log_2(N)). It switches to insertion sort for partitions with less than 20 elements, or to heapsort
if the recursion depth is reached.
Old answer: Defining a custom Comparable structure and setting in breakpoint in <:
struct MyStruct : Comparable {
let val : Int
}
func ==(x: MyStruct, y: MyStruct) -> Bool {
println("\(x.val) == \(y.val)")
return x.val == y.val
}
func <(x: MyStruct, y: MyStruct) -> Bool {
println("\(x.val) < \(y.val)")
return x.val < y.val // <--- SET BREAKPOINT HERE
}
var array = [MyStruct]()
for _ in 1 ... 30 {
array.append(MyStruct(val: Int(arc4random_uniform(1000))))
}
sort(&array)
shows the following stack backtrace:
(lldb) bt
* thread #1: tid = 0x5a00, 0x00000001001cb806 sort`sort. Swift.Bool + 454 at main.swift:22, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00000001001cb806 sort`sort. Swift.Bool + 454 at main.swift:22
frame #1: 0x00000001001cb62b sort`protocol witness for Swift._Comparable.(Swift._Comparable.Self.Type)(Swift._Comparable.Self, Swift._Comparable.Self) -> Swift.Bool in conformance sort.MyStruct : Swift._Comparable + 27 at main.swift:20
frame #2: 0x00000001000f5a98 sort`Swift._partition (inout A, Swift.Range) -> A.Index + 3224
frame #3: 0x00000001000f756a sort`Swift._introSortImpl (inout A, Swift.Range, Swift.Int) -> () + 2138
frame #4: 0x00000001000f6c01 sort`Swift._introSort (inout A, Swift.Range) -> () + 1233
frame #5: 0x00000001000fc47f sort`Swift.sort (inout A) -> () + 607
frame #6: 0x000000010013ea77 sort`partial apply forwarder for Swift.(sort (inout Swift.Array) -> ()).(closure #1) + 183
frame #7: 0x000000010013eaf8 sort`partial apply forwarder for reabstraction thunk helper from #callee_owned (#inout Swift.UnsafeMutableBufferPointer) -> (#unowned ()) to #callee_owned (#inout Swift.UnsafeMutableBufferPointer) -> (#out ()) + 56
frame #8: 0x0000000100046c4b sort`Swift.Array.withUnsafeMutableBufferPointer (inout Swift.Array)((inout Swift.UnsafeMutableBufferPointer) -> B) -> B + 475
frame #9: 0x00000001000fc5ad sort`Swift.sort (inout Swift.Array) -> () + 157
frame #10: 0x00000001001cb465 sort`top_level_code + 1237 at main.swift:29
frame #11: 0x00000001001cbdca sort`main + 42 at main.swift:0
frame #12: 0x00007fff8aa9a5fd libdyld.dylib`start + 1
and later
(lldb) bt
* thread #1: tid = 0x5a00, 0x00000001001cb806 sort`sort. Swift.Bool + 454 at main.swift:22, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00000001001cb806 sort`sort. Swift.Bool + 454 at main.swift:22
frame #1: 0x00000001001cb62b sort`protocol witness for Swift._Comparable.(Swift._Comparable.Self.Type)(Swift._Comparable.Self, Swift._Comparable.Self) -> Swift.Bool in conformance sort.MyStruct : Swift._Comparable + 27 at main.swift:20
frame #2: 0x00000001000f449e sort`Swift._insertionSort (inout A, Swift.Range) -> () + 2958
frame #3: 0x00000001000f730e sort`Swift._introSortImpl (inout A, Swift.Range, Swift.Int) -> () + 1534
frame #4: 0x00000001000f797d sort`Swift._introSortImpl (inout A, Swift.Range, Swift.Int) -> () + 3181
frame #5: 0x00000001000f6c01 sort`Swift._introSort (inout A, Swift.Range) -> () + 1233
frame #6: 0x00000001000fc47f sort`Swift.sort (inout A) -> () + 607
frame #7: 0x000000010013ea77 sort`partial apply forwarder for Swift.(sort (inout Swift.Array) -> ()).(closure #1) + 183
frame #8: 0x000000010013eaf8 sort`partial apply forwarder for reabstraction thunk helper from #callee_owned (#inout Swift.UnsafeMutableBufferPointer) -> (#unowned ()) to #callee_owned (#inout Swift.UnsafeMutableBufferPointer) -> (#out ()) + 56
frame #9: 0x0000000100046c4b sort`Swift.Array.withUnsafeMutableBufferPointer (inout Swift.Array)((inout Swift.UnsafeMutableBufferPointer) -> B) -> B + 475
frame #10: 0x00000001000fc5ad sort`Swift.sort (inout Swift.Array) -> () + 157
frame #11: 0x00000001001cb465 sort`top_level_code + 1237 at main.swift:29
frame #12: 0x00000001001cbdca sort`main + 42 at main.swift:0
frame #13: 0x00007fff8aa9a5fd libdyld.dylib`start + 1
This confirms the conjecture of Airspeed's answer that introsort is used
in combination with insertion sort for the smaller ranges.
If the array has less than 20 elements then only insertion sort seems to be used.
This could indicate that the threshold for switching from introsort to
insertion sort is 20.
Of course the implementation might change in the future.
Not a definitive answer, just guesswork – only the Swift std lib dev team can tell and they haven’t (scratch that, #martin-r shows how you can tell via the debugger! It's a hybrid introsort/insertion sort):
The docs for sort don’t state complexity. They do state it isn’t stable though (i.e. equal elements aren’t guaranteed to stay in their original order), which suggests it’s not a merge sort (which is usually stable).
There’s several functions in the Swift std lib that look like they’re there as helpers for other functions in the lib. There’s a partition function, which is a key building block for quick sorts. In the very early Swift betas, there used to be two sorts in addition to the non-brand-name one: quickSort and insertionSort.
The GNU implementation of the C++ std library sort uses a hybrid of an introsort (which is itself a hybrid of quicksort and heapsort) sometimes combined with an insertion sort. So it’s possible these two variants were originally implemented as building blocks for the actual sort feature.
quickSort and insertionSort disappeared in later betas – if sort were a best-case hybrid of both, there’d be little point calling one of them. partition is still there tho, presumably since it’s useful as a standalone function.
I am wondering how Swift's sort function is implemented. Which sorting algorithm does it use—is it a mergesort, quicksort, or something completely different? What are the timing/complexity guarantees provided by this function?
I can't find any indication of how it is implemented either online or in the official documentation.
Update 2: As we can see in Sort.swift, sort() now uses a “modified timsort” in Swift 5. Timsort is a
... hybrid stable sorting algorithm, derived from merge sort and insertion sort ...
In the worst case, Timsort takes O(n log n) comparisons to sort an array of n elements. In the best case, which occurs when the input is already sorted, it runs in linear time, meaning that it is an adaptive sorting algorithm.
This means that sort() happens to be a stable sort in Swift 5, but that is still an implementation detail. The MutableCollection.sort documentation states that
The sorting algorithm is not guaranteed to be stable. A stable sort preserves the relative order of elements that compare equal.
See also Is sort() stable in Swift 5? in the Swift forum:
The algorithm was only recently made stable in preparation for a proposal to make it guaranteed as such.
Update: Swift is open source now, and in
https://github.com/apple/swift/blob/master/stdlib/public/core/Sort.swift
one can see that sorting a collection is done using introsort
with a maximum recursion depth of 2*floor(log_2(N)). It switches to insertion sort for partitions with less than 20 elements, or to heapsort
if the recursion depth is reached.
Old answer: Defining a custom Comparable structure and setting in breakpoint in <:
struct MyStruct : Comparable {
let val : Int
}
func ==(x: MyStruct, y: MyStruct) -> Bool {
println("\(x.val) == \(y.val)")
return x.val == y.val
}
func <(x: MyStruct, y: MyStruct) -> Bool {
println("\(x.val) < \(y.val)")
return x.val < y.val // <--- SET BREAKPOINT HERE
}
var array = [MyStruct]()
for _ in 1 ... 30 {
array.append(MyStruct(val: Int(arc4random_uniform(1000))))
}
sort(&array)
shows the following stack backtrace:
(lldb) bt
* thread #1: tid = 0x5a00, 0x00000001001cb806 sort`sort. Swift.Bool + 454 at main.swift:22, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00000001001cb806 sort`sort. Swift.Bool + 454 at main.swift:22
frame #1: 0x00000001001cb62b sort`protocol witness for Swift._Comparable.(Swift._Comparable.Self.Type)(Swift._Comparable.Self, Swift._Comparable.Self) -> Swift.Bool in conformance sort.MyStruct : Swift._Comparable + 27 at main.swift:20
frame #2: 0x00000001000f5a98 sort`Swift._partition (inout A, Swift.Range) -> A.Index + 3224
frame #3: 0x00000001000f756a sort`Swift._introSortImpl (inout A, Swift.Range, Swift.Int) -> () + 2138
frame #4: 0x00000001000f6c01 sort`Swift._introSort (inout A, Swift.Range) -> () + 1233
frame #5: 0x00000001000fc47f sort`Swift.sort (inout A) -> () + 607
frame #6: 0x000000010013ea77 sort`partial apply forwarder for Swift.(sort (inout Swift.Array) -> ()).(closure #1) + 183
frame #7: 0x000000010013eaf8 sort`partial apply forwarder for reabstraction thunk helper from #callee_owned (#inout Swift.UnsafeMutableBufferPointer) -> (#unowned ()) to #callee_owned (#inout Swift.UnsafeMutableBufferPointer) -> (#out ()) + 56
frame #8: 0x0000000100046c4b sort`Swift.Array.withUnsafeMutableBufferPointer (inout Swift.Array)((inout Swift.UnsafeMutableBufferPointer) -> B) -> B + 475
frame #9: 0x00000001000fc5ad sort`Swift.sort (inout Swift.Array) -> () + 157
frame #10: 0x00000001001cb465 sort`top_level_code + 1237 at main.swift:29
frame #11: 0x00000001001cbdca sort`main + 42 at main.swift:0
frame #12: 0x00007fff8aa9a5fd libdyld.dylib`start + 1
and later
(lldb) bt
* thread #1: tid = 0x5a00, 0x00000001001cb806 sort`sort. Swift.Bool + 454 at main.swift:22, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
* frame #0: 0x00000001001cb806 sort`sort. Swift.Bool + 454 at main.swift:22
frame #1: 0x00000001001cb62b sort`protocol witness for Swift._Comparable.(Swift._Comparable.Self.Type)(Swift._Comparable.Self, Swift._Comparable.Self) -> Swift.Bool in conformance sort.MyStruct : Swift._Comparable + 27 at main.swift:20
frame #2: 0x00000001000f449e sort`Swift._insertionSort (inout A, Swift.Range) -> () + 2958
frame #3: 0x00000001000f730e sort`Swift._introSortImpl (inout A, Swift.Range, Swift.Int) -> () + 1534
frame #4: 0x00000001000f797d sort`Swift._introSortImpl (inout A, Swift.Range, Swift.Int) -> () + 3181
frame #5: 0x00000001000f6c01 sort`Swift._introSort (inout A, Swift.Range) -> () + 1233
frame #6: 0x00000001000fc47f sort`Swift.sort (inout A) -> () + 607
frame #7: 0x000000010013ea77 sort`partial apply forwarder for Swift.(sort (inout Swift.Array) -> ()).(closure #1) + 183
frame #8: 0x000000010013eaf8 sort`partial apply forwarder for reabstraction thunk helper from #callee_owned (#inout Swift.UnsafeMutableBufferPointer) -> (#unowned ()) to #callee_owned (#inout Swift.UnsafeMutableBufferPointer) -> (#out ()) + 56
frame #9: 0x0000000100046c4b sort`Swift.Array.withUnsafeMutableBufferPointer (inout Swift.Array)((inout Swift.UnsafeMutableBufferPointer) -> B) -> B + 475
frame #10: 0x00000001000fc5ad sort`Swift.sort (inout Swift.Array) -> () + 157
frame #11: 0x00000001001cb465 sort`top_level_code + 1237 at main.swift:29
frame #12: 0x00000001001cbdca sort`main + 42 at main.swift:0
frame #13: 0x00007fff8aa9a5fd libdyld.dylib`start + 1
This confirms the conjecture of Airspeed's answer that introsort is used
in combination with insertion sort for the smaller ranges.
If the array has less than 20 elements then only insertion sort seems to be used.
This could indicate that the threshold for switching from introsort to
insertion sort is 20.
Of course the implementation might change in the future.
Not a definitive answer, just guesswork – only the Swift std lib dev team can tell and they haven’t (scratch that, #martin-r shows how you can tell via the debugger! It's a hybrid introsort/insertion sort):
The docs for sort don’t state complexity. They do state it isn’t stable though (i.e. equal elements aren’t guaranteed to stay in their original order), which suggests it’s not a merge sort (which is usually stable).
There’s several functions in the Swift std lib that look like they’re there as helpers for other functions in the lib. There’s a partition function, which is a key building block for quick sorts. In the very early Swift betas, there used to be two sorts in addition to the non-brand-name one: quickSort and insertionSort.
The GNU implementation of the C++ std library sort uses a hybrid of an introsort (which is itself a hybrid of quicksort and heapsort) sometimes combined with an insertion sort. So it’s possible these two variants were originally implemented as building blocks for the actual sort feature.
quickSort and insertionSort disappeared in later betas – if sort were a best-case hybrid of both, there’d be little point calling one of them. partition is still there tho, presumably since it’s useful as a standalone function.
Read all of the posts regarding this error being memory related and trying to access something that is no longer there.
Problem: Error pops up at virtually random intervals. It can appear after the first enemy is killed or the Nth enemy is killed. However, it ONLY appears when an enemy is killed.
Testing: Running iOS 8 beta 5, Xcode 6 beta 5 on iPhone 5s.
Code flow:
Enemy SKNodes class instances are created at start of level and stored in NSMutableArray for reference:
Goblin *newGoblin = [[Goblin alloc] initFacingDirection:1];
// set various properties…
[enemyGoblins addObject:newGoblin];
Player’s sword makes contact with enemy:
NSMutableArray *discardedItems = [NSMutableArray array];
for(Goblin *object in enemyGoblins)
{
[object runBloodBurst:true damagePoints:_player.swordDamage];
if(object.goblinHealth < 0)
[discardedItems addObject:object];
}
if([discardedItems count] > 0)
[enemyGoblins removeObjectsInArray:discardedItems];
In the Goblin class, the “die” code is:
if(self.goblinHealth < 0)
{
SKAction *wait0 = [SKAction waitForDuration:1.0];
SKAction *block0 = [SKAction runBlock:^{
[self removeActionForKey:#"animation"];
[self runAction:[_animations goblin_dieLeft]];
}];
SKAction *block1 = [SKAction runBlock:^{
[self removeFromParent];
}];
[self runAction:[SKAction sequence:#[block0, wait0, block1]]];
}
What I’ve tried:
I disabled the “discardedItems” code because I thought ARC might dump the object from memory once the reference was lost and the subsequent Goblin class’ “die animation” would cause the crash but this did not resolve the issue.
I tried zombies and breakpoints but got no useful clues either.
Am I barking up the wrong tree in regards to what I’ve tried or has anyone experienced a similar issue in Beta 5?
EDIT
Here is the backtrace:
(lldb) bt
* thread #1: tid = 0x3264b, 0x000000018cb13434 SpriteKitSKCSprite::update(double) + 404, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x7000000000000018)
frame #0: 0x000000018cb13434 SpriteKitSKCSprite::update(double) + 404
frame #1: 0x000000018cb13440 SpriteKitSKCSprite::update(double) + 416
frame #2: 0x000000018cb13440 SpriteKitSKCSprite::update(double) + 416
frame #3: 0x000000018cacbf28 SpriteKit-[SKScene _update:] + 140
frame #4: 0x000000018cae63f8 SpriteKit-[SKView(Private) _update:] + 568
frame #5: 0x000000018cae3a10 SpriteKit-[SKView renderCallback:] + 764
frame #6: 0x000000018cae0a9c SpriteKit__29-[SKView setUpRenderCallback]_block_invoke + 60
frame #7: 0x000000018cb0d890 SpriteKit-[SKDisplayLink _callbackForNextFrame:] + 272
frame #8: 0x000000010042ca9c libglInterpose.dylib-[DYDisplayLinkInterposer forwardDisplayLinkCallback:] + 168
frame #9: 0x000000018c615b90 QuartzCoreCA::Display::DisplayLinkItem::dispatch() + 32
frame #10: 0x000000018c615a28 QuartzCoreCA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 324
frame #11: 0x00000001897dddc0 IOKitIODispatchCalloutFromCFMessage + 376
frame #12: 0x00000001885dcf34 CoreFoundation__CFMachPortPerform + 180
frame #13: 0x00000001885f1b38 CoreFoundation__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 56
frame #14: 0x00000001885f1a98 CoreFoundation__CFRunLoopDoSource1 + 436
frame #15: 0x00000001885efa18 CoreFoundation__CFRunLoopRun + 1640
frame #16: 0x000000018851d664 CoreFoundationCFRunLoopRunSpecific + 396
frame #17: 0x000000019154f5a4 GraphicsServicesGSEventRunModal + 168
frame #18: 0x000000018ccd6164 UIKitUIApplicationMain + 1488
* frame #19: 0x0000000100165530 CarcerQuestmain(argc=1, argv=0x000000016fdab9d8) + 116 at main.m:16
frame #20: 0x000000019885aa08 libdyld.dylibstart + 4
(lldb)
change
[self runAction:[SKAction sequence:#[block0, wait0, block1]]];
to
[self runAction:[SKAction sequence:#[block0, wait0]] completion:^{
[_self removeFromParent];
}];
I ran in to the same issue when updating IOS7 code to run on IOS8, and using the completion block fixed the issue.
Reading through the comments of your question, I'm not sure if you've solved this problem, and your code snippet isn't complete enough for me to see your issue, but I recently ran into a similar problem and it took me a while to figure out, so I'd post it in case it's helpful to you or some future reader of the post.
You can see my code change here: https://github.com/ik/2048/commit/3ffec547367320c7e179624a14ac5867ed1acea2
Basically what happens is runAction is async. It is executed in the next screen refresh cycle (hence the display link call in your stack trace). So if you call removeSomething after your runAction, it can be executed before the action is run, and you will crash.
At least that's what caught me - I don't know why it never occurred in iOS 7. See code below.
- [self removeFromParentCell]; // Used to call it here - wrong.
SKAction *wait = [SKAction waitForDuration:GSTATE.animationDuration];
SKAction *remove = [SKAction removeFromParent];
- [self runAction:[SKAction sequence:#[wait, remove]]];
+ [self runAction:[SKAction sequence:#[wait, remove]] completion:^{
+ [self removeFromParentCell]; // This is right.
+ }];
After scouring the Apple Support Forums and running the same project on iOS 7, it appears this is a Beta release bug and not faulty code after all.