[cost] Fix cost models that accept blocks to take captured vars into account

Summary:
Function calls that accept blocks as arguments may have additional arguments for the captured variables of the block. Cost models for these functions only considered the case where the block arguments didn't capture variables. This diff extends the model so that we handle captured variable case.

This fixes some FNs in the analysis.

Reviewed By: skcho

Differential Revision: D28183071

fbshipit-source-id: 6a045e80e
master
Ezgi Çiçek 4 years ago committed by Facebook GitHub Bot
parent 13858e8d09
commit d713b98a94

@ -10,6 +10,7 @@ module BasicCost = CostDomain.BasicCost
module BasicCostWithReason = CostDomain.BasicCostWithReason module BasicCostWithReason = CostDomain.BasicCostWithReason
open BufferOverrunUtils.ModelEnv open BufferOverrunUtils.ModelEnv
open CostUtils.CostModelEnv open CostUtils.CostModelEnv
open ProcnameDispatcher.Call.FuncArg
let unit_cost_model _model_env ~ret:_ _inferbo_mem = BasicCost.one () let unit_cost_model _model_env ~ret:_ _inferbo_mem = BasicCost.one ()
@ -173,25 +174,29 @@ module NSCollection = struct
cost_op (get_length coll1) (get_length coll2) cost_op (get_length coll1) (get_length coll2)
let enumerate_using_block array ({get_summary; model_env} as cost_model_env) ~ret inferbo_mem = let enumerate_using_block args ({get_summary; model_env} as cost_model_env) ~ret inferbo_mem =
let pname = model_env.pname in let pname = model_env.pname in
match pname with match List.rev args with
| WithBlockParameters (_, [block_name]) -> ( | _block :: {exp= array} :: _captured_args -> (
match get_summary (Procname.Block block_name) with let length =
| Some {CostDomain.post= callee_summary} -> BoundsOfNSCollection.linear_length
let {BasicCostWithReason.cost= callee_cost} = ~of_function:(Procname.to_simplified_string pname)
CostDomain.get_cost_kind OperationCost callee_summary array cost_model_env ~ret inferbo_mem
in in
let length = match pname with
BoundsOfNSCollection.linear_length | WithBlockParameters (_, [block_name]) -> (
~of_function:(Procname.to_simplified_string pname) match get_summary (Procname.Block block_name) with
array cost_model_env ~ret inferbo_mem | Some {CostDomain.post= callee_summary} ->
in let {BasicCostWithReason.cost= callee_cost} =
BasicCost.mult_loop ~iter:length ~body:callee_cost CostDomain.get_cost_kind OperationCost callee_summary
| None -> in
BasicCost.zero ) BasicCost.mult_loop ~iter:length ~body:callee_cost
| None ->
length )
| _ ->
length )
| _ -> | _ ->
BasicCost.zero BasicCost.one ()
end end
module ImmutableSet = struct module ImmutableSet = struct
@ -278,8 +283,7 @@ module Call = struct
&:: "addObjectsFromArray:" <>$ any_arg $+ capt_exp &:: "addObjectsFromArray:" <>$ any_arg $+ capt_exp
$--> BoundsOfNSCollection.linear_length ~of_function:"NSArray.addObjectsFromArray:" $--> BoundsOfNSCollection.linear_length ~of_function:"NSArray.addObjectsFromArray:"
; +PatternMatch.ObjectiveC.implements_collection ; +PatternMatch.ObjectiveC.implements_collection
&:: "enumerateObjectsUsingBlock:" <>$ capt_exp $+ any_arg &:: "enumerateObjectsUsingBlock:" &::.*++> NSCollection.enumerate_using_block
$--> NSCollection.enumerate_using_block
; +PatternMatch.Java.implements_collections ; +PatternMatch.Java.implements_collections
&:: "sort" $ capt_exp &:: "sort" $ capt_exp
$+...$--> BoundsOfCollection.n_log_n_length ~of_function:"Collections.sort" $+...$--> BoundsOfCollection.n_log_n_length ~of_function:"Collections.sort"

@ -230,7 +230,7 @@ void loop_with_my_enumerator_next_object_linear_FP(MyEnumerator* enumerator) {
void enumerate_via_block_linear(NSArray* array) { void enumerate_via_block_linear(NSArray* array) {
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL* stop){ [array enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL* stop){
// do something with obj NSLog(@"index: %@", index);
}]; }];
} }
@ -239,15 +239,14 @@ void enumerate_via_block_linear(NSArray* array) {
@implementation MyBlock @implementation MyBlock
+ (void)call_enumerate_via_block_param_linear_FN:(NSArray*)x:(int)size { + (void)call_enumerate_via_block_param_quadratic:(NSArray*)x:(int)size {
void (^b)(id, NSUInteger, BOOL*) = void (^b)(id, NSUInteger, BOOL*) =
^(id object, NSUInteger indexPath, BOOL* stop) { ^(id object, NSUInteger indexPath, BOOL* stop) {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
} }
}; };
// Here, captured arg size is passed as the first argument to the block, // Here, captured arg size is passed as the first argument to the block,
// not the array x. Hence, currently we don't recognize the mode which expects // not the array x.
// only two args.
[x enumerateObjectsUsingBlock:b]; [x enumerateObjectsUsingBlock:b];
} }

@ -1,13 +1,13 @@
${XCODE_ISYSROOT}/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h, NSArray.enumerateObjectsUsingBlock:[objc_blockMyBlock.call_enumerate_via_block_param_linear_FN::_3], 0, OnUIThread:false, [] ${XCODE_ISYSROOT}/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h, NSArray.enumerateObjectsUsingBlock:[objc_blockMyBlock.call_enumerate_via_block_param_quadratic::_3], 0, OnUIThread:false, []
${XCODE_ISYSROOT}/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h, NSArray.enumerateObjectsUsingBlock:[objc_blockenumerate_via_block_linear_2], 0, OnUIThread:false, [] ${XCODE_ISYSROOT}/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h, NSArray.enumerateObjectsUsingBlock:[objc_blockenumerate_via_block_linear_2], 0, OnUIThread:false, []
${XCODE_ISYSROOT}/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h, NSArray.indexOfObject:inSortedRange:options:usingComparator:[objc_blocknsarray_binary_search_log_FN_1], 0, OnUIThread:false, [] ${XCODE_ISYSROOT}/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h, NSArray.indexOfObject:inSortedRange:options:usingComparator:[objc_blocknsarray_binary_search_log_FN_1], 0, OnUIThread:false, []
codetoanalyze/objc/performance/MyEnumerator.m, MyEnumerator.dealloc, 0, OnUIThread:false, [] codetoanalyze/objc/performance/MyEnumerator.m, MyEnumerator.dealloc, 0, OnUIThread:false, []
codetoanalyze/objc/performance/MyEnumerator.m, MyEnumerator.nextObject, 5 + 3 ⋅ self->n.ub + 3 ⋅ (1+max(0, self->n.ub)), OnUIThread:false, [{1+max(0, self->n.ub)},Loop,{self->n.ub},Loop] codetoanalyze/objc/performance/MyEnumerator.m, MyEnumerator.nextObject, 5 + 3 ⋅ self->n.ub + 3 ⋅ (1+max(0, self->n.ub)), OnUIThread:false, [{1+max(0, self->n.ub)},Loop,{self->n.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, MyBlock.call_enumerate_via_block_param_linear_FN::, 5, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, MyBlock.call_enumerate_via_block_param_quadratic::, 4 + 3 ⋅ size × x->elements.length.ub + 2 ⋅ x->elements.length.ub + 2 ⋅ x->elements.length.ub × (1+max(0, size)), OnUIThread:false, [{1+max(0, size)},Loop,{x->elements.length.ub},Modeled call to enumerateObjectsUsingBlock:,{x->elements.length.ub},Modeled call to enumerateObjectsUsingBlock:,{size},Loop]
codetoanalyze/objc/performance/NSArray.m, MyBlock.dealloc, 0, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, MyBlock.dealloc, 0, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, call_my_enumerator_next_object_linear, 7 + 3 ⋅ enumerator->n.ub + 3 ⋅ (1+max(0, enumerator->n.ub)), OnUIThread:false, [{1+max(0, enumerator->n.ub)},Call to MyEnumerator.nextObject,Loop,{enumerator->n.ub},Call to MyEnumerator.nextObject,Loop] codetoanalyze/objc/performance/NSArray.m, call_my_enumerator_next_object_linear, 7 + 3 ⋅ enumerator->n.ub + 3 ⋅ (1+max(0, enumerator->n.ub)), OnUIThread:false, [{1+max(0, enumerator->n.ub)},Call to MyEnumerator.nextObject,Loop,{enumerator->n.ub},Call to MyEnumerator.nextObject,Loop]
codetoanalyze/objc/performance/NSArray.m, call_nsarray_enumerator_param_linear, 5, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, call_nsarray_enumerator_param_linear, 5, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, enumerate_via_block_linear, 1, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, enumerate_via_block_linear, 1 + 11 ⋅ array->elements.length.ub, OnUIThread:false, [{array->elements.length.ub},Modeled call to enumerateObjectsUsingBlock:]
codetoanalyze/objc/performance/NSArray.m, loop_with_my_enumerator_next_object_linear_FP, 1 + 3 ⋅ enumerator->n.ub × (enumerator.length + 1) + 9 ⋅ (enumerator.length + 1) + 3 ⋅ (enumerator.length + 1) × (1+max(0, enumerator->n.ub)), OnUIThread:false, [{1+max(0, enumerator->n.ub)},Call to MyEnumerator.nextObject,Loop,{enumerator.length + 1},Loop,{enumerator.length + 1},Loop,{enumerator->n.ub},Call to MyEnumerator.nextObject,Loop] codetoanalyze/objc/performance/NSArray.m, loop_with_my_enumerator_next_object_linear_FP, 1 + 3 ⋅ enumerator->n.ub × (enumerator.length + 1) + 9 ⋅ (enumerator.length + 1) + 3 ⋅ (enumerator.length + 1) × (1+max(0, enumerator->n.ub)), OnUIThread:false, [{1+max(0, enumerator->n.ub)},Call to MyEnumerator.nextObject,Loop,{enumerator.length + 1},Loop,{enumerator.length + 1},Loop,{enumerator->n.ub},Call to MyEnumerator.nextObject,Loop]
codetoanalyze/objc/performance/NSArray.m, multiple_nsarray_enumerators_param_linear, 9 + 5 ⋅ (enumerator2.length + enumerator1.length + 2), OnUIThread:false, [{enumerator2.length + enumerator1.length + 2},Loop] codetoanalyze/objc/performance/NSArray.m, multiple_nsarray_enumerators_param_linear, 9 + 5 ⋅ (enumerator2.length + enumerator1.length + 2), OnUIThread:false, [{enumerator2.length + enumerator1.length + 2},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_access_constant, 49, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_access_constant, 49, OnUIThread:false, []
@ -38,8 +38,8 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_next_object_linear, 4 + 5 ⋅
codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant, 33, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant, 33, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_constant, 38, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_constant, 38, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_nlogn, 8 + array->elements.length.ub × log(array->elements.length.ub), OnUIThread:false, [{array->elements.length.ub},Modeled call to NSArray.sortedArrayUsingDescriptors:,{array->elements.length.ub},Modeled call to NSArray.sortedArrayUsingDescriptors:] codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_nlogn, 8 + array->elements.length.ub × log(array->elements.length.ub), OnUIThread:false, [{array->elements.length.ub},Modeled call to NSArray.sortedArrayUsingDescriptors:,{array->elements.length.ub},Modeled call to NSArray.sortedArrayUsingDescriptors:]
codetoanalyze/objc/performance/NSArray.m, objc_blockMyBlock.call_enumerate_via_block_param_linear_FN::_3, 2 + 3 ⋅ size + 2 ⋅ (1+max(0, size)), OnUIThread:false, [{1+max(0, size)},Loop,{size},Loop] codetoanalyze/objc/performance/NSArray.m, objc_blockMyBlock.call_enumerate_via_block_param_quadratic::_3, 2 + 3 ⋅ size + 2 ⋅ (1+max(0, size)), OnUIThread:false, [{1+max(0, size)},Loop,{size},Loop]
codetoanalyze/objc/performance/NSArray.m, objc_blockenumerate_via_block_linear_2, 0, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, objc_blockenumerate_via_block_linear_2, 11, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, objc_blocknsarray_binary_search_log_FN_1, 4, OnUIThread:false, [] codetoanalyze/objc/performance/NSArray.m, objc_blocknsarray_binary_search_log_FN_1, 4, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_all_keys_linear1, 2 + 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_linear1, 2 + 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, 5 + 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_keys_linear2, 5 + 3 ⋅ dict->elements.length.ub + 3 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop]

Loading…
Cancel
Save