From a7ff42069cc525bbef33c88cbc9fb81814eb1acd Mon Sep 17 00:00:00 2001 From: Qianyi Shu Date: Mon, 17 Aug 2020 05:36:38 -0700 Subject: [PATCH] [cost] write ObjC's NSCollection model separately and refactor Summary: When implementing iterator, we find out that because some semantics of inferbo is Java-specific, we cannot simply use Java's `Collection` model for `NSCollection`. So this diff writing `NSCollection` model separately. This diff also extracts the common parts of `NSCollection` and `Collection` into `AbstractCollection` to combine the duplicate the parts. Reviewed By: ezgicicek Differential Revision: D22975159 fbshipit-source-id: daed3f99f --- infer/src/bufferoverrun/bufferOverrunField.ml | 2 + .../src/bufferoverrun/bufferOverrunField.mli | 3 + .../src/bufferoverrun/bufferOverrunModels.ml | 116 +++++++++++++----- .../src/bufferoverrun/bufferOverrunModels.mli | 5 + infer/src/cost/costModels.ml | 21 ++++ .../codetoanalyze/objc/performance/NSArray.m | 11 +- .../objc/performance/cost-issues.exp | 31 ++--- 7 files changed, 141 insertions(+), 48 deletions(-) diff --git a/infer/src/bufferoverrun/bufferOverrunField.ml b/infer/src/bufferoverrun/bufferOverrunField.ml index ff899c6e2..48535271d 100644 --- a/infer/src/bufferoverrun/bufferOverrunField.ml +++ b/infer/src/bufferoverrun/bufferOverrunField.ml @@ -41,6 +41,8 @@ let java_list_files_length = mk "java.list_files_length" Typ.(int) let is_java_collection_internal_array fn = Fieldname.equal fn java_collection_internal_array +let objc_collection_internal_array = mk "nscollection.elements" Typ.(mk_array void) + let c_strlen () = if Language.curr_language_is Java then mk "length" Typ.uint else mk "c.strlen" Typ.uint diff --git a/infer/src/bufferoverrun/bufferOverrunField.mli b/infer/src/bufferoverrun/bufferOverrunField.mli index 01c8ba001..61beef4d9 100644 --- a/infer/src/bufferoverrun/bufferOverrunField.mli +++ b/infer/src/bufferoverrun/bufferOverrunField.mli @@ -47,6 +47,9 @@ val is_cpp_vector_elem : Fieldname.t -> bool val is_java_collection_internal_array : Fieldname.t -> bool (** Check if the field is for Java collection's elements *) +val objc_collection_internal_array : Fieldname.t +(** Field for ObjC's collection's elements *) + (** {2 Field domain constructor} *) type field_typ = Typ.t option diff --git a/infer/src/bufferoverrun/bufferOverrunModels.ml b/infer/src/bufferoverrun/bufferOverrunModels.ml index d1cd4ac87..11abc24c3 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunModels.ml @@ -783,11 +783,15 @@ module JavaInteger = struct {exec; check= no_check} end -(* Java's Collections are represented like arrays. But we don't care about the elements. +module type Lang = sig + val collection_internal_array_field : Fieldname.t +end + +(* Abstract Collections are represented like arrays. But we don't care about the elements. - when they are constructed, we set the size to 0 - each time we add an element, we increase the length of the array - each time we delete an element, we decrease the length of the array *) -module Collection = struct +module AbstractCollection (Lang : Lang) = struct let create_collection {pname; node_hash; location} ~ret:(id, _) mem ~length = let represents_multiple_values = true in let traces = Trace.(Set.singleton location ArrayDeclaration) in @@ -803,9 +807,7 @@ module Collection = struct Dom.Val.of_java_array_alloc allocsite ~length ~traces in let coll_loc = Loc.of_allocsite coll_allocsite in - let internal_array_loc = - Loc.append_field coll_loc BufferOverrunField.java_collection_internal_array - in + let internal_array_loc = Loc.append_field coll_loc Lang.collection_internal_array_field in mem |> Dom.Mem.add_heap internal_array_loc internal_array |> Dom.Mem.add_stack (Loc.of_id id) (coll_loc |> PowLoc.singleton |> Dom.Val.of_pow_loc ~traces) @@ -825,14 +827,12 @@ module Collection = struct let eval_collection_internal_array_locs coll_exp mem = - Sem.eval_locs coll_exp mem - |> PowLoc.append_field ~fn:BufferOverrunField.java_collection_internal_array + Sem.eval_locs coll_exp mem |> PowLoc.append_field ~fn:Lang.collection_internal_array_field let get_collection_internal_array_locs coll_id mem = let coll = Dom.Mem.find (Loc.of_id coll_id) mem in - Dom.Val.get_pow_loc coll - |> PowLoc.append_field ~fn:BufferOverrunField.java_collection_internal_array + Dom.Val.get_pow_loc coll |> PowLoc.append_field ~fn:Lang.collection_internal_array_field let get_collection_internal_elements_locs coll_id mem = @@ -1031,14 +1031,49 @@ module Collection = struct {exec; check= check_index ~last_included:false coll_id index_exp} end +module Collection = AbstractCollection (struct + let collection_internal_array_field = BufferOverrunField.java_collection_internal_array +end) + module NSCollection = struct + include AbstractCollection (struct + let collection_internal_array_field = BufferOverrunField.objc_collection_internal_array + end) + + let create_collection {pname; node_hash; location; integer_type_widths} ~ret:(coll_id, _) mem + ~size_exp = + let represents_multiple_values = true in + let _, stride, length0, _ = get_malloc_info size_exp in + let length = Sem.eval integer_type_widths length0 mem in + let traces = Trace.(Set.add_elem location ArrayDeclaration) (Dom.Val.get_traces length) in + let internal_array = + let allocsite = + Allocsite.make pname ~node_hash ~inst_num:1 ~dimension:1 ~path:None + ~represents_multiple_values + in + let offset, size = (Itv.zero, Dom.Val.get_itv length) in + Dom.Val.of_c_array_alloc allocsite ~stride ~offset ~size ~traces + in + let coll_allocsite = + Allocsite.make pname ~node_hash ~inst_num:0 ~dimension:1 ~path:None + ~represents_multiple_values + in + let coll_loc = Loc.of_allocsite coll_allocsite in + let internal_array_loc = + Loc.append_field coll_loc BufferOverrunField.objc_collection_internal_array + in + mem + |> Dom.Mem.add_heap internal_array_loc internal_array + |> Dom.Mem.add_stack (Loc.of_id coll_id) + (coll_loc |> PowLoc.singleton |> Dom.Val.of_pow_loc ~traces) + + (** Creates a new array from the given c array by copying the first X elements. *) let create_from_array src_exp size_exp = - let exec ({integer_type_widths} as model_env) ~ret:((id, _) as ret) mem = - let size_v = Sem.eval integer_type_widths size_exp mem |> Dom.Val.get_itv in + let exec model_env ~ret:((id, _) as ret) mem = let src_arr_v = Dom.Mem.find_set (Sem.eval_locs src_exp mem) mem in - let mem = Collection.create_collection model_env ~ret mem ~length:size_v in - let dest_arr_loc = Collection.get_collection_internal_elements_locs id mem in + let mem = create_collection model_env ~ret mem ~size_exp in + let dest_arr_loc = get_collection_internal_elements_locs id mem in Dom.Mem.update_mem dest_arr_loc src_arr_v mem and check {location; integer_type_widths} mem cond_set = BoUtils.Check.lindex integer_type_widths ~array_exp:src_exp ~index_exp:size_exp @@ -1047,11 +1082,27 @@ module NSCollection = struct {exec; check} + let new_collection = + let exec = create_collection ~size_exp:Exp.zero in + {exec; check= no_check} + + + let get_first coll_id = get_at_index coll_id Exp.zero + + let of_list list = + let exec env ~ret:((id, _) as ret) mem = + let mem = new_collection.exec env ~ret mem in + List.fold_left list ~init:mem ~f:(fun acc {exp= elem_exp} -> + (add id elem_exp).exec env ~ret acc ) + in + {exec; check= no_check} + + let copy coll_id src_exp = let exec model_env ~ret:((id, _) as ret) mem = let coll = Dom.Mem.find_stack (Loc.of_id coll_id) mem in - let set_length = Collection.eval_collection_length src_exp mem |> Dom.Val.get_itv in - Collection.change_size_by ~size_f:(fun _ -> set_length) coll_id model_env ~ret mem + let set_length = eval_collection_length src_exp mem |> Dom.Val.get_itv in + change_size_by ~size_f:(fun _ -> set_length) coll_id model_env ~ret mem |> model_by_value coll id in {exec; check= no_check} @@ -1378,11 +1429,12 @@ module NSString = struct let concat = JavaString.concat let split exp = - let exec model_env ~ret mem = - let itv = + let exec model_env ~ret:((coll_id, _) as ret) mem = + let to_add_length = ArrObjCommon.eval_size model_env exp ~fn mem |> JavaString.range_itv_one_max_one_mone in - Collection.create_collection ~length:itv model_env ~ret mem + NSCollection.create_collection ~size_exp:Exp.zero model_env ~ret mem + |> NSCollection.change_size_by ~size_f:(Itv.plus to_add_length) coll_id model_env ~ret in {exec; check= no_check} @@ -1404,7 +1456,7 @@ let objc_malloc exp = let exec ({tenv} as model) ~ret mem = match exp with | Exp.Sizeof {typ} when PatternMatch.ObjectiveC.implements "NSArray" tenv (Typ.to_string typ) -> - Collection.new_collection.exec model ~ret mem + NSCollection.new_collection.exec model ~ret mem | Exp.Sizeof {typ} when PatternMatch.ObjectiveC.implements "NSString" tenv (Typ.to_string typ) -> (NSString.create_with_c_string (Exp.Const (Const.Cstr ""))).exec model ~ret mem @@ -1555,32 +1607,36 @@ module Call = struct ; -"CFArrayCreate" <>$ any_arg $+ capt_exp $+ capt_exp $+...$--> NSCollection.create_from_array ; -"CFArrayCreateCopy" <>$ any_arg $+ capt_exp $!--> create_copy_array - ; -"CFArrayGetCount" <>$ capt_exp $!--> Collection.size - ; -"CFArrayGetValueAtIndex" <>$ capt_var_exn $+ capt_exp $!--> Collection.get_at_index - ; -"CFDictionaryGetCount" <>$ capt_exp $!--> Collection.size - ; -"MCFArrayGetCount" <>$ capt_exp $!--> Collection.size + ; -"CFArrayGetCount" <>$ capt_exp $!--> NSCollection.size + ; -"CFArrayGetValueAtIndex" <>$ capt_var_exn $+ capt_exp $!--> NSCollection.get_at_index + ; -"CFDictionaryGetCount" <>$ capt_exp $!--> NSCollection.size + ; -"MCFArrayGetCount" <>$ capt_exp $!--> NSCollection.size ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "init" <>$ capt_exp $--> id - ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "array" <>--> Collection.new_collection + ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "array" <>--> NSCollection.new_collection + ; +PatternMatch.ObjectiveC.implements "NSArray" + &:: "firstObject" <>$ capt_var_exn $!--> NSCollection.get_first ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "initWithArray:" <>$ capt_var_exn $+ capt_exp $--> NSCollection.copy ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "initWithArray:copyItems:" <>$ capt_var_exn $+ capt_exp $+ any_arg $--> NSCollection.copy - ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "count" <>$ capt_exp $!--> Collection.size ; +PatternMatch.ObjectiveC.implements "NSArray" - &:: "objectAtIndexedSubscript:" <>$ capt_var_exn $+ capt_exp $!--> Collection.get_at_index + &:: "count" <>$ capt_exp $!--> NSCollection.size + ; +PatternMatch.ObjectiveC.implements "NSArray" + &:: "objectAtIndexedSubscript:" <>$ capt_var_exn $+ capt_exp $!--> NSCollection.get_at_index ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "arrayWithObjects:count:" <>$ capt_exp $+ capt_exp $--> NSCollection.create_from_array - ; +PatternMatch.ObjectiveC.implements "NSArray" &:: "arrayWithObjects" &++> Collection.of_list + ; +PatternMatch.ObjectiveC.implements "NSArray" + &:: "arrayWithObjects" &++> NSCollection.of_list ; +PatternMatch.ObjectiveC.implements "NSDictionary" &:: "dictionaryWithObjects:forKeys:count:" <>$ any_arg $+ capt_exp $+ capt_exp $--> NSCollection.create_from_array ; +PatternMatch.ObjectiveC.implements "NSDictionary" - &:: "objectForKeyedSubscript:" <>$ capt_var_exn $+ capt_exp $--> Collection.get_at_index + &:: "objectForKeyedSubscript:" <>$ capt_var_exn $+ capt_exp $--> NSCollection.get_at_index ; +PatternMatch.ObjectiveC.implements "NSDictionary" - &:: "objectForKey:" <>$ capt_var_exn $+ capt_exp $--> Collection.get_at_index + &:: "objectForKey:" <>$ capt_var_exn $+ capt_exp $--> NSCollection.get_at_index ; +PatternMatch.ObjectiveC.implements "NSDictionary" - &:: "count" <>$ capt_exp $--> Collection.size + &:: "count" <>$ capt_exp $--> NSCollection.size ; +PatternMatch.ObjectiveC.implements "NSDictionary" &:: "allKeys" <>$ capt_exp $--> create_copy_array ; +PatternMatch.ObjectiveC.implements "NSDictionary" diff --git a/infer/src/bufferoverrun/bufferOverrunModels.mli b/infer/src/bufferoverrun/bufferOverrunModels.mli index fd6877d25..397726234 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.mli +++ b/infer/src/bufferoverrun/bufferOverrunModels.mli @@ -36,6 +36,11 @@ module Collection : sig (** Evaluate length of Java collection *) end +module NSCollection : sig + val eval_collection_length : Exp.t -> BufferOverrunDomain.Mem.t -> BufferOverrunDomain.Val.t + (** Evaluate length of ObjC collection *) +end + module NSString : sig val get_length : BufferOverrunUtils.ModelEnv.model_env diff --git a/infer/src/cost/costModels.ml b/infer/src/cost/costModels.ml index da3fd5e38..f83489e54 100644 --- a/infer/src/cost/costModels.ml +++ b/infer/src/cost/costModels.ml @@ -156,6 +156,20 @@ module NSString = struct let substring_from_index = JavaString.substring_no_end end +module NSCollection = struct + let get_length str ~of_function {location} ~ret:_ mem = + let itv = + BufferOverrunModels.NSCollection.eval_collection_length str mem + |> BufferOverrunDomain.Val.get_itv + in + CostUtils.of_itv ~itv ~degree_kind:Polynomials.DegreeKind.Linear ~of_function location + + + let op_on_two_coll cost_op ~of_function coll1 coll2 model_env ~ret mem = + let get_length coll = get_length coll ~of_function model_env ~ret mem in + cost_op (get_length coll1) (get_length coll2) +end + module ImmutableSet = struct let construct = linear ~of_function:"ImmutableSet.construct" @@ -200,6 +214,13 @@ module Call = struct &:: "componentsSeparatedByString:" <>$ capt_exp $+ capt_exp $--> NSString.op_on_two_str BasicCost.mult ~of_function:"NSString.componentsSeparatedByString:" + ; -"NSArray" &:: "initWithArray:" <>$ any_arg $+ capt_exp + $--> NSCollection.get_length ~of_function:"NSArray.initWithArray:" + ; -"NSArray" &:: "isEqualToArray:" <>$ capt_exp $+ capt_exp + $--> NSCollection.op_on_two_coll BasicCost.min_default_left + ~of_function:"NSArray.isEqualToArray:" + ; -"NSArray" &:: "containsObject:" <>$ capt_exp $+ any_arg + $--> NSCollection.get_length ~of_function:"NSArray.containsObject:" ; +PatternMatch.Java.implements_collections &:: "sort" $ capt_exp $+...$--> BoundsOfCollection.n_log_n_length ~of_function:"Collections.sort" diff --git a/infer/tests/codetoanalyze/objc/performance/NSArray.m b/infer/tests/codetoanalyze/objc/performance/NSArray.m index 3ce345acd..cc1c377df 100644 --- a/infer/tests/codetoanalyze/objc/performance/NSArray.m +++ b/infer/tests/codetoanalyze/objc/performance/NSArray.m @@ -77,6 +77,12 @@ NSArray* nsarray_add_objects_from_array_linear_FN(NSArray* append_array) { // query element +void nsarray_get_first_constant() { + NSArray* array = @[ @1, @2 ]; + for (int i = 0; i < [[array firstObject] integerValue]; i++) { + } +} + void nsarray_access_constant() { NSArray* array = @[ @1.0f, @2.0f, @3.0f, @4.0f, @5.0f, @6.0f, @7.0f, @8.0f ]; for (int i = 0; i < 4; i++) { @@ -103,7 +109,7 @@ void nsarray_find_linear(NSArray* array) { } } -void nsarray_contains_object_linear_FN(NSArray* array) { +void nsarray_contains_object_linear(NSArray* array) { [array containsObject:@1]; } @@ -163,8 +169,7 @@ void nsarray_next_object_linear_FN(NSArray* array) { } // compare array -boolean_t nsarray_is_equal_to_array_linear_FN(NSArray* array1, - NSArray* array2) { +boolean_t nsarray_is_equal_to_array_linear(NSArray* array1, NSArray* array2) { return [array1 isEqualToArray:array2]; } diff --git a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp index f047d9489..4fb9711e1 100644 --- a/infer/tests/codetoanalyze/objc/performance/cost-issues.exp +++ b/infer/tests/codetoanalyze/objc/performance/cost-issues.exp @@ -1,21 +1,22 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_access_constant, 50, OnUIThread:false, [] -codetoanalyze/objc/performance/NSArray.m, nsarray_access_linear, 3 + 7 ⋅ array.length.ub + 3 ⋅ (array.length.ub + 1), OnUIThread:false, [{array.length.ub + 1},Loop,{array.length.ub},Loop] +codetoanalyze/objc/performance/NSArray.m, nsarray_access_linear, 3 + 7 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop] codetoanalyze/objc/performance/NSArray.m, nsarray_add_object_constant, 8, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_add_objects_from_array_linear_FN, 8, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_array_with_objects_constant, 27, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_binary_search_log_FN, 10, OnUIThread:false, [] -codetoanalyze/objc/performance/NSArray.m, nsarray_contains_object_linear_FN, 4, OnUIThread:false, [] -codetoanalyze/objc/performance/NSArray.m, nsarray_count_bounded_linear, 3 + 3 ⋅ array.length.ub + 3 ⋅ (array.length.ub + 1), OnUIThread:false, [{array.length.ub + 1},Loop,{array.length.ub},Loop] +codetoanalyze/objc/performance/NSArray.m, nsarray_contains_object_linear, 3 + array->elements.length.ub, OnUIThread:false, [{array->elements.length.ub},Modeled call to NSArray.containsObject:] +codetoanalyze/objc/performance/NSArray.m, nsarray_count_bounded_linear, 3 + 3 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop] codetoanalyze/objc/performance/NSArray.m, nsarray_empty_array_constant, 8, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_enumerator_linear_FN, 14, OnUIThread:false, [] -codetoanalyze/objc/performance/NSArray.m, nsarray_find_linear, 4 + 9 ⋅ array.length.ub + 3 ⋅ (array.length.ub + 1), OnUIThread:false, [{array.length.ub + 1},Loop,{array.length.ub},Loop] +codetoanalyze/objc/performance/NSArray.m, nsarray_find_linear, 4 + 9 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop] codetoanalyze/objc/performance/NSArray.m, nsarray_first_object_constant, 4, OnUIThread:false, [] +codetoanalyze/objc/performance/NSArray.m, nsarray_get_first_constant, 27, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_init_constant, 9, OnUIThread:false, [] -codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_constant, 15, OnUIThread:false, [] -codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_copy_linear, 7 + 3 ⋅ array.length.ub + 3 ⋅ (array.length.ub + 1), OnUIThread:false, [{array.length.ub + 1},Loop,{array.length.ub},Loop] -codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_linear, 7 + 3 ⋅ array.length.ub + 3 ⋅ (array.length.ub + 1), OnUIThread:false, [{array.length.ub + 1},Loop,{array.length.ub},Loop] +codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_constant, 14, OnUIThread:false, [] +codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_copy_linear, 7 + 3 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop] +codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_linear, 6 + 3 ⋅ array->elements.length.ub + array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Modeled call to NSArray.initWithArray:,{array->elements.length.ub},Loop] codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_objects_constant, 39, OnUIThread:false, [] -codetoanalyze/objc/performance/NSArray.m, nsarray_is_equal_to_array_linear_FN, 5, OnUIThread:false, [] +codetoanalyze/objc/performance/NSArray.m, nsarray_is_equal_to_array_linear, 4 + array1->elements.length.ub, OnUIThread:false, [{array1->elements.length.ub},Modeled call to NSArray.isEqualToArray:] codetoanalyze/objc/performance/NSArray.m, nsarray_iterate_linear_FN, 14, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_last_object_constant, 4, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_next_object_linear_FN, 10, OnUIThread:false, [] @@ -23,9 +24,9 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant, 34 codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_constant, 34, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_nlogn_FN, 10, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, objc_blocknsarray_binary_search_log_FN_1, 5, OnUIThread:false, [] -codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear1, 3 + 3 ⋅ dict.length.ub + 4 ⋅ (dict.length.ub + 1), OnUIThread:false, [{dict.length.ub + 1},Loop,{dict.length.ub},Loop] -codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear2, 6 + 3 ⋅ dict.length.ub + 3 ⋅ (dict.length.ub + 1), OnUIThread:false, [{dict.length.ub + 1},Loop,{dict.length.ub},Loop] -codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear, 3 + 3 ⋅ dict.length.ub + 4 ⋅ (dict.length.ub + 1), OnUIThread:false, [{dict.length.ub + 1},Loop,{dict.length.ub},Loop] +codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear1, 3 + 3 ⋅ dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop] +codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear2, 6 + 3 ⋅ dict->elements.length.ub + 3 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop] +codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_values_linear, 3 + 3 ⋅ dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop] codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_dictionary_with_objects_linear, 14 + 15 ⋅ n_entries + 3 ⋅ n_entries + 2 ⋅ (1+max(0, n_entries)) + 4 ⋅ (1+max(0, n_entries)), OnUIThread:false, [{1+max(0, n_entries)},Loop,{1+max(0, n_entries)},Loop,{n_entries},Loop,{n_entries},Loop] codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_constant, 52, OnUIThread:false, [] codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerator_linear_FN, 10, OnUIThread:false, [] @@ -46,7 +47,7 @@ codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_init_with_capacity_con codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_constant, 15, OnUIThread:false, [] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_in_loop_constant, 92, OnUIThread:false, [] codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_in_loop_constant, 18, OnUIThread:false, [] -codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_linear, 3 + 11 ⋅ array.length.ub + 3 ⋅ (array.length.ub + 1), OnUIThread:false, [{array.length.ub + 1},Loop,{array.length.ub},Loop] +codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_linear, 3 + 11 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop] codetoanalyze/objc/performance/NSMutableDictionary.m, nsmutabledictionary_set_element_in_loop_linear_FN, 14, OnUIThread:false, [] codetoanalyze/objc/performance/NSMutableString.m, nsmstring_append_string_constant, 14 + 3 ⋅ (str.length.ub + 5) + 3 ⋅ (str.length.ub + 6), OnUIThread:false, [{str.length.ub + 6},Loop,{str.length.ub + 5},Loop] codetoanalyze/objc/performance/NSMutableString.m, nsmstring_append_string_linear, 5 + str2.length.ub + 3 ⋅ (str2.length.ub + str1.length.ub) + 3 ⋅ (str2.length.ub + str1.length.ub + 1), OnUIThread:false, [{str2.length.ub + str1.length.ub + 1},Loop,{str2.length.ub + str1.length.ub},Loop,{str2.length.ub},Modeled call to NSMutableString.appendString:] @@ -80,10 +81,10 @@ codetoanalyze/objc/performance/block.m, objc_blockblock_multiply_array_linear_FN codetoanalyze/objc/performance/break.m, break_constant_FP, 8 + 5 ⋅ p + 2 ⋅ (1+max(0, p)), OnUIThread:false, [{1+max(0, p)},Call to break_loop,Loop,{p},Call to break_loop,Loop] codetoanalyze/objc/performance/break.m, break_loop, 5 + 5 ⋅ p + 2 ⋅ (1+max(0, p)), OnUIThread:false, [{1+max(0, p)},Loop,{p},Loop] codetoanalyze/objc/performance/break.m, break_loop_with_t, 7 + 5 ⋅ p + 2 ⋅ (1+max(0, p)), OnUIThread:false, [{1+max(0, p)},Loop,{p},Loop] -codetoanalyze/objc/performance/cf.m, array_count_linear, 6 + 3 ⋅ arr.length.ub + 2 ⋅ (arr.length.ub + 1), OnUIThread:false, [{arr.length.ub + 1},Loop,{arr.length.ub},Loop] -codetoanalyze/objc/performance/cf.m, cf_array_create_copy_linear, 8 + 3 ⋅ arrayValues.length + 2 ⋅ (arrayValues.length + 1), OnUIThread:false, [{arrayValues.length + 1},Loop,{arrayValues.length},Loop] +codetoanalyze/objc/performance/cf.m, array_count_linear, 6 + 3 ⋅ arr->elements.length.ub + 2 ⋅ (arr->elements.length.ub + 1), OnUIThread:false, [{arr->elements.length.ub + 1},Loop,{arr->elements.length.ub},Loop] +codetoanalyze/objc/performance/cf.m, cf_array_create_copy_linear, 8 + 3 ⋅ arrayValues.elements.length + 2 ⋅ (arrayValues.elements.length + 1), OnUIThread:false, [{arrayValues.elements.length + 1},Loop,{arrayValues.elements.length},Loop] codetoanalyze/objc/performance/cf.m, cf_array_create_linear, 11 + 3 ⋅ x + 2 ⋅ (1+max(0, x)), OnUIThread:false, [{1+max(0, x)},Loop,{x},Loop] -codetoanalyze/objc/performance/cf.m, dict_count_linear, 6 + 3 ⋅ dict.length.ub + 2 ⋅ (dict.length.ub + 1), OnUIThread:false, [{dict.length.ub + 1},Loop,{dict.length.ub},Loop] +codetoanalyze/objc/performance/cf.m, dict_count_linear, 6 + 3 ⋅ dict->elements.length.ub + 2 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop] codetoanalyze/objc/performance/compound_loop_guard.m, compound_while, 7 + 3 ⋅ m + 4 ⋅ (1+max(0, m)), OnUIThread:false, [{1+max(0, m)},Loop,{m},Loop] codetoanalyze/objc/performance/compound_loop_guard.m, nested_while_and_or_constant, 20, OnUIThread:false, [] codetoanalyze/objc/performance/compound_loop_guard.m, simplified_simulated_while_with_and_constant, 605, OnUIThread:false, []