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.Opcodes 24 import org.objectweb.asm.TypePath 25 26 /** 27 * A method visitor that removes everything from method body. 28 * 29 * To inject a method body, override [visitCode] and create the opcodes there. 30 */ 31 abstract class BodyReplacingMethodVisitor( 32 access: Int, 33 name: String, 34 descriptor: String, 35 signature: String?, 36 exceptions: Array<String>?, 37 next: MethodVisitor?, 38 ) : MethodVisitor(OPCODE_VERSION, next) { 39 val isVoid: Boolean 40 val isStatic: Boolean 41 42 init { 43 isVoid = descriptor.endsWith(")V") 44 isStatic = access and Opcodes.ACC_STATIC != 0 45 } 46 47 // Following methods are for things that we need to keep. 48 // Since they're all calling the super method, we can just remove them, but we keep them 49 // just to clarify what we're keeping. 50 visitParameternull51 final override fun visitParameter( 52 name: String?, 53 access: Int 54 ) { 55 super.visitParameter(name, access) 56 } 57 visitAnnotationDefaultnull58 final override fun visitAnnotationDefault(): AnnotationVisitor? { 59 return super.visitAnnotationDefault() 60 } 61 visitAnnotationnull62 final override fun visitAnnotation( 63 descriptor: String?, 64 visible: Boolean 65 ): AnnotationVisitor? { 66 return super.visitAnnotation(descriptor, visible) 67 } 68 visitTypeAnnotationnull69 final override fun visitTypeAnnotation( 70 typeRef: Int, 71 typePath: TypePath?, 72 descriptor: String?, 73 visible: Boolean 74 ): AnnotationVisitor? { 75 return super.visitTypeAnnotation(typeRef, typePath, descriptor, visible) 76 } 77 visitAnnotableParameterCountnull78 final override fun visitAnnotableParameterCount( 79 parameterCount: Int, 80 visible: Boolean 81 ) { 82 super.visitAnnotableParameterCount(parameterCount, visible) 83 } 84 visitParameterAnnotationnull85 final override fun visitParameterAnnotation( 86 parameter: Int, 87 descriptor: String?, 88 visible: Boolean 89 ): AnnotationVisitor? { 90 return super.visitParameterAnnotation(parameter, descriptor, visible) 91 } 92 visitAttributenull93 final override fun visitAttribute(attribute: Attribute?) { 94 super.visitAttribute(attribute) 95 } 96 visitEndnull97 override fun visitEnd() { 98 super.visitEnd() 99 } 100 101 /** 102 * Control when to emit the code. We use this to ignore all visitXxx method calls caused by 103 * the original method, so we'll remove all the original code. 104 * 105 * Only when visitXxx methods are called from [emitNewCode], we pass-through to the base class, 106 * so the body will be generated. 107 * 108 * (See also https://asm.ow2.io/asm4-guide.pdf section 3.2.1 about the MethovVisitor 109 * call order.) 110 */ 111 var emitCode = false 112 visitCodenull113 final override fun visitCode() { 114 super.visitCode() 115 116 try { 117 emitCode = true 118 119 emitNewCode() 120 } finally { 121 emitCode = false 122 } 123 } 124 125 /** 126 * Subclass must implement it and emit code, and call [visitMaxs] at the end. 127 */ emitNewCodenull128 abstract fun emitNewCode() 129 130 final override fun visitMaxs( 131 maxStack: Int, 132 maxLocals: Int 133 ) { 134 if (emitCode) { 135 super.visitMaxs(maxStack, maxLocals) 136 } 137 } 138 139 // Following methods are called inside a method body, and we don't want to 140 // emit any of them, so they are all no-op. 141 visitFramenull142 final override fun visitFrame( 143 type: Int, 144 numLocal: Int, 145 local: Array<out Any>?, 146 numStack: Int, 147 stack: Array<out Any>? 148 ) { 149 if (emitCode) { 150 super.visitFrame(type, numLocal, local, numStack, stack) 151 } 152 } 153 visitInsnnull154 final override fun visitInsn(opcode: Int) { 155 if (emitCode) { 156 super.visitInsn(opcode) 157 } 158 } 159 visitIntInsnnull160 final override fun visitIntInsn( 161 opcode: Int, 162 operand: Int 163 ) { 164 if (emitCode) { 165 super.visitIntInsn(opcode, operand) 166 } 167 } 168 visitVarInsnnull169 final override fun visitVarInsn( 170 opcode: Int, 171 varIndex: Int 172 ) { 173 if (emitCode) { 174 super.visitVarInsn(opcode, varIndex) 175 } 176 } 177 visitTypeInsnnull178 final override fun visitTypeInsn( 179 opcode: Int, 180 type: String? 181 ) { 182 if (emitCode) { 183 super.visitTypeInsn(opcode, type) 184 } 185 } 186 visitFieldInsnnull187 final override fun visitFieldInsn( 188 opcode: Int, 189 owner: String?, 190 name: String?, 191 descriptor: String? 192 ) { 193 if (emitCode) { 194 super.visitFieldInsn(opcode, owner, name, descriptor) 195 } 196 } 197 visitMethodInsnnull198 final override fun visitMethodInsn( 199 opcode: Int, 200 owner: String?, 201 name: String?, 202 descriptor: String?, 203 isInterface: Boolean 204 ) { 205 if (emitCode) { 206 super.visitMethodInsn(opcode, owner, name, descriptor, isInterface) 207 } 208 } 209 visitInvokeDynamicInsnnull210 final override fun visitInvokeDynamicInsn( 211 name: String?, 212 descriptor: String?, 213 bootstrapMethodHandle: Handle?, 214 vararg bootstrapMethodArguments: Any? 215 ) { 216 if (emitCode) { 217 super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, 218 *bootstrapMethodArguments) 219 } 220 } 221 visitJumpInsnnull222 final override fun visitJumpInsn( 223 opcode: Int, 224 label: Label? 225 ) { 226 if (emitCode) { 227 super.visitJumpInsn(opcode, label) 228 } 229 } 230 visitLabelnull231 final override fun visitLabel(label: Label?) { 232 if (emitCode) { 233 super.visitLabel(label) 234 } 235 } 236 visitLdcInsnnull237 final override fun visitLdcInsn(value: Any?) { 238 if (emitCode) { 239 super.visitLdcInsn(value) 240 } 241 } 242 visitIincInsnnull243 final override fun visitIincInsn( 244 varIndex: Int, 245 increment: Int 246 ) { 247 if (emitCode) { 248 super.visitIincInsn(varIndex, increment) 249 } 250 } 251 visitTableSwitchInsnnull252 final override fun visitTableSwitchInsn( 253 min: Int, 254 max: Int, 255 dflt: Label?, 256 vararg labels: Label? 257 ) { 258 if (emitCode) { 259 super.visitTableSwitchInsn(min, max, dflt, *labels) 260 } 261 } 262 visitLookupSwitchInsnnull263 final override fun visitLookupSwitchInsn( 264 dflt: Label?, 265 keys: IntArray?, 266 labels: Array<out Label>? 267 ) { 268 if (emitCode) { 269 super.visitLookupSwitchInsn(dflt, keys, labels) 270 } 271 } 272 visitMultiANewArrayInsnnull273 final override fun visitMultiANewArrayInsn( 274 descriptor: String?, 275 numDimensions: Int 276 ) { 277 if (emitCode) { 278 super.visitMultiANewArrayInsn(descriptor, numDimensions) 279 } 280 } 281 visitInsnAnnotationnull282 final override fun visitInsnAnnotation( 283 typeRef: Int, 284 typePath: TypePath?, 285 descriptor: String?, 286 visible: Boolean 287 ): AnnotationVisitor? { 288 if (emitCode) { 289 return super.visitInsnAnnotation(typeRef, typePath, descriptor, visible) 290 } 291 return null 292 } 293 visitTryCatchBlocknull294 final override fun visitTryCatchBlock( 295 start: Label?, 296 end: Label?, 297 handler: Label?, 298 type: String? 299 ) { 300 if (emitCode) { 301 super.visitTryCatchBlock(start, end, handler, type) 302 } 303 } 304 visitTryCatchAnnotationnull305 final override fun visitTryCatchAnnotation( 306 typeRef: Int, 307 typePath: TypePath?, 308 descriptor: String?, 309 visible: Boolean 310 ): AnnotationVisitor? { 311 if (emitCode) { 312 return super.visitTryCatchAnnotation(typeRef, typePath, descriptor, visible) 313 } 314 return null 315 } 316 visitLocalVariablenull317 final override fun visitLocalVariable( 318 name: String?, 319 descriptor: String?, 320 signature: String?, 321 start: Label?, 322 end: Label?, 323 index: Int 324 ) { 325 if (emitCode) { 326 super.visitLocalVariable(name, descriptor, signature, start, end, index) 327 } 328 } 329 visitLocalVariableAnnotationnull330 final override fun visitLocalVariableAnnotation( 331 typeRef: Int, 332 typePath: TypePath?, 333 start: Array<out Label>?, 334 end: Array<out Label>?, 335 index: IntArray?, 336 descriptor: String?, 337 visible: Boolean 338 ): AnnotationVisitor? { 339 if (emitCode) { 340 return super.visitLocalVariableAnnotation( 341 typeRef, typePath, start, end, index, descriptor, visible) 342 } 343 return null 344 } 345 visitLineNumbernull346 final override fun visitLineNumber( 347 line: Int, 348 start: Label? 349 ) { 350 if (emitCode) { 351 super.visitLineNumber(line, start) 352 } 353 } 354 } 355