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