]> gerrit.simantics Code Review - simantics/platform.git/blob
7fb83fb49e3fd210dddd0ed7228a9febdaa792da
[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         methodVisitor.visitMethodInsn(Opcodes.INVOKEINTERFACE, className, methodName,
383                 MethodDesc.forArguments(ret, params).getDescriptor(), true);
384     }
385
386     public void invokeInterface(TypeDesc className, String methodName,
387             TypeDesc ret, TypeDesc[] params) {
388         invokeInterface(getClassName(className), methodName, ret, params);
389     }
390
391     public void invokeVirtual(String className, String methodName,
392             TypeDesc ret, TypeDesc[] params) {
393         checkClassName(className);
394         methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, methodName,
395                 MethodDesc.forArguments(ret, params).getDescriptor(), false);
396     }
397
398     public void invokeVirtual(TypeDesc className, String methodName, TypeDesc ret,
399             TypeDesc[] params) {
400         invokeVirtual(getClassName(className), methodName, ret, params);
401     }
402
403     public void invokeConstructor(String className, TypeDesc[] params) {
404         checkClassName(className);
405         methodVisitor.visitMethodInsn(Opcodes.INVOKESPECIAL, className, "<init>",
406                 MethodDesc.forArguments(TypeDesc.VOID, params).getDescriptor(), false);
407     }
408
409     public void invokeConstructor(TypeDesc className, TypeDesc[] params) {
410         invokeConstructor(getClassName(className), params);
411     }
412
413     public void invokeSuperConstructor(TypeDesc[] params) {
414         invokeConstructor(classBuilder.getSuperClassName(), params);
415     }
416
417     public void invokeStatic(String className, String methodName, TypeDesc ret,
418             TypeDesc[] params) {
419         checkClassName(className);
420         methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, className, methodName,
421                 MethodDesc.forArguments(ret, params).getDescriptor(), false);
422     }
423
424     public void invokeStatic(TypeDesc className, String methodName, TypeDesc ret,
425             TypeDesc[] params) {
426         invokeStatic(getClassName(className), methodName, ret, params);
427     }
428
429     public void newObject(TypeDesc type) {
430         methodVisitor.visitTypeInsn(Opcodes.NEW, getClassName(type));
431     }
432     
433     public void newObject(String type) {
434         methodVisitor.visitTypeInsn(Opcodes.NEW, type);
435     }
436
437     public void newObject(TypeDesc type, int dimensions) {
438         methodVisitor.visitMultiANewArrayInsn(type.getDescriptor(), dimensions);
439     }
440
441     public void loadStaticField(String className, String fieldName, TypeDesc type) {
442         checkClassName(className);
443         methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, className, fieldName, type.getDescriptor());
444     }
445
446     public void loadStaticField(TypeDesc className, String fieldName,
447             TypeDesc type) {
448         loadStaticField(getClassName(className), fieldName, type);
449     }
450
451     public void loadField(String className, String fieldName, TypeDesc type) {
452         checkClassName(className);
453         methodVisitor.visitFieldInsn(Opcodes.GETFIELD, className, fieldName, type.getDescriptor());
454     }
455
456     public void storeStaticField(String className, String fieldName,
457             TypeDesc type) {
458         checkClassName(className);
459         methodVisitor.visitFieldInsn(Opcodes.PUTSTATIC, className, fieldName, type.getDescriptor());
460     }
461
462     public void storeField(String className, String fieldName, TypeDesc type) {
463         checkClassName(className);
464         methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, className, fieldName, type.getDescriptor());
465     }
466
467     public void storeToArray(TypeDesc type) {
468         switch(type.getTypeCode()) {
469         case TypeDesc.BOOLEAN_CODE:
470             methodVisitor.visitInsn(Opcodes.BASTORE);
471             break;
472         case TypeDesc.BYTE_CODE:
473             methodVisitor.visitInsn(Opcodes.BASTORE);
474             break;
475         case TypeDesc.CHAR_CODE:
476             methodVisitor.visitInsn(Opcodes.CASTORE);
477             break;
478         case TypeDesc.SHORT_CODE:
479             methodVisitor.visitInsn(Opcodes.SASTORE);
480             break;
481         case TypeDesc.INT_CODE:
482             methodVisitor.visitInsn(Opcodes.IASTORE);
483             break;     
484         case TypeDesc.FLOAT_CODE:
485             methodVisitor.visitInsn(Opcodes.FASTORE);
486             break;     
487         case TypeDesc.DOUBLE_CODE:
488             methodVisitor.visitInsn(Opcodes.DASTORE);
489             break;     
490         case TypeDesc.LONG_CODE:
491             methodVisitor.visitInsn(Opcodes.LASTORE);
492             break;     
493         case TypeDesc.OBJECT_CODE:
494             methodVisitor.visitInsn(Opcodes.AASTORE);
495             break;     
496         default: throw new IllegalArgumentException();
497         }
498     }
499
500     public void math(int opcode) {
501         methodVisitor.visitInsn(opcode);
502     }
503
504     public void throwObject() {
505         methodVisitor.visitInsn(Opcodes.ATHROW);
506     }
507
508     public void checkCast(TypeDesc type) {
509         methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, getClassName(type));
510     }
511
512     public void instanceOf(TypeDesc type) {
513         methodVisitor.visitTypeInsn(Opcodes.INSTANCEOF, getClassName(type));
514     }
515
516     public void arrayLength() {
517         methodVisitor.visitInsn(Opcodes.ARRAYLENGTH);
518     }
519
520     public void loadThis() {
521         methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
522     }
523
524     public LocalVariable getParameter(int index) {
525         return parameters[index];
526     }
527
528     public void returnVoid() {
529         methodVisitor.visitInsn(Opcodes.RETURN);
530     }
531
532     public void returnValue(TypeDesc type) {
533         switch(type.getTypeCode()) {
534         case TypeDesc.VOID_CODE:
535             methodVisitor.visitInsn(Opcodes.RETURN);
536             break;     
537         case TypeDesc.BOOLEAN_CODE:
538         case TypeDesc.BYTE_CODE:
539         case TypeDesc.CHAR_CODE:
540         case TypeDesc.SHORT_CODE:
541         case TypeDesc.INT_CODE:
542             methodVisitor.visitInsn(Opcodes.IRETURN);
543             break;     
544         case TypeDesc.FLOAT_CODE:
545             methodVisitor.visitInsn(Opcodes.FRETURN);
546             break;     
547         case TypeDesc.DOUBLE_CODE:
548             methodVisitor.visitInsn(Opcodes.DRETURN);
549             break;     
550         case TypeDesc.LONG_CODE:
551             methodVisitor.visitInsn(Opcodes.LRETURN);
552             break;     
553         case TypeDesc.OBJECT_CODE:
554             methodVisitor.visitInsn(Opcodes.ARETURN);
555             break;     
556         default: throw new IllegalArgumentException();
557         }
558     }
559     
560     public void finish() {
561         methodVisitor.visitMaxs(0, 0);
562         methodVisitor.visitEnd();
563     }
564
565     public String getClassName() {
566         return classBuilder.className;
567     }
568     
569     public static String getClassName(TypeDesc typeDesc) {
570         if(typeDesc.isArray())
571             return typeDesc.getDescriptor();
572         else
573             return typeDesc.getFullName().replace('.', '/');
574     }
575     
576     private static void checkClassName(String className) {
577         ClassBuilder.checkClassName(className);
578     }
579
580     public static String getClassName(Class<?> clazz) {
581         return clazz.getName().replace('.', '/');
582     }
583     
584     public void switch_(int[] values, Label[] labels, Label defaultLabel) {
585         int lo = values[0];
586         int hi = values[values.length-1];
587         long table_space_cost = 4 + ((long) hi - lo + 1); // words
588         long table_time_cost = 3; // comparisons
589         long lookup_space_cost = 3 + 2 * (long) values.length;
590         long lookup_time_cost = values.length;
591         if(values.length > 0 &&
592             table_space_cost + 3 * table_time_cost <=
593             lookup_space_cost + 3 * lookup_time_cost) {
594             Label[] table = new Label[hi - lo + 1];
595             for(int i=0,j=0;i<table.length;++i) {
596                 int id = lo+i;
597                 if(values[j] == id) {
598                     table[i] = labels[j];
599                     ++j;
600                 }
601                 else
602                     table[i] = defaultLabel;
603             }
604             methodVisitor.visitTableSwitchInsn(lo, hi, defaultLabel, table);
605         }
606         else
607             methodVisitor.visitLookupSwitchInsn(defaultLabel, values, labels);
608     }
609 }