File: ClassBuilder.java

package info (click to toggle)
openjdk-17 17.0.17%2B10-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 764,928 kB
  • sloc: java: 5,319,061; xml: 1,291,711; cpp: 1,202,358; ansic: 428,746; asm: 404,978; objc: 20,861; sh: 14,754; javascript: 10,743; python: 6,402; makefile: 2,404; perl: 357; awk: 351; sed: 172; jsp: 24; csh: 3
file content (240 lines) | stat: -rw-r--r-- 8,099 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*
 * Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package selectionresolution;

import java.util.ArrayList;
import java.util.Iterator;

import static jdk.internal.org.objectweb.asm.Opcodes.ACC_ABSTRACT;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PROTECTED;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;

/**
 * Constructs classes and interfaces based on the information from a
 * DefaultMethodTestCase
 *
 */
public class ClassBuilder extends Builder {
    private final ArrayList<ClassConstruct> classes;

    // Add a class in every package to be able to instantiate package
    // private classes from outside the package
    private final Clazz[] helpers = new Clazz[4];
    private ClassConstruct callsiteClass;

    public enum ExecutionMode { DIRECT, INDY, MH_INVOKE_EXACT, MH_INVOKE_GENERIC}
    private final ExecutionMode execMode;

    public ClassBuilder(SelectionResolutionTestCase testcase,
                        ExecutionMode execMode) {
        super(testcase);
        this.classes = new ArrayList<>();
        this.execMode = execMode;
    }

    public ClassConstruct[] build() throws Exception {
        buildClassConstructs();
        return classes.toArray(new ClassConstruct[0]);
    }

    public ClassConstruct getCallsiteClass() {
        return callsiteClass;
    }

    private void buildClassConstructs() throws Exception {
        TestBuilder tb = new TestBuilder(testcase.methodref, testcase);

        classes.add(new Clazz("Test", ACC_PUBLIC, -1));

        for (int classId = 0; classId < classdata.size(); classId++) {
            ClassConstruct C;
            String[] interfaces = getInterfaces(classId);
            ClassData data = classdata.get(classId);

            if (isClass(classId)) {
                C = new Clazz(getName(classId),
                              getExtending(classId),
                              getClassModifiers(data),
                              classId,
                              interfaces);

                addHelperMethod(classId);

            } else {
                C = new Interface(getName(classId),
                                  getAccessibility(data.access),
                                  classId, interfaces);
            }

            // Add a method "m()LTestObject;" if applicable
            if (containsMethod(data)) {
                // Method will either be abstract or concrete depending on the
                // abstract modifier
                C.addTestMethod(getMethodModifiers(data));
            }

            if (classId == testcase.callsite) {
                // Add test() method
                tb.addTest(C, execMode);
                callsiteClass = C;
            }

            classes.add(C);
        }
        classes.add(tb.getMainTestClass());

    }

    private void addHelperMethod(int classId) {
        int packageId = classdata.get(classId).packageId.ordinal();
        Clazz C = helpers[packageId];
        if (C == null) {
            C = new Clazz(getPackageName(packageId) + "Helper", ACC_PUBLIC, -1);
            helpers[packageId] = C;
            classes.add(C);
        }

        Method m = C.addMethod("get" + getClassName(classId),
                               "()L" + getName(classId) + ";",
                               ACC_PUBLIC + ACC_STATIC);
        m.makeInstantiateMethod(getName(classId));
    }

    private String[] getInterfaces(int classId) {
        ArrayList<String> interfaces = new ArrayList<>();

        // Figure out if we're extending/implementing an interface
        for (final int intf : hier.interfaces()) {
            if (hier.inherits(classId, intf)) {
                interfaces.add(getName(intf));
            }
        }
        return interfaces.toArray(new String[0]);
    }

    private String getExtending(int classId) {
        int extending = -1;

        // See if we're extending another class
        for (final int extendsClass : hier.classes()) {
            if (hier.inherits(classId, extendsClass)) {
                // Sanity check that we haven't already found an extending class
                if (extending != -1) {
                    throw new RuntimeException("Multiple extending classes");
                }
                extending = extendsClass;
            }
        }

        return extending == -1 ? null : getName(extending);
    }

    /**
     * Returns modifiers for a Class
     * @param cd ClassData for the Class
     * @return ASM modifiers for a Class
     */
    private int getClassModifiers(ClassData cd) {
        // For Classes we only care about accessibility (public, private etc)
        return getAccessibility(cd.access) | getAbstraction(cd.abstraction);
    }

    /**
     * Returns modifiers for Method type
     * @param cd ClassData for the Class or Interface where the Method resides
     * @return ASM modifiers for the Method
     */
    private int getMethodModifiers(ClassData cd) {
        int mod = 0;

        // For methods we want everything
        mod += getAccessibility(cd.methoddata.access);
        mod += getAbstraction(cd.methoddata.context);
        mod += getContext(cd.methoddata.context);
        mod += getExtensibility();
        return mod;
    }


    /**
     * Convert ClassData access type to ASM
     * @param access
     * @return ASM version of accessibility (public / private / protected)
     */
    private int getAccessibility(MethodData.Access access) {
        switch(access) {
        case PACKAGE:
            //TODO: Do I need to set this or will this be the default?
            return 0;
        case PRIVATE:
            return ACC_PRIVATE;
        case PROTECTED:
            return ACC_PROTECTED;
        case PUBLIC:
            return ACC_PUBLIC;
        default:
            throw new RuntimeException("Illegal accessibility modifier: " + access);
        }
    }

    /**
     * Convert ClassData abstraction type to ASM
     * @param abstraction
     * @return ASM version of abstraction (abstract / non-abstract)
     */
    private int getAbstraction(MethodData.Context context) {
        return context == MethodData.Context.ABSTRACT ? ACC_ABSTRACT : 0;
    }

    /**
     * Convert ClassData context type to ASM
     * @param context
     * @return ASM version of context (static / non-static)
     */
    private int getContext(MethodData.Context context) {
        return context == MethodData.Context.STATIC ? ACC_STATIC : 0;
    }

    /**
     * Convert ClassData extensibility type to ASM
     * @param extensibility
     * @return ASM version of extensibility (final / non-final)
     */
    private int getExtensibility() {
        return 0;
    }

    /**
     * Determine if we need a method at all, abstraction is set to null if this
     * Class/Interface should not have a test method
     * @param cd
     * @return
     */
    private boolean containsMethod(ClassData cd) {
        return cd.methoddata != null;
    }

}