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