MethodGenerator.java revision 973:d564abed1e6a
1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.tools.nasgen;
27
28import static jdk.internal.org.objectweb.asm.Opcodes.AALOAD;
29import static jdk.internal.org.objectweb.asm.Opcodes.AASTORE;
30import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
31import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL;
32import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
33import static jdk.internal.org.objectweb.asm.Opcodes.ANEWARRAY;
34import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
35import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE;
36import static jdk.internal.org.objectweb.asm.Opcodes.BALOAD;
37import static jdk.internal.org.objectweb.asm.Opcodes.BASTORE;
38import static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH;
39import static jdk.internal.org.objectweb.asm.Opcodes.CALOAD;
40import static jdk.internal.org.objectweb.asm.Opcodes.CASTORE;
41import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
42import static jdk.internal.org.objectweb.asm.Opcodes.DALOAD;
43import static jdk.internal.org.objectweb.asm.Opcodes.DASTORE;
44import static jdk.internal.org.objectweb.asm.Opcodes.DCONST_0;
45import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN;
46import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
47import static jdk.internal.org.objectweb.asm.Opcodes.DUP2;
48import static jdk.internal.org.objectweb.asm.Opcodes.FALOAD;
49import static jdk.internal.org.objectweb.asm.Opcodes.FASTORE;
50import static jdk.internal.org.objectweb.asm.Opcodes.FCONST_0;
51import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN;
52import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
53import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
54import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
55import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
56import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
57import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
58import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
59import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
60import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
61import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
62import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
63import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
64import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
65import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD;
66import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
67import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0;
68import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
69import static jdk.internal.org.objectweb.asm.Opcodes.NEW;
70import static jdk.internal.org.objectweb.asm.Opcodes.POP;
71import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
72import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
73import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
74import static jdk.internal.org.objectweb.asm.Opcodes.SALOAD;
75import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE;
76import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH;
77import static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
78import static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE;
79import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE;
80
81import java.util.List;
82import jdk.internal.org.objectweb.asm.Handle;
83import jdk.internal.org.objectweb.asm.MethodVisitor;
84import jdk.internal.org.objectweb.asm.Type;
85
86/**
87 * Base class for all method generating classes.
88 *
89 */
90public class MethodGenerator extends MethodVisitor {
91    private final int access;
92    private final String name;
93    private final String descriptor;
94    private final Type returnType;
95    private final Type[] argumentTypes;
96
97    MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) {
98        super(Main.ASM_VERSION, mv);
99        this.access        = access;
100        this.name          = name;
101        this.descriptor    = descriptor;
102        this.returnType    = Type.getReturnType(descriptor);
103        this.argumentTypes = Type.getArgumentTypes(descriptor);
104    }
105
106    int getAccess() {
107        return access;
108    }
109
110    final String getName() {
111        return name;
112    }
113
114    final String getDescriptor() {
115        return descriptor;
116    }
117
118    final Type getReturnType() {
119        return returnType;
120    }
121
122    final Type[] getArgumentTypes() {
123        return argumentTypes;
124    }
125
126    /**
127     * Check whether access for this method is static
128     * @return true if static
129     */
130    protected final boolean isStatic() {
131        return (getAccess() & ACC_STATIC) != 0;
132    }
133
134    /**
135     * Check whether this method is a constructor
136     * @return true if constructor
137     */
138    protected final boolean isConstructor() {
139        return "<init>".equals(name);
140    }
141
142    void newObject(final String type) {
143        super.visitTypeInsn(NEW, type);
144    }
145
146    void newObjectArray(final String type) {
147        super.visitTypeInsn(ANEWARRAY, type);
148    }
149
150    void loadThis() {
151        if ((access & ACC_STATIC) != 0) {
152            throw new IllegalStateException("no 'this' inside static method");
153        }
154        super.visitVarInsn(ALOAD, 0);
155    }
156
157    void returnValue() {
158        super.visitInsn(returnType.getOpcode(IRETURN));
159    }
160
161    void returnVoid() {
162        super.visitInsn(RETURN);
163    }
164
165    // load, store
166    void arrayLoad(final Type type) {
167        super.visitInsn(type.getOpcode(IALOAD));
168    }
169
170    void arrayLoad() {
171        super.visitInsn(AALOAD);
172    }
173
174    void arrayStore(final Type type) {
175        super.visitInsn(type.getOpcode(IASTORE));
176    }
177
178    void arrayStore() {
179        super.visitInsn(AASTORE);
180    }
181
182    void loadLiteral(final Object value) {
183        super.visitLdcInsn(value);
184    }
185
186    void classLiteral(final String className) {
187        super.visitLdcInsn(className);
188    }
189
190    void loadLocal(final Type type, final int index) {
191        super.visitVarInsn(type.getOpcode(ILOAD), index);
192    }
193
194    void loadLocal(final int index) {
195        super.visitVarInsn(ALOAD, index);
196    }
197
198    void storeLocal(final Type type, final int index) {
199        super.visitVarInsn(type.getOpcode(ISTORE), index);
200    }
201
202    void storeLocal(final int index) {
203        super.visitVarInsn(ASTORE, index);
204    }
205
206    void checkcast(final String type) {
207        super.visitTypeInsn(CHECKCAST, type);
208    }
209
210    // push constants/literals
211    void pushNull() {
212        super.visitInsn(ACONST_NULL);
213    }
214
215    void push(final int value) {
216        if (value >= -1 && value <= 5) {
217            super.visitInsn(ICONST_0 + value);
218        } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
219            super.visitIntInsn(BIPUSH, value);
220        } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
221            super.visitIntInsn(SIPUSH, value);
222        } else {
223            super.visitLdcInsn(value);
224        }
225    }
226
227    void loadClass(final String className) {
228        super.visitLdcInsn(Type.getObjectType(className));
229    }
230
231    void pop() {
232        super.visitInsn(POP);
233    }
234
235    // various "dups"
236    void dup() {
237        super.visitInsn(DUP);
238    }
239
240    void dup2() {
241        super.visitInsn(DUP2);
242    }
243
244    void swap() {
245        super.visitInsn(SWAP);
246    }
247
248    void dupArrayValue(final int arrayOpcode) {
249        switch (arrayOpcode) {
250            case IALOAD: case FALOAD:
251            case AALOAD: case BALOAD:
252            case CALOAD: case SALOAD:
253            case IASTORE: case FASTORE:
254            case AASTORE: case BASTORE:
255            case CASTORE: case SASTORE:
256                dup();
257            break;
258
259            case LALOAD: case DALOAD:
260            case LASTORE: case DASTORE:
261                dup2();
262            break;
263            default:
264                throw new AssertionError("invalid dup");
265        }
266    }
267
268    void dupReturnValue(final int returnOpcode) {
269        switch (returnOpcode) {
270            case IRETURN:
271            case FRETURN:
272            case ARETURN:
273                super.visitInsn(DUP);
274                return;
275            case LRETURN:
276            case DRETURN:
277                super.visitInsn(DUP2);
278                return;
279            case RETURN:
280                return;
281            default:
282                throw new IllegalArgumentException("not return");
283        }
284    }
285
286    void dupValue(final Type type) {
287        switch (type.getSize()) {
288            case 1:
289                dup();
290            break;
291            case 2:
292                dup2();
293            break;
294            default:
295                throw new AssertionError("invalid dup");
296        }
297    }
298
299    void dupValue(final String desc) {
300        final int typeCode = desc.charAt(0);
301        switch (typeCode) {
302            case '[':
303            case 'L':
304            case 'Z':
305            case 'C':
306            case 'B':
307            case 'S':
308            case 'I':
309                super.visitInsn(DUP);
310                break;
311            case 'J':
312            case 'D':
313                super.visitInsn(DUP2);
314                break;
315            default:
316                throw new RuntimeException("invalid signature");
317        }
318    }
319
320    // push default value of given type desc
321    void defaultValue(final String desc) {
322        final int typeCode = desc.charAt(0);
323        switch (typeCode) {
324            case '[':
325            case 'L':
326                super.visitInsn(ACONST_NULL);
327                break;
328            case 'Z':
329            case 'C':
330            case 'B':
331            case 'S':
332            case 'I':
333                super.visitInsn(ICONST_0);
334                break;
335            case 'J':
336                super.visitInsn(LCONST_0);
337                break;
338            case 'F':
339                super.visitInsn(FCONST_0);
340                break;
341            case 'D':
342                super.visitInsn(DCONST_0);
343                break;
344            default:
345                throw new AssertionError("invalid desc " + desc);
346        }
347    }
348
349    // invokes, field get/sets
350    void invokeInterface(final String owner, final String method, final String desc) {
351        super.visitMethodInsn(INVOKEINTERFACE, owner, method, desc, true);
352    }
353
354    void invokeVirtual(final String owner, final String method, final String desc) {
355        super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc, false);
356    }
357
358    void invokeSpecial(final String owner, final String method, final String desc) {
359        super.visitMethodInsn(INVOKESPECIAL, owner, method, desc, false);
360    }
361
362    void invokeStatic(final String owner, final String method, final String desc) {
363        super.visitMethodInsn(INVOKESTATIC, owner, method, desc, false);
364    }
365
366    void putStatic(final String owner, final String field, final String desc) {
367        super.visitFieldInsn(PUTSTATIC, owner, field, desc);
368    }
369
370    void getStatic(final String owner, final String field, final String desc) {
371        super.visitFieldInsn(GETSTATIC, owner, field, desc);
372    }
373
374    void putField(final String owner, final String field, final String desc) {
375        super.visitFieldInsn(PUTFIELD, owner, field, desc);
376    }
377
378    void getField(final String owner, final String field, final String desc) {
379        super.visitFieldInsn(GETFIELD, owner, field, desc);
380    }
381
382    void memberInfoArray(final String className, final List<MemberInfo> mis) {
383        if (mis.isEmpty()) {
384            pushNull();
385            return;
386        }
387
388        int pos = 0;
389        push(mis.size());
390        newObjectArray(METHODHANDLE_TYPE);
391        for (final MemberInfo mi : mis) {
392            dup();
393            push(pos++);
394            visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc()));
395            arrayStore(TYPE_METHODHANDLE);
396        }
397    }
398
399    void computeMaxs() {
400        // These values are ignored as we create class writer
401        // with ClassWriter.COMPUTE_MAXS flag.
402        super.visitMaxs(Short.MAX_VALUE, Short.MAX_VALUE);
403    }
404
405    // debugging support - print calls
406    void println(final String msg) {
407        super.visitFieldInsn(GETSTATIC,
408                    "java/lang/System",
409                    "out",
410                    "Ljava/io/PrintStream;");
411        super.visitLdcInsn(msg);
412        super.visitMethodInsn(INVOKEVIRTUAL,
413                    "java/io/PrintStream",
414                    "println",
415                    "(Ljava/lang/String;)V",
416                    false);
417    }
418
419    // print the object on the top of the stack
420    void printObject() {
421        super.visitFieldInsn(GETSTATIC,
422                    "java/lang/System",
423                    "out",
424                    "Ljava/io/PrintStream;");
425        super.visitInsn(SWAP);
426        super.visitMethodInsn(INVOKEVIRTUAL,
427                    "java/io/PrintStream",
428                    "println",
429                    "(Ljava/lang/Object;)V",
430                    false);
431    }
432}
433