• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.dx.rop.code;
17 
18 import com.android.dx.rop.cst.CstMethodRef;
19 import com.android.dx.rop.cst.CstNat;
20 import com.android.dx.rop.cst.CstProtoRef;
21 import com.android.dx.rop.cst.CstString;
22 import com.android.dx.rop.cst.CstType;
23 import com.android.dx.rop.type.Type;
24 import com.android.dx.rop.type.TypeList;
25 
26 /**
27  * An invoke-polymorphic instruction. This is a throwing instruction with
28  * multiple constants.
29  */
30 public class InvokePolymorphicInsn extends Insn {
31     private static final CstString INVOKE_DESCRIPTOR =
32             new CstString("([Ljava/lang/Object;)Ljava/lang/Object;");
33 
34     /** {@code non-null;} list of exceptions caught */
35     private final TypeList catches;
36 
37     /**
38      * {@code non-null;} method as it appears at the call site of the original
39      * invoke-virtual instruction. This is used to construct the invoke method
40      * to target and the call-site prototype.
41      */
42     private final CstMethodRef callSiteMethod;
43 
44     /**
45      * {@code non-null;} method to invoke, either {@code java.lang.invoke.MethodHandle.invoke} or
46      * {@code java.lang.invoke.MethodHandle.invokeExact}.
47      */
48     private final CstMethodRef invokeMethod;
49 
50     /**
51      * {@code non-null;} the call site prototype.
52      */
53     private final CstProtoRef callSiteProto;
54 
55     /**
56      * Constructs an instance.
57      *
58      * @param opcode {@code non-null;} the opcode
59      * @param position {@code non-null;} source position
60      * @param sources {@code non-null;} specs for all the sources
61      * @param catches {@code non-null;} list of exceptions caught
62      * @param callSiteMethod {@code non-null;} the method called by
63      * invoke-virtual that this instance will replace.
64      */
InvokePolymorphicInsn(Rop opcode, SourcePosition position, RegisterSpecList sources, TypeList catches, CstMethodRef callSiteMethod)65     public InvokePolymorphicInsn(Rop opcode, SourcePosition position, RegisterSpecList sources, TypeList catches,
66             CstMethodRef callSiteMethod) {
67         super(opcode, position, null, sources);
68 
69         if (opcode.getBranchingness() != Rop.BRANCH_THROW) {
70             throw new IllegalArgumentException("opcode with invalid branchingness: " + opcode.getBranchingness());
71         }
72 
73         if (catches == null) {
74             throw new NullPointerException("catches == null");
75         }
76         this.catches = catches;
77 
78         if (callSiteMethod == null) {
79             throw new NullPointerException("callSiteMethod == null");
80         } else if (!callSiteMethod.isSignaturePolymorphic()) {
81             throw new IllegalArgumentException("callSiteMethod is not signature polymorphic");
82         }
83 
84         this.callSiteMethod = callSiteMethod;
85         this.invokeMethod = makeInvokeMethod(callSiteMethod);
86         this.callSiteProto = makeCallSiteProto(callSiteMethod);
87     }
88 
89     /** {@inheritDoc} */
90     @Override
getCatches()91     public TypeList getCatches() {
92         return this.catches;
93     }
94 
95     /** {@inheritDoc} */
96     @Override
accept(Visitor visitor)97     public void accept(Visitor visitor) {
98         visitor.visitInvokePolymorphicInsn(this);
99     }
100 
101     /** {@inheritDoc} */
102     @Override
withAddedCatch(Type type)103     public Insn withAddedCatch(Type type) {
104         return new InvokePolymorphicInsn(getOpcode(), getPosition(),
105                 getSources(), catches.withAddedType(type), getCallSiteMethod());
106     }
107 
108     /** {@inheritDoc} */
109     @Override
withRegisterOffset(int delta)110     public Insn withRegisterOffset(int delta) {
111         return new InvokePolymorphicInsn(getOpcode(), getPosition(),
112                 getSources().withOffset(delta),
113                 catches, getCallSiteMethod());
114     }
115 
116     /** {@inheritDoc} */
117     @Override
withNewRegisters(RegisterSpec result, RegisterSpecList sources)118     public Insn withNewRegisters(RegisterSpec result, RegisterSpecList sources) {
119         return new InvokePolymorphicInsn(getOpcode(), getPosition(),
120                 sources, catches, getCallSiteMethod());
121     }
122 
123     /**
124      * Gets the method as it appears at the call site of the original
125      * invoke-virtual instruction.
126      *
127      * @return {@code non-null;} the original method reference
128      */
getCallSiteMethod()129     public CstMethodRef getCallSiteMethod() {
130         return callSiteMethod;
131     }
132 
133     /**
134      * Gets the method to be invoked. This will be will either be
135      * {@code java.lang.invoke.MethodHandle.invoke()} or
136      * {@code java.lang.invoke.MethodHandle.invokeExact()}.
137      *
138      * @return {@code non-null;} method reference to be invoked
139      */
getInvokeMethod()140     public CstMethodRef getInvokeMethod() {
141         return invokeMethod;
142     }
143 
144     /**
145      * Gets the call site prototype. The call site prototype is provided
146      * as an argument to invoke-polymorphic to enable type checking and
147      * type conversion.
148      *
149      * @return {@code non-null;} Prototype reference for call site
150      */
getCallSiteProto()151     public CstProtoRef getCallSiteProto() {
152         return callSiteProto;
153     }
154 
155     /** {@inheritDoc} */
156     @Override
getInlineString()157     public String getInlineString() {
158         return getInvokeMethod().toString() + " " +
159             getCallSiteProto().toString() + " " +
160             ThrowingInsn.toCatchString(catches);
161     }
162 
makeInvokeMethod(final CstMethodRef callSiteMethod)163     private static CstMethodRef makeInvokeMethod(final CstMethodRef callSiteMethod) {
164         // The name is either invoke or invokeExact. The INVOKE_DESCRIPTOR is fixed.
165         CstNat cstNat = new CstNat(callSiteMethod.getNat().getName(), INVOKE_DESCRIPTOR);
166         return new CstMethodRef(CstType.METHOD_HANDLE, cstNat);
167     }
168 
makeCallSiteProto(final CstMethodRef callSiteMethod)169     private static CstProtoRef makeCallSiteProto(final CstMethodRef callSiteMethod) {
170         return new CstProtoRef(callSiteMethod.getPrototype(true));
171     }
172 }
173