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