Summary: Type is not enough to say a function call of `Provider.get` is expensive or not. Reviewed By: jvillard Differential Revision: D20366206 fbshipit-source-id: 83d3e8741master
parent
83062c0499
commit
117ab1164b
@ -1,103 +0,0 @@
|
|||||||
(*
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*)
|
|
||||||
|
|
||||||
open! IStd
|
|
||||||
module CFG = ProcCfg.Backward (ProcCfg.NormalOneInstrPerNode)
|
|
||||||
module F = Format
|
|
||||||
|
|
||||||
module Loc = struct
|
|
||||||
type t = Ident of Ident.t | Pvar of Pvar.t [@@deriving compare]
|
|
||||||
|
|
||||||
let pp f = function Ident id -> Ident.pp f id | Pvar pvar -> Pvar.pp Pp.text f pvar
|
|
||||||
end
|
|
||||||
|
|
||||||
module Val = struct
|
|
||||||
include AbstractDomain.FiniteSet (struct
|
|
||||||
include Typ
|
|
||||||
|
|
||||||
let pp = pp Pp.text
|
|
||||||
end)
|
|
||||||
|
|
||||||
let is_integer_type =
|
|
||||||
let is_integer_type = function
|
|
||||||
| Typ.{desc= Tstruct (JavaClass name)} ->
|
|
||||||
JavaClassName.(equal name java_lang_integer)
|
|
||||||
| _ ->
|
|
||||||
false
|
|
||||||
in
|
|
||||||
fun x -> (not (is_empty x)) && for_all is_integer_type x
|
|
||||||
end
|
|
||||||
|
|
||||||
module Dom = struct
|
|
||||||
include AbstractDomain.Map (Loc) (Val)
|
|
||||||
|
|
||||||
let lookup l m = Option.value (find_opt l m) ~default:Val.bottom
|
|
||||||
|
|
||||||
let lookup_ident id m = lookup (Loc.Ident id) m
|
|
||||||
|
|
||||||
let lookup_pvar pvar m = lookup (Loc.Pvar pvar) m
|
|
||||||
|
|
||||||
let cast id typ m =
|
|
||||||
let f = function None -> Some (Val.singleton typ) | Some prev -> Some (Val.add typ prev) in
|
|
||||||
update (Loc.Ident id) f m
|
|
||||||
|
|
||||||
|
|
||||||
let load id pvar m = add (Loc.Pvar pvar) (lookup_ident id m) m
|
|
||||||
|
|
||||||
let store pvar id m = add (Loc.Ident id) (lookup_pvar pvar m) m
|
|
||||||
end
|
|
||||||
|
|
||||||
module TransferFunctions = struct
|
|
||||||
module CFG = CFG
|
|
||||||
module Domain = Dom
|
|
||||||
|
|
||||||
type extras = unit
|
|
||||||
|
|
||||||
let exec_instr mem _pdata _node = function
|
|
||||||
| Sil.Load {id; e= Exp.Lvar pvar} ->
|
|
||||||
Dom.load id pvar mem
|
|
||||||
| Sil.Store {e1= Exp.Lvar pvar; e2= Exp.Var id} ->
|
|
||||||
Dom.store pvar id mem
|
|
||||||
| Sil.Call (_, Const (Cfun callee_pname), (Exp.Var id, _) :: (Exp.Sizeof {typ}, _) :: _, _, _)
|
|
||||||
when Procname.equal callee_pname BuiltinDecl.__cast ->
|
|
||||||
Dom.cast id typ mem
|
|
||||||
| _ ->
|
|
||||||
mem
|
|
||||||
|
|
||||||
|
|
||||||
let pp_session_name node f = F.fprintf f "Cast type analysis %a" CFG.Node.pp_id (CFG.Node.id node)
|
|
||||||
end
|
|
||||||
|
|
||||||
module Analyzer = AbstractInterpreter.MakeWTO (TransferFunctions)
|
|
||||||
|
|
||||||
let compute_invariant_map summary tenv =
|
|
||||||
let pdata = ProcData.make summary tenv () in
|
|
||||||
Analyzer.exec_pdesc ~do_narrowing:false ~initial:Dom.bottom pdata
|
|
||||||
|
|
||||||
|
|
||||||
type get_cast_type = Ident.t -> Val.t
|
|
||||||
|
|
||||||
let compute_get_cast_type =
|
|
||||||
let cache_get, cache_set = Procname.UnitCache.create () in
|
|
||||||
fun {Callbacks.exe_env; summary} ->
|
|
||||||
let pname = Summary.get_proc_name summary in
|
|
||||||
let casted_types =
|
|
||||||
match cache_get pname with
|
|
||||||
| Some casted_types ->
|
|
||||||
casted_types
|
|
||||||
| None ->
|
|
||||||
let pdesc = Summary.get_proc_desc summary in
|
|
||||||
let cfg = CFG.from_pdesc pdesc in
|
|
||||||
let tenv = Exe_env.get_tenv exe_env pname in
|
|
||||||
let inv_map = compute_invariant_map summary tenv in
|
|
||||||
let exit_node_id = CFG.exit_node cfg |> CFG.Node.id in
|
|
||||||
let casted_types =
|
|
||||||
Analyzer.extract_post exit_node_id inv_map |> Option.value ~default:Dom.bottom
|
|
||||||
in
|
|
||||||
cache_set pname casted_types ; casted_types
|
|
||||||
in
|
|
||||||
fun id -> Dom.lookup_ident id casted_types
|
|
@ -1,18 +0,0 @@
|
|||||||
(*
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*)
|
|
||||||
|
|
||||||
open! IStd
|
|
||||||
|
|
||||||
module Val : sig
|
|
||||||
type t
|
|
||||||
|
|
||||||
val is_integer_type : t -> bool
|
|
||||||
end
|
|
||||||
|
|
||||||
type get_cast_type = Ident.t -> Val.t
|
|
||||||
|
|
||||||
val compute_get_cast_type : Callbacks.proc_callback_args -> Ident.t -> Val.t
|
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
import javax.inject.*;
|
|
||||||
|
|
||||||
class ProviderTest {
|
|
||||||
/* Assume that injecting A is expensive, on the other hand injecting Integer is cheap. */
|
|
||||||
class A {}
|
|
||||||
|
|
||||||
@Inject private Provider<A> mProviderA;
|
|
||||||
@Inject private Provider<Integer> mProviderInteger;
|
|
||||||
|
|
||||||
void use_provided_A(A a) {}
|
|
||||||
|
|
||||||
void use_provided_Integer(Integer i) {}
|
|
||||||
|
|
||||||
void expensive_get_A_constant() {
|
|
||||||
use_provided_A(mProviderA.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
void cheap_get_Integer_linear() {
|
|
||||||
use_provided_Integer(mProviderInteger.get());
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in new issue