• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2024 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 
17 package com.android.xts.apimapper.asm
18 
19 import org.objectweb.asm.MethodVisitor
20 import org.objectweb.asm.Opcodes
21 import org.objectweb.asm.Type
22 
23 /** Name of the class initializer method. */
24 const val CLASS_INITIALIZER_NAME = "<clinit>"
25 
26 /** Descriptor of the class initializer methods. */
27 const val CLASS_INITIALIZER_DESC = "()V"
28 
29 /** Descriptor of the constructor. */
30 const val CTOR_DESC = "()V"
31 
32 /** Name of the constructor. */
33 const val CTOR_NAME = "<init>"
34 
35 /** Convert the class name to jvm format. */
36 fun String.toJvmClassName(): String = replace('.', '/')
37 
38 /** Convert the class name from jvm format. */
39 fun String.toHumanReadableClassName() = replace(Regex("[/$]"), ".")
40 
41 /** Convert method params from jvm format. */
42 fun String.toHumanReadableDesc(): String {
43     val params = ArrayList<String>()
44     Type.getArgumentTypes(this).forEach {
45         params.add(it.className.toHumanReadableClassName())
46     }
47     return params.joinToString(", ")
48 }
49 
50 /** Extract the class name from a .class file. */
zipEntryNameToClassNamenull51 fun zipEntryNameToClassName(entryFilename: String): String? {
52     val suffix = ".class"
53     return if (entryFilename.endsWith(suffix)) {
54         entryFilename.removeSuffix(suffix)
55     } else {
56         null
57     }
58 }
59 
60 /**
61  * Write bytecode to "RETURN" that matches the method's return type, according to
62  * [methodDescriptor].
63  */
writeByteCodeToReturnnull64 fun writeByteCodeToReturn(methodDescriptor: String, writer: MethodVisitor) {
65     Type.getReturnType(methodDescriptor).let { type ->
66         // See https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions
67         when (type) {
68             Type.VOID_TYPE -> writer.visitInsn(Opcodes.RETURN)
69             Type.BOOLEAN_TYPE, Type.CHAR_TYPE, Type.BYTE_TYPE, Type.SHORT_TYPE, Type.INT_TYPE
70             -> writer.visitInsn(Opcodes.IRETURN)
71             Type.FLOAT_TYPE -> writer.visitInsn(Opcodes.FRETURN)
72             Type.LONG_TYPE -> writer.visitInsn(Opcodes.LRETURN)
73             Type.DOUBLE_TYPE -> writer.visitInsn(Opcodes.DRETURN)
74             else -> writer.visitInsn(Opcodes.ARETURN)
75         }
76     }
77 }
78 
79 /** Given a method descriptor, insert an [argType] as the first argument to it. */
prependArgTypeToMethodDescriptornull80 fun prependArgTypeToMethodDescriptor(methodDescriptor: String, argType: Type): String {
81     val returnType = Type.getReturnType(methodDescriptor)
82     val argTypes = Type.getArgumentTypes(methodDescriptor).toMutableList()
83     argTypes.add(0, argType)
84     return Type.getMethodDescriptor(returnType, *argTypes.toTypedArray())
85 }
86 
87 /**
88  * Write bytecode to push all the method arguments to the stack. The number of arguments and their
89  * type are taken from [methodDesc].
90  */
writeByteCodeToPushArgumentsnull91 fun writeByteCodeToPushArguments(
92     methodDesc: String,
93     mv: MethodVisitor,
94     offset: Int,
95 ) {
96     var i = offset
97     Type.getArgumentTypes(methodDesc).forEach { type ->
98         // See https://en.wikipedia.org/wiki/List_of_Java_bytecode_instructions
99         // Long and Double will consume two local variable spaces.
100         when (type) {
101             Type.VOID_TYPE -> throw AsmGenException("VOID_TYPE not expected")
102             Type.BOOLEAN_TYPE, Type.CHAR_TYPE, Type.BYTE_TYPE, Type.SHORT_TYPE, Type.INT_TYPE
103             -> mv.visitVarInsn(Opcodes.ILOAD, i)
104             Type.FLOAT_TYPE -> mv.visitVarInsn(Opcodes.FLOAD, i)
105             Type.LONG_TYPE -> mv.visitVarInsn(Opcodes.LLOAD, i++)
106             Type.DOUBLE_TYPE -> mv.visitVarInsn(Opcodes.DLOAD, i++)
107             else -> mv.visitVarInsn(Opcodes.ALOAD, i)
108         }
109         i++
110     }
111 }
112