MethodGenerator.java revision 818:26a5fdb90de2
1159784Ssam/*
2159784Ssam * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3159784Ssam * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4159784Ssam *
5159784Ssam * This code is free software; you can redistribute it and/or modify it
6159784Ssam * under the terms of the GNU General Public License version 2 only, as
7159784Ssam * published by the Free Software Foundation.  Oracle designates this
8159784Ssam * particular file as subject to the "Classpath" exception as provided
9159784Ssam * by Oracle in the LICENSE file that accompanied this code.
10159784Ssam *
11159784Ssam * This code is distributed in the hope that it will be useful, but WITHOUT
12159784Ssam * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13159784Ssam * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14159784Ssam * version 2 for more details (a copy is included in the LICENSE file that
15159784Ssam * accompanied this code).
16159784Ssam *
17159784Ssam * You should have received a copy of the GNU General Public License version
18159784Ssam * 2 along with this work; if not, write to the Free Software Foundation,
19159784Ssam * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20159784Ssam *
21159784Ssam * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22159784Ssam * or visit www.oracle.com if you need additional information or have any
23159784Ssam * questions.
24159784Ssam */
25159784Ssam
26159784Ssampackage jdk.nashorn.internal.tools.nasgen;
27159784Ssam
28159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.AALOAD;
29159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.AASTORE;
30159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
31159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL;
32159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
33159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ANEWARRAY;
34159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
35159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ASM4;
36159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ASTORE;
37159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.BALOAD;
38159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.BASTORE;
39159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH;
40159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.CALOAD;
41159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.CASTORE;
42159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
43159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DALOAD;
44159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DASTORE;
45159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DCONST_0;
46159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DRETURN;
47159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DUP;
48159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DUP2;
49159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.FALOAD;
50159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.FASTORE;
51159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.FCONST_0;
52159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.FRETURN;
53159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
54159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC;
55159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
56159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
57159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
58159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
59159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
60159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
61159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
62159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
63159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
64159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
65159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ISTORE;
66159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.LALOAD;
67159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
68159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0;
69159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.LRETURN;
70159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.NEW;
71159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.POP;
72159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
73159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC;
74159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
75159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.SALOAD;
76159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.SASTORE;
77159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH;
78159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
79159784Ssamimport static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE;
80159784Ssamimport static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE;
81159784Ssam
82159784Ssamimport java.util.List;
83159784Ssamimport jdk.internal.org.objectweb.asm.Handle;
84159784Ssamimport jdk.internal.org.objectweb.asm.MethodVisitor;
85159784Ssamimport jdk.internal.org.objectweb.asm.Type;
86159784Ssam
87159784Ssam/**
88159784Ssam * Base class for all method generating classes.
89159784Ssam *
90159784Ssam */
91159784Ssampublic class MethodGenerator extends MethodVisitor {
92298881Spfg    private final int access;
93159784Ssam    private final String name;
94159784Ssam    private final String descriptor;
95159784Ssam    private final Type returnType;
96159784Ssam    private final Type[] argumentTypes;
97159784Ssam
98159784Ssam    MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) {
99159784Ssam        super(ASM4, mv);
100159784Ssam        this.access        = access;
101159784Ssam        this.name          = name;
102159784Ssam        this.descriptor    = descriptor;
103159784Ssam        this.returnType    = Type.getReturnType(descriptor);
104159784Ssam        this.argumentTypes = Type.getArgumentTypes(descriptor);
105159784Ssam    }
106159784Ssam
107159784Ssam    int getAccess() {
108159784Ssam        return access;
109159784Ssam    }
110159784Ssam
111159784Ssam    final String getName() {
112159784Ssam        return name;
113159784Ssam    }
114159784Ssam
115159784Ssam    final String getDescriptor() {
116159784Ssam        return descriptor;
117159784Ssam    }
118159784Ssam
119159784Ssam    final Type getReturnType() {
120159784Ssam        return returnType;
121159784Ssam    }
122159784Ssam
123159784Ssam    final Type[] getArgumentTypes() {
124159784Ssam        return argumentTypes;
125159784Ssam    }
126159784Ssam
127159784Ssam    /**
128159784Ssam     * Check whether access for this method is static
129159784Ssam     * @return true if static
130159784Ssam     */
131159784Ssam    protected final boolean isStatic() {
132159784Ssam        return (getAccess() & ACC_STATIC) != 0;
133159784Ssam    }
134159784Ssam
135159784Ssam    /**
136159784Ssam     * Check whether this method is a constructor
137159784Ssam     * @return true if constructor
138159784Ssam     */
139159784Ssam    protected final boolean isConstructor() {
140298881Spfg        return "<init>".equals(name);
141159784Ssam    }
142159784Ssam
143159784Ssam    void newObject(final String type) {
144159784Ssam        super.visitTypeInsn(NEW, type);
145159784Ssam    }
146159784Ssam
147159784Ssam    void newObjectArray(final String type) {
148159784Ssam        super.visitTypeInsn(ANEWARRAY, type);
149159784Ssam    }
150159784Ssam
151159784Ssam    void loadThis() {
152159784Ssam        if ((access & ACC_STATIC) != 0) {
153159784Ssam            throw new IllegalStateException("no 'this' inside static method");
154159784Ssam        }
155159784Ssam        super.visitVarInsn(ALOAD, 0);
156159784Ssam    }
157159784Ssam
158159784Ssam    void returnValue() {
159159784Ssam        super.visitInsn(returnType.getOpcode(IRETURN));
160159784Ssam    }
161159784Ssam
162159784Ssam    void returnVoid() {
163159784Ssam        super.visitInsn(RETURN);
164159784Ssam    }
165159784Ssam
166159784Ssam    // load, store
167159784Ssam    void arrayLoad(final Type type) {
168159784Ssam        super.visitInsn(type.getOpcode(IALOAD));
169159784Ssam    }
170159784Ssam
171159784Ssam    void arrayLoad() {
172159784Ssam        super.visitInsn(AALOAD);
173159784Ssam    }
174159784Ssam
175159784Ssam    void arrayStore(final Type type) {
176159784Ssam        super.visitInsn(type.getOpcode(IASTORE));
177159784Ssam    }
178159784Ssam
179159784Ssam    void arrayStore() {
180159784Ssam        super.visitInsn(AASTORE);
181159784Ssam    }
182159784Ssam
183159784Ssam    void loadLiteral(final Object value) {
184159784Ssam        super.visitLdcInsn(value);
185159784Ssam    }
186159784Ssam
187159784Ssam    void classLiteral(final String className) {
188159784Ssam        super.visitLdcInsn(className);
189159784Ssam    }
190159784Ssam
191159784Ssam    void loadLocal(final Type type, final int index) {
192159784Ssam        super.visitVarInsn(type.getOpcode(ILOAD), index);
193159784Ssam    }
194159784Ssam
195159784Ssam    void loadLocal(final int index) {
196159784Ssam        super.visitVarInsn(ALOAD, index);
197159784Ssam    }
198159784Ssam
199159784Ssam    void storeLocal(final Type type, final int index) {
200159784Ssam        super.visitVarInsn(type.getOpcode(ISTORE), index);
201159784Ssam    }
202159784Ssam
203159784Ssam    void storeLocal(final int index) {
204159784Ssam        super.visitVarInsn(ASTORE, index);
205159784Ssam    }
206159784Ssam
207159784Ssam    void checkcast(final String type) {
208159784Ssam        super.visitTypeInsn(CHECKCAST, type);
209159784Ssam    }
210159784Ssam
211159784Ssam    // push constants/literals
212159784Ssam    void pushNull() {
213159784Ssam        super.visitInsn(ACONST_NULL);
214159784Ssam    }
215159784Ssam
216159784Ssam    void push(final int value) {
217159784Ssam        if (value >= -1 && value <= 5) {
218159784Ssam            super.visitInsn(ICONST_0 + value);
219159784Ssam        } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
220159784Ssam            super.visitIntInsn(BIPUSH, value);
221159784Ssam        } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
222159784Ssam            super.visitIntInsn(SIPUSH, value);
223159784Ssam        } else {
224159784Ssam            super.visitLdcInsn(value);
225159784Ssam        }
226159784Ssam    }
227159784Ssam
228159784Ssam    void loadClass(final String className) {
229159784Ssam        super.visitLdcInsn(Type.getObjectType(className));
230159784Ssam    }
231159784Ssam
232159784Ssam    void pop() {
233159784Ssam        super.visitInsn(POP);
234159784Ssam    }
235159784Ssam
236159784Ssam    // various "dups"
237159784Ssam    void dup() {
238159784Ssam        super.visitInsn(DUP);
239159784Ssam    }
240159784Ssam
241159784Ssam    void dup2() {
242159784Ssam        super.visitInsn(DUP2);
243159784Ssam    }
244159784Ssam
245159784Ssam    void swap() {
246159784Ssam        super.visitInsn(SWAP);
247159784Ssam    }
248159784Ssam
249159784Ssam    void dupArrayValue(final int arrayOpcode) {
250159784Ssam        switch (arrayOpcode) {
251159784Ssam            case IALOAD: case FALOAD:
252159784Ssam            case AALOAD: case BALOAD:
253159784Ssam            case CALOAD: case SALOAD:
254159784Ssam            case IASTORE: case FASTORE:
255159784Ssam            case AASTORE: case BASTORE:
256159784Ssam            case CASTORE: case SASTORE:
257159784Ssam                dup();
258159784Ssam            break;
259159784Ssam
260159784Ssam            case LALOAD: case DALOAD:
261159784Ssam            case LASTORE: case DASTORE:
262159784Ssam                dup2();
263159829Sobrien            break;
264159784Ssam            default:
265159784Ssam                throw new AssertionError("invalid dup");
266159784Ssam        }
267159784Ssam    }
268159784Ssam
269159829Sobrien    void dupReturnValue(final int returnOpcode) {
270159784Ssam        switch (returnOpcode) {
271159784Ssam            case IRETURN:
272159784Ssam            case FRETURN:
273159829Sobrien            case ARETURN:
274159784Ssam                super.visitInsn(DUP);
275159784Ssam                return;
276159784Ssam            case LRETURN:
277159784Ssam            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