Transparent proxies for java futures

Polyvios Pratikakis, Jaime Spacco, Michael Hicks
2004 Proceedings of the 19th annual ACM SIGPLAN Conference on Object-oriented programming, systems, languages, and applications - OOPSLA '04  
A proxy object is a surrogate or placeholder that controls access to another target object. Proxies can be used to support distributed programming, lazy or parallel evaluation, access control, and other simple forms of behavioral reflection. However, wrapper proxies (like futures or suspensions for yet-to-be-computed results) can require significant code changes to be used in statically-typed languages, while proxies more generally can inadvertently violate assumptions of transparency,
more » ... nsparency, resulting in subtle bugs. To solve these problems, we have designed and implemented a simple framework for proxy programming that employs a static analysis based on qualifier inference, but with additional novelties. Code for using wrapper proxies is automatically introduced via a classfile-to-classfile transformation, and potential violations of transparency are signaled to the programmer. We have formalized our analysis and proven it sound. Our framework has a variety of applications, including support for asynchronous method calls returning futures. Experimental results demonstrate the benefits of our framework: programmers are relieved of managing and/or checking proxy usage, analysis times are reasonably fast, overheads introduced by added dynamic checks are negligible, and performance improvements can be significant. For example, changing two lines in a simple RMI-based peer-to-peer application and then using our framework resulted in a large performance gain. B.1 Progress Here we prove Lemma 3.1 (Progress), which states Given that (S, e 0 ) : T , then either • e 0 is a variable x. • (S, e 0 ) → (S , e 0 ) for some S and e 0 . • (S, e 0 ) is stuck due to a failed dynamic downcast. Proof The proof is by induction on (S, e 0 ) : T . From (S, e 0 ) : T and [CheckState] we get that there are Γ, Γ such that S : Γ and Γ e 0 ; Γ . Case e 0 ≡ (x): In this case the lemma is true by definition, the expression is a value. Case e 0 ≡ e. f : From Γ e 0 : T and [Field] we get Γ e : nonproxy N; Γ . Also fields(C) = Tf . So, e 0 reduces by [TransField]. Case e 0 ≡ e. f : From Γ e : nonproxy N; Γ and the induction hypothesis, e 0 reduces by [C-CongruenceE]. Case e 0 ≡ (e 1 .m(ē)): From Γ e 0 : T and [Invoke] we get Γ e 1 : nonproxy N; Γ . Case e 0 ≡ (x.m(ȳ)): From Γ x : nonproxy N; Γ , and S : Γ we have S(x) = (nonproxy, new C(ȳ)) for some {C} C ≤ N. Moreover by definition, from mtype(m,C) =T → U we get that mbody(m,C) = (z, e m ). So, e 0 can reduce by [TransInvoke]. Case e 0 ≡ (e 1 .m(ē)): From Γ e 1 : nonproxy N; Γ and the induction hypothesis, e 1 → e 1 and the whole expression reduces by [C-CongruenceE]. Case e 0 ≡ (x.m(ē)): From Γ e 0 : T and [Invoke] we get Γ ē :T , so by induction hypothesis,ē →ē and the whole expression reduces by [C-CongruenceBarE]. Case e 0 ≡ (new C(ē)): Case e 0 ≡ (new C(x)): Reduces by [TransAnnot]. Case e 0 ≡ (new C(ē)): From [New] and Γ e 0 : T we get Γ ē :S; Γ . So, by the induction hypothesis e 0 can reduce by [C-CongruenceBarE]. Case e 0 ≡ ((C)e): Case e 0 ≡ ((C)e ): From [Cast] or [SCast] we have Γ e : T , so by induction hypothesis, e 0 reduces by [C-CongruenceE]. Case e 0 ≡ (let x = e 1 in e 2 ): Case e 0 ≡ (let x = y in e 2 ): The term reduces by [TransLet]. Case e 0 ≡ (let x = e 1 in e 2 ): Given Γ e 0 : T we have from [Let] Γ e 1 : T ; Γ 1 . From induction hypothesis, we get that e 1 → e 1 , therefore e 0 reduces by [C-CongruenceE]. Case e 0 ≡ (makeproxy e ): Case e 0 ≡ makeproxy x: e 0 typechecks, so from [MakeProxy] we get Γ x : nonproxy N; Γ . From S : Γ we get that S(x) = (nonproxy, new C(ȳ)), for some C such that {C} C ≤ N. So, we can reduce by [TransProxy]. Case e 0 ≡ makeproxy e : From Γ e 0 : T and [MakeProxyCheck] we get that Γ e : T , therefore from the induction hypothesis, it reduces by [C-CongruenceE]. Case e 0 ≡ (coerce e ): Case e 0 ≡ (coerce x): From Γ e 0 : T and [CoerceVarCheck] we get that Γ can be written as Γ[x → Q N] such that: Γ [x → Q N] x : Q N; Γ [x → Q N]. From this and S : Γ we get that S can be written as S {x → (Q, new C(ȳ))} for some C such that {C} C ≤ N. So, e 0 reduces by [TransCoerce]. Case e 0 ≡ (coerce e ): From Γ e 0 : T and [CoerceExpCheck] we get that Γ e : Q N; Γ . Therefore, by induction hypothesis, e 0 reduces by [C-CongruenceE]. Case e 0 ≡ (if e = e then e else e) Case e 0 ≡ (if x 1 = x 2 then e 1 else e 2 ) From Γ e 0 : T and [If] we get that Γ x 1 : nonproxy N 1 and Γ x 2 : nonproxy N 2 . From this and S : Γ we get that S(x 1 ) = (nonproxy, new C 1 (ȳ 1 )) where {C 1 } C 1 ≤ N 1 and S(x 2 ) = (nonproxy, new C 2 (ȳ 2 )) where {C 2 } C 2 ≤ N 2 . So, e 0 reduces by [TransIfTrue] or [TransIfFalse]. Case e 0 ≡ (if e 1 = e 2 then e 3 else e 4 ) From Γ e 0 : T and [If] we get that Γ e 1 : nonproxy N 1 ; Γ . Therefore, by induction hypothesis, e 0 reduces by [C-CongruenceE]. 40 Case e 0 ≡ (if x 1 = e 2 then e 3 else e 4 ) From Γ e 0 : T and [If] we get that Γ e 2 : nonproxy N 2 ; Γ . Therefore, by induction hypothesis, e 0 reduces by [C-CongruenceE]. B.2 Preservation Here we prove Lemma 3.2 (Preservation), which states Given that (S, e 0 ) : T , and that (S, e 0 ) → (S , e 0 ), then (S , e 0 ) : U such that U ≤ T . Proof The proof is by induction on (S, e 0 ) → (S , e 0 ). Case (S, e 0 ) ≡ (S, x): In this case the program cannot take an evaluation step, therefore by definition the lemma is true. Case (S, e 0 ) ≡ (S, e. f ): From Γ e 0 : T ; Γ and [Field] we get Γ e : nonproxy N; Γ . Also fields(C) =Tf . Case e 0 ≡ x. f : Then (S, e 0 ) reduces by [TransField]: (S, x. f i ) → (S, x i ). Given (S, e 0 ), we have from [Field] that fields(C) =Tf . By hypothesis S : Γ, which gives by [CheckState] that S(x) : Γ(x). So from [New], Γ x i : S i ; Γ where S i ≤ T i . Case e 0 ≡ e 1 . f : From the induction hypothesis, (S, e 1 ) → (S , e 1 ) and (S, e 1 ) : T 1 mean that (S , e 1 ) : T 1 where T 1 ≤ T 1 . So, fields(T 1 ) ⊂ fieldsT 1 , and therefore, (S , e 1 . f ) : T Case (S, e 0 ) ≡ (S, e 1 .m(ē)): From Γ e 0 : T 0 and [Invoke] we get Γ e 1 : nonproxy N; Γ . Case e 0 ≡ (o.m(ȳ)): From [Invoke] we have:
doi:10.1145/1028976.1028994 dblp:conf/oopsla/PratikakisSH04 fatcat:jlse37f5vbct7gguvlpidv4q5u