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 com.android.hoststubgen.asm.ClassNodes
19 import com.android.hoststubgen.filters.FilterPolicy
20 import com.android.hoststubgen.filters.FilterPolicyWithReason
21 import com.android.hoststubgen.filters.OutputFilter
22 import com.android.hoststubgen.log
23 import org.objectweb.asm.ClassVisitor
24 import org.objectweb.asm.MethodVisitor
25 import org.objectweb.asm.Opcodes
26 
27 /**
28  * An adapter that generates the "impl" class file from an input class file.
29  */
30 class StubGeneratingAdapter(
31         classes: ClassNodes,
32         nextVisitor: ClassVisitor,
33         filter: OutputFilter,
34         options: Options,
35 ) : BaseAdapter(classes, nextVisitor, filter, options) {
36 
shouldEmitnull37     override fun shouldEmit(policy: FilterPolicy): Boolean {
38         return policy.needsInStub
39     }
40 
visitMethodInnernull41     override fun visitMethodInner(
42             access: Int,
43             name: String,
44             descriptor: String,
45             signature: String?,
46             exceptions: Array<String>?,
47             policy: FilterPolicyWithReason,
48             substituted: Boolean,
49             superVisitor: MethodVisitor?,
50     ): MethodVisitor? {
51         return StubMethodVisitor(access, name, descriptor, signature, exceptions, superVisitor)
52     }
53 
54     private inner class StubMethodVisitor(
55             access: Int,
56             val name: String,
57             descriptor: String,
58             signature: String?,
59             exceptions: Array<String>?,
60             next: MethodVisitor?
61     ) : BodyReplacingMethodVisitor(access, name, descriptor, signature, exceptions, next) {
emitNewCodenull62         override fun emitNewCode() {
63             log.d("  Generating stub method for $currentClassName.$name")
64 
65             // Inject the following code:
66             //   throw new RuntimeException("Stub!");
67 
68             /*
69                 NEW java/lang/RuntimeException
70                 DUP
71                 LDC "not supported on host side"
72                 INVOKESPECIAL java/lang/RuntimeException.<init> (Ljava/lang/String;)V
73                 ATHROW
74                 MAXSTACK = 3
75                 MAXLOCALS = 2 <- 1 for this, 1 for return value.
76              */
77             visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException")
78             visitInsn(Opcodes.DUP)
79             visitLdcInsn("Stub!")
80             visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/RuntimeException",
81                     "<init>", "(Ljava/lang/String;)V", false)
82             visitInsn(Opcodes.ATHROW)
83             visitMaxs(0, 0) // We let ASM figure them out.
84         }
85     }
86 }
87