File: GenFullCP.java

package info (click to toggle)
openjdk-25 25.0.1%2B8-1~deb13u1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 825,408 kB
  • sloc: java: 5,585,680; cpp: 1,333,948; xml: 1,321,242; ansic: 488,034; asm: 404,003; objc: 21,088; sh: 15,106; javascript: 13,265; python: 8,319; makefile: 2,518; perl: 357; awk: 351; pascal: 103; exp: 83; sed: 72; jsp: 24
file content (316 lines) | stat: -rw-r--r-- 13,264 bytes parent folder | download | duplicates (3)
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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/*
 * Copyright (c) 2011, 2025, 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 vm.mlvm.cp.share;

import org.objectweb.asm.ByteVector;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.ClassWriterExt;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

import vm.mlvm.share.ClassfileGenerator;
import vm.mlvm.share.Env;

public abstract class GenFullCP extends ClassfileGenerator {

    /**
     * Generate field description for object type from class name:
     * return "L" + className + ";";
     * @param className Class name
     * @return field descriptor representing the class type
     */
    protected static String fd(String className) {
        return "L" + className + ";";
    }

    // Universal constants
    protected static final String JL_OBJECT = "java/lang/Object";
    protected static final String JL_CLASS = "java/lang/Class";
    protected static final String JL_CLASSLOADER  = "java/lang/ClassLoader";
    protected static final String JL_STRING = "java/lang/String";
    protected static final String JL_RUNTIMEEXCEPTION = "java/lang/RuntimeException";
    protected static final String JL_BOOTSTRAPMETHODERROR = "java/lang/BootstrapMethodError";
    protected static final String JL_THROWABLE = "java/lang/Throwable";
    protected static final String JLI_METHODTYPE = "java/lang/invoke/MethodType";
    protected static final String JLI_METHODHANDLE = "java/lang/invoke/MethodHandle";
    protected static final String JLI_METHODHANDLES = "java/lang/invoke/MethodHandles";
    protected static final String JLI_METHODHANDLES_LOOKUP = "java/lang/invoke/MethodHandles$Lookup";
    protected static final String JLI_CALLSITE = "java/lang/invoke/CallSite";
    protected static final String JLI_CONSTANTCALLSITE = "java/lang/invoke/ConstantCallSite";

    protected static final String VOID_NO_ARG_METHOD_SIGNATURE = "()V";

    protected static final String NEW_INVOKE_SPECIAL_CLASS_NAME = "java/lang/invoke/NewInvokeSpecialCallSite";
    protected static final String NEW_INVOKE_SPECIAL_BOOTSTRAP_METHOD_SIGNATURE = "(" + fd(JLI_METHODHANDLES_LOOKUP) + fd(JL_STRING) + fd(JLI_METHODTYPE) + ")V";

    protected static final String INIT_METHOD_NAME = "<init>";
    protected static final String STATIC_INIT_METHOD_NAME = "<clinit>";

    // Generated class constants
    protected static final int CLASSFILE_VERSION = 51;

    protected static final int CP_CONST_COUNT = 65400;
    protected static final int MAX_METHOD_SIZE = 65400;
    protected static final int BYTES_PER_LDC = 5;
    protected static final int LDC_PER_METHOD = MAX_METHOD_SIZE / BYTES_PER_LDC;
    protected static final int METHOD_COUNT = CP_CONST_COUNT / LDC_PER_METHOD;

    protected static final String PARENT_CLASS_NAME = JL_OBJECT;

    protected static final String INIT_METHOD_SIGNATURE = VOID_NO_ARG_METHOD_SIGNATURE;

    protected static final String MAIN_METHOD_NAME = "main";
    protected static final String MAIN_METHOD_SIGNATURE = "(" + "[" + fd(JL_STRING) + ")V";

    protected static final String TEST_METHOD_NAME = "test";
    protected static final String TEST_METHOD_SIGNATURE = VOID_NO_ARG_METHOD_SIGNATURE;

    protected static final String STATIC_FIELD_NAME = "testStatic";
    protected static final String STATIC_FIELD_SIGNATURE = "Z";

    protected static final String INSTANCE_FIELD_NAME = "testInstance";
    protected static final String INSTANCE_FIELD_SIGNATURE = "Z";

    protected static final String STATIC_BOOTSTRAP_FIELD_NAME = "testCSStatic";
    protected static final String STATIC_BOOTSTRAP_FIELD_SIGNATURE = fd(JLI_CALLSITE);

    protected static final String INSTANCE_BOOTSTRAP_FIELD_NAME = "testCSInstance";
    protected static final String INSTANCE_BOOTSTRAP_FIELD_SIGNATURE = fd(JLI_CALLSITE);

    protected static final String BOOTSTRAP_METHOD_NAME = "bootstrap";
    protected static final String BOOTSTRAP_METHOD_SIGNATURE = "(" +  fd(JLI_METHODHANDLES_LOOKUP) + fd(JL_STRING) + fd(JLI_METHODTYPE) + ")" + fd(JLI_CALLSITE);

    protected static final String INSTANCE_BOOTSTRAP_METHOD_NAME = "bootstrapInstance";
    protected static final String INSTANCE_BOOTSTRAP_METHOD_SIGNATURE = BOOTSTRAP_METHOD_SIGNATURE;

    protected static final String TARGET_METHOD_NAME = "target";
    protected static final String TARGET_METHOD_SIGNATURE = VOID_NO_ARG_METHOD_SIGNATURE;

    protected static final String INSTANCE_TARGET_METHOD_NAME = "targetInstance";
    protected static final String INSTANCE_TARGET_METHOD_SIGNATURE = VOID_NO_ARG_METHOD_SIGNATURE;

    protected interface DummyInterface {
        public void targetInstance();
    }

    // Helper methods

    protected static String getDummyInterfaceClassName() {
        return DummyInterface.class.getName().replace('.', '/');
    }

    protected static void createLogMsgCode(MethodVisitor mv, String msg) {
        mv.visitLdcInsn(msg);
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "vm/mlvm/share/Env", "traceVerbose", "(Ljava/lang/String;)V");
    }

    protected static void createThrowRuntimeExceptionCode(MethodVisitor mv, String msg) {
        createThrowRuntimeExceptionCodeHelper(mv, msg, false);
    }

    // Expects a throwable (the cause) to be on top of the stack when called.
    protected static void createThrowRuntimeExceptionCodeWithCause(MethodVisitor mv, String msg) {
        createThrowRuntimeExceptionCodeHelper(mv, msg, true);
    }

    // If set_cause is true it expects a Throwable (the cause) to be on top of the stack when called.
    protected static void createThrowRuntimeExceptionCodeHelper(MethodVisitor mv, String msg, boolean set_cause) {
        mv.visitTypeInsn(Opcodes.NEW, JL_RUNTIMEEXCEPTION);
        mv.visitInsn(Opcodes.DUP);
        mv.visitLdcInsn(msg);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, JL_RUNTIMEEXCEPTION,
                INIT_METHOD_NAME, "(" + fd(JL_STRING) + ")V");
        if (set_cause) {
          mv.visitInsn(Opcodes.SWAP);
          mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, JL_RUNTIMEEXCEPTION,
                  "initCause", "(" + fd(JL_THROWABLE) + ")"+ fd(JL_THROWABLE));
        }
        mv.visitInsn(Opcodes.ATHROW);
    }

    protected static void createThrowRuntimeExceptionMethod(ClassWriter cw, boolean isStatic, String methodName, String methodSignature) {
        MethodVisitor mv = cw.visitMethod(
                Opcodes.ACC_PUBLIC | (isStatic ? Opcodes.ACC_STATIC : 0),
                methodName, methodSignature,
                null,
                new String[0]);

        createThrowRuntimeExceptionCode(mv, "Method " + methodName + methodSignature + " should not be called!");

        mv.visitMaxs(-1,  -1);
        mv.visitEnd();
    }

    protected static void finishMethodCode(MethodVisitor mv) {
        finishMethodCode(mv, Opcodes.RETURN);
    }

    protected static void finishMethodCode(MethodVisitor mv, int returnOpcode) {
        mv.visitInsn(returnOpcode);
        mv.visitMaxs(-1, -1);
        mv.visitEnd();
    }

    protected void createClassInitMethod(ClassWriter cw) {
    }

    protected void createInitMethod(ClassWriter cw) {
        MethodVisitor mv = cw.visitMethod(
                Opcodes.ACC_PUBLIC,
                INIT_METHOD_NAME, INIT_METHOD_SIGNATURE,
                null,
                new String[0]);

        mv.visitIntInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL,
                PARENT_CLASS_NAME,
                INIT_METHOD_NAME, INIT_METHOD_SIGNATURE);

        createLogMsgCode(mv, fullClassName + " constructor called");

        finishMethodCode(mv);
    }

    protected void createTargetMethod(ClassWriter cw) {
        MethodVisitor mv = cw.visitMethod(
                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
                TARGET_METHOD_NAME, TARGET_METHOD_SIGNATURE,
                null,
                new String[0]);

        createLogMsgCode(mv, fullClassName + "." + TARGET_METHOD_NAME + TARGET_METHOD_SIGNATURE + " called");

        finishMethodCode(mv);
    }

    protected void createBootstrapMethod(ClassWriter cw) {
         createBootstrapMethod(cw, true, BOOTSTRAP_METHOD_NAME, BOOTSTRAP_METHOD_SIGNATURE);
    }

    protected void createBootstrapMethod(ClassWriter cw, boolean isStatic, String methodName, String methodSignature) {
        MethodVisitor mv = cw.visitMethod(
                (isStatic ? Opcodes.ACC_STATIC : 0) | Opcodes.ACC_PUBLIC,
                methodName, methodSignature,
                null, new String[0]);

        createLogMsgCode(mv, fullClassName + "." + BOOTSTRAP_METHOD_NAME + BOOTSTRAP_METHOD_SIGNATURE + " called");

        int argShift = isStatic ? 0 : 1;

        mv.visitTypeInsn(Opcodes.NEW, JLI_CONSTANTCALLSITE);
        mv.visitInsn(Opcodes.DUP);
        mv.visitVarInsn(Opcodes.ALOAD, 0 + argShift);
        mv.visitLdcInsn(Type.getObjectType(fullClassName));
        mv.visitVarInsn(Opcodes.ALOAD, 1 + argShift);
        mv.visitVarInsn(Opcodes.ALOAD, 2 + argShift);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                JLI_METHODHANDLES_LOOKUP, "findStatic",
                "(" + fd(JL_CLASS) + fd(JL_STRING) + fd(JLI_METHODTYPE) + ")" + fd(JLI_METHODHANDLE));
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, JLI_CONSTANTCALLSITE,
                INIT_METHOD_NAME, "(" + fd(JLI_METHODHANDLE) + ")V");

        finishMethodCode(mv, Opcodes.ARETURN);
    }

    @Override
    public Klass[] generateBytecodes() {

        // COMPUTE_FRAMES were disabled due to JDK-8079697
        ClassWriterExt cw = new ClassWriterExt(/*ClassWriter.COMPUTE_FRAMES |*/ ClassWriter.COMPUTE_MAXS);

        String[] interfaces = new String[1];
        interfaces[0] = getDummyInterfaceClassName();
        cw.visit(CLASSFILE_VERSION, Opcodes.ACC_PUBLIC, fullClassName, null, PARENT_CLASS_NAME, interfaces);

        generateCommonData(cw);

        MethodVisitor mainMV = cw.visitMethod(
                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
                MAIN_METHOD_NAME, MAIN_METHOD_SIGNATURE,
                null, new String[0]);

        mainMV.visitTypeInsn(Opcodes.NEW, fullClassName);
        mainMV.visitInsn(Opcodes.DUP);
        mainMV.visitMethodInsn(Opcodes.INVOKESPECIAL, fullClassName, INIT_METHOD_NAME, INIT_METHOD_SIGNATURE);

        int constCount = 0;
        int methodNum = 0;

        // TODO: check real CP size and also limit number of iterations in this cycle
        while (constCount < CP_CONST_COUNT) {
            final String methodName = TEST_METHOD_NAME + String.format("%02d", methodNum);

            MethodVisitor mw = cw.visitMethod(
                    Opcodes.ACC_PUBLIC,
                    methodName, TEST_METHOD_SIGNATURE,
                    null, new String[0]);

            generateTestMethodProlog(mw);

            // TODO: check real CP size and also limit number of iterations in this cycle
            while (constCount < CP_CONST_COUNT && cw.getBytecodeLength(mw) < MAX_METHOD_SIZE) {
                generateCPEntryData(cw, mw);
                ++constCount;
            }

            generateTestMethodEpilog(mw);

            mw.visitMaxs(-1, -1);
            mw.visitEnd();

            Env.traceNormal("Method " + fullClassName + "." + methodName + "(): "
                          + constCount + " constants in CP, "
                          + cw.getBytecodeLength(mw) + " bytes of code");

            mainMV.visitInsn(Opcodes.DUP);
            mainMV.visitMethodInsn(Opcodes.INVOKEVIRTUAL, fullClassName, methodName, TEST_METHOD_SIGNATURE);

            ++methodNum;
        }

        mainMV.visitInsn(Opcodes.POP);
        finishMethodCode(mainMV);

        cw.visitEnd();
        return new Klass[] { new Klass(this.pkgName, this.shortClassName, MAIN_METHOD_NAME, MAIN_METHOD_SIGNATURE, cw.toByteArray()) };
    }

    protected void generateCommonData(ClassWriterExt cw) {
        createClassInitMethod(cw);
        createInitMethod(cw);
        createTargetMethod(cw);
        createBootstrapMethod(cw);
    }

    protected void generateTestMethodProlog(MethodVisitor mw) {
    }

    protected abstract void generateCPEntryData(ClassWriter cw, MethodVisitor mw);

    protected void generateTestMethodEpilog(MethodVisitor mw) {
        mw.visitInsn(Opcodes.RETURN);
    }

}