Is it possible to get the target of a delegate on iOS?

I’m trying to improve my cross-platform implementation of the weak event pattern (https://msdn.microsoft.com/en-us/library/aa970850(v=vs.100).aspx).

Currently my impl require the listener register to pass an additional gcTarget parameter as below:

public class WeakSimpleEvent {

    public void addWeak(object gcTarget, Action listener) {
        // GcBinder will ensure a strong ref to listener until the gcTarget is recycled.
        GcBinder.bind(listener, gcTarget);
        addImpl(listener);
    }

But in the impl of .NET’s WeakEventManager, it’s easy to ignore such a gcTarget, because it can be obtained directly by listener.Target.

And in Java, since each delegate is implemented as a new anoymous class, it will certainly contain a hidden ref of outer object if it’s non-static, which is named as “argN” by Elements compiler and “this$N” in official Java. So it’s still possible to make the improvement.

But for iOS, I’ve found the delegate is implemented as a NSMallocBlock object which I still can’t find a way to get sth equivalent to gcTarget. After learning this artical (http://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html), I think in theory, the block’s invoke needs to call another object’s method, so the block structure must store a pointer to that object.

I know this improvement depends on details of specific compiler, but the weak event pattern is really useful for UI dev. Maybe Elements can consider to provide a Target property for cross-platform Delegate implementation.

Oke that’s a bit tricky. OSX doesn’t really do “delegates”. They have function pointers (which can’t take a “self”) and blocks, which only take lambdas/anonymous methods. We use a trick to make them act like they are function pointers:
Given this code:

                public void Do(Action x) { 	
  		    x();
		}

		private void Method() {}
		private void StaticMethod() {}

		private void DoMethod()		
		{			 
			Do(Method);
		}
		private void DoStaticMethod()		
		{			 
			Do(StaticMethod);
		}
		private void DoAnonymous()		
		{			 
			Do(() => { 
			});
		}

it generates three anonymous methods:

// DoAnonymous
global void  @"__ConsoleApplication372_Program <DoAnonymous>b__0$0"(block_literalex* value) {
  return
}

// DoMethod
global void @"__ConsoleApplication372_Program__Program.<>c__DisplayClass0 <DoMethod>b__0$0"(block_literalex* param) {
  var blockholder = (nested0*)((*param).extrainfo);
  var self = (nested0*)(*blockholder).self;
   ...
}

global void @"__ConsoleApplication372_Program__Program.<>c__DisplayClass0 <DoStaticMethod>b__0$0"(block_literalex* param) {
  var blockholder = (nested1*)((*param).extrainfo);
  var self = (nested1*)(*blockholder).self;
   ...
}


struct block_literal = { byte* tty, int flags1, int flags2, byte*ptr1, byte* ptr2  }
struct block_literalex = { byte* tty, int flags1, int flags2, byte*ptr1, byte* ptr2, byte* extrainfo }
struct _nested0 { byte* tty, nested0* selfptr, int flags1, int flags2, byte* ptr1, byte* ptr2, %._ConsoleApplication372.Program* self }
struct _nested0 { byte* tty, nested0* selfptr, int flags1, int flags2, byte* ptr1, byte* ptr2, %._ConsoleApplication372.Program* self }

The problem here is that there’s no really good way to make sure it’s a call vs anonymous.

(Full IR below:)

; ModuleID = 'ConsoleApplication372'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.11"

%struct._class_t = type { %struct._class_t*, %struct._class_t*, %struct._objc_cache*, i8* (i8*, i8*)**, %struct._class_ro_t* }
%struct._objc_cache = type opaque
%struct._class_ro_t = type { i32, i32, i32, i8*, i8*, %struct.__method_list_t*, %struct._objc_protocol_list*, %struct._ivar_list_t*, i8*, %struct._prop_list_t* }
%struct.__method_list_t = type { i32, i32, [0 x %struct._objc_method] }
%struct._objc_method = type { i8*, i8*, i8* }
%struct._objc_protocol_list = type { i64, [0 x %struct._protocol_t*] }
%struct._protocol_t = type { i8*, i8*, %struct._objc_protocol_list*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct.__method_list_t*, %struct._prop_list_t*, i32, i32, i8**, i8** }
%struct._ivar_list_t = type { i32, i32, [0 x %struct._ivar_t] }
%struct._ivar_t = type { i64*, i8*, i8*, i32, i32 }
%struct._prop_list_t = type { i32, i32, [0 x %struct._prop_t] }
%struct._prop_t = type { i8*, i8* }
%struct._block_literal = type { i8*, i32, i32, i8*, i8* }
%struct.NSConstantString = type { i32*, i32, i8*, i64 }
%._ConsoleApplication372.Program = type opaque
%struct._block_literalex = type { i8*, i32, i32, i8*, i8*, i8* }
%._nested0 = type { i8*, %._nested0*, i32, i32, i8*, i8*, %._ConsoleApplication372.Program* }
%._nested1 = type { i8*, %._nested1*, i32, i32, i8*, i8*, %._ConsoleApplication372.Program* }
%._Foundation.NSString = type opaque
%._Foundation.NSArray = type opaque
%._Foundation.NSProcessInfo = type opaque
%._RemObjects.Oxygene.System.id = type opaque

@"OBJC_METACLASS_$___ConsoleApplication372_Program" = global %struct._class_t { %struct._class_t* @"OBJC_METACLASS_$_NSObject", %struct._class_t* @"OBJC_METACLASS_$_NSObject", %struct._objc_cache* @_objc_empty_cache, i8* (i8*, i8*)** @_objc_empty_vtable, %struct._class_ro_t* @"\01l_OBJC_METACLASS_RO_$___ConsoleApplication372_Program" }, section "__DATA, __objc_data", align 8
@"\01L_OBJC_METHNAME_0_Do:" = internal global [4 x i8] c"Do:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_VARTYPE_1_v24@0:8^?16" = internal global [12 x i8] c"v24@0:8^?16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
@"\01L_OBJC_METHNAME_2_Method" = internal global [7 x i8] c"Method\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_VARTYPE_3_v16@0:8" = internal global [8 x i8] c"v16@0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
@"\01L_OBJC_METHNAME_4_StaticMethod" = internal global [13 x i8] c"StaticMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_METHNAME_5_DoMethod" = internal global [9 x i8] c"DoMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_METHNAME_6_DoStaticMethod" = internal global [15 x i8] c"DoStaticMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_METHNAME_7_DoAnonymous" = internal global [12 x i8] c"DoAnonymous\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_METHNAME_8_Main:" = internal global [6 x i8] c"Main:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_VARTYPE_9_l24@0:8^@16" = internal global [12 x i8] c"l24@0:8^@16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
@"\01l_OBJC_$_CLASS_METHODS___ConsoleApplication372_Program" = internal global { i32, i32, [7 x %struct._objc_method] } { i32 24, i32 7, [7 x %struct._objc_method] [%struct._objc_method { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_OBJC_METHNAME_0_Do:", i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"\01L_OBJC_VARTYPE_1_v24@0:8^?16", i32 0, i32 0), i8* bitcast (void (%._ConsoleApplication372.Program*, i8*, %struct._block_literalex*)* @"\01+[__ConsoleApplication372_Program Do:]" to i8*) }, %struct._objc_method { i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_OBJC_METHNAME_2_Method", i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01L_OBJC_VARTYPE_3_v16@0:8", i32 0, i32 0), i8* bitcast (void (%._ConsoleApplication372.Program*, i8*)* @"\01+[__ConsoleApplication372_Program Method]" to i8*) }, %struct._objc_method { i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"\01L_OBJC_METHNAME_4_StaticMethod", i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01L_OBJC_VARTYPE_3_v16@0:8", i32 0, i32 0), i8* bitcast (void (%._ConsoleApplication372.Program*, i8*)* @"\01+[__ConsoleApplication372_Program StaticMethod]" to i8*) }, %struct._objc_method { i8* getelementptr inbounds ([9 x i8], [9 x i8]* @"\01L_OBJC_METHNAME_5_DoMethod", i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01L_OBJC_VARTYPE_3_v16@0:8", i32 0, i32 0), i8* bitcast (void (%._ConsoleApplication372.Program*, i8*)* @"\01+[__ConsoleApplication372_Program DoMethod]" to i8*) }, %struct._objc_method { i8* getelementptr inbounds ([15 x i8], [15 x i8]* @"\01L_OBJC_METHNAME_6_DoStaticMethod", i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01L_OBJC_VARTYPE_3_v16@0:8", i32 0, i32 0), i8* bitcast (void (%._ConsoleApplication372.Program*, i8*)* @"\01+[__ConsoleApplication372_Program DoStaticMethod]" to i8*) }, %struct._objc_method { i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"\01L_OBJC_METHNAME_7_DoAnonymous", i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01L_OBJC_VARTYPE_3_v16@0:8", i32 0, i32 0), i8* bitcast (void (%._ConsoleApplication372.Program*, i8*)* @"\01+[__ConsoleApplication372_Program DoAnonymous]" to i8*) }, %struct._objc_method { i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_OBJC_METHNAME_8_Main:", i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"\01L_OBJC_VARTYPE_9_l24@0:8^@16", i32 0, i32 0), i8* bitcast (i32 (%._ConsoleApplication372.Program*, i8*, %._Foundation.NSString**)* @"\01+[__ConsoleApplication372_Program Main:]" to i8*) }] }, section "__DATA, __objc_const", align 8
@"\01L_OBJC_CLASS_NAME_10___ConsoleApplication372_Program" = internal global [32 x i8] c"__ConsoleApplication372_Program\00", section "__TEXT,__objc_classname,cstring_literals", align 1
@"\01l_OBJC_METACLASS_RO_$___ConsoleApplication372_Program" = internal global %struct._class_ro_t { i32 129, i32 40, i32 40, i8* null, i8* getelementptr inbounds ([32 x i8], [32 x i8]* @"\01L_OBJC_CLASS_NAME_10___ConsoleApplication372_Program", i32 0, i32 0), %struct.__method_list_t* bitcast ({ i32, i32, [7 x %struct._objc_method] }* @"\01l_OBJC_$_CLASS_METHODS___ConsoleApplication372_Program" to %struct.__method_list_t*), %struct._objc_protocol_list* null, %struct._ivar_list_t* null, i8* null, %struct._prop_list_t* null }, section "__DATA, __objc_const", align 8
@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
@_objc_empty_cache = external global %struct._objc_cache
@_objc_empty_vtable = external global i8* (i8*, i8*)*
@"\01l_OBJC_CLASS_RO_$___ConsoleApplication372_Program" = internal global %struct._class_ro_t { i32 128, i32 8, i32 8, i8* null, i8* getelementptr inbounds ([32 x i8], [32 x i8]* @"\01L_OBJC_CLASS_NAME_10___ConsoleApplication372_Program", i32 0, i32 0), %struct.__method_list_t* null, %struct._objc_protocol_list* null, %struct._ivar_list_t* null, i8* null, %struct._prop_list_t* null }, section "__DATA, __objc_const", align 8
@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
@".RealClassDataFor___ConsoleApplication372_Program$Real" = internal global { [8 x i8], i8*, %struct._class_t } { [8 x i8] c"Elements", i8* bitcast ({ i64, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @".RealClassDataFor___ConsoleApplication372_Program$ExtraMetadata" to i8*), %struct._class_t { %struct._class_t* @"OBJC_METACLASS_$___ConsoleApplication372_Program", %struct._class_t* @"OBJC_CLASS_$_NSObject", %struct._objc_cache* @_objc_empty_cache, i8* (i8*, i8*)** @_objc_empty_vtable, %struct._class_ro_t* @"\01l_OBJC_CLASS_RO_$___ConsoleApplication372_Program" } }, section "__DATA, __objc_data", align 8
@"\01L_OBJC_SEL_REF_11_Do:" = internal global i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_OBJC_METHNAME_0_Do:", i64 0, i64 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8
@_NSConcreteStackBlock = external global i8*
@__block_descriptor_1 = internal constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 40, i8* bitcast (void (%struct._block_literalex*, %struct._block_literalex*)* @"\01block_copy_helper_1" to i8*), i8* bitcast (void (%struct._block_literalex*)* @"\01block_destroy_helper_1" to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str0, i32 0, i32 0), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_OBJC_CLASS_NAME_12_\011", i32 0, i32 0) }
@.str0 = private unnamed_addr constant [6 x i8] c"v8@?0\00", section "__TEXT,__cstring,cstring_literals", align 1
@"\01L_OBJC_CLASS_NAME_12_\011" = internal global [3 x i8] c"\011\00", section "__TEXT,__objc_classname,cstring_literals", align 1
@__block_descriptor_3 = internal constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 40, i8* bitcast (void (%struct._block_literalex*, %struct._block_literalex*)* @"\01block_copy_helper_3" to i8*), i8* bitcast (void (%struct._block_literalex*)* @"\01block_destroy_helper_3" to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str0, i32 0, i32 0), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_OBJC_CLASS_NAME_12_\011", i32 0, i32 0) }
@_NSConcreteGlobalBlock = external global i8*
@__block_descriptor_4 = internal constant { i64, i64, i8*, i8* } { i64 0, i64 32, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str0, i32 0, i32 0), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_OBJC_CLASS_NAME_12_\011", i32 0, i32 0) }
@.block_literal_4 = internal global %struct._block_literal { i8* bitcast (i8** @_NSConcreteGlobalBlock to i8*), i32 1342177280, i32 0, i8* bitcast (void (%struct._block_literalex*)* @"__ConsoleApplication372_Program <DoAnonymous>b__0$0" to i8*), i8* bitcast ({ i64, i64, i8*, i8* }* @__block_descriptor_4 to i8*) }
@.str1 = private unnamed_addr constant [24 x i8] c"The magic happens here.\00", section "__TEXT,__cstring,cstring_literals", align 1
@"\01L_OBJC_METHNAME_13_class" = internal global [6 x i8] c"class\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_SEL_REF_14_class" = internal global i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_OBJC_METHNAME_13_class", i64 0, i64 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8
@"OBJC_CLASS_$_NSException" = external global %struct._class_t
@"\01L_OBJC_CLASSLIST_REFERENCES_$_15_NSException" = internal global %struct._class_t* @"OBJC_CLASS_$_NSException", section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8
@"\01L_OBJC_METHNAME_16_raise:format:" = internal global [14 x i8] c"raise:format:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_SEL_REF_17_raise:format:" = internal global i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_OBJC_METHNAME_16_raise:format:", i64 0, i64 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8
@__CFConstantStringClassReference = external global [0 x i32]
@.str2 = private unnamed_addr constant [23 x i8] c"NullReferenceException\00", section "__TEXT,__cstring,cstring_literals", align 1
@_unnamed_cfstring_3 = private constant %struct.NSConstantString { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr inbounds ([23 x i8], [23 x i8]* @.str2, i32 0, i32 0), i64 22 }, section "__DATA,__cfstring"
@.str4 = private unnamed_addr constant [25 x i8] c"Null Reference Exception\00", section "__TEXT,__cstring,cstring_literals", align 1
@_unnamed_cfstring_5 = private constant %struct.NSConstantString { i32* getelementptr inbounds ([0 x i32], [0 x i32]* @__CFConstantStringClassReference, i32 0, i32 0), i32 1992, i8* getelementptr inbounds ([25 x i8], [25 x i8]* @.str4, i32 0, i32 0), i64 24 }, section "__DATA,__cfstring"
@"\01L_OBJC_SEL_REF_18_Method" = internal global i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_OBJC_METHNAME_2_Method", i64 0, i64 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8
@"\01L_OBJC_SEL_REF_19_StaticMethod" = internal global i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"\01L_OBJC_METHNAME_4_StaticMethod", i64 0, i64 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8
@"OBJC_CLASS_$_NSProcessInfo" = external global %struct._class_t
@"\01L_OBJC_CLASSLIST_REFERENCES_$_20_NSProcessInfo" = internal global %struct._class_t* @"OBJC_CLASS_$_NSProcessInfo", section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8
@"\01L_OBJC_METHNAME_21_processInfo" = internal global [12 x i8] c"processInfo\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_SEL_REF_22_processInfo" = internal global i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"\01L_OBJC_METHNAME_21_processInfo", i64 0, i64 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8
@"\01L_OBJC_METHNAME_23_arguments" = internal global [10 x i8] c"arguments\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_SEL_REF_24_arguments" = internal global i8* getelementptr inbounds ([10 x i8], [10 x i8]* @"\01L_OBJC_METHNAME_23_arguments", i64 0, i64 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8
@"\01L_OBJC_METHNAME_25_count" = internal global [6 x i8] c"count\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_SEL_REF_26_count" = internal global i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_OBJC_METHNAME_25_count", i64 0, i64 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8
@0 = private constant <{ i32, i64, i64, i8* }> <{ i32 1, i64 8, i64 1, i8* bitcast (void (i8*)* @objc_release to i8*) }>
@"\01L_OBJC_METHNAME_27_objectAtIndexedSubscript:" = internal global [26 x i8] c"objectAtIndexedSubscript:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
@"\01L_OBJC_SEL_REF_28_objectAtIndexedSubscript:" = internal global i8* getelementptr inbounds ([26 x i8], [26 x i8]* @"\01L_OBJC_METHNAME_27_objectAtIndexedSubscript:", i64 0, i64 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8
@"\01L_OBJC_CLASSLIST_REFERENCES_$_29___ConsoleApplication372_Program" = internal global %struct._class_t* @"OBJC_CLASS_$___ConsoleApplication372_Program", section "__DATA, __objc_classrefs, regular, no_dead_strip", align 8
@"\01L_OBJC_SEL_REF_30_Main:" = internal global i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_OBJC_METHNAME_8_Main:", i64 0, i64 0), section "__DATA, __objc_selrefs, literal_pointers, no_dead_strip", align 8
@".RealClassDataFor___ConsoleApplication372_Program$ExtraMetadata" = internal constant { i64, i8*, i8*, i8*, i8*, i8*, i8*, i8* } { i64 64, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null, i8* null }
@"\01L_OBJC_LABEL_CLASS_$" = internal global [1 x i8*] [i8* bitcast (%struct._class_t* @"OBJC_CLASS_$___ConsoleApplication372_Program" to i8*)], section "__DATA, __objc_classlist, regular, no_dead_strip", align 8
@llvm.used = appending global [32 x i8*] [i8* bitcast (%struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_15_NSException" to i8*), i8* bitcast (%struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_20_NSProcessInfo" to i8*), i8* bitcast (%struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_29___ConsoleApplication372_Program" to i8*), i8* getelementptr inbounds ([32 x i8], [32 x i8]* @"\01L_OBJC_CLASS_NAME_10___ConsoleApplication372_Program", i32 0, i32 0), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_OBJC_CLASS_NAME_12_\011", i32 0, i32 0), i8* bitcast ([1 x i8*]* @"\01L_OBJC_LABEL_CLASS_$" to i8*), i8* getelementptr inbounds ([4 x i8], [4 x i8]* @"\01L_OBJC_METHNAME_0_Do:", i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_OBJC_METHNAME_13_class", i32 0, i32 0), i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_OBJC_METHNAME_16_raise:format:", i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"\01L_OBJC_METHNAME_21_processInfo", i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @"\01L_OBJC_METHNAME_23_arguments", i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_OBJC_METHNAME_25_count", i32 0, i32 0), i8* getelementptr inbounds ([26 x i8], [26 x i8]* @"\01L_OBJC_METHNAME_27_objectAtIndexedSubscript:", i32 0, i32 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_OBJC_METHNAME_2_Method", i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"\01L_OBJC_METHNAME_4_StaticMethod", i32 0, i32 0), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @"\01L_OBJC_METHNAME_5_DoMethod", i32 0, i32 0), i8* getelementptr inbounds ([15 x i8], [15 x i8]* @"\01L_OBJC_METHNAME_6_DoStaticMethod", i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"\01L_OBJC_METHNAME_7_DoAnonymous", i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @"\01L_OBJC_METHNAME_8_Main:", i32 0, i32 0), i8* bitcast (i8** @"\01L_OBJC_SEL_REF_11_Do:" to i8*), i8* bitcast (i8** @"\01L_OBJC_SEL_REF_14_class" to i8*), i8* bitcast (i8** @"\01L_OBJC_SEL_REF_17_raise:format:" to i8*), i8* bitcast (i8** @"\01L_OBJC_SEL_REF_18_Method" to i8*), i8* bitcast (i8** @"\01L_OBJC_SEL_REF_19_StaticMethod" to i8*), i8* bitcast (i8** @"\01L_OBJC_SEL_REF_22_processInfo" to i8*), i8* bitcast (i8** @"\01L_OBJC_SEL_REF_24_arguments" to i8*), i8* bitcast (i8** @"\01L_OBJC_SEL_REF_26_count" to i8*), i8* bitcast (i8** @"\01L_OBJC_SEL_REF_28_objectAtIndexedSubscript:" to i8*), i8* bitcast (i8** @"\01L_OBJC_SEL_REF_30_Main:" to i8*), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"\01L_OBJC_VARTYPE_1_v24@0:8^?16", i32 0, i32 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @"\01L_OBJC_VARTYPE_3_v16@0:8", i32 0, i32 0), i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"\01L_OBJC_VARTYPE_9_l24@0:8^@16", i32 0, i32 0)], section "llvm.metadata"

@"OBJC_CLASS_$___ConsoleApplication372_Program" = alias %struct._class_t, getelementptr inbounds ({ [8 x i8], i8*, %struct._class_t }, { [8 x i8], i8*, %struct._class_t }* @".RealClassDataFor___ConsoleApplication372_Program$Real", i32 0, i32 2)

; Function Attrs: uwtable
define void @"\01+[__ConsoleApplication372_Program Do:]"(%._ConsoleApplication372.Program* nocapture readnone, i8* nocapture readnone, %struct._block_literalex*) #0 {
  %4 = getelementptr %struct._block_literalex, %struct._block_literalex* %2, i64 0, i32 3
  %5 = bitcast i8** %4 to void (%struct._block_literalex*)**
  %6 = load void (%struct._block_literalex*)*, void (%struct._block_literalex*)** %5, align 8
  tail call void %6(%struct._block_literalex* %2)
  ret void
}

; Function Attrs: norecurse nounwind readnone uwtable
define void @"\01+[__ConsoleApplication372_Program Method]"(%._ConsoleApplication372.Program* nocapture, i8* nocapture) #1 {
  ret void
}

; Function Attrs: norecurse nounwind readnone uwtable
define void @"\01+[__ConsoleApplication372_Program StaticMethod]"(%._ConsoleApplication372.Program* nocapture, i8* nocapture) #1 {
  ret void
}

; Function Attrs: uwtable
define void @"\01+[__ConsoleApplication372_Program DoMethod]"(%._ConsoleApplication372.Program*, i8* nocapture readnone) #0 personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
  %_block1 = alloca %struct._block_literalex, align 8
  %_blockholder = alloca %._nested0, align 8
  %3 = getelementptr %._nested0, %._nested0* %_blockholder, i64 0, i32 0
  store i8* null, i8** %3, align 8
  %4 = getelementptr %._nested0, %._nested0* %_blockholder, i64 0, i32 1
  store %._nested0* %_blockholder, %._nested0** %4, align 8
  %5 = getelementptr %._nested0, %._nested0* %_blockholder, i64 0, i32 2
  store i32 33554432, i32* %5, align 8
  %6 = getelementptr %._nested0, %._nested0* %_blockholder, i64 0, i32 3
  store i32 48, i32* %6, align 4
  %7 = getelementptr %._nested0, %._nested0* %_blockholder, i64 0, i32 4
  store i8* bitcast (void (%._nested0*, %._nested0*)* @"\01block_byref_copy_helper_0" to i8*), i8** %7, align 8
  %8 = getelementptr %._nested0, %._nested0* %_blockholder, i64 0, i32 5
  store i8* bitcast (void (%._nested0*)* @"\01block_byref_destroy_helper_0" to i8*), i8** %8, align 8
  %9 = getelementptr %._nested0, %._nested0* %_blockholder, i64 0, i32 6
  store %._ConsoleApplication372.Program* null, %._ConsoleApplication372.Program** %9, align 8
  %10 = bitcast %._ConsoleApplication372.Program* %0 to i8*
  %11 = bitcast %._ConsoleApplication372.Program** %9 to i8**
  %12 = call i8* @objc_storeStrong(i8** %11, i8* %10)
  %13 = load i8*, i8** @"\01L_OBJC_SEL_REF_11_Do:", align 8
  %14 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block1, i64 0, i32 0
  store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %14, align 8
  %15 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block1, i64 0, i32 1
  store i32 -1040187392, i32* %15, align 8
  %16 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block1, i64 0, i32 2
  store i32 0, i32* %16, align 4
  %17 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block1, i64 0, i32 3
  store i8* bitcast (void (%struct._block_literalex*)* @"__ConsoleApplication372_Program__Program.<>c__DisplayClass0 <DoMethod>b__0$0" to i8*), i8** %17, align 8
  %18 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block1, i64 0, i32 4
  store i8* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @__block_descriptor_1 to i8*), i8** %18, align 8
  %19 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block1, i64 0, i32 5
  %20 = bitcast %._nested0* %_blockholder to i8*
  %21 = bitcast i8** %19 to %._nested0**
  store %._nested0* %_blockholder, %._nested0** %21, align 8
  %22 = bitcast %struct._block_literalex* %_block1 to i8*
  %23 = call i8* @objc_retainBlock(i8* %22)
  %24 = bitcast i8* %23 to %struct._block_literalex*
  invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%._ConsoleApplication372.Program*, i8*, %struct._block_literalex*)*)(%._ConsoleApplication372.Program* %0, i8* %13, %struct._block_literalex* %24)
          to label %30 unwind label %25

; <label>:25:                                     ; preds = %2
  %26 = landingpad { i8*, i32 }
          cleanup
  %27 = extractvalue { i8*, i32 } %26, 0
  %28 = extractvalue { i8*, i32 } %26, 1
  %29 = icmp eq i32 %28, 0
  br i1 %29, label %30, label %32

; <label>:30:                                     ; preds = %25, %2
  %.0 = phi i1 [ true, %2 ], [ false, %25 ]
  %eh_ptr.0 = phi i8* [ undef, %2 ], [ %27, %25 ]
  call void @objc_release(i8* %23) #3
  %31 = load i8*, i8** %11, align 8
  call void @_Block_object_dispose(i8* %20, i32 8)
  call void @objc_release(i8* %31) #3
  br i1 %.0, label %35, label %32

; <label>:32:                                     ; preds = %30, %25
  %eh_vals.1 = phi i32 [ 0, %30 ], [ %28, %25 ]
  %eh_ptr.1 = phi i8* [ %eh_ptr.0, %30 ], [ %27, %25 ]
  %33 = insertvalue { i8*, i32 } undef, i8* %eh_ptr.1, 0
  %34 = insertvalue { i8*, i32 } %33, i32 %eh_vals.1, 1
  resume { i8*, i32 } %34

; <label>:35:                                     ; preds = %30
  ret void
}

; Function Attrs: uwtable
define void @"\01+[__ConsoleApplication372_Program DoStaticMethod]"(%._ConsoleApplication372.Program*, i8* nocapture readnone) #0 personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
  %_block3 = alloca %struct._block_literalex, align 8
  %_blockholder = alloca %._nested1, align 8
  %3 = getelementptr %._nested1, %._nested1* %_blockholder, i64 0, i32 0
  store i8* null, i8** %3, align 8
  %4 = getelementptr %._nested1, %._nested1* %_blockholder, i64 0, i32 1
  store %._nested1* %_blockholder, %._nested1** %4, align 8
  %5 = getelementptr %._nested1, %._nested1* %_blockholder, i64 0, i32 2
  store i32 33554432, i32* %5, align 8
  %6 = getelementptr %._nested1, %._nested1* %_blockholder, i64 0, i32 3
  store i32 48, i32* %6, align 4
  %7 = getelementptr %._nested1, %._nested1* %_blockholder, i64 0, i32 4
  store i8* bitcast (void (%._nested1*, %._nested1*)* @"\01block_byref_copy_helper_2" to i8*), i8** %7, align 8
  %8 = getelementptr %._nested1, %._nested1* %_blockholder, i64 0, i32 5
  store i8* bitcast (void (%._nested1*)* @"\01block_byref_destroy_helper_2" to i8*), i8** %8, align 8
  %9 = getelementptr %._nested1, %._nested1* %_blockholder, i64 0, i32 6
  store %._ConsoleApplication372.Program* null, %._ConsoleApplication372.Program** %9, align 8
  %10 = bitcast %._ConsoleApplication372.Program* %0 to i8*
  %11 = bitcast %._ConsoleApplication372.Program** %9 to i8**
  %12 = call i8* @objc_storeStrong(i8** %11, i8* %10)
  %13 = load i8*, i8** @"\01L_OBJC_SEL_REF_11_Do:", align 8
  %14 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block3, i64 0, i32 0
  store i8* bitcast (i8** @_NSConcreteStackBlock to i8*), i8** %14, align 8
  %15 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block3, i64 0, i32 1
  store i32 -1040187392, i32* %15, align 8
  %16 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block3, i64 0, i32 2
  store i32 0, i32* %16, align 4
  %17 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block3, i64 0, i32 3
  store i8* bitcast (void (%struct._block_literalex*)* @"__ConsoleApplication372_Program__Program.<>c__DisplayClass1 <DoStaticMethod>b__0$0" to i8*), i8** %17, align 8
  %18 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block3, i64 0, i32 4
  store i8* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @__block_descriptor_3 to i8*), i8** %18, align 8
  %19 = getelementptr %struct._block_literalex, %struct._block_literalex* %_block3, i64 0, i32 5
  %20 = bitcast %._nested1* %_blockholder to i8*
  %21 = bitcast i8** %19 to %._nested1**
  store %._nested1* %_blockholder, %._nested1** %21, align 8
  %22 = bitcast %struct._block_literalex* %_block3 to i8*
  %23 = call i8* @objc_retainBlock(i8* %22)
  %24 = bitcast i8* %23 to %struct._block_literalex*
  invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%._ConsoleApplication372.Program*, i8*, %struct._block_literalex*)*)(%._ConsoleApplication372.Program* %0, i8* %13, %struct._block_literalex* %24)
          to label %30 unwind label %25

; <label>:25:                                     ; preds = %2
  %26 = landingpad { i8*, i32 }
          cleanup
  %27 = extractvalue { i8*, i32 } %26, 0
  %28 = extractvalue { i8*, i32 } %26, 1
  %29 = icmp eq i32 %28, 0
  br i1 %29, label %30, label %32

; <label>:30:                                     ; preds = %25, %2
  %.0 = phi i1 [ true, %2 ], [ false, %25 ]
  %eh_ptr.0 = phi i8* [ undef, %2 ], [ %27, %25 ]
  call void @objc_release(i8* %23) #3
  %31 = load i8*, i8** %11, align 8
  call void @_Block_object_dispose(i8* %20, i32 8)
  call void @objc_release(i8* %31) #3
  br i1 %.0, label %35, label %32

; <label>:32:                                     ; preds = %30, %25
  %eh_vals.1 = phi i32 [ 0, %30 ], [ %28, %25 ]
  %eh_ptr.1 = phi i8* [ %eh_ptr.0, %30 ], [ %27, %25 ]
  %33 = insertvalue { i8*, i32 } undef, i8* %eh_ptr.1, 0
  %34 = insertvalue { i8*, i32 } %33, i32 %eh_vals.1, 1
  resume { i8*, i32 } %34

; <label>:35:                                     ; preds = %30
  ret void
}

; Function Attrs: uwtable
define void @"\01+[__ConsoleApplication372_Program DoAnonymous]"(%._ConsoleApplication372.Program*, i8* nocapture readnone) #0 personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
  %3 = load i8*, i8** @"\01L_OBJC_SEL_REF_11_Do:", align 8
  %4 = tail call i8* @objc_retainBlock(i8* bitcast (%struct._block_literal* @.block_literal_4 to i8*))
  %5 = bitcast i8* %4 to %struct._block_literalex*
  invoke void bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (%._ConsoleApplication372.Program*, i8*, %struct._block_literalex*)*)(%._ConsoleApplication372.Program* %0, i8* %3, %struct._block_literalex* %5)
          to label %13 unwind label %6

; <label>:6:                                      ; preds = %2
  %7 = landingpad { i8*, i32 }
          cleanup
  %8 = extractvalue { i8*, i32 } %7, 1
  %9 = icmp eq i32 %8, 0
  br i1 %9, label %10, label %11

; <label>:10:                                     ; preds = %6
  tail call void @objc_release(i8* %4) #3
  br label %11

; <label>:11:                                     ; preds = %10, %6
  %eh_vals.1 = phi i32 [ 0, %10 ], [ %8, %6 ]
  %12 = insertvalue { i8*, i32 } %7, i32 %eh_vals.1, 1
  resume { i8*, i32 } %12

; <label>:13:                                     ; preds = %2
  tail call void @objc_release(i8* %4) #3
  ret void
}

; Function Attrs: nounwind uwtable
define i32 @"\01+[__ConsoleApplication372_Program Main:]"(%._ConsoleApplication372.Program* nocapture readnone, i8* nocapture readnone, %._Foundation.NSString** nocapture readnone) #2 personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
  %4 = tail call i8* @objc_autoreleasePoolPush() #3
  %5 = tail call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([24 x i8], [24 x i8]* @.str1, i64 0, i64 0))
  tail call void @objc_autoreleasePoolPop(i8* %4) #3
  ret i32 0
}

; Function Attrs: norecurse nounwind readnone uwtable
define void @"__ConsoleApplication372_Program <DoAnonymous>b__0$0"(%struct._block_literalex* nocapture) #1 {
  ret void
}

; Function Attrs: uwtable
define void @"__ConsoleApplication372_Program__Program.<>c__DisplayClass0 <DoMethod>b__0$0"(%struct._block_literalex* nocapture readonly) #0 {
  %2 = getelementptr %struct._block_literalex, %struct._block_literalex* %0, i64 0, i32 5
  %3 = bitcast i8** %2 to %._nested0**
  %4 = load %._nested0*, %._nested0** %3, align 8
  %5 = getelementptr %._nested0, %._nested0* %4, i64 0, i32 1
  %6 = load %._nested0*, %._nested0** %5, align 8
  %7 = getelementptr %._nested0, %._nested0* %6, i64 0, i32 6
  %8 = bitcast %._ConsoleApplication372.Program** %7 to i8**
  %9 = load i8*, i8** %8, align 8
  %10 = load i8*, i8** @"\01L_OBJC_SEL_REF_14_class", align 8
  %11 = tail call %._ConsoleApplication372.Program* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %._ConsoleApplication372.Program* (i8*, i8*)*)(i8* %9, i8* %10)
  %12 = icmp eq %._ConsoleApplication372.Program* %11, null
  br i1 %12, label %13, label %14

; <label>:13:                                     ; preds = %1
  tail call void @RaiseNullReferenceException()
  unreachable

; <label>:14:                                     ; preds = %1
  ret void
}

; Function Attrs: uwtable
define void @"__ConsoleApplication372_Program__Program.<>c__DisplayClass1 <DoStaticMethod>b__0$0"(%struct._block_literalex* nocapture readonly) #0 {
  %2 = getelementptr %struct._block_literalex, %struct._block_literalex* %0, i64 0, i32 5
  %3 = bitcast i8** %2 to %._nested1**
  %4 = load %._nested1*, %._nested1** %3, align 8
  %5 = getelementptr %._nested1, %._nested1* %4, i64 0, i32 1
  %6 = load %._nested1*, %._nested1** %5, align 8
  %7 = getelementptr %._nested1, %._nested1* %6, i64 0, i32 6
  %8 = bitcast %._ConsoleApplication372.Program** %7 to i8**
  %9 = load i8*, i8** %8, align 8
  %10 = load i8*, i8** @"\01L_OBJC_SEL_REF_14_class", align 8
  %11 = tail call %._ConsoleApplication372.Program* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %._ConsoleApplication372.Program* (i8*, i8*)*)(i8* %9, i8* %10)
  %12 = icmp eq %._ConsoleApplication372.Program* %11, null
  br i1 %12, label %13, label %14

; <label>:13:                                     ; preds = %1
  tail call void @RaiseNullReferenceException()
  unreachable

; <label>:14:                                     ; preds = %1
  ret void
}

; Function Attrs: uwtable
define i32 @main(i32, i8** nocapture readnone) #0 personality i8* bitcast (i32 (...)* @__objc_personality_v0 to i8*) {
  %3 = alloca %._Foundation.NSArray*, align 8
  store %._Foundation.NSArray* null, %._Foundation.NSArray** %3, align 8
  %4 = load %._Foundation.NSProcessInfo*, %._Foundation.NSProcessInfo** bitcast (%struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_20_NSProcessInfo" to %._Foundation.NSProcessInfo**), align 8
  %5 = load i8*, i8** @"\01L_OBJC_SEL_REF_22_processInfo", align 8
  %6 = invoke %._Foundation.NSProcessInfo* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %._Foundation.NSProcessInfo* (%._Foundation.NSProcessInfo*, i8*)*)(%._Foundation.NSProcessInfo* %4, i8* %5)
          to label %7 unwind label %.loopexit.split-lp

; <label>:7:                                      ; preds = %2
  %8 = bitcast %._Foundation.NSProcessInfo* %6 to i8*
  %9 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %8) #3
  %10 = icmp eq %._Foundation.NSProcessInfo* %6, null
  br i1 %10, label %11, label %12

; <label>:11:                                     ; preds = %7
  invoke void @RaiseNullReferenceException()
          to label %15 unwind label %.loopexit.split-lp

; <label>:12:                                     ; preds = %7
  %13 = load i8*, i8** @"\01L_OBJC_SEL_REF_24_arguments", align 8
  %14 = invoke %._Foundation.NSArray* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %._Foundation.NSArray* (%._Foundation.NSProcessInfo*, i8*)*)(%._Foundation.NSProcessInfo* nonnull %6, i8* %13)
          to label %16 unwind label %.loopexit.split-lp

; <label>:15:                                     ; preds = %11
  unreachable

; <label>:16:                                     ; preds = %12
  %17 = bitcast %._Foundation.NSArray* %14 to i8*
  %18 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %17) #3
  %19 = bitcast %._Foundation.NSArray** %3 to i8**
  %20 = call i8* @objc_storeStrong(i8** %19, i8* %17)
  call void @objc_release(i8* %17) #3
  %21 = load %._Foundation.NSArray*, %._Foundation.NSArray** %3, align 8
  %22 = icmp eq %._Foundation.NSArray* %21, null
  br i1 %22, label %23, label %24

; <label>:23:                                     ; preds = %16
  invoke void @RaiseNullReferenceException()
          to label %27 unwind label %.loopexit.split-lp

; <label>:24:                                     ; preds = %16
  %25 = load i8*, i8** @"\01L_OBJC_SEL_REF_26_count", align 8
  %26 = invoke i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (%._Foundation.NSArray*, i8*)*)(%._Foundation.NSArray* nonnull %21, i8* %25)
          to label %28 unwind label %.loopexit.split-lp

; <label>:27:                                     ; preds = %23
  unreachable

; <label>:28:                                     ; preds = %24
  %29 = add i64 %26, 4294967295
  %30 = and i64 %29, 4294967295
  %31 = call i64* @"\01array_create"(i64 8, i64 %30)
  %32 = bitcast i64* %31 to %._Foundation.NSString**
  call void @"\01array_dispose"(i64* null, <{ i32, i64, i64, i8* }>* nonnull @0)
  %33 = load %._Foundation.NSArray*, %._Foundation.NSArray** %3, align 8
  %34 = icmp eq %._Foundation.NSArray* %33, null
  br i1 %34, label %35, label %36

; <label>:35:                                     ; preds = %28
  invoke void @RaiseNullReferenceException()
          to label %39 unwind label %.loopexit.split-lp

; <label>:36:                                     ; preds = %28
  %37 = load i8*, i8** @"\01L_OBJC_SEL_REF_26_count", align 8
  %38 = invoke i64 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i64 (%._Foundation.NSArray*, i8*)*)(%._Foundation.NSArray* nonnull %33, i8* %37)
          to label %40 unwind label %.loopexit.split-lp

; <label>:39:                                     ; preds = %35
  unreachable

; <label>:40:                                     ; preds = %36
  %41 = add i64 %38, 4294967294
  %42 = trunc i64 %41 to i32
  %43 = icmp sgt i32 %42, -1
  br i1 %43, label %.preheader.preheader, label %.loopexit20

.preheader.preheader:                             ; preds = %40
  br label %.preheader

.loopexit20.loopexit:                             ; preds = %58
  br label %.loopexit20

.loopexit20:                                      ; preds = %.loopexit20.loopexit, %40
  %44 = load %._ConsoleApplication372.Program*, %._ConsoleApplication372.Program** bitcast (%struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_29___ConsoleApplication372_Program" to %._ConsoleApplication372.Program**), align 8
  %45 = load i8*, i8** @"\01L_OBJC_SEL_REF_30_Main:", align 8
  %46 = invoke i32 bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i32 (%._ConsoleApplication372.Program*, i8*, %._Foundation.NSString**)*)(%._ConsoleApplication372.Program* %44, i8* %45, %._Foundation.NSString** %32)
          to label %70 unwind label %.loopexit.split-lp

.preheader:                                       ; preds = %.preheader.preheader, %58
  %.016 = phi i32 [ %54, %58 ], [ 0, %.preheader.preheader ]
  %47 = sext i32 %.016 to i64
  %48 = getelementptr i64, i64* %31, i64 %47
  %49 = load %._Foundation.NSArray*, %._Foundation.NSArray** %3, align 8
  %50 = icmp eq %._Foundation.NSArray* %49, null
  br i1 %50, label %51, label %52

; <label>:51:                                     ; preds = %.preheader
  invoke void @RaiseNullReferenceException()
          to label %57 unwind label %.loopexit.split-lp

; <label>:52:                                     ; preds = %.preheader
  %53 = load i8*, i8** @"\01L_OBJC_SEL_REF_28_objectAtIndexedSubscript:", align 8
  %54 = add i32 %.016, 1
  %55 = sext i32 %54 to i64
  %56 = invoke %._RemObjects.Oxygene.System.id* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to %._RemObjects.Oxygene.System.id* (%._Foundation.NSArray*, i8*, i64)*)(%._Foundation.NSArray* nonnull %49, i8* %53, i64 %55)
          to label %58 unwind label %.loopexit

; <label>:57:                                     ; preds = %51
  unreachable

; <label>:58:                                     ; preds = %52
  %59 = bitcast %._RemObjects.Oxygene.System.id* %56 to i8*
  %60 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %59) #3
  %61 = bitcast i64* %48 to i8**
  %62 = call i8* @objc_storeStrong(i8** %61, i8* %59)
  call void @objc_release(i8* %59) #3
  %63 = icmp eq i32 %.016, %42
  br i1 %63, label %.loopexit20.loopexit, label %.preheader

; <label>:64:                                     ; preds = %70
  ret i32 %.017

.loopexit:                                        ; preds = %52
  %lpad.loopexit = landingpad { i8*, i32 }
          cleanup
  br label %65

.loopexit.split-lp:                               ; preds = %2, %11, %12, %23, %24, %35, %36, %.loopexit20, %51
  %.018.ph = phi i8* [ null, %2 ], [ %8, %12 ], [ %8, %24 ], [ %8, %36 ], [ %8, %.loopexit20 ], [ %8, %51 ], [ %8, %35 ], [ %8, %23 ], [ %8, %11 ]
  %.ph = phi i64* [ null, %2 ], [ null, %12 ], [ null, %24 ], [ %31, %36 ], [ %31, %.loopexit20 ], [ %31, %51 ], [ %31, %35 ], [ null, %23 ], [ null, %11 ]
  %lpad.loopexit.split-lp = landingpad { i8*, i32 }
          cleanup
  br label %65

; <label>:65:                                     ; preds = %.loopexit.split-lp, %.loopexit
  %.018 = phi i8* [ %8, %.loopexit ], [ %.018.ph, %.loopexit.split-lp ]
  %66 = phi i64* [ %31, %.loopexit ], [ %.ph, %.loopexit.split-lp ]
  %lpad.phi = phi { i8*, i32 } [ %lpad.loopexit, %.loopexit ], [ %lpad.loopexit.split-lp, %.loopexit.split-lp ]
  %67 = extractvalue { i8*, i32 } %lpad.phi, 0
  %68 = extractvalue { i8*, i32 } %lpad.phi, 1
  %69 = icmp eq i32 %68, 0
  br i1 %69, label %._crit_edge, label %73

._crit_edge:                                      ; preds = %65
  %.pre = bitcast %._Foundation.NSArray** %3 to i8**
  br label %70

; <label>:70:                                     ; preds = %._crit_edge, %.loopexit20
  %.pre-phi = phi i8** [ %.pre, %._crit_edge ], [ %19, %.loopexit20 ]
  %.119 = phi i8* [ %.018, %._crit_edge ], [ %8, %.loopexit20 ]
  %.017 = phi i32 [ 0, %._crit_edge ], [ %46, %.loopexit20 ]
  %71 = phi i64* [ %66, %._crit_edge ], [ %31, %.loopexit20 ]
  %.0 = phi i1 [ true, %._crit_edge ], [ false, %.loopexit20 ]
  %eh_ptr.0 = phi i8* [ %67, %._crit_edge ], [ undef, %.loopexit20 ]
  call void @objc_release(i8* %.119) #3
  %72 = load i8*, i8** %.pre-phi, align 8
  call void @objc_release(i8* %72) #3
  call void @"\01array_dispose"(i64* %71, <{ i32, i64, i64, i8* }>* nonnull @0)
  br i1 %.0, label %73, label %64

; <label>:73:                                     ; preds = %70, %65
  %eh_vals.1 = phi i32 [ 0, %70 ], [ %68, %65 ]
  %eh_ptr.1 = phi i8* [ %eh_ptr.0, %70 ], [ %67, %65 ]
  %74 = insertvalue { i8*, i32 } undef, i8* %eh_ptr.1, 0
  %75 = insertvalue { i8*, i32 } %74, i32 %eh_vals.1, 1
  resume { i8*, i32 } %75
}

; Function Attrs: nounwind
define internal void @"\01block_byref_copy_helper_0"(%._nested0* nocapture, %._nested0* nocapture readonly) #3 {
  %3 = getelementptr %._nested0, %._nested0* %0, i64 0, i32 6
  %4 = getelementptr %._nested0, %._nested0* %1, i64 0, i32 6
  %5 = bitcast %._ConsoleApplication372.Program** %4 to i8**
  %6 = load i8*, i8** %5, align 8
  %7 = tail call i8* @objc_retain(i8* %6) #3
  %8 = bitcast %._ConsoleApplication372.Program** %3 to i8**
  store i8* %6, i8** %8, align 8
  ret void
}

; Function Attrs: nounwind
declare i8* @objc_retain(i8*) #3

; Function Attrs: nounwind
define internal void @"\01block_byref_destroy_helper_0"(%._nested0* nocapture readonly) #3 {
  %2 = getelementptr %._nested0, %._nested0* %0, i64 0, i32 6
  %3 = bitcast %._ConsoleApplication372.Program** %2 to i8**
  %4 = load i8*, i8** %3, align 8
  tail call void @objc_release(i8* %4) #3
  ret void
}

; Function Attrs: nounwind
declare void @objc_release(i8*) #3

declare i8* @objc_storeStrong(i8**, i8*)

define internal void @"\01block_copy_helper_1"(%struct._block_literalex*, %struct._block_literalex* nocapture readonly) {
  %3 = getelementptr %struct._block_literalex, %struct._block_literalex* %0, i64 0, i32 5
  %4 = getelementptr %struct._block_literalex, %struct._block_literalex* %1, i64 0, i32 5
  %5 = bitcast i8** %3 to i8*
  %6 = load i8*, i8** %4, align 8
  tail call void @_Block_object_assign(i8* %5, i8* %6, i32 8)
  ret void
}

declare void @_Block_object_assign(i8*, i8*, i32)

define internal void @"\01block_destroy_helper_1"(%struct._block_literalex* nocapture readonly) {
  %2 = getelementptr %struct._block_literalex, %struct._block_literalex* %0, i64 0, i32 5
  %3 = load i8*, i8** %2, align 8
  tail call void @_Block_object_dispose(i8* %3, i32 8)
  ret void
}

declare void @_Block_object_dispose(i8*, i32)

declare i8* @objc_retainBlock(i8*)

declare i8* @objc_msgSend(i8*, i8*, ...)

declare i32 @__objc_personality_v0(...)

; Function Attrs: nounwind
define internal void @"\01block_byref_copy_helper_2"(%._nested1* nocapture, %._nested1* nocapture readonly) #3 {
  %3 = getelementptr %._nested1, %._nested1* %0, i64 0, i32 6
  %4 = getelementptr %._nested1, %._nested1* %1, i64 0, i32 6
  %5 = bitcast %._ConsoleApplication372.Program** %4 to i8**
  %6 = load i8*, i8** %5, align 8
  %7 = tail call i8* @objc_retain(i8* %6) #3
  %8 = bitcast %._ConsoleApplication372.Program** %3 to i8**
  store i8* %6, i8** %8, align 8
  ret void
}

; Function Attrs: nounwind
define internal void @"\01block_byref_destroy_helper_2"(%._nested1* nocapture readonly) #3 {
  %2 = getelementptr %._nested1, %._nested1* %0, i64 0, i32 6
  %3 = bitcast %._ConsoleApplication372.Program** %2 to i8**
  %4 = load i8*, i8** %3, align 8
  tail call void @objc_release(i8* %4) #3
  ret void
}

define internal void @"\01block_copy_helper_3"(%struct._block_literalex*, %struct._block_literalex* nocapture readonly) {
  %3 = getelementptr %struct._block_literalex, %struct._block_literalex* %0, i64 0, i32 5
  %4 = getelementptr %struct._block_literalex, %struct._block_literalex* %1, i64 0, i32 5
  %5 = bitcast i8** %3 to i8*
  %6 = load i8*, i8** %4, align 8
  tail call void @_Block_object_assign(i8* %5, i8* %6, i32 8)
  ret void
}

define internal void @"\01block_destroy_helper_3"(%struct._block_literalex* nocapture readonly) {
  %2 = getelementptr %struct._block_literalex, %struct._block_literalex* %0, i64 0, i32 5
  %3 = load i8*, i8** %2, align 8
  tail call void @_Block_object_dispose(i8* %3, i32 8)
  ret void
}

; Function Attrs: nounwind
declare i8* @objc_autoreleasePoolPush() #3

; Function Attrs: nounwind
declare i32 @printf(i8* nocapture readonly, ...) #3

; Function Attrs: nounwind
declare void @objc_autoreleasePoolPop(i8*) #3

; Function Attrs: noreturn uwtable
define linkonce void @RaiseNullReferenceException() #4 {
  %1 = load i8*, i8** bitcast (%struct._class_t** @"\01L_OBJC_CLASSLIST_REFERENCES_$_15_NSException" to i8**), align 8
  %2 = load i8*, i8** @"\01L_OBJC_SEL_REF_17_raise:format:", align 8
  tail call void (i8*, i8*, %._Foundation.NSString*, %._Foundation.NSString*, ...) bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to void (i8*, i8*, %._Foundation.NSString*, %._Foundation.NSString*, ...)*)(i8* %1, i8* %2, %._Foundation.NSString* bitcast (%struct.NSConstantString* @_unnamed_cfstring_3 to %._Foundation.NSString*), %._Foundation.NSString* bitcast (%struct.NSConstantString* @_unnamed_cfstring_5 to %._Foundation.NSString*))
  unreachable
}

; Function Attrs: nounwind
declare i8* @objc_retainAutoreleasedReturnValue(i8*) #3

; Function Attrs: uwtable
define linkonce i64* @"\01array_create"(i64, i64) #5 {
  %3 = mul i64 %1, %0
  %4 = add i64 %3, 16
  %5 = tail call i8* @malloc(i64 %4)
  %6 = icmp eq i8* %5, null
  br i1 %6, label %7, label %8

; <label>:7:                                      ; preds = %2
  ret i64* null

; <label>:8:                                      ; preds = %2
  tail call void @llvm.memset.p0i8.i64(i8* nonnull %5, i8 0, i64 %4, i32 8, i1 false)
  %9 = bitcast i8* %5 to i64*
  store i64 1, i64* %9, align 8
  %10 = getelementptr i8, i8* %5, i64 8
  %11 = bitcast i8* %10 to i64*
  store i64 %1, i64* %11, align 8
  %12 = getelementptr i8, i8* %5, i64 16
  %13 = bitcast i8* %12 to i64*
  ret i64* %13
}

; Function Attrs: nounwind
declare noalias i8* @malloc(i64) #3

; Function Attrs: argmemonly nounwind
declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) #6

; Function Attrs: uwtable
define linkonce void @"\01array_dispose"(i64*, <{ i32, i64, i64, i8* }>*) #5 {
  %3 = icmp eq i64* %0, null
  br i1 %3, label %8, label %4

; <label>:4:                                      ; preds = %2
  %5 = getelementptr i64, i64* %0, i64 -2
  %6 = atomicrmw sub i64* %5, i64 1 singlethread seq_cst
  %7 = icmp slt i64 %6, 2
  br i1 %7, label %9, label %8

; <label>:8:                                      ; preds = %4, %2
  ret void

; <label>:9:                                      ; preds = %4
  %10 = getelementptr <{ i32, i64, i64, i8* }>, <{ i32, i64, i64, i8* }>* %1, i64 0, i32 0
  %11 = load i32, i32* %10, align 4
  %12 = icmp eq i32 %11, 0
  br i1 %12, label %17, label %13

; <label>:13:                                     ; preds = %9
  %14 = getelementptr i64, i64* %0, i64 -1
  %15 = load i64, i64* %14, align 8
  %16 = bitcast i64* %0 to i8*
  tail call void @"\01element_dispose"(i8* %16, <{ i32, i64, i64, i8* }>* nonnull %1, i64 %15)
  br label %17

; <label>:17:                                     ; preds = %13, %9
  %18 = bitcast i64* %5 to i8*
  tail call void @free(i8* %18)
  ret void
}

; Function Attrs: uwtable
define linkonce void @"\01element_dispose"(i8*, <{ i32, i64, i64, i8* }>*, i64) #5 {
  %4 = getelementptr <{ i32, i64, i64, i8* }>, <{ i32, i64, i64, i8* }>* %1, i64 0, i32 2
  %5 = load i64, i64* %4, align 8
  %6 = mul i64 %5, %2
  %7 = getelementptr <{ i32, i64, i64, i8* }>, <{ i32, i64, i64, i8* }>* %1, i64 0, i32 1
  %8 = load i64, i64* %7, align 8
  %9 = getelementptr <{ i32, i64, i64, i8* }>, <{ i32, i64, i64, i8* }>* %1, i64 0, i32 3
  %10 = load i8*, i8** %9, align 8
  %11 = icmp sgt i64 %6, 0
  br i1 %11, label %.lr.ph, label %._crit_edge

.lr.ph:                                           ; preds = %3
  %12 = getelementptr <{ i32, i64, i64, i8* }>, <{ i32, i64, i64, i8* }>* %1, i64 0, i32 0
  %13 = load i32, i32* %12, align 4
  %14 = bitcast i8* %10 to <{ i32, i64, i64, i8* }>*
  %15 = bitcast i8* %10 to void (i8*)*
  switch i32 %13, label %._crit_edge [
    i32 3, label %.lr.ph.split.us.preheader
    i32 1, label %.lr.ph.split.split.us.preheader
    i32 2, label %.lr.ph.split.split.split.us.preheader
  ]

.lr.ph.split.split.split.us.preheader:            ; preds = %.lr.ph
  br label %.lr.ph.split.split.split.us

.lr.ph.split.split.us.preheader:                  ; preds = %.lr.ph
  br label %.lr.ph.split.split.us

.lr.ph.split.us.preheader:                        ; preds = %.lr.ph
  br label %.lr.ph.split.us

.lr.ph.split.us:                                  ; preds = %.lr.ph.split.us.preheader, %.lr.ph.split.us
  %16 = phi i64 [ %19, %.lr.ph.split.us ], [ %6, %.lr.ph.split.us.preheader ]
  %.04.us = phi i8* [ %20, %.lr.ph.split.us ], [ %0, %.lr.ph.split.us.preheader ]
  %17 = bitcast i8* %.04.us to i64**
  %18 = load i64*, i64** %17, align 8
  tail call void @"\01array_dispose"(i64* %18, <{ i32, i64, i64, i8* }>* %14)
  %19 = add nsw i64 %16, -1
  %20 = getelementptr i8, i8* %.04.us, i64 %8
  %21 = icmp sgt i64 %16, 1
  br i1 %21, label %.lr.ph.split.us, label %._crit_edge.loopexit

.lr.ph.split.split.us:                            ; preds = %.lr.ph.split.split.us.preheader, %.lr.ph.split.split.us
  %22 = phi i64 [ %25, %.lr.ph.split.split.us ], [ %6, %.lr.ph.split.split.us.preheader ]
  %.04.us5 = phi i8* [ %26, %.lr.ph.split.split.us ], [ %0, %.lr.ph.split.split.us.preheader ]
  %23 = bitcast i8* %.04.us5 to i8**
  %24 = load i8*, i8** %23, align 8
  tail call void %15(i8* %24)
  %25 = add nsw i64 %22, -1
  %26 = getelementptr i8, i8* %.04.us5, i64 %8
  %27 = icmp sgt i64 %22, 1
  br i1 %27, label %.lr.ph.split.split.us, label %._crit_edge.loopexit19

.lr.ph.split.split.split.us:                      ; preds = %.lr.ph.split.split.split.us.preheader, %.lr.ph.split.split.split.us
  %28 = phi i64 [ %29, %.lr.ph.split.split.split.us ], [ %6, %.lr.ph.split.split.split.us.preheader ]
  %.04.us8 = phi i8* [ %30, %.lr.ph.split.split.split.us ], [ %0, %.lr.ph.split.split.split.us.preheader ]
  tail call void %15(i8* %.04.us8)
  %29 = add nsw i64 %28, -1
  %30 = getelementptr i8, i8* %.04.us8, i64 %8
  %31 = icmp sgt i64 %28, 1
  br i1 %31, label %.lr.ph.split.split.split.us, label %._crit_edge.loopexit20

._crit_edge.loopexit:                             ; preds = %.lr.ph.split.us
  br label %._crit_edge

._crit_edge.loopexit19:                           ; preds = %.lr.ph.split.split.us
  br label %._crit_edge

._crit_edge.loopexit20:                           ; preds = %.lr.ph.split.split.split.us
  br label %._crit_edge

._crit_edge:                                      ; preds = %._crit_edge.loopexit20, %._crit_edge.loopexit19, %._crit_edge.loopexit, %.lr.ph, %3
  ret void
}

; Function Attrs: nounwind
declare void @free(i8* nocapture) #3

attributes #0 = { uwtable "no-frame-pointer-elim"="true" }
attributes #1 = { norecurse nounwind readnone uwtable "no-frame-pointer-elim"="true" }
attributes #2 = { nounwind uwtable "no-frame-pointer-elim"="true" }
attributes #3 = { nounwind }
attributes #4 = { noreturn uwtable "no-frame-pointer-elim"="true" }
attributes #5 = { uwtable }
attributes #6 = { argmemonly nounwind }

!llvm.module.flags = !{!0, !1, !2, !3, !4, !7, !8}

!0 = !{i32 1, !"Objective-C Version", i32 2}
!1 = !{i32 1, !"Objective-C Image Info Version", i32 0}
!2 = !{i32 1, !"Objective-C Image Info Section", !"__DATA, __objc_imageinfo, regular, no_dead_strip"}
!3 = !{i32 4, !"Objective-C Garbage Collection", i32 0}
!4 = !{i32 6, !"Linker Options", !5}
!5 = !{!6}
!6 = !{!"-framework", !"Foundation"}
!7 = !{i32 2, !"Dwarf Version", i32 4}
!8 = !{i32 2, !"Debug Info Version", i32 3}

Thanks for your help!

Now here’s my way to obtain the gcTarget object pointer for the Method and StaticMethod cases:

    public void addWeak(Action listener) {
        object* gcTargetPointer = ((MyBlock*)(*((NativeUInt*)(&listener))))->gcTargetPointer;
        object gcTarget = *gcTargetPointer;  // crash if the pointer is invalid
        addWeakImpl(gcTarget, listener);
    }

struct MyBlock{void *isa; int flags; int reserved; NativeUInt func; BlockDescriptor* dp; public object* gcTargetPointer;}

struct BlockDescriptor {NativeUInt reserved; NativeUInt size;}

But unfortunately you are right: it seems no way to do the same thing for lambdas/anonymous methods, because they don’t need that gcTargetPointer to invoke the method. So it’s impossible to infer the gcTarget automatically if lambdas are allowable, unless the compiler can add that additional pointer in generated block_literal.

BTW, it’s odd to see the block also contains the gcTargetPointer for StaticMethod. In my opinion it’s needless, am I wrong?

On ObjC all static methods are virtual too, so yes they do have a “self”.

Got it, thx!