]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/internal/codegen/utils/MethodBuilderBase.java
SCL compiler generates line numbers to bytecode
[simantics/platform.git] / bundles / org.simantics.scl.compiler / src / org / simantics / scl / compiler / internal / codegen / utils / MethodBuilderBase.java
1 package org.simantics.scl.compiler.internal.codegen.utils;
2
3 import org.cojen.classfile.MethodDesc;
4 import org.cojen.classfile.TypeDesc;
5 import org.objectweb.asm.Label;
6 import org.objectweb.asm.MethodVisitor;
7 import org.objectweb.asm.Opcodes;
8 import org.objectweb.asm.Type;
9
10 public class MethodBuilderBase {
11     private ClassBuilder classBuilder;
12     private MethodVisitor methodVisitor;
13     private LocalVariable[] parameters;
14     private int localVariableCount = 0;
15     private int currentLineNumber = -1;
16     
17     public MethodBuilderBase(ClassBuilder classBuilder, boolean isStatic, MethodVisitor methodVisitor, TypeDesc[] parameterTypes) {
18         this.classBuilder = classBuilder;
19         this.methodVisitor = methodVisitor;
20         this.parameters = new LocalVariable[parameterTypes.length];
21         if(!isStatic)
22             ++localVariableCount;
23         for(int i=0;i<parameterTypes.length;++i) {
24             parameters[i] = createLocalVariable("p" + i, parameterTypes[i]);
25             methodVisitor.visitParameter("p" + i, Opcodes.ACC_PUBLIC);
26         }
27         methodVisitor.visitCode();
28     }
29     
30     public LocalVariable getThis(TypeDesc type) {
31         return new LocalVariable(0, type);
32     }
33
34     public void loadConstant(boolean value) {
35         if(value)
36             methodVisitor.visitInsn(Opcodes.ICONST_1);
37         else
38             methodVisitor.visitInsn(Opcodes.ICONST_0);
39     }
40     
41     public void loadConstant(int value) {
42         if (value >= -1 && value <= 5) {
43             methodVisitor.visitInsn(Opcodes.ICONST_0 + value);
44         } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) {
45             methodVisitor.visitIntInsn(Opcodes.BIPUSH, value);
46         } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) {
47             methodVisitor.visitIntInsn(Opcodes.SIPUSH, value);
48         } else {
49             methodVisitor.visitLdcInsn(value);
50         }
51     }
52     
53     public void loadConstant(long value) {
54         if(value == 0L)
55             methodVisitor.visitInsn(Opcodes.LCONST_0);
56         else if(value == 1L)
57             methodVisitor.visitInsn(Opcodes.LCONST_1);
58         else
59             methodVisitor.visitLdcInsn(value);
60     }
61     
62     public void loadConstant(float value) {
63         if(value == 0.0f)
64             methodVisitor.visitInsn(Opcodes.FCONST_0);
65         else if(value == 1.0f)
66             methodVisitor.visitInsn(Opcodes.FCONST_1);
67         else
68             methodVisitor.visitLdcInsn(value);
69     }
70     
71     public void loadConstant(double value) {
72         if(value == 0.0)
73             methodVisitor.visitInsn(Opcodes.DCONST_0);
74         else if(value == 1.0)
75             methodVisitor.visitInsn(Opcodes.DCONST_1);
76         else
77             methodVisitor.visitLdcInsn(value);
78     }
79     
80     public void loadConstant(String value) {
81         methodVisitor.visitLdcInsn(value);
82     }
83     
84     public void loadConstant(TypeDesc value) {
85         if(value.isPrimitive())
86             loadStaticField(getClassName(value.toObjectType()), "TYPE", Constants.CLASS);
87         else
88             methodVisitor.visitLdcInsn(Type.getType(value.getDescriptor()));
89     }
90
91     
92     public int lineNumber(int lineNumber) {
93         if(lineNumber != currentLineNumber) {
94             int oldLineNumber = currentLineNumber;
95             Label label = createLabel();
96             setLocation(label);
97             methodVisitor.visitLineNumber(lineNumber, label);
98             currentLineNumber = lineNumber;
99             return oldLineNumber;
100         }
101         else
102             return currentLineNumber;
103     }
104
105     public void dup() {
106         methodVisitor.visitInsn(Opcodes.DUP);
107     }
108     
109     public void dup2() {
110         methodVisitor.visitInsn(Opcodes.DUP2);
111     }
112
113     public void dupX1() {
114         methodVisitor.visitInsn(Opcodes.DUP_X1);
115     }
116     
117     public void swap() {
118         methodVisitor.visitInsn(Opcodes.SWAP);
119     }
120
121     public void pop() {
122         methodVisitor.visitInsn(Opcodes.POP);
123     }
124     
125     public void pop2() {
126         methodVisitor.visitInsn(Opcodes.POP2);
127     }
128
129     public void convert(TypeDesc fromType, TypeDesc toType) {
130         switch(fromType.getTypeCode() + 16*toType.getTypeCode()) {
131         case TypeDesc.OBJECT_CODE + 16*TypeDesc.BOOLEAN_CODE:
132             methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z", false);
133             return;
134         case TypeDesc.OBJECT_CODE + 16*TypeDesc.INT_CODE:
135             methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I", false);
136             return;
137         case TypeDesc.OBJECT_CODE + 16*TypeDesc.FLOAT_CODE:
138             methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F", false);
139             return;
140         case TypeDesc.OBJECT_CODE + 16*TypeDesc.DOUBLE_CODE:
141             methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D", false);
142             return;
143         case TypeDesc.OBJECT_CODE + 16*TypeDesc.CHAR_CODE:
144             methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C", false);
145             return;
146         case TypeDesc.OBJECT_CODE + 16*TypeDesc.LONG_CODE:
147             methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J", false);
148             return;
149         case TypeDesc.OBJECT_CODE + 16*TypeDesc.SHORT_CODE:
150             methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S", false);
151             return;
152         case TypeDesc.OBJECT_CODE + 16*TypeDesc.BYTE_CODE:
153             methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B", false);
154             return;
155         case TypeDesc.DOUBLE_CODE + 16*TypeDesc.FLOAT_CODE:
156             methodVisitor.visitInsn(Opcodes.D2F);
157             return;
158         case TypeDesc.FLOAT_CODE + 16*TypeDesc.DOUBLE_CODE:
159             methodVisitor.visitInsn(Opcodes.F2D);
160             return;
161         case TypeDesc.INT_CODE + 16*TypeDesc.DOUBLE_CODE:
162             methodVisitor.visitInsn(Opcodes.I2D);
163             return;
164         case TypeDesc.DOUBLE_CODE + 16*TypeDesc.INT_CODE:
165             methodVisitor.visitInsn(Opcodes.D2I);
166             return;
167         case TypeDesc.INT_CODE + 16*TypeDesc.FLOAT_CODE:
168             methodVisitor.visitInsn(Opcodes.I2F);
169             return;
170         case TypeDesc.FLOAT_CODE + 16*TypeDesc.INT_CODE:
171             methodVisitor.visitInsn(Opcodes.F2I);
172             return;
173         case TypeDesc.LONG_CODE + 16*TypeDesc.FLOAT_CODE:
174             methodVisitor.visitInsn(Opcodes.L2F);
175             return;
176         case TypeDesc.FLOAT_CODE + 16*TypeDesc.LONG_CODE:
177             methodVisitor.visitInsn(Opcodes.F2L);
178             return;
179         case TypeDesc.LONG_CODE + 16*TypeDesc.DOUBLE_CODE:
180             methodVisitor.visitInsn(Opcodes.L2D);
181             return;
182         case TypeDesc.DOUBLE_CODE + 16*TypeDesc.LONG_CODE:
183             methodVisitor.visitInsn(Opcodes.D2L);
184             return;
185         case TypeDesc.INT_CODE + 16*TypeDesc.LONG_CODE:
186             methodVisitor.visitInsn(Opcodes.I2L);
187             return;
188         case TypeDesc.LONG_CODE + 16*TypeDesc.INT_CODE:
189             methodVisitor.visitInsn(Opcodes.L2I);
190             return;
191         case TypeDesc.INT_CODE + 16*TypeDesc.SHORT_CODE:
192             methodVisitor.visitInsn(Opcodes.I2S);
193             return;
194         case TypeDesc.SHORT_CODE + 16*TypeDesc.INT_CODE:
195         case TypeDesc.BOOLEAN_CODE + 16*TypeDesc.INT_CODE:
196             // NOP
197             return;
198         case TypeDesc.INT_CODE + 16*TypeDesc.BYTE_CODE:
199             methodVisitor.visitInsn(Opcodes.I2B);
200             return;
201         case TypeDesc.BYTE_CODE + 16*TypeDesc.INT_CODE:
202             // NOP
203             return;
204         case TypeDesc.INT_CODE + 16*TypeDesc.CHAR_CODE:
205             methodVisitor.visitInsn(Opcodes.I2C);
206             return;
207         case TypeDesc.CHAR_CODE + 16*TypeDesc.INT_CODE:
208             // NOP
209             return;
210         default:
211             System.out.println("convert: " + fromType + " -> " + toType);
212         }
213     }
214
215     public void convert(TypeDesc fromType, TypeDesc toType,
216             int convertFpNormal) {
217         convert(fromType, toType);
218     }
219
220     public LocalVariable createLocalVariable(String name, TypeDesc type) {
221         int index = localVariableCount;
222         localVariableCount += type == TypeDesc.DOUBLE || type == TypeDesc.LONG ? 2 : 1;
223         return new LocalVariable(index, type);
224     }
225
226     public void storeLocal(LocalVariable local) {
227         switch(local.type.getTypeCode()) {
228         case TypeDesc.BOOLEAN_CODE:
229         case TypeDesc.BYTE_CODE:
230         case TypeDesc.CHAR_CODE:
231         case TypeDesc.SHORT_CODE:
232         case TypeDesc.INT_CODE:
233             methodVisitor.visitVarInsn(Opcodes.ISTORE, local.index);
234             break;     
235         case TypeDesc.FLOAT_CODE:
236             methodVisitor.visitVarInsn(Opcodes.FSTORE, local.index);
237             break;     
238         case TypeDesc.DOUBLE_CODE:
239             methodVisitor.visitVarInsn(Opcodes.DSTORE, local.index);
240             break;     
241         case TypeDesc.LONG_CODE:
242             methodVisitor.visitVarInsn(Opcodes.LSTORE, local.index);
243             break;     
244         case TypeDesc.OBJECT_CODE:
245             methodVisitor.visitVarInsn(Opcodes.ASTORE, local.index);
246             break;     
247         default: throw new IllegalArgumentException();
248         }
249     }
250
251     public void ifZeroComparisonBranch(Label location, String choice) {
252         int opcode;
253         if(choice.equals("!="))
254             opcode = Opcodes.IFNE; 
255         else if(choice.equals("=="))
256             opcode = Opcodes.IFEQ;
257         else if(choice.equals("<"))
258             opcode = Opcodes.IFLT;
259         else if(choice.equals(">"))
260             opcode = Opcodes.IFGT;
261         else if(choice.equals("<="))
262             opcode = Opcodes.IFLE;
263         else if(choice.equals(">="))
264             opcode = Opcodes.IFGE;
265         else
266             throw new IllegalArgumentException("Invalid choice \"" + choice + "\".");
267         methodVisitor.visitJumpInsn(opcode, location);
268     }
269
270     public void ifComparisonBranch(Label location, String choice, TypeDesc type) {
271         switch(type.getTypeCode()) {
272         case TypeDesc.BOOLEAN_CODE:
273         case TypeDesc.BYTE_CODE:
274         case TypeDesc.CHAR_CODE:
275         case TypeDesc.SHORT_CODE:
276         case TypeDesc.INT_CODE: {
277             int opcode;
278             if(choice.equals("!="))
279                 opcode = Opcodes.IF_ICMPNE; 
280             else if(choice.equals("=="))
281                 opcode = Opcodes.IF_ICMPEQ;
282             else if(choice.equals("<"))
283                 opcode = Opcodes.IF_ICMPLT;
284             else if(choice.equals(">"))
285                 opcode = Opcodes.IF_ICMPGT;
286             else if(choice.equals("<="))
287                 opcode = Opcodes.IF_ICMPLE;
288             else if(choice.equals(">="))
289                 opcode = Opcodes.IF_ICMPGE;
290             else
291                 throw new IllegalArgumentException("Invalid choice \"" + choice + "\".");
292             methodVisitor.visitJumpInsn(opcode, location);
293         } break;     
294         case TypeDesc.FLOAT_CODE:
295             methodVisitor.visitInsn(Opcodes.FCMPL);
296             ifZeroComparisonBranch(location, choice);
297             break;     
298         case TypeDesc.DOUBLE_CODE:
299             methodVisitor.visitInsn(Opcodes.DCMPL);
300             ifZeroComparisonBranch(location, choice);
301             break;     
302         case TypeDesc.LONG_CODE:
303             methodVisitor.visitInsn(Opcodes.LCMP);
304             ifZeroComparisonBranch(location, choice);
305             break;     
306         case TypeDesc.OBJECT_CODE: {
307             int opcode;
308             if(choice.equals("!="))
309                 opcode = Opcodes.IF_ACMPNE; 
310             else if(choice.equals("=="))
311                 opcode = Opcodes.IF_ACMPEQ;
312             else
313                 throw new IllegalArgumentException("Invalid choice \"" + choice + "\".");
314             methodVisitor.visitJumpInsn(opcode, location);
315         } break;     
316         default: throw new IllegalArgumentException();
317         }
318     }
319
320     public void ifNullBranch(Label location, boolean choice) {
321         methodVisitor.visitJumpInsn(choice ? Opcodes.IFNULL : Opcodes.IFNONNULL, location);
322     }
323     
324     public void branch(Label location) {
325         methodVisitor.visitJumpInsn(Opcodes.GOTO, location);
326     }
327
328     public Label createLabel() {
329         return new Label();
330     }
331     
332     public void setLocation(Label label) {
333         methodVisitor.visitLabel(label);
334     }
335
336     public void loadLocal(LocalVariable local) {
337         switch(local.type.getTypeCode()) {
338         case TypeDesc.BOOLEAN_CODE:
339         case TypeDesc.BYTE_CODE:
340         case TypeDesc.CHAR_CODE:
341         case TypeDesc.SHORT_CODE:
342         case TypeDesc.INT_CODE:
343             methodVisitor.visitVarInsn(Opcodes.ILOAD, local.index);
344             break;     
345         case TypeDesc.FLOAT_CODE:
346             methodVisitor.visitVarInsn(Opcodes.FLOAD, local.index);
347             break;     
348         case TypeDesc.DOUBLE_CODE:
349             methodVisitor.visitVarInsn(Opcodes.DLOAD, local.index);
350             break;     
351         case TypeDesc.LONG_CODE:
352             methodVisitor.visitVarInsn(Opcodes.LLOAD, local.index);
353             break;     
354         case TypeDesc.OBJECT_CODE:
355             methodVisitor.visitVarInsn(Opcodes.ALOAD, local.index);
356             break;     
357         default: throw new IllegalArgumentException();
358         }
359     }
360
361     public void loadNull() {
362         methodVisitor.visitInsn(Opcodes.ACONST_NULL);
363     }
364
365     public void loadFromArray(TypeDesc type) {
366         switch(type.getTypeCode()) {
367         case TypeDesc.BOOLEAN_CODE:
368             methodVisitor.visitInsn(Opcodes.BALOAD);
369             break;
370         case TypeDesc.BYTE_CODE:
371             methodVisitor.visitInsn(Opcodes.BALOAD);
372             break;
373         case TypeDesc.CHAR_CODE:
374             methodVisitor.visitInsn(Opcodes.CALOAD);
375             break;
376         case TypeDesc.SHORT_CODE:
377             methodVisitor.visitInsn(Opcodes.SALOAD);
378             break;
379         case TypeDesc.INT_CODE:
380             methodVisitor.visitInsn(Opcodes.IALOAD);
381             break;     
382         case TypeDesc.FLOAT_CODE:
383             methodVisitor.visitInsn(Opcodes.FALOAD);
384             break;     
385         case TypeDesc.DOUBLE_CODE:
386             methodVisitor.visitInsn(Opcodes.DALOAD);
387             break;     
388         case TypeDesc.LONG_CODE:
389             methodVisitor.visitInsn(Opcodes.LALOAD);
390             break;     
391         case TypeDesc.OBJECT_CODE:
392             methodVisitor.visitInsn(Opcodes.AALOAD);
393             break;     
394         default: throw new IllegalArgumentException();
395         }
396     }
397
398     public void invokeInterface(String className, String methodName,
399             TypeDesc ret, TypeDesc[] params) {
400         checkClassName(className);
401         checkParameters(params);
402         methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, className, methodName,
403                 MethodDesc.forArguments(ret, params).getDescriptor(), true);
404     }
405
406     public void invokeInterface(TypeDesc className, String methodName,
407             TypeDesc ret, TypeDesc[] params) {
408         invokeInterface(getClassName(className), methodName, ret, params);
409     }
410
411     public void invokeVirtual(String className, String methodName,
412             TypeDesc ret, TypeDesc[] params) {
413         checkClassName(className);
414         checkParameters(params);
415         methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, methodName,
416                 MethodDesc.forArguments(ret, params).getDescriptor(), false);
417     }
418
419     public void invokeVirtual(TypeDesc className, String methodName, TypeDesc ret,
420             TypeDesc[] params) {
421         invokeVirtual(getClassName(className), methodName, ret, params);
422     }
423
424     public void invokeConstructor(String className, TypeDesc[] params) {
425         checkClassName(className);
426         checkParameters(params);
427         methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, className, "<init>",
428                 MethodDesc.forArguments(TypeDesc.VOID, params).getDescriptor(), false);
429     }
430
431     public void invokeConstructor(TypeDesc className, TypeDesc[] params) {
432         invokeConstructor(getClassName(className), params);
433     }
434
435     public void invokeSuperConstructor(TypeDesc[] params) {
436         invokeConstructor(classBuilder.getSuperClassName(), params);
437     }
438
439     public void invokeStatic(String className, String methodName, TypeDesc ret,
440             TypeDesc[] params) {
441         checkClassName(className);
442         checkParameters(params);
443         methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, className, methodName,
444                 MethodDesc.forArguments(ret, params).getDescriptor(), false);
445     }
446
447     public void invokeStatic(TypeDesc className, String methodName, TypeDesc ret,
448             TypeDesc[] params) {
449         invokeStatic(getClassName(className), methodName, ret, params);
450     }
451
452     public void newObject(TypeDesc type) {
453         methodVisitor.visitTypeInsn(Opcodes.NEW, getClassName(type));
454     }
455     
456     public void newObject(String type) {
457         methodVisitor.visitTypeInsn(Opcodes.NEW, type);
458     }
459
460     public void newObject(TypeDesc type, int dimensions) {
461         methodVisitor.visitMultiANewArrayInsn(type.getDescriptor(), dimensions);
462     }
463
464     public void loadStaticField(String className, String fieldName, TypeDesc type) {
465         checkClassName(className);
466         methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, className, fieldName, type.getDescriptor());
467     }
468
469     public void loadStaticField(TypeDesc className, String fieldName,
470             TypeDesc type) {
471         loadStaticField(getClassName(className), fieldName, type);
472     }
473
474     public void loadField(String className, String fieldName, TypeDesc type) {
475         checkClassName(className);
476         methodVisitor.visitFieldInsn(Opcodes.GETFIELD, className, fieldName, type.getDescriptor());
477     }
478
479     public void storeStaticField(String className, String fieldName,
480             TypeDesc type) {
481         checkClassName(className);
482         methodVisitor.visitFieldInsn(Opcodes.PUTSTATIC, className, fieldName, type.getDescriptor());
483     }
484
485     public void storeField(String className, String fieldName, TypeDesc type) {
486         checkClassName(className);
487         methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, className, fieldName, type.getDescriptor());
488     }
489
490     public void storeToArray(TypeDesc type) {
491         switch(type.getTypeCode()) {
492         case TypeDesc.BOOLEAN_CODE:
493             methodVisitor.visitInsn(Opcodes.BASTORE);
494             break;
495         case TypeDesc.BYTE_CODE:
496             methodVisitor.visitInsn(Opcodes.BASTORE);
497             break;
498         case TypeDesc.CHAR_CODE:
499             methodVisitor.visitInsn(Opcodes.CASTORE);
500             break;
501         case TypeDesc.SHORT_CODE:
502             methodVisitor.visitInsn(Opcodes.SASTORE);
503             break;
504         case TypeDesc.INT_CODE:
505             methodVisitor.visitInsn(Opcodes.IASTORE);
506             break;     
507         case TypeDesc.FLOAT_CODE:
508             methodVisitor.visitInsn(Opcodes.FASTORE);
509             break;     
510         case TypeDesc.DOUBLE_CODE:
511             methodVisitor.visitInsn(Opcodes.DASTORE);
512             break;     
513         case TypeDesc.LONG_CODE:
514             methodVisitor.visitInsn(Opcodes.LASTORE);
515             break;     
516         case TypeDesc.OBJECT_CODE:
517             methodVisitor.visitInsn(Opcodes.AASTORE);
518             break;     
519         default: throw new IllegalArgumentException();
520         }
521     }
522
523     public void math(int opcode) {
524         methodVisitor.visitInsn(opcode);
525     }
526
527     public void throwObject() {
528         methodVisitor.visitInsn(Opcodes.ATHROW);
529     }
530
531     public void checkCast(TypeDesc type) {
532         methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, getClassName(type));
533     }
534
535     public void instanceOf(TypeDesc type) {
536         methodVisitor.visitTypeInsn(Opcodes.INSTANCEOF, getClassName(type));
537     }
538
539     public void arrayLength() {
540         methodVisitor.visitInsn(Opcodes.ARRAYLENGTH);
541     }
542
543     public void loadThis() {
544         methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
545     }
546
547     public LocalVariable getParameter(int index) {
548         return parameters[index];
549     }
550
551     public void returnVoid() {
552         methodVisitor.visitInsn(Opcodes.RETURN);
553     }
554
555     public void returnValue(TypeDesc type) {
556         switch(type.getTypeCode()) {
557         case TypeDesc.VOID_CODE:
558             methodVisitor.visitInsn(Opcodes.RETURN);
559             break;     
560         case TypeDesc.BOOLEAN_CODE:
561         case TypeDesc.BYTE_CODE:
562         case TypeDesc.CHAR_CODE:
563         case TypeDesc.SHORT_CODE:
564         case TypeDesc.INT_CODE:
565             methodVisitor.visitInsn(Opcodes.IRETURN);
566             break;     
567         case TypeDesc.FLOAT_CODE:
568             methodVisitor.visitInsn(Opcodes.FRETURN);
569             break;     
570         case TypeDesc.DOUBLE_CODE:
571             methodVisitor.visitInsn(Opcodes.DRETURN);
572             break;     
573         case TypeDesc.LONG_CODE:
574             methodVisitor.visitInsn(Opcodes.LRETURN);
575             break;     
576         case TypeDesc.OBJECT_CODE:
577             methodVisitor.visitInsn(Opcodes.ARETURN);
578             break;     
579         default: throw new IllegalArgumentException();
580         }
581     }
582     
583     public void finish() {
584         methodVisitor.visitMaxs(0, 0);
585         methodVisitor.visitEnd();
586     }
587
588     public String getClassName() {
589         return classBuilder.className;
590     }
591     
592     public static String getClassName(TypeDesc typeDesc) {
593         if(typeDesc.isArray())
594             return typeDesc.getDescriptor();
595         else
596             return typeDesc.getFullName().replace('.', '/');
597     }
598     
599     private static void checkClassName(String className) {
600         ClassBuilder.checkClassName(className);
601     }
602
603     public static String getClassName(Class<?> clazz) {
604         return clazz.getName().replace('.', '/');
605     }
606     
607     public void switch_(int[] values, Label[] labels, Label defaultLabel) {
608         int lo = values[0];
609         int hi = values[values.length-1];
610         long table_space_cost = 4 + ((long) hi - lo + 1); // words
611         long table_time_cost = 3; // comparisons
612         long lookup_space_cost = 3 + 2 * (long) values.length;
613         long lookup_time_cost = values.length;
614         if(values.length > 0 &&
615             table_space_cost + 3 * table_time_cost <=
616             lookup_space_cost + 3 * lookup_time_cost) {
617             Label[] table = new Label[hi - lo + 1];
618             for(int i=0,j=0;i<table.length;++i) {
619                 int id = lo+i;
620                 if(values[j] == id) {
621                     table[i] = labels[j];
622                     ++j;
623                 }
624                 else
625                     table[i] = defaultLabel;
626             }
627             methodVisitor.visitTableSwitchInsn(lo, hi, defaultLabel, table);
628         }
629         else
630             methodVisitor.visitLookupSwitchInsn(defaultLabel, values, labels);
631     }
632     
633     private static void checkParameters(TypeDesc[] params) {
634         for(TypeDesc param : params)
635             if(param.equals(TypeDesc.VOID))
636                 throw new IllegalArgumentException();
637     }
638 }