OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [tools/] [external/] [asm/] [org/] [objectweb/] [asm/] [util/] [CheckMethodAdapter.java] - Blame information for rev 779

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 779 jeremybenn
/***
2
 * ASM: a very small and fast Java bytecode manipulation framework
3
 * Copyright (c) 2000-2005 INRIA, France Telecom
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. Neither the name of the copyright holders nor the names of its
15
 *    contributors may be used to endorse or promote products derived from
16
 *    this software without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28
 * THE POSSIBILITY OF SUCH DAMAGE.
29
 */
30
package org.objectweb.asm.util;
31
 
32
import org.objectweb.asm.AnnotationVisitor;
33
import org.objectweb.asm.Label;
34
import org.objectweb.asm.MethodAdapter;
35
import org.objectweb.asm.MethodVisitor;
36
import org.objectweb.asm.Opcodes;
37
import org.objectweb.asm.Attribute;
38
import org.objectweb.asm.Type;
39
 
40
import java.util.HashMap;
41
 
42
/**
43
 * A {@link MethodAdapter} that checks that its methods are properly used. More
44
 * precisely this code adapter checks each instruction individually (i.e., each
45
 * visit method checks some preconditions based <i>only</i> on its arguments -
46
 * such as the fact that the given opcode is correct for a given visit method),
47
 * but does <i>not</i> check the <i>sequence</i> of instructions. For example,
48
 * in a method whose signature is <tt>void m ()</tt>, the invalid instruction
49
 * IRETURN, or the invalid sequence IADD L2I will <i>not</i> be detected by
50
 * this code adapter.
51
 *
52
 * @author Eric Bruneton
53
 */
54
public class CheckMethodAdapter extends MethodAdapter {
55
 
56
    /**
57
     * <tt>true</tt> if the visitCode method has been called.
58
     */
59
    private boolean startCode;
60
 
61
    /**
62
     * <tt>true</tt> if the visitMaxs method has been called.
63
     */
64
    private boolean endCode;
65
 
66
    /**
67
     * <tt>true</tt> if the visitEnd method has been called.
68
     */
69
    private boolean endMethod;
70
 
71
    /**
72
     * The already visited labels. This map associate Integer values to Label
73
     * keys.
74
     */
75
    private HashMap labels;
76
 
77
    /**
78
     * Code of the visit method to be used for each opcode.
79
     */
80
    private final static int[] TYPE;
81
 
82
    static {
83
        String s = "BBBBBBBBBBBBBBBBCCIAADDDDDAAAAAAAAAAAAAAAAAAAABBBBBBBBDD"
84
                + "DDDAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
85
                + "BBBBBBBBBBBBBBBBBBBJBBBBBBBBBBBBBBBBBBBBHHHHHHHHHHHHHHHHD"
86
                + "KLBBBBBBFFFFGGGGAECEBBEEBBAMHHAA";
87
        TYPE = new int[s.length()];
88
        for (int i = 0; i < TYPE.length; ++i) {
89
            TYPE[i] = (s.charAt(i) - 'A' - 1);
90
        }
91
    }
92
 
93
    // code to generate the above string
94
    // public static void main (String[] args) {
95
    // int[] TYPE = new int[] {
96
    // 0, //NOP
97
    // 0, //ACONST_NULL
98
    // 0, //ICONST_M1
99
    // 0, //ICONST_0
100
    // 0, //ICONST_1
101
    // 0, //ICONST_2
102
    // 0, //ICONST_3
103
    // 0, //ICONST_4
104
    // 0, //ICONST_5
105
    // 0, //LCONST_0
106
    // 0, //LCONST_1
107
    // 0, //FCONST_0
108
    // 0, //FCONST_1
109
    // 0, //FCONST_2
110
    // 0, //DCONST_0
111
    // 0, //DCONST_1
112
    // 1, //BIPUSH
113
    // 1, //SIPUSH
114
    // 7, //LDC
115
    // -1, //LDC_W
116
    // -1, //LDC2_W
117
    // 2, //ILOAD
118
    // 2, //LLOAD
119
    // 2, //FLOAD
120
    // 2, //DLOAD
121
    // 2, //ALOAD
122
    // -1, //ILOAD_0
123
    // -1, //ILOAD_1
124
    // -1, //ILOAD_2
125
    // -1, //ILOAD_3
126
    // -1, //LLOAD_0
127
    // -1, //LLOAD_1
128
    // -1, //LLOAD_2
129
    // -1, //LLOAD_3
130
    // -1, //FLOAD_0
131
    // -1, //FLOAD_1
132
    // -1, //FLOAD_2
133
    // -1, //FLOAD_3
134
    // -1, //DLOAD_0
135
    // -1, //DLOAD_1
136
    // -1, //DLOAD_2
137
    // -1, //DLOAD_3
138
    // -1, //ALOAD_0
139
    // -1, //ALOAD_1
140
    // -1, //ALOAD_2
141
    // -1, //ALOAD_3
142
    // 0, //IALOAD
143
    // 0, //LALOAD
144
    // 0, //FALOAD
145
    // 0, //DALOAD
146
    // 0, //AALOAD
147
    // 0, //BALOAD
148
    // 0, //CALOAD
149
    // 0, //SALOAD
150
    // 2, //ISTORE
151
    // 2, //LSTORE
152
    // 2, //FSTORE
153
    // 2, //DSTORE
154
    // 2, //ASTORE
155
    // -1, //ISTORE_0
156
    // -1, //ISTORE_1
157
    // -1, //ISTORE_2
158
    // -1, //ISTORE_3
159
    // -1, //LSTORE_0
160
    // -1, //LSTORE_1
161
    // -1, //LSTORE_2
162
    // -1, //LSTORE_3
163
    // -1, //FSTORE_0
164
    // -1, //FSTORE_1
165
    // -1, //FSTORE_2
166
    // -1, //FSTORE_3
167
    // -1, //DSTORE_0
168
    // -1, //DSTORE_1
169
    // -1, //DSTORE_2
170
    // -1, //DSTORE_3
171
    // -1, //ASTORE_0
172
    // -1, //ASTORE_1
173
    // -1, //ASTORE_2
174
    // -1, //ASTORE_3
175
    // 0, //IASTORE
176
    // 0, //LASTORE
177
    // 0, //FASTORE
178
    // 0, //DASTORE
179
    // 0, //AASTORE
180
    // 0, //BASTORE
181
    // 0, //CASTORE
182
    // 0, //SASTORE
183
    // 0, //POP
184
    // 0, //POP2
185
    // 0, //DUP
186
    // 0, //DUP_X1
187
    // 0, //DUP_X2
188
    // 0, //DUP2
189
    // 0, //DUP2_X1
190
    // 0, //DUP2_X2
191
    // 0, //SWAP
192
    // 0, //IADD
193
    // 0, //LADD
194
    // 0, //FADD
195
    // 0, //DADD
196
    // 0, //ISUB
197
    // 0, //LSUB
198
    // 0, //FSUB
199
    // 0, //DSUB
200
    // 0, //IMUL
201
    // 0, //LMUL
202
    // 0, //FMUL
203
    // 0, //DMUL
204
    // 0, //IDIV
205
    // 0, //LDIV
206
    // 0, //FDIV
207
    // 0, //DDIV
208
    // 0, //IREM
209
    // 0, //LREM
210
    // 0, //FREM
211
    // 0, //DREM
212
    // 0, //INEG
213
    // 0, //LNEG
214
    // 0, //FNEG
215
    // 0, //DNEG
216
    // 0, //ISHL
217
    // 0, //LSHL
218
    // 0, //ISHR
219
    // 0, //LSHR
220
    // 0, //IUSHR
221
    // 0, //LUSHR
222
    // 0, //IAND
223
    // 0, //LAND
224
    // 0, //IOR
225
    // 0, //LOR
226
    // 0, //IXOR
227
    // 0, //LXOR
228
    // 8, //IINC
229
    // 0, //I2L
230
    // 0, //I2F
231
    // 0, //I2D
232
    // 0, //L2I
233
    // 0, //L2F
234
    // 0, //L2D
235
    // 0, //F2I
236
    // 0, //F2L
237
    // 0, //F2D
238
    // 0, //D2I
239
    // 0, //D2L
240
    // 0, //D2F
241
    // 0, //I2B
242
    // 0, //I2C
243
    // 0, //I2S
244
    // 0, //LCMP
245
    // 0, //FCMPL
246
    // 0, //FCMPG
247
    // 0, //DCMPL
248
    // 0, //DCMPG
249
    // 6, //IFEQ
250
    // 6, //IFNE
251
    // 6, //IFLT
252
    // 6, //IFGE
253
    // 6, //IFGT
254
    // 6, //IFLE
255
    // 6, //IF_ICMPEQ
256
    // 6, //IF_ICMPNE
257
    // 6, //IF_ICMPLT
258
    // 6, //IF_ICMPGE
259
    // 6, //IF_ICMPGT
260
    // 6, //IF_ICMPLE
261
    // 6, //IF_ACMPEQ
262
    // 6, //IF_ACMPNE
263
    // 6, //GOTO
264
    // 6, //JSR
265
    // 2, //RET
266
    // 9, //TABLESWITCH
267
    // 10, //LOOKUPSWITCH
268
    // 0, //IRETURN
269
    // 0, //LRETURN
270
    // 0, //FRETURN
271
    // 0, //DRETURN
272
    // 0, //ARETURN
273
    // 0, //RETURN
274
    // 4, //GETSTATIC
275
    // 4, //PUTSTATIC
276
    // 4, //GETFIELD
277
    // 4, //PUTFIELD
278
    // 5, //INVOKEVIRTUAL
279
    // 5, //INVOKESPECIAL
280
    // 5, //INVOKESTATIC
281
    // 5, //INVOKEINTERFACE
282
    // -1, //UNUSED
283
    // 3, //NEW
284
    // 1, //NEWARRAY
285
    // 3, //ANEWARRAY
286
    // 0, //ARRAYLENGTH
287
    // 0, //ATHROW
288
    // 3, //CHECKCAST
289
    // 3, //INSTANCEOF
290
    // 0, //MONITORENTER
291
    // 0, //MONITOREXIT
292
    // -1, //WIDE
293
    // 11, //MULTIANEWARRAY
294
    // 6, //IFNULL
295
    // 6, //IFNONNULL
296
    // -1, //GOTO_W
297
    // -1 //JSR_W
298
    // };
299
    // for (int i = 0; i < TYPE.length; ++i) {
300
    // System.out.print((char)(TYPE[i] + 1 + 'A'));
301
    // }
302
    // System.out.println();
303
    // }
304
 
305
    /**
306
     * Constructs a new {@link CheckMethodAdapter} object.
307
     *
308
     * @param cv the code visitor to which this adapter must delegate calls.
309
     */
310
    public CheckMethodAdapter(final MethodVisitor cv) {
311
        super(cv);
312
        this.labels = new HashMap();
313
    }
314
 
315
    public AnnotationVisitor visitAnnotation(
316
        final String desc,
317
        final boolean visible)
318
    {
319
        checkEndMethod();
320
        checkDesc(desc, false);
321
        return new CheckAnnotationAdapter(mv.visitAnnotation(desc, visible));
322
    }
323
 
324
    public AnnotationVisitor visitAnnotationDefault() {
325
        checkEndMethod();
326
        return new CheckAnnotationAdapter(mv.visitAnnotationDefault(), false);
327
    }
328
 
329
    public AnnotationVisitor visitParameterAnnotation(
330
        final int parameter,
331
        final String desc,
332
        final boolean visible)
333
    {
334
        checkEndMethod();
335
        checkDesc(desc, false);
336
        return new CheckAnnotationAdapter(mv.visitParameterAnnotation(parameter,
337
                desc,
338
                visible));
339
    }
340
 
341
    public void visitAttribute(final Attribute attr) {
342
        checkEndMethod();
343
        if (attr == null) {
344
            throw new IllegalArgumentException("Invalid attribute (must not be null)");
345
        }
346
        mv.visitAttribute(attr);
347
    }
348
 
349
    public void visitCode() {
350
        startCode = true;
351
        mv.visitCode();
352
    }
353
 
354
    public void visitInsn(final int opcode) {
355
        checkStartCode();
356
        checkEndCode();
357
        checkOpcode(opcode, 0);
358
        mv.visitInsn(opcode);
359
    }
360
 
361
    public void visitIntInsn(final int opcode, final int operand) {
362
        checkStartCode();
363
        checkEndCode();
364
        checkOpcode(opcode, 1);
365
        switch (opcode) {
366
            case Opcodes.BIPUSH:
367
                checkSignedByte(operand, "Invalid operand");
368
                break;
369
            case Opcodes.SIPUSH:
370
                checkSignedShort(operand, "Invalid operand");
371
                break;
372
            // case Constants.NEWARRAY:
373
            default:
374
                if (operand < Opcodes.T_BOOLEAN || operand > Opcodes.T_LONG) {
375
                    throw new IllegalArgumentException("Invalid operand (must be an array type code T_...): "
376
                            + operand);
377
                }
378
        }
379
        mv.visitIntInsn(opcode, operand);
380
    }
381
 
382
    public void visitVarInsn(final int opcode, final int var) {
383
        checkStartCode();
384
        checkEndCode();
385
        checkOpcode(opcode, 2);
386
        checkUnsignedShort(var, "Invalid variable index");
387
        mv.visitVarInsn(opcode, var);
388
    }
389
 
390
    public void visitTypeInsn(final int opcode, final String desc) {
391
        checkStartCode();
392
        checkEndCode();
393
        checkOpcode(opcode, 3);
394
        if (desc != null && desc.length() > 0 && desc.charAt(0) == '[') {
395
            checkDesc(desc, false);
396
        } else {
397
            checkInternalName(desc, "type");
398
        }
399
        if (opcode == Opcodes.NEW && desc.charAt(0) == '[') {
400
            throw new IllegalArgumentException("NEW cannot be used to create arrays: "
401
                    + desc);
402
        }
403
        mv.visitTypeInsn(opcode, desc);
404
    }
405
 
406
    public void visitFieldInsn(
407
        final int opcode,
408
        final String owner,
409
        final String name,
410
        final String desc)
411
    {
412
        checkStartCode();
413
        checkEndCode();
414
        checkOpcode(opcode, 4);
415
        checkInternalName(owner, "owner");
416
        checkIdentifier(name, "name");
417
        checkDesc(desc, false);
418
        mv.visitFieldInsn(opcode, owner, name, desc);
419
    }
420
 
421
    public void visitMethodInsn(
422
        final int opcode,
423
        final String owner,
424
        final String name,
425
        final String desc)
426
    {
427
        checkStartCode();
428
        checkEndCode();
429
        checkOpcode(opcode, 5);
430
        checkMethodIdentifier(name, "name");
431
        if (!name.equals("clone")) {
432
            // In JDK1.5, clone method can be called on array class descriptors
433
            checkInternalName(owner, "owner");
434
        }
435
        checkMethodDesc(desc);
436
        mv.visitMethodInsn(opcode, owner, name, desc);
437
    }
438
 
439
    public void visitJumpInsn(final int opcode, final Label label) {
440
        checkStartCode();
441
        checkEndCode();
442
        checkOpcode(opcode, 6);
443
        checkLabel(label, false, "label");
444
        mv.visitJumpInsn(opcode, label);
445
    }
446
 
447
    public void visitLabel(final Label label) {
448
        checkStartCode();
449
        checkEndCode();
450
        checkLabel(label, false, "label");
451
        if (labels.get(label) != null) {
452
            throw new IllegalArgumentException("Already visited label");
453
        } else {
454
            labels.put(label, new Integer(labels.size()));
455
        }
456
        mv.visitLabel(label);
457
    }
458
 
459
    public void visitLdcInsn(final Object cst) {
460
        checkStartCode();
461
        checkEndCode();
462
        if (!(cst instanceof Type)) {
463
            checkConstant(cst);
464
        }
465
        mv.visitLdcInsn(cst);
466
    }
467
 
468
    public void visitIincInsn(final int var, final int increment) {
469
        checkStartCode();
470
        checkEndCode();
471
        checkUnsignedShort(var, "Invalid variable index");
472
        checkSignedShort(increment, "Invalid increment");
473
        mv.visitIincInsn(var, increment);
474
    }
475
 
476
    public void visitTableSwitchInsn(
477
        final int min,
478
        final int max,
479
        final Label dflt,
480
        final Label labels[])
481
    {
482
        checkStartCode();
483
        checkEndCode();
484
        if (max < min) {
485
            throw new IllegalArgumentException("Max = " + max
486
                    + " must be greater than or equal to min = " + min);
487
        }
488
        checkLabel(dflt, false, "default label");
489
        if (labels == null || labels.length != max - min + 1) {
490
            throw new IllegalArgumentException("There must be max - min + 1 labels");
491
        }
492
        for (int i = 0; i < labels.length; ++i) {
493
            checkLabel(labels[i], false, "label at index " + i);
494
        }
495
        mv.visitTableSwitchInsn(min, max, dflt, labels);
496
    }
497
 
498
    public void visitLookupSwitchInsn(
499
        final Label dflt,
500
        final int keys[],
501
        final Label labels[])
502
    {
503
        checkEndCode();
504
        checkStartCode();
505
        checkLabel(dflt, false, "default label");
506
        if (keys == null || labels == null || keys.length != labels.length) {
507
            throw new IllegalArgumentException("There must be the same number of keys and labels");
508
       }
509
        for (int i = 0; i < labels.length; ++i) {
510
            checkLabel(labels[i], false, "label at index " + i);
511
        }
512
        mv.visitLookupSwitchInsn(dflt, keys, labels);
513
    }
514
 
515
    public void visitMultiANewArrayInsn(final String desc, final int dims) {
516
        checkStartCode();
517
        checkEndCode();
518
        checkDesc(desc, false);
519
        if (desc.charAt(0) != '[') {
520
            throw new IllegalArgumentException("Invalid descriptor (must be an array type descriptor): "
521
                    + desc);
522
        }
523
        if (dims < 1) {
524
            throw new IllegalArgumentException("Invalid dimensions (must be greater than 0): "
525
                    + dims);
526
        }
527
        if (dims > desc.lastIndexOf('[') + 1) {
528
            throw new IllegalArgumentException("Invalid dimensions (must not be greater than dims(desc)): "
529
                    + dims);
530
        }
531
        mv.visitMultiANewArrayInsn(desc, dims);
532
    }
533
 
534
    public void visitTryCatchBlock(
535
        final Label start,
536
        final Label end,
537
        final Label handler,
538
        final String type)
539
    {
540
        checkStartCode();
541
        checkEndCode();
542
        if (type != null) {
543
            checkInternalName(type, "type");
544
        }
545
        mv.visitTryCatchBlock(start, end, handler, type);
546
    }
547
 
548
    public void visitLocalVariable(
549
        final String name,
550
        final String desc,
551
        final String signature,
552
        final Label start,
553
        final Label end,
554
        final int index)
555
    {
556
        checkStartCode();
557
        checkEndCode();
558
        checkIdentifier(name, "name");
559
        checkDesc(desc, false);
560
        checkLabel(start, true, "start label");
561
        checkLabel(end, true, "end label");
562
        checkUnsignedShort(index, "Invalid variable index");
563
        int s = ((Integer) labels.get(start)).intValue();
564
        int e = ((Integer) labels.get(end)).intValue();
565
        if (e < s) {
566
            throw new IllegalArgumentException("Invalid start and end labels (end must be greater than start)");
567
        }
568
        mv.visitLocalVariable(name, desc, signature, start, end, index);
569
    }
570
 
571
    public void visitLineNumber(final int line, final Label start) {
572
        checkStartCode();
573
        checkEndCode();
574
        checkUnsignedShort(line, "Invalid line number");
575
        checkLabel(start, true, "start label");
576
        mv.visitLineNumber(line, start);
577
    }
578
 
579
    public void visitMaxs(final int maxStack, final int maxLocals) {
580
        checkStartCode();
581
        checkEndCode();
582
        endCode = true;
583
        checkUnsignedShort(maxStack, "Invalid max stack");
584
        checkUnsignedShort(maxLocals, "Invalid max locals");
585
        mv.visitMaxs(maxStack, maxLocals);
586
    }
587
 
588
    public void visitEnd() {
589
        checkEndMethod();
590
        endMethod = true;
591
        mv.visitEnd();
592
    }
593
 
594
    // -------------------------------------------------------------------------
595
 
596
    /**
597
     * Checks that the visitCode method has been called.
598
     */
599
    void checkStartCode() {
600
        if (!startCode) {
601
            throw new IllegalStateException("Cannot visit instructions before visitCode has been called.");
602
        }
603
    }
604
 
605
    /**
606
     * Checks that the visitMaxs method has not been called.
607
     */
608
    void checkEndCode() {
609
        if (endCode) {
610
            throw new IllegalStateException("Cannot visit instructions after visitMaxs has been called.");
611
        }
612
    }
613
 
614
    /**
615
     * Checks that the visitEnd method has not been called.
616
     */
617
    void checkEndMethod() {
618
        if (endMethod) {
619
            throw new IllegalStateException("Cannot visit elements after visitEnd has been called.");
620
        }
621
    }
622
 
623
    /**
624
     * Checks that the type of the given opcode is equal to the given type.
625
     *
626
     * @param opcode the opcode to be checked.
627
     * @param type the expected opcode type.
628
     */
629
    static void checkOpcode(final int opcode, final int type) {
630
        if (opcode < 0 || opcode > 199 || TYPE[opcode] != type) {
631
            throw new IllegalArgumentException("Invalid opcode: " + opcode);
632
        }
633
    }
634
 
635
    /**
636
     * Checks that the given value is a signed byte.
637
     *
638
     * @param value the value to be checked.
639
     * @param msg an message to be used in case of error.
640
     */
641
    static void checkSignedByte(final int value, final String msg) {
642
        if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
643
            throw new IllegalArgumentException(msg
644
                    + " (must be a signed byte): " + value);
645
        }
646
    }
647
 
648
    /**
649
     * Checks that the given value is a signed short.
650
     *
651
     * @param value the value to be checked.
652
     * @param msg an message to be used in case of error.
653
     */
654
    static void checkSignedShort(final int value, final String msg) {
655
        if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
656
            throw new IllegalArgumentException(msg
657
                    + " (must be a signed short): " + value);
658
        }
659
    }
660
 
661
    /**
662
     * Checks that the given value is an unsigned short.
663
     *
664
     * @param value the value to be checked.
665
     * @param msg an message to be used in case of error.
666
     */
667
    static void checkUnsignedShort(final int value, final String msg) {
668
        if (value < 0 || value > 65535) {
669
            throw new IllegalArgumentException(msg
670
                    + " (must be an unsigned short): " + value);
671
        }
672
    }
673
 
674
    /**
675
     * Checks that the given value is an {@link Integer}, a{@link Float}, a
676
     * {@link Long}, a {@link Double} or a {@link String}.
677
     *
678
     * @param cst the value to be checked.
679
     */
680
    static void checkConstant(final Object cst) {
681
        if (!(cst instanceof Integer) && !(cst instanceof Float)
682
                && !(cst instanceof Long) && !(cst instanceof Double)
683
                && !(cst instanceof String))
684
        {
685
            throw new IllegalArgumentException("Invalid constant: " + cst);
686
        }
687
    }
688
 
689
    /**
690
     * Checks that the given string is a valid Java identifier.
691
     *
692
     * @param name the string to be checked.
693
     * @param msg a message to be used in case of error.
694
     */
695
    static void checkIdentifier(final String name, final String msg) {
696
        checkIdentifier(name, 0, -1, msg);
697
    }
698
 
699
    /**
700
     * Checks that the given substring is a valid Java identifier.
701
     *
702
     * @param name the string to be checked.
703
     * @param start index of the first character of the identifier (inclusive).
704
     * @param end index of the last character of the identifier (exclusive). -1
705
     *        is equivalent to <tt>name.length()</tt> if name is not
706
     *        <tt>null</tt>.
707
     * @param msg a message to be used in case of error.
708
     */
709
    static void checkIdentifier(
710
        final String name,
711
        final int start,
712
        final int end,
713
        final String msg)
714
    {
715
        if (name == null || (end == -1 ? name.length() <= start : end <= start))
716
        {
717
            throw new IllegalArgumentException("Invalid " + msg
718
                    + " (must not be null or empty)");
719
        }
720
        if (!Character.isJavaIdentifierStart(name.charAt(start))) {
721
            throw new IllegalArgumentException("Invalid " + msg
722
                    + " (must be a valid Java identifier): " + name);
723
        }
724
        int max = (end == -1 ? name.length() : end);
725
        for (int i = start + 1; i < max; ++i) {
726
            if (!Character.isJavaIdentifierPart(name.charAt(i))) {
727
                throw new IllegalArgumentException("Invalid " + msg
728
                        + " (must be a valid Java identifier): " + name);
729
            }
730
        }
731
    }
732
 
733
    /**
734
     * Checks that the given string is a valid Java identifier or is equal to
735
     * '&lt;init&gt;' or '&lt;clinit&gt;'.
736
     *
737
     * @param name the string to be checked.
738
     * @param msg a message to be used in case of error.
739
     */
740
    static void checkMethodIdentifier(final String name, final String msg) {
741
        if (name == null || name.length() == 0) {
742
            throw new IllegalArgumentException("Invalid " + msg
743
                    + " (must not be null or empty)");
744
        }
745
        if (name.equals("<init>") || name.equals("<clinit>")) {
746
            return;
747
        }
748
        if (!Character.isJavaIdentifierStart(name.charAt(0))) {
749
            throw new IllegalArgumentException("Invalid "
750
                    + msg
751
                    + " (must be a '<init>', '<clinit>' or a valid Java identifier): "
752
                    + name);
753
        }
754
        for (int i = 1; i < name.length(); ++i) {
755
            if (!Character.isJavaIdentifierPart(name.charAt(i))) {
756
                throw new IllegalArgumentException("Invalid "
757
                        + msg
758
                        + " (must be '<init>' or '<clinit>' or a valid Java identifier): "
759
                        + name);
760
            }
761
        }
762
    }
763
 
764
    /**
765
     * Checks that the given string is a valid internal class name.
766
     *
767
     * @param name the string to be checked.
768
     * @param msg a message to be used in case of error.
769
     */
770
    static void checkInternalName(final String name, final String msg) {
771
        checkInternalName(name, 0, -1, msg);
772
    }
773
 
774
    /**
775
     * Checks that the given substring is a valid internal class name.
776
     *
777
     * @param name the string to be checked.
778
     * @param start index of the first character of the identifier (inclusive).
779
     * @param end index of the last character of the identifier (exclusive). -1
780
     *        is equivalent to <tt>name.length()</tt> if name is not
781
     *        <tt>null</tt>.
782
     * @param msg a message to be used in case of error.
783
     */
784
    static void checkInternalName(
785
        final String name,
786
        final int start,
787
        final int end,
788
        final String msg)
789
    {
790
        if (name == null || name.length() == 0) {
791
            throw new IllegalArgumentException("Invalid " + msg
792
                    + " (must not be null or empty)");
793
        }
794
        int max = (end == -1 ? name.length() : end);
795
        try {
796
            int begin = start;
797
            int slash;
798
            do {
799
                slash = name.indexOf('/', begin + 1);
800
                if (slash == -1 || slash > max) {
801
                    slash = max;
802
                }
803
                checkIdentifier(name, begin, slash, null);
804
                begin = slash + 1;
805
            } while (slash != max);
806
        } catch (IllegalArgumentException _) {
807
            throw new IllegalArgumentException("Invalid "
808
                    + msg
809
                    + " (must be a fully qualified class name in internal form): "
810
                    + name);
811
        }
812
    }
813
 
814
    /**
815
     * Checks that the given string is a valid type descriptor.
816
     *
817
     * @param desc the string to be checked.
818
     * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
819
     */
820
    static void checkDesc(final String desc, final boolean canBeVoid) {
821
        int end = checkDesc(desc, 0, canBeVoid);
822
        if (end != desc.length()) {
823
            throw new IllegalArgumentException("Invalid descriptor: " + desc);
824
        }
825
    }
826
 
827
    /**
828
     * Checks that a the given substring is a valid type descriptor.
829
     *
830
     * @param desc the string to be checked.
831
     * @param start index of the first character of the identifier (inclusive).
832
     * @param canBeVoid <tt>true</tt> if <tt>V</tt> can be considered valid.
833
     * @return the index of the last character of the type decriptor, plus one.
834
     */
835
    static int checkDesc(
836
        final String desc,
837
        final int start,
838
        final boolean canBeVoid)
839
    {
840
        if (desc == null || start >= desc.length()) {
841
            throw new IllegalArgumentException("Invalid type descriptor (must not be null or empty)");
842
        }
843
        int index;
844
        switch (desc.charAt(start)) {
845
            case 'V':
846
                if (canBeVoid) {
847
                    return start + 1;
848
                } else {
849
                    throw new IllegalArgumentException("Invalid descriptor: "
850
                            + desc);
851
                }
852
            case 'Z':
853
            case 'C':
854
            case 'B':
855
            case 'S':
856
            case 'I':
857
            case 'F':
858
            case 'J':
859
            case 'D':
860
                return start + 1;
861
            case '[':
862
                index = start + 1;
863
                while (index < desc.length() && desc.charAt(index) == '[') {
864
                    ++index;
865
                }
866
                if (index < desc.length()) {
867
                    return checkDesc(desc, index, false);
868
                } else {
869
                    throw new IllegalArgumentException("Invalid descriptor: "
870
                            + desc);
871
                }
872
            case 'L':
873
                index = desc.indexOf(';', start);
874
                if (index == -1 || index - start < 2) {
875
                    throw new IllegalArgumentException("Invalid descriptor: "
876
                            + desc);
877
                }
878
                try {
879
                    checkInternalName(desc, start + 1, index, null);
880
                } catch (IllegalArgumentException _) {
881
                    throw new IllegalArgumentException("Invalid descriptor: "
882
                            + desc);
883
                }
884
                return index + 1;
885
            default:
886
                throw new IllegalArgumentException("Invalid descriptor: "
887
                        + desc);
888
        }
889
    }
890
 
891
    /**
892
     * Checks that the given string is a valid method descriptor.
893
     *
894
     * @param desc the string to be checked.
895
     */
896
    static void checkMethodDesc(final String desc) {
897
        if (desc == null || desc.length() == 0) {
898
            throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)");
899
        }
900
        if (desc.charAt(0) != '(' || desc.length() < 3) {
901
            throw new IllegalArgumentException("Invalid descriptor: " + desc);
902
        }
903
        int start = 1;
904
        if (desc.charAt(start) != ')') {
905
            do {
906
                if (desc.charAt(start) == 'V') {
907
                    throw new IllegalArgumentException("Invalid descriptor: "
908
                            + desc);
909
                }
910
                start = checkDesc(desc, start, false);
911
            } while (start < desc.length() && desc.charAt(start) != ')');
912
        }
913
        start = checkDesc(desc, start + 1, true);
914
        if (start != desc.length()) {
915
            throw new IllegalArgumentException("Invalid descriptor: " + desc);
916
        }
917
    }
918
 
919
    /**
920
     * Checks that the given label is not null. This method can also check that
921
     * the label has been visited.
922
     *
923
     * @param label the label to be checked.
924
     * @param checkVisited <tt>true</tt> to check that the label has been
925
     *        visited.
926
     * @param msg a message to be used in case of error.
927
     */
928
    void checkLabel(
929
        final Label label,
930
        final boolean checkVisited,
931
        final String msg)
932
    {
933
        if (label == null) {
934
            throw new IllegalArgumentException("Invalid " + msg
935
                    + " (must not be null)");
936
        }
937
        if (checkVisited && labels.get(label) == null) {
938
            throw new IllegalArgumentException("Invalid " + msg
939
                    + " (must be visited first)");
940
        }
941
    }
942
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.