• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.hoststubgen.visitors
17 
18 import org.objectweb.asm.AnnotationVisitor
19 import org.objectweb.asm.Attribute
20 import org.objectweb.asm.Handle
21 import org.objectweb.asm.Label
22 import org.objectweb.asm.MethodVisitor
23 import org.objectweb.asm.TypePath
24 
25 /**
26  * A method visitor that creates or replaces a method body.
27  *
28  * Override [emitNewCode] to build the method body.
29  */
30 abstract class BodyReplacingMethodVisitor(
31     private val createBody: Boolean,
32     next: MethodVisitor?
33 ) : MethodVisitor(OPCODE_VERSION, next) {
34 
35     // Following methods are for things that we need to keep.
36     // Since they're all calling the super method, we can just remove them, but we keep them
37     // just to clarify what we're keeping.
38 
visitParameternull39     final override fun visitParameter(name: String?, access: Int) {
40         super.visitParameter(name, access)
41     }
42 
visitAnnotationDefaultnull43     final override fun visitAnnotationDefault(): AnnotationVisitor? {
44         return super.visitAnnotationDefault()
45     }
46 
visitAnnotationnull47     final override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? {
48         return super.visitAnnotation(descriptor, visible)
49     }
50 
visitTypeAnnotationnull51     final override fun visitTypeAnnotation(
52         typeRef: Int,
53         typePath: TypePath?,
54         descriptor: String?,
55         visible: Boolean
56     ): AnnotationVisitor? {
57         return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible)
58     }
59 
visitAnnotableParameterCountnull60     final override fun visitAnnotableParameterCount(parameterCount: Int, visible: Boolean) {
61         super.visitAnnotableParameterCount(parameterCount, visible)
62     }
63 
visitParameterAnnotationnull64     final override fun visitParameterAnnotation(
65         parameter: Int,
66         descriptor: String?,
67         visible: Boolean
68     ): AnnotationVisitor? {
69         return super.visitParameterAnnotation(parameter, descriptor, visible)
70     }
71 
visitAttributenull72     final override fun visitAttribute(attribute: Attribute?) {
73         super.visitAttribute(attribute)
74     }
75 
76     /**
77      * Control when to emit the code. We use this to ignore all visitXxx method calls caused by
78      * the original method, so we'll remove all the original code.
79      *
80      * Only when visitXxx methods are called from [emitNewCode], we pass-through to the base class,
81      * so the body will be generated.
82      *
83      * (See also https://asm.ow2.io/asm4-guide.pdf section 3.2.1 about the MethovVisitor
84      * call order.)
85      */
86     private var emitCode = false
87 
88     /**
89      * This value will be set as true when [visitCode] is called. In [visitEnd], if this value
90      * is still false, this means that the original method does not have a body.
91      *
92      * We want to forcefully inject a method body in [visitEnd] if [createBody] is true.
93      */
94     private var visitedCode = false
95 
visitCodenull96     final override fun visitCode() {
97         visitedCode = true
98         super.visitCode()
99 
100         try {
101             emitCode = true
102 
103             emitNewCode()
104         } finally {
105             emitCode = false
106         }
107     }
108 
visitEndnull109     final override fun visitEnd() {
110         if (!visitedCode && createBody) {
111             visitCode()
112         }
113         super.visitEnd()
114     }
115 
116     /**
117      * Subclass must implement it and emit code, and call [visitMaxs] at the end.
118      */
emitNewCodenull119     abstract fun emitNewCode()
120 
121     final override fun visitMaxs(maxStack: Int, maxLocals: Int) {
122         if (emitCode) {
123             super.visitMaxs(maxStack, maxLocals)
124         }
125     }
126 
127     // Following methods are called inside a method body, and we don't want to
128     // emit any of them, so they are all no-op.
129 
visitFramenull130     final override fun visitFrame(
131         type: Int,
132         numLocal: Int,
133         local: Array<out Any>?,
134         numStack: Int,
135         stack: Array<out Any>?
136     ) {
137         if (emitCode) {
138             super.visitFrame(type, numLocal, local, numStack, stack)
139         }
140     }
141 
visitInsnnull142     final override fun visitInsn(opcode: Int) {
143         if (emitCode) {
144             super.visitInsn(opcode)
145         }
146     }
147 
visitIntInsnnull148     final override fun visitIntInsn(opcode: Int, operand: Int) {
149         if (emitCode) {
150             super.visitIntInsn(opcode, operand)
151         }
152     }
153 
visitVarInsnnull154     final override fun visitVarInsn(opcode: Int, varIndex: Int) {
155         if (emitCode) {
156             super.visitVarInsn(opcode, varIndex)
157         }
158     }
159 
visitTypeInsnnull160     final override fun visitTypeInsn(opcode: Int, type: String?) {
161         if (emitCode) {
162             super.visitTypeInsn(opcode, type)
163         }
164     }
165 
visitFieldInsnnull166     final override fun visitFieldInsn(
167         opcode: Int,
168         owner: String?,
169         name: String?,
170         descriptor: String?
171     ) {
172         if (emitCode) {
173             super.visitFieldInsn(opcode, owner, name, descriptor)
174         }
175     }
176 
visitMethodInsnnull177     final override fun visitMethodInsn(
178         opcode: Int,
179         owner: String?,
180         name: String?,
181         descriptor: String?,
182         isInterface: Boolean
183     ) {
184         if (emitCode) {
185             super.visitMethodInsn(opcode, owner, name, descriptor, isInterface)
186         }
187     }
188 
visitInvokeDynamicInsnnull189     final override fun visitInvokeDynamicInsn(
190         name: String?,
191         descriptor: String?,
192         bootstrapMethodHandle: Handle?,
193         vararg bootstrapMethodArguments: Any?
194     ) {
195         if (emitCode) {
196             super.visitInvokeDynamicInsn(
197                 name, descriptor, bootstrapMethodHandle,
198                 *bootstrapMethodArguments
199             )
200         }
201     }
202 
visitJumpInsnnull203     final override fun visitJumpInsn(opcode: Int, label: Label?) {
204         if (emitCode) {
205             super.visitJumpInsn(opcode, label)
206         }
207     }
208 
visitLabelnull209     final override fun visitLabel(label: Label?) {
210         if (emitCode) {
211             super.visitLabel(label)
212         }
213     }
214 
visitLdcInsnnull215     final override fun visitLdcInsn(value: Any?) {
216         if (emitCode) {
217             super.visitLdcInsn(value)
218         }
219     }
220 
visitIincInsnnull221     final override fun visitIincInsn(varIndex: Int, increment: Int) {
222         if (emitCode) {
223             super.visitIincInsn(varIndex, increment)
224         }
225     }
226 
visitTableSwitchInsnnull227     final override fun visitTableSwitchInsn(
228         min: Int,
229         max: Int,
230         dflt: Label?,
231         vararg labels: Label?
232     ) {
233         if (emitCode) {
234             super.visitTableSwitchInsn(min, max, dflt, *labels)
235         }
236     }
237 
visitLookupSwitchInsnnull238     final override fun visitLookupSwitchInsn(
239         dflt: Label?,
240         keys: IntArray?,
241         labels: Array<out Label>?
242     ) {
243         if (emitCode) {
244             super.visitLookupSwitchInsn(dflt, keys, labels)
245         }
246     }
247 
visitMultiANewArrayInsnnull248     final override fun visitMultiANewArrayInsn(descriptor: String?, numDimensions: Int) {
249         if (emitCode) {
250             super.visitMultiANewArrayInsn(descriptor, numDimensions)
251         }
252     }
253 
visitInsnAnnotationnull254     final override fun visitInsnAnnotation(
255         typeRef: Int,
256         typePath: TypePath?,
257         descriptor: String?,
258         visible: Boolean
259     ): AnnotationVisitor? {
260         if (emitCode) {
261             return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible)
262         }
263         return null
264     }
265 
visitTryCatchBlocknull266     final override fun visitTryCatchBlock(
267         start: Label?,
268         end: Label?,
269         handler: Label?,
270         type: String?
271     ) {
272         if (emitCode) {
273             super.visitTryCatchBlock(start, end, handler, type)
274         }
275     }
276 
visitTryCatchAnnotationnull277     final override fun visitTryCatchAnnotation(
278         typeRef: Int,
279         typePath: TypePath?,
280         descriptor: String?,
281         visible: Boolean
282     ): AnnotationVisitor? {
283         if (emitCode) {
284             return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible)
285         }
286         return null
287     }
288 
visitLocalVariablenull289     final override fun visitLocalVariable(
290         name: String?,
291         descriptor: String?,
292         signature: String?,
293         start: Label?,
294         end: Label?,
295         index: Int
296     ) {
297         if (emitCode) {
298             super.visitLocalVariable(name, descriptor, signature, start, end, index)
299         }
300     }
301 
visitLocalVariableAnnotationnull302     final override fun visitLocalVariableAnnotation(
303         typeRef: Int,
304         typePath: TypePath?,
305         start: Array<out Label>?,
306         end: Array<out Label>?,
307         index: IntArray?,
308         descriptor: String?,
309         visible: Boolean
310     ): AnnotationVisitor? {
311         if (emitCode) {
312             return super.visitLocalVariableAnnotation(
313                 typeRef, typePath, start, end, index, descriptor, visible
314             )
315         }
316         return null
317     }
318 
visitLineNumbernull319     final override fun visitLineNumber(line: Int, start: Label?) {
320         if (emitCode) {
321             super.visitLineNumber(line, start)
322         }
323     }
324 }
325