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