diff options
author | Nicola Pero <nicola.pero@meta-innovation.com> | 2010-10-06 10:10:14 +0000 |
---|---|---|
committer | Nicola Pero <nicola@gcc.gnu.org> | 2010-10-06 10:10:14 +0000 |
commit | f05b9d93e96c2a97d80e7fc3b10df7b86c6081b0 (patch) | |
tree | 9dd722f6e098569456083c38fb1b313e672cd799 /gcc/objc | |
parent | b938bc48d844e85327c603e01bb6c303462c2613 (diff) | |
download | gcc-f05b9d93e96c2a97d80e7fc3b10df7b86c6081b0.tar.gz |
In gcc/: 2010-10-06 Nicola Pero <nicola.pero@meta-innovation.com>
In gcc/:
2010-10-06 Nicola Pero <nicola.pero@meta-innovation.com>
Implemented fast enumeration for Objective-C.
* c-parser.c (objc_could_be_foreach_context): New.
(c_lex_one_token): Recognize RID_IN keyword in a potential
Objective-C foreach context.
(c_parser_declaration_or_fndef): Added parameter. Accept
Objective-C RID_IN keyword as terminating a declaration; in that
case, return the declaration in the new parameter.
(c_parser_extenral_declaration): Updated calls to
c_parser_declaration_or_fndef.
(c_parser_declaration_or_fndef): Same change.
(c_parser_compound_statement_nostart): Same change.
(c_parser_label): Same change.
(c_parser_objc_methodprotolist): Same change.
(c_parser_omp_for_loop): Same change.
(c_parser_for_statement): Detect and parse Objective-C foreach
statements.
(c_parser_omp_for_loop): Updated call to check_for_loop_decls().
* c-decl.c (check_for_loop_decls): Added parameter to allow ObjC
fast enumeration parsing code to turn off the c99 error but still
perform checks on the loop declarations.
* c-tree.h (check_for_loop_decls): Updated declaration.
* doc/objc.texi: Document fast enumeration.
In gcc/c-family/:
2010-10-06 Nicola Pero <nicola.pero@meta-innovation.com>
Implemented fast enumeration for Objective-C.
* c-common.h (objc_finish_foreach_loop): New.
* stub-objc.c (objc_finish_foreach_loop): New.
In gcc/objc/:
2010-10-06 Nicola Pero <nicola.pero@meta-innovation.com>
Implemented fast enumeration for Objective-C.
* objc-act.c (build_fast_enumeration_state_template): New.
(TAG_ENUMERATION_MUTATION): New.
(TAG_FAST_ENUMERATION_STATE): New.
(synth_module_prologue): Call build_fast_enumeration_state_template() and set up
objc_enumeration_mutation_decl.
(objc_create_temporary_var): Allow providing a name to temporary
variables.
(objc_build_exc_ptr): Updated calls to
objc_create_temporary_var().
(next_sjlj_build_try_catch_finally): Same change.
(objc_finish_foreach_loop): New.
* objc-act.h: Added OCTI_FAST_ENUM_STATE_TEMP,
OCTI_ENUM_MUTATION_DECL, objc_fast_enumeration_state_template,
objc_enumeration_mutation_decl.
Merge from 'apple/trunk' branch on FSF servers.
2006-04-12 Fariborz Jahanian <fjahanian@apple.com>
Radar 4507230
* objc-act.c (objc_type_valid_for_messaging): New routine to check
for valid objc object types.
(objc_finish_foreach_loop): Check for invalid objc objects in
foreach header.
In gcc/testsuite/:
2010-10-05 Nicola Pero <nicola.pero@meta-innovation.com>
Implemented fast enumeration for Objective-C.
* objc.dg/foreach-1.m: New.
* objc.dg/foreach-2.m: New.
* objc.dg/foreach-3.m: New.
* objc.dg/foreach-4.m: New.
* objc.dg/foreach-5.m: New.
* objc.dg/foreach-6.m: New.
* objc.dg/foreach-7.m: New.
Merge from 'apple/trunk' branch on FSF servers:
2006-04-13 Fariborz Jahanian <fjahanian@apple.com>
Radar 4502236
* objc.dg/objc-foreach-5.m: New.
2006-04-12 Fariborz Jahanian <fjahanian@apple.com>
Radar 4507230
* objc.dg/objc-foreach-4.m: New.
2006-03-13 Fariborz Jahanian <fjahanian@apple.com>
Radar 4472881
* objc.dg/objc-foreach-3.m: New.
2005-03-07 Fariborz Jahanian <fjahanian@apple.com>
Radar 4468498
* objc.dg/objc-foreach-2.m: New.
2006-02-15 Fariborz Jahanian <fjahanian@apple.com>
Radar 4294910
* objc.dg/objc-foreach-1.m: New
In libobjc/:
2010-10-06 Nicola Pero <nicola.pero@meta-innovation.com>
Implemented fast enumeration for Objective-C.
* Makefile.in (C_SOURCE_FILES): Added objc-foreach.c.
(OBJC_H): Added runtime.h
* objc-foreach.c: New file.
* objc/runtime.h: New file.
From-SVN: r165019
Diffstat (limited to 'gcc/objc')
-rw-r--r-- | gcc/objc/ChangeLog | 32 | ||||
-rw-r--r-- | gcc/objc/objc-act.c | 585 | ||||
-rw-r--r-- | gcc/objc/objc-act.h | 7 |
3 files changed, 616 insertions, 8 deletions
diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog index a68b46d71e7..eed86bd4a06 100644 --- a/gcc/objc/ChangeLog +++ b/gcc/objc/ChangeLog @@ -1,3 +1,31 @@ +2010-10-06 Nicola Pero <nicola.pero@meta-innovation.com> + + Implemented fast enumeration for Objective-C. + * objc-act.c (build_fast_enumeration_state_template): New. + (TAG_ENUMERATION_MUTATION): New. + (TAG_FAST_ENUMERATION_STATE): New. + (synth_module_prologue): Call build_fast_enumeration_state_template() and set up + objc_enumeration_mutation_decl. + (objc_create_temporary_var): Allow providing a name to temporary + variables. + (objc_build_exc_ptr): Updated calls to + objc_create_temporary_var(). + (next_sjlj_build_try_catch_finally): Same change. + (objc_finish_foreach_loop): New. + * objc-act.h: Added OCTI_FAST_ENUM_STATE_TEMP, + OCTI_ENUM_MUTATION_DECL, objc_fast_enumeration_state_template, + objc_enumeration_mutation_decl. + + Merge from 'apple/trunk' branch on FSF servers. + + 2006-04-12 Fariborz Jahanian <fjahanian@apple.com> + + Radar 4507230 + * objc-act.c (objc_type_valid_for_messaging): New routine to check + for valid objc object types. + (objc_finish_foreach_loop): Check for invalid objc objects in + foreach header. + 2010-10-05 Nicola Pero <nicola.pero@meta-innovation.com> Merge from 'apple/trunk' branch on FSF servers. @@ -5,8 +33,8 @@ 2005-10-17 Fariborz Jahanian <fjahanian@apple.com> Radar 4290840 - * objc-act.c (objc_start_method_definition): Check for error_mark_node for - the selector name and make a quick exit. + * objc-act.c (objc_start_method_definition): Check for + error_mark_node for the selector name and make a quick exit. 2010-10-04 Andi Kleen <ak@linux.intel.com> diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 5aaadc67ceb..730efba48d8 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -171,6 +171,8 @@ static tree get_class_ivars (tree, bool); static tree generate_protocol_list (tree); static void build_protocol_reference (tree); +static void build_fast_enumeration_state_template (void); + #ifdef OBJCPLUS static void objc_generate_cxx_cdtors (void); #endif @@ -240,6 +242,7 @@ static void generate_struct_by_value_array (void) ATTRIBUTE_NORETURN; static void mark_referenced_methods (void); static void generate_objc_image_info (void); +static bool objc_type_valid_for_messaging (tree typ); /*** Private Interface (data) ***/ @@ -274,6 +277,9 @@ static void generate_objc_image_info (void); #define PROTOCOL_OBJECT_CLASS_NAME "Protocol" +#define TAG_ENUMERATION_MUTATION "objc_enumerationMutation" +#define TAG_FAST_ENUMERATION_STATE "__objcFastEnumerationState" + static const char *TAG_GETCLASS; static const char *TAG_GETMETACLASS; static const char *TAG_MSGSEND; @@ -1952,6 +1958,17 @@ synth_module_prologue (void) self_id = get_identifier ("self"); ucmd_id = get_identifier ("_cmd"); + /* Declare struct _objc_fast_enumeration_state { ... }; */ + build_fast_enumeration_state_template (); + + /* void objc_enumeration_mutation (id) */ + type = build_function_type (void_type_node, + tree_cons (NULL_TREE, objc_object_type, NULL_TREE)); + objc_enumeration_mutation_decl + = add_builtin_function (TAG_ENUMERATION_MUTATION, type, 0, NOT_BUILT_IN, + NULL, NULL_TREE); + TREE_NOTHROW (objc_enumeration_mutation_decl) = 0; + #ifdef OBJCPLUS pop_lang_context (); #endif @@ -3596,13 +3613,25 @@ get_class_ivars (tree interface, bool inherited) return ivar_chain; } +/* Create a temporary variable of type 'type'. If 'name' is set, uses + the specified name, else use no name. Returns the declaration of + the type. The 'name' is mostly useful for debugging. +*/ static tree -objc_create_temporary_var (tree type) +objc_create_temporary_var (tree type, const char *name) { tree decl; - decl = build_decl (input_location, - VAR_DECL, NULL_TREE, type); + if (name != NULL) + { + decl = build_decl (input_location, + VAR_DECL, get_identifier (name), type); + } + else + { + decl = build_decl (input_location, + VAR_DECL, NULL_TREE, type); + } TREE_USED (decl) = 1; DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; @@ -3687,7 +3716,7 @@ objc_build_exc_ptr (void) tree var = cur_try_context->caught_decl; if (!var) { - var = objc_create_temporary_var (objc_object_type); + var = objc_create_temporary_var (objc_object_type, NULL); cur_try_context->caught_decl = var; } return var; @@ -3888,10 +3917,10 @@ next_sjlj_build_try_catch_finally (void) /* Create the declarations involved. */ t = xref_tag (RECORD_TYPE, get_identifier (UTAG_EXCDATA)); - stack_decl = objc_create_temporary_var (t); + stack_decl = objc_create_temporary_var (t, NULL); cur_try_context->stack_decl = stack_decl; - rethrow_decl = objc_create_temporary_var (objc_object_type); + rethrow_decl = objc_create_temporary_var (objc_object_type, NULL); cur_try_context->rethrow_decl = rethrow_decl; TREE_CHAIN (rethrow_decl) = stack_decl; @@ -9980,4 +10009,548 @@ objc_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) #endif } +/* This routine returns true if TYP is a valid objc object type, + suitable for messaging; false otherwise. +*/ + +static bool +objc_type_valid_for_messaging (tree typ) +{ + if (!POINTER_TYPE_P (typ)) + return false; + + do + typ = TREE_TYPE (typ); /* Remove indirections. */ + while (POINTER_TYPE_P (typ)); + + if (TREE_CODE (typ) != RECORD_TYPE) + return false; + + return objc_is_object_id (typ) || TYPE_HAS_OBJC_INFO (typ); +} + +/* Begin code generation for fast enumeration (foreach) ... */ + +/* Defines + + struct __objcFastEnumerationState + { + unsigned long state; + id *itemsPtr; + unsigned long *mutationsPtr; + unsigned long extra[5]; + }; + + Confusingly enough, NSFastEnumeration is then defined by libraries + to be the same structure. +*/ + +static void +build_fast_enumeration_state_template (void) +{ + tree decls, *chain = NULL; + + /* { */ + objc_fast_enumeration_state_template = objc_start_struct (get_identifier + (TAG_FAST_ENUMERATION_STATE)); + + /* unsigned long state; */ + decls = add_field_decl (long_unsigned_type_node, "state", &chain); + + /* id *itemsPtr; */ + add_field_decl (build_pointer_type (objc_object_type), + "itemsPtr", &chain); + + /* unsigned long *mutationsPtr; */ + add_field_decl (build_pointer_type (long_unsigned_type_node), + "mutationsPtr", &chain); + + /* unsigned long extra[5]; */ + add_field_decl (build_sized_array_type (long_unsigned_type_node, 5), + "extra", &chain); + + /* } */ + objc_finish_struct (objc_fast_enumeration_state_template, decls); +} + +/* + 'objc_finish_foreach_loop()' generates the code for an Objective-C + foreach loop. The 'location' argument is the location of the 'for' + that starts the loop. The 'object_expression' is the expression of + the 'object' that iterates; the 'collection_expression' is the + expression of the collection that we iterate over (we need to make + sure we evaluate this only once); the 'for_body' is the set of + statements to be executed in each iteration; 'break_label' and + 'continue_label' are the break and continue labels which we need to + emit since the <statements> may be jumping to 'break_label' (if they + contain 'break') or to 'continue_label' (if they contain + 'continue'). + + The syntax is + + for (<object expression> in <collection expression>) + <statements> + + which is compiled into the following blurb: + + { + id __objc_foreach_collection; + __objc_fast_enumeration_state __objc_foreach_enum_state; + unsigned long __objc_foreach_batchsize; + id __objc_foreach_items[16]; + __objc_foreach_collection = <collection expression>; + __objc_foreach_enum_state = { 0 }; + __objc_foreach_batchsize = [__objc_foreach_collection countByEnumeratingWithState: &__objc_foreach_enum_state objects: __objc_foreach_items count: 16]; + + if (__objc_foreach_batchsize == 0) + <object expression> = nil; + else + { + unsigned long __objc_foreach_mutations_pointer = *__objc_foreach_enum_state.mutationsPtr; + next_batch: + { + unsigned long __objc_foreach_index; + __objc_foreach_index = 0; + + next_object: + if (__objc_foreach_mutation_pointer != *__objc_foreach_enum_state.mutationsPtr) objc_enumeration_mutation (<collection expression>); + <object expression> = enumState.itemsPtr[__objc_foreach_index]; + <statements> [PS: inside <statments>, 'break' jumps to break_label and 'continue' jumps to continue_label] + + continue_label: + __objc_foreach_index++; + if (__objc_foreach_index < __objc_foreach_batchsize) goto next_object; + __objc_foreach_batchsize = [__objc_foreach_collection countByEnumeratingWithState: &__objc_foreach_enum_state objects: __objc_foreach_items count: 16]; + } + if (__objc_foreach_batchsize != 0) goto next_batch; + <object expression> = nil; + break_label: + } + } + + 'statements' may contain a 'continue' or 'break' instruction, which + the user expects to 'continue' or 'break' the entire foreach loop. + We are provided the labels that 'break' and 'continue' jump to, so + we place them where we want them to jump to when they pick them. + + Optimization TODO: we could cache the IMP of + countByEnumeratingWithState:objects:count:. +*/ + +/* If you need to debug objc_finish_foreach_loop(), uncomment the following line. */ +/* #define DEBUG_OBJC_FINISH_FOREACH_LOOP 1 */ + +#ifdef DEBUG_OBJC_FINISH_FOREACH_LOOP +#include "tree-pretty-print.h" +#endif + +void +objc_finish_foreach_loop (location_t location, tree object_expression, tree collection_expression, tree for_body, + tree break_label, tree continue_label) +{ + /* A tree representing the __objcFastEnumerationState struct type, + or NSFastEnumerationState struct, whatever we are using. */ + tree objc_fast_enumeration_state_type; + + /* The trees representing the declarations of each of the local variables. */ + tree objc_foreach_collection_decl; + tree objc_foreach_enum_state_decl; + tree objc_foreach_items_decl; + tree objc_foreach_batchsize_decl; + tree objc_foreach_mutations_pointer_decl; + tree objc_foreach_index_decl; + + /* A tree representing the selector countByEnumeratingWithState:objects:count:. */ + tree selector_name; + + /* A tree representing the local bind. */ + tree bind; + + /* A tree representing the external 'if (__objc_foreach_batchsize)' */ + tree first_if; + + /* A tree representing the 'else' part of 'first_if' */ + tree first_else; + + /* A tree representing the 'next_batch' label. */ + tree next_batch_label_decl; + + /* A tree representing the binding after the 'next_batch' label. */ + tree next_batch_bind; + + /* A tree representing the 'next_object' label. */ + tree next_object_label_decl; + + /* Temporary variables. */ + tree t; + int i; + + if (object_expression == error_mark_node) + return; + + if (collection_expression == error_mark_node) + return; + + if (!objc_type_valid_for_messaging (TREE_TYPE (object_expression))) + { + error ("iterating variable in fast enumeration is not an object"); + return; + } + + if (!objc_type_valid_for_messaging (TREE_TYPE (collection_expression))) + { + error ("collection in fast enumeration is not an object"); + return; + } + + /* TODO: Check that object_expression is either a variable + declaration, or an lvalue. */ + + /* This kludge is an idea from apple. We use the + __objcFastEnumerationState struct implicitly defined by the + compiler, unless a NSFastEnumerationState struct has been defined + (by a Foundation library such as GNUstep Base) in which case, we + use that one. + */ + objc_fast_enumeration_state_type = objc_fast_enumeration_state_template; + { + tree objc_NSFastEnumeration_type = lookup_name (get_identifier ("NSFastEnumerationState")); + + if (objc_NSFastEnumeration_type) + { + /* TODO: We really need to check that + objc_NSFastEnumeration_type is the same as ours! */ + if (TREE_CODE (objc_NSFastEnumeration_type) == TYPE_DECL) + { + /* If it's a typedef, use the original type. */ + if (DECL_ORIGINAL_TYPE (objc_NSFastEnumeration_type)) + objc_fast_enumeration_state_type = DECL_ORIGINAL_TYPE (objc_NSFastEnumeration_type); + else + objc_fast_enumeration_state_type = TREE_TYPE (objc_NSFastEnumeration_type); + } + } + } + + /* { */ + /* Done by c-parser.c. */ + + /* type object; */ + /* Done by c-parser.c. */ + + /* id __objc_foreach_collection */ + objc_foreach_collection_decl = objc_create_temporary_var (objc_object_type, "__objc_foreach_collection"); + + /* __objcFastEnumerationState __objc_foreach_enum_state; */ + objc_foreach_enum_state_decl = objc_create_temporary_var (objc_fast_enumeration_state_type, "__objc_foreach_enum_state"); + TREE_CHAIN (objc_foreach_enum_state_decl) = objc_foreach_collection_decl; + + /* id __objc_foreach_items[16]; */ + objc_foreach_items_decl = objc_create_temporary_var (build_sized_array_type (objc_object_type, 16), "__objc_foreach_items"); + TREE_CHAIN (objc_foreach_items_decl) = objc_foreach_enum_state_decl; + + /* unsigned long __objc_foreach_batchsize; */ + objc_foreach_batchsize_decl = objc_create_temporary_var (long_unsigned_type_node, "__objc_foreach_batchsize"); + TREE_CHAIN (objc_foreach_batchsize_decl) = objc_foreach_items_decl; + + /* Generate the local variable binding. */ + bind = build3 (BIND_EXPR, void_type_node, objc_foreach_batchsize_decl, NULL, NULL); + SET_EXPR_LOCATION (bind, location); + TREE_SIDE_EFFECTS (bind) = 1; + + /* __objc_foreach_collection = <collection expression>; */ + t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_collection_decl, collection_expression); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (bind)); + + /* __objc_foreach_enum_state.state = 0; */ + t = build2 (MODIFY_EXPR, void_type_node, objc_build_component_ref (objc_foreach_enum_state_decl, + get_identifier ("state")), + build_int_cst (long_unsigned_type_node, 0)); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (bind)); + + /* __objc_foreach_enum_state.itemsPtr = NULL; */ + t = build2 (MODIFY_EXPR, void_type_node, objc_build_component_ref (objc_foreach_enum_state_decl, + get_identifier ("itemsPtr")), + null_pointer_node); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (bind)); + + /* __objc_foreach_enum_state.mutationsPtr = NULL; */ + t = build2 (MODIFY_EXPR, void_type_node, objc_build_component_ref (objc_foreach_enum_state_decl, + get_identifier ("mutationsPtr")), + null_pointer_node); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (bind)); + + /* __objc_foreach_enum_state.extra[0] = 0; */ + /* __objc_foreach_enum_state.extra[1] = 0; */ + /* __objc_foreach_enum_state.extra[2] = 0; */ + /* __objc_foreach_enum_state.extra[3] = 0; */ + /* __objc_foreach_enum_state.extra[4] = 0; */ + for (i = 0; i < 5 ; i++) + { + t = build2 (MODIFY_EXPR, void_type_node, + build_array_ref (location, objc_build_component_ref (objc_foreach_enum_state_decl, + get_identifier ("extra")), + build_int_cst (NULL_TREE, i)), + build_int_cst (long_unsigned_type_node, 0)); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (bind)); + } + + /* __objc_foreach_batchsize = [__objc_foreach_collection countByEnumeratingWithState: &__objc_foreach_enum_state objects: __objc_foreach_items count: 16]; */ + selector_name = get_identifier ("countByEnumeratingWithState:objects:count:"); +#ifdef OBJCPLUS + t = objc_finish_message_expr (objc_foreach_collection_decl, selector_name, + /* Parameters. */ + tree_cons /* &__objc_foreach_enum_state */ + (NULL_TREE, build_fold_addr_expr_loc (location, objc_foreach_enum_state_decl), + tree_cons /* __objc_foreach_items */ + (NULL_TREE, objc_foreach_items_decl, + tree_cons /* 16 */ + (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE)))); +#else + /* In C, we need to decay the __objc_foreach_items array that we are passing. */ + { + struct c_expr array; + array.value = objc_foreach_items_decl; + t = objc_finish_message_expr (objc_foreach_collection_decl, selector_name, + /* Parameters. */ + tree_cons /* &__objc_foreach_enum_state */ + (NULL_TREE, build_fold_addr_expr_loc (location, objc_foreach_enum_state_decl), + tree_cons /* __objc_foreach_items */ + (NULL_TREE, default_function_array_conversion (location, array).value, + tree_cons /* 16 */ + (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE)))); + } +#endif + t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_batchsize_decl, t); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (bind)); + + /* if (__objc_foreach_batchsize == 0) */ + first_if = build3 (COND_EXPR, void_type_node, + /* Condition. */ + c_fully_fold + (c_common_truthvalue_conversion + (location, + build_binary_op (location, + EQ_EXPR, + objc_foreach_batchsize_decl, + build_int_cst (long_unsigned_type_node, 0), 1)), + false, NULL), + /* Then block (we fill it in later). */ + NULL_TREE, + /* Else block (we fill it in later). */ + NULL_TREE); + SET_EXPR_LOCATION (first_if, location); + append_to_statement_list (first_if, &BIND_EXPR_BODY (bind)); + + /* then <object expression> = nil; */ + t = build2 (MODIFY_EXPR, void_type_node, object_expression, convert (objc_object_type, null_pointer_node)); + SET_EXPR_LOCATION (t, location); + COND_EXPR_THEN (first_if) = t; + + /* Now we build the 'else' part of the if; once we finish building + it, we attach it to first_if as the 'else' part. */ + + /* else */ + /* { */ + + /* unsigned long __objc_foreach_mutations_pointer; */ + objc_foreach_mutations_pointer_decl = objc_create_temporary_var (long_unsigned_type_node, "__objc_foreach_mutations_pointer"); + + /* Generate the local variable binding. */ + first_else = build3 (BIND_EXPR, void_type_node, objc_foreach_mutations_pointer_decl, NULL, NULL); + SET_EXPR_LOCATION (first_else, location); + TREE_SIDE_EFFECTS (first_else) = 1; + + /* __objc_foreach_mutations_pointer = *__objc_foreach_enum_state.mutationsPtr; */ + t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_mutations_pointer_decl, + build_indirect_ref (location, objc_build_component_ref (objc_foreach_enum_state_decl, + get_identifier ("mutationsPtr")), + RO_UNARY_STAR)); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (first_else)); + + /* next_batch: */ + next_batch_label_decl = create_artificial_label (location); + t = build1 (LABEL_EXPR, void_type_node, next_batch_label_decl); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (first_else)); + + /* { */ + + /* unsigned long __objc_foreach_index; */ + objc_foreach_index_decl = objc_create_temporary_var (long_unsigned_type_node, "__objc_foreach_index"); + + /* Generate the local variable binding. */ + next_batch_bind = build3 (BIND_EXPR, void_type_node, objc_foreach_index_decl, NULL, NULL); + SET_EXPR_LOCATION (next_batch_bind, location); + TREE_SIDE_EFFECTS (next_batch_bind) = 1; + append_to_statement_list (next_batch_bind, &BIND_EXPR_BODY (first_else)); + + /* __objc_foreach_index = 0; */ + t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_index_decl, + build_int_cst (long_unsigned_type_node, 0)); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (next_batch_bind)); + + /* next_object: */ + next_object_label_decl = create_artificial_label (location); + t = build1 (LABEL_EXPR, void_type_node, next_object_label_decl); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (next_batch_bind)); + + /* if (__objc_foreach_mutation_pointer != *__objc_foreach_enum_state.mutationsPtr) objc_enumeration_mutation (<collection expression>); */ + t = build3 (COND_EXPR, void_type_node, + /* Condition. */ + c_fully_fold + (c_common_truthvalue_conversion + (location, + build_binary_op + (location, + NE_EXPR, + objc_foreach_mutations_pointer_decl, + build_indirect_ref (location, + objc_build_component_ref (objc_foreach_enum_state_decl, + get_identifier ("mutationsPtr")), + RO_UNARY_STAR), 1)), + false, NULL), + /* Then block. */ + build_function_call (input_location, + objc_enumeration_mutation_decl, + tree_cons (NULL, collection_expression, NULL)), + /* Else block. */ + NULL_TREE); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (next_batch_bind)); + + /* <object expression> = enumState.itemsPtr[__objc_foreach_index]; */ + t = build2 (MODIFY_EXPR, void_type_node, object_expression, + build_array_ref (location, objc_build_component_ref (objc_foreach_enum_state_decl, + get_identifier ("itemsPtr")), + objc_foreach_index_decl)); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (next_batch_bind)); + + /* <statements> [PS: in <statments>, 'break' jumps to break_label and 'continue' jumps to continue_label] */ + append_to_statement_list (for_body, &BIND_EXPR_BODY (next_batch_bind)); + + /* continue_label: */ + if (continue_label) + { + t = build1 (LABEL_EXPR, void_type_node, continue_label); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (next_batch_bind)); + } + + /* __objc_foreach_index++; */ + t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_index_decl, + build_binary_op (location, + PLUS_EXPR, + objc_foreach_index_decl, + build_int_cst (long_unsigned_type_node, 1), 1)); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (next_batch_bind)); + + /* if (__objc_foreach_index < __objc_foreach_batchsize) goto next_object; */ + t = build3 (COND_EXPR, void_type_node, + /* Condition. */ + c_fully_fold + (c_common_truthvalue_conversion + (location, + build_binary_op (location, + LT_EXPR, + objc_foreach_index_decl, + objc_foreach_batchsize_decl, 1)), + false, NULL), + /* Then block. */ + build1 (GOTO_EXPR, void_type_node, next_object_label_decl), + /* Else block. */ + NULL_TREE); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (next_batch_bind)); + + /* __objc_foreach_batchsize = [__objc_foreach_collection countByEnumeratingWithState: &__objc_foreach_enum_state objects: __objc_foreach_items count: 16]; */ +#ifdef OBJCPLUS + t = objc_finish_message_expr (objc_foreach_collection_decl, selector_name, + /* Parameters. */ + tree_cons /* &__objc_foreach_enum_state */ + (NULL_TREE, build_fold_addr_expr_loc (location, objc_foreach_enum_state_decl), + tree_cons /* __objc_foreach_items */ + (NULL_TREE, objc_foreach_items_decl, + tree_cons /* 16 */ + (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE)))); +#else + /* In C, we need to decay the __objc_foreach_items array that we are passing. */ + { + struct c_expr array; + array.value = objc_foreach_items_decl; + t = objc_finish_message_expr (objc_foreach_collection_decl, selector_name, + /* Parameters. */ + tree_cons /* &__objc_foreach_enum_state */ + (NULL_TREE, build_fold_addr_expr_loc (location, objc_foreach_enum_state_decl), + tree_cons /* __objc_foreach_items */ + (NULL_TREE, default_function_array_conversion (location, array).value, + tree_cons /* 16 */ + (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE)))); + } +#endif + t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_batchsize_decl, t); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (next_batch_bind)); + + /* } */ + + /* if (__objc_foreach_batchsize != 0) goto next_batch; */ + t = build3 (COND_EXPR, void_type_node, + /* Condition. */ + c_fully_fold + (c_common_truthvalue_conversion + (location, + build_binary_op (location, + NE_EXPR, + objc_foreach_batchsize_decl, + build_int_cst (long_unsigned_type_node, 0), 1)), + false, NULL), + /* Then block. */ + build1 (GOTO_EXPR, void_type_node, next_batch_label_decl), + /* Else block. */ + NULL_TREE); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (first_else)); + + /* <object expression> = nil; */ + t = build2 (MODIFY_EXPR, void_type_node, object_expression, convert (objc_object_type, null_pointer_node)); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (first_else)); + + /* break_label: */ + if (break_label) + { + t = build1 (LABEL_EXPR, void_type_node, break_label); + SET_EXPR_LOCATION (t, location); + append_to_statement_list (t, &BIND_EXPR_BODY (first_else)); + } + + /* } */ + COND_EXPR_ELSE (first_if) = first_else; + + /* Do the whole thing. */ + add_stmt (bind); + +#ifdef DEBUG_OBJC_FINISH_FOREACH_LOOP + /* This will print to stderr the whole blurb generated by the + compiler while compiling (assuming the compiler doesn't crash + before getting here). + */ + debug_generic_stmt (bind); +#endif + + /* } */ + /* Done by c-parser.c */ +} + #include "gt-objc-objc-act.h" diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index 61312e95094..9f6ddcac724 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -269,6 +269,9 @@ enum objc_tree_index OCTI_ASSIGN_GLOBAL_DECL, OCTI_ASSIGN_STRONGCAST_DECL, + OCTI_FAST_ENUM_STATE_TEMP, + OCTI_ENUM_MUTATION_DECL, + OCTI_MAX }; @@ -433,5 +436,9 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX]; #define string_class_decl objc_global_trees[OCTI_STRING_CLASS_DECL] #define internal_const_str_type objc_global_trees[OCTI_INTERNAL_CNST_STR_TYPE] #define UOBJC_SUPER_decl objc_global_trees[OCTI_SUPER_DECL] +#define objc_fast_enumeration_state_template \ + objc_global_trees[OCTI_FAST_ENUM_STATE_TEMP] +#define objc_enumeration_mutation_decl \ + objc_global_trees[OCTI_ENUM_MUTATION_DECL] #endif /* GCC_OBJC_ACT_H */ |