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