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