[objc blocks] Specialize store instructions with current closure in methods specialized with blocks as arguments

Reviewed By: mbouaziz, jvillard

Differential Revision: D7744403

fbshipit-source-id: 42ad5f8
master
Dulma Churchill 7 years ago committed by Facebook Github Bot
parent 496e5e8c0a
commit 28200b87d7

@ -662,6 +662,18 @@ let specialize_with_block_args_instrs resolved_pdesc substitutions =
exp
in
let convert_instr (instrs, id_map) instr =
let get_block_name_and_load_captured_vars_instrs block_var loc =
let block_name, extra_formals = Mangled.Map.find block_var substitutions in
let ids, id_exp_typs, load_instrs =
List.map extra_formals ~f:(fun (var, typ) ->
let id = Ident.create_fresh Ident.knormal in
let pvar = Pvar.mk var resolved_pname in
(id, (Exp.Var id, pvar, typ), Sil.Load (id, Exp.Lvar pvar, typ, loc)) )
|> List.unzip3
in
let remove_temps_instr = Sil.Remove_temps (ids, loc) in
(block_name, id_exp_typs, load_instrs, remove_temps_instr)
in
let convert_generic_call return_ids exp origin_args loc call_flags =
let converted_args = List.map ~f:(fun (exp, typ) -> (convert_exp exp, typ)) origin_args in
let call_instr = Sil.Call (return_ids, exp, converted_args, loc, call_flags) in
@ -675,6 +687,14 @@ let specialize_with_block_args_instrs resolved_pdesc substitutions =
(instrs, id_map)
| Sil.Load (id, origin_exp, origin_typ, loc) ->
(Sil.Load (id, convert_exp origin_exp, origin_typ, loc) :: instrs, id_map)
| Sil.Store (assignee_exp, origin_typ, Exp.Var id, loc) when Ident.Map.mem id id_map ->
let block_param = Ident.Map.find id id_map in
let block_name, id_exp_typs, load_instrs, remove_temps_instr =
get_block_name_and_load_captured_vars_instrs block_param loc
in
let closure = Exp.Closure {name= block_name; captured_vars= id_exp_typs} in
let instr = Sil.Store (assignee_exp, origin_typ, closure, loc) in
(remove_temps_instr :: instr :: load_instrs @ instrs, id_map)
| Sil.Store (assignee_exp, origin_typ, origin_exp, loc) ->
let set_instr =
Sil.Store (convert_exp assignee_exp, origin_typ, convert_exp origin_exp, loc)
@ -682,23 +702,12 @@ let specialize_with_block_args_instrs resolved_pdesc substitutions =
(set_instr :: instrs, id_map)
| Sil.Call (return_ids, Exp.Var id, origin_args, loc, call_flags) -> (
try
let block_name, extra_formals =
let block_name, id_exp_typs, load_instrs, remove_temps_instr =
let block_var = Ident.Map.find id id_map in
Mangled.Map.find block_var substitutions
in
(* once we find the block in the map, it means that we need to subsitute it with the
call to the concrete block, and pass the fresh formals as arguments *)
let ids_typs, load_instrs =
let captured_ids_instrs =
List.map extra_formals ~f:(fun (var, typ) ->
let id = Ident.create_fresh Ident.knormal in
let pvar = Pvar.mk var resolved_pname in
((id, typ), Sil.Load (id, Exp.Lvar pvar, typ, loc)) )
in
List.unzip captured_ids_instrs
get_block_name_and_load_captured_vars_instrs block_var loc
in
let call_instr =
let id_exps = List.map ~f:(fun (id, typ) -> (Exp.Var id, typ)) ids_typs in
let id_exps = List.map ~f:(fun (id, _, typ) -> (id, typ)) id_exp_typs in
let converted_args =
List.map ~f:(fun (exp, typ) -> (convert_exp exp, typ)) origin_args
in
@ -709,11 +718,7 @@ let specialize_with_block_args_instrs resolved_pdesc substitutions =
, loc
, call_flags )
in
let remove_temps_instrs =
let ids = List.map ~f:(fun (id, _) -> id) ids_typs in
Sil.Remove_temps (ids, loc)
in
let instrs = remove_temps_instrs :: call_instr :: load_instrs @ instrs in
let instrs = remove_temps_instr :: call_instr :: load_instrs @ instrs in
(instrs, id_map)
with Caml.Not_found ->
convert_generic_call return_ids (Exp.Var id) origin_args loc call_flags )

@ -95,6 +95,7 @@ SOURCES_ARC = \
memory_leaks_benchmark/retain_cycle2.m \
memory_leaks_benchmark/RetainCycleBlocks.m \
memory_leaks_benchmark/RetainCyclePropertyInProtocol.m \
memory_leaks_benchmark/RetainCycleBlockAsParameter.m \
memory_leaks_benchmark/RetainCycleBlockCapturedVar.m \
memory_leaks_benchmark/RetainCycleDeduplication.m \
npe/BoxedNumberExample.m \

@ -28,6 +28,7 @@ codetoanalyze/objc/errors/field_superclass/SubtypingExample.m, subtyping_test, 0
codetoanalyze/objc/errors/initialization/struct_initlistexpr.c, field_set_correctly, 2, DIVIDE_BY_ZERO, ERROR, [start of procedure field_set_correctly()]
codetoanalyze/objc/errors/initialization/struct_initlistexpr.c, implicit_expr_set_correctly, 3, DIVIDE_BY_ZERO, ERROR, [start of procedure implicit_expr_set_correctly()]
codetoanalyze/objc/errors/initialization/struct_initlistexpr.c, point_coords_set_correctly, 2, DIVIDE_BY_ZERO, ERROR, [start of procedure point_coords_set_correctly()]
codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleBlockAsParameter.m, FBSomeDataManager_fetchNewData, 2, RETAIN_CYCLE, ERROR, [start of procedure fetchNewData,start of procedure initWithCompletionBlock:,return from a call to Fetcher_initWithCompletionBlock:_objc_blockFBSomeDataManager_fetchNewData_1]
codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleBlockCapturedVar.m, LinkResolver_test_bad, 3, RETAIN_CYCLE, ERROR, [start of procedure test_bad,Executing synthesized setter setDidFinishLoad:]
codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleBlocks.m, RCBlock_retain_self_in_block, 1, RETAIN_CYCLE, ERROR, [start of procedure retain_self_in_block,Executing synthesized setter setHandler:]
codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleBlocks.m, objc_blockretain_a_in_block_cycle_3, 1, RETAIN_CYCLE, ERROR, [start of procedure block,Executing synthesized setter setChild:]

@ -0,0 +1,54 @@
/*
* Copyright (c) 2018 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/NSObject.h>
#import <Foundation/NSData.h>
typedef void (^MyHandler)(NSData* newData);
@interface Fetcher : NSObject
@property(nonatomic, strong) MyHandler completionBlock;
- (instancetype)initWithCompletionBlock:(MyHandler)block;
@end
@implementation Fetcher
- (instancetype)initWithCompletionBlock:(_Nonnull MyHandler)block {
_completionBlock = block;
return self;
}
@end
@interface FBSomeDataManager : NSObject
- (void)setData:(NSData*)data;
@end
@implementation FBSomeDataManager {
Fetcher* _fetcher;
NSData* _data;
}
- (void)setData:(NSData*)data {
_data = data;
}
- (void)fetchNewData {
// We retain fetcher
_fetcher = [[Fetcher alloc] initWithCompletionBlock:^(NSData* newData) {
// fetcher retains us
[self setData:newData];
}];
}
@end
Loading…
Cancel
Save