KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > bytecode > CodeVisitor


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.bytecode;
31
32 import com.caucho.log.Log;
33 import com.caucho.util.IntArray;
34 import com.caucho.util.L10N;
35
36 import java.util.ArrayList JavaDoc;
37 import java.util.logging.Logger JavaDoc;
38
39 /**
40  * Visitor for travelling the code.
41  */

42 public class CodeVisitor {
43   static private final Logger JavaDoc log = Log.open(CodeVisitor.class);
44   static private final L10N L = new L10N(CodeVisitor.class);
45
46   private JavaClass _javaClass;
47   protected CodeAttribute _codeAttr;
48   private byte []_code;
49   protected int _offset;
50
51   public CodeVisitor()
52   {
53   }
54
55   public CodeVisitor(JavaClass javaClass, CodeAttribute codeAttr)
56   {
57     init(javaClass, codeAttr);
58   }
59
60   public void init(JavaClass javaClass, CodeAttribute codeAttr)
61   {
62     _javaClass = javaClass;
63     _codeAttr = codeAttr;
64     _code = codeAttr.getCode();
65     _offset = 0;
66   }
67
68   /**
69    * Returns the java class.
70    */

71   public JavaClass getJavaClass()
72   {
73     return _javaClass;
74   }
75   
76   /**
77    * Returns the code attribute.
78    */

79   public CodeAttribute getCodeAttribute()
80   {
81     return _codeAttr;
82   }
83
84   /**
85    * Returns the offset.
86    */

87   public int getOffset()
88   {
89     return _offset;
90   }
91
92   /**
93    * Sets the offset.
94    */

95   public void setOffset(int offset)
96   {
97     _offset = offset;
98   }
99
100   /**
101    * Returns the code buffer.
102    */

103   public byte []getCode()
104   {
105     return _code;
106   }
107
108   /**
109    * Returns the exceptions.
110    */

111   public ArrayList JavaDoc<CodeAttribute.ExceptionItem> getExceptions()
112   {
113     return _codeAttr.getExceptions();
114   }
115
116   /**
117    * Returns the opcode at the cursor.
118    */

119   public int getOpcode()
120   {
121     int op = getCode()[_offset] & 0xff;
122
123     if (op == WIDE)
124       return getCode()[_offset + 1] & 0xff;
125     else
126       return op;
127   }
128
129   /**
130    * Goes to the next opcode.
131    */

132   public boolean next()
133   {
134     _offset = nextOffset();
135
136     return _offset >= 0;
137   }
138
139   /**
140    * Goes to the next opcode.
141    */

142   protected int nextOffset()
143   {
144     int opcode = getCode()[_offset] & 0xff;
145     
146     int length = OP_LEN[opcode];
147
148     switch (opcode) {
149     case GOTO:
150     case GOTO_W:
151     case RET:
152     case IRETURN:
153     case LRETURN:
154     case FRETURN:
155     case DRETURN:
156     case ARETURN:
157     case RETURN:
158     case ATHROW:
159       return -1;
160
161     case TABLESWITCH:
162       {
163     int arg = _offset + 1;
164     arg += (4 - arg % 4) % 4;
165
166     int low = getInt(arg + 4);
167     int high = getInt(arg + 8);
168
169     return arg + 12 + (high - low + 1) * 4;
170       }
171
172     case LOOKUPSWITCH:
173       {
174     return -1;
175     
176     /*
177     int arg = _offset + 1;
178     arg += (4 - arg % 4) % 4;
179
180     int n = getInt(arg + 4);
181
182     int next = arg + 12 + n * 8;
183
184     return next;
185     */

186       }
187
188     case WIDE:
189       {
190     int op2 = getCode()[_offset + 1] & 0xff;
191
192     if (op2 == IINC)
193       length = 5;
194     else
195       length = 3;
196     break;
197       }
198     }
199     
200     if (length < 0 || length > 0x10)
201       throw new UnsupportedOperationException JavaDoc(L.l("{0}: can't handle opcode {1}",
202                           "" + _offset,
203                           "" + getOpcode()));
204
205     return _offset + length + 1;
206   }
207
208   /**
209    * Returns true for a simple branch, i.e. a branch with a simple target.
210    */

211   public boolean isBranch()
212   {
213     switch (getOpcode()) {
214     case IFNULL:
215     case IFNONNULL:
216     case IFNE:
217     case IFEQ:
218     case IFLT:
219     case IFGE:
220     case IFGT:
221     case IFLE:
222     case IF_ICMPEQ:
223     case IF_ICMPNE:
224     case IF_ICMPLT:
225     case IF_ICMPGE:
226     case IF_ICMPGT:
227     case IF_ICMPLE:
228     case IF_ACMPEQ:
229     case IF_ACMPNE:
230     case JSR:
231     case JSR_W:
232     case GOTO:
233     case GOTO_W:
234       return true;
235     }
236
237     return false;
238   }
239
240   /**
241    * Returns the branch target.
242    */

243   public int getBranchTarget()
244   {
245     switch (getOpcode()) {
246     case IFNULL:
247     case IFNONNULL:
248     case IFNE:
249     case IFEQ:
250     case IFLT:
251     case IFGE:
252     case IFGT:
253     case IFLE:
254     case IF_ICMPEQ:
255     case IF_ICMPNE:
256     case IF_ICMPLT:
257     case IF_ICMPLE:
258     case IF_ICMPGE:
259     case IF_ICMPGT:
260     case IF_ACMPEQ:
261     case IF_ACMPNE:
262     case GOTO:
263     case JSR:
264       return _offset + getShortArg();
265       
266     case GOTO_W:
267     case JSR_W:
268       return _offset + getIntArg();
269
270     default:
271       throw new UnsupportedOperationException JavaDoc();
272     }
273   }
274
275   /**
276    * Returns true for a switch.
277    */

278   public boolean isSwitch()
279   {
280     switch (getOpcode()) {
281     case TABLESWITCH:
282     case LOOKUPSWITCH:
283       return true;
284     default:
285       return false;
286     }
287   }
288
289   /**
290    * Returns the branch target.
291    */

292   public int []getSwitchTargets()
293   {
294     switch (getOpcode()) {
295     case TABLESWITCH:
296       {
297     int arg = _offset + 1;
298     arg += (4 - arg % 4) % 4;
299     
300     int low = getInt(arg + 4);
301     int high = getInt(arg + 8);
302
303     int []targets = new int[high - low + 2];
304     targets[0] = getInt(arg) + _offset;
305     
306     for (int i = 0; i <= high - low; i++) {
307       targets[i + 1] = getInt(arg + 12 + i * 4) + _offset;
308     }
309
310     return targets;
311       }
312       
313     case LOOKUPSWITCH:
314       {
315     int arg = _offset + 1;
316     arg += (4 - arg % 4) % 4;
317
318     int n = getInt(arg + 4);
319
320     int []targets = new int[n + 1];
321     targets[0] = getInt(arg) + _offset;
322     
323     for (int i = 0; i < n; i++) {
324       int off = arg + 8 + i * 8 + 4;
325       
326       targets[i + 1] = getInt(off) + _offset;
327     }
328
329     return targets;
330       }
331
332     default:
333       throw new UnsupportedOperationException JavaDoc("getSwitchTargets");
334     }
335   }
336
337   /**
338    * Returns a constant pool item.
339    */

340   public ConstantPoolEntry getConstantArg()
341   {
342     switch (getOpcode()) {
343     case LDC:
344       return _javaClass.getConstantPool().getEntry(getByteArg());
345       
346     case LDC_W:
347       return _javaClass.getConstantPool().getEntry(getShortArg());
348
349     default:
350       throw new UnsupportedOperationException JavaDoc();
351     }
352   }
353
354   /**
355    * Reads a byte argument.
356    */

357   public int getByteArg()
358   {
359     return getCode()[_offset + 1];
360   }
361
362   /**
363    * Gets a byte arg
364    */

365   public int getByteArg(int offset)
366   {
367     return getByte(_offset + offset);
368   }
369
370   /**
371    * Sets a byte value.
372    */

373   public void setByteArg(int offset, int value)
374   {
375     getCode()[_offset + offset + 0] = (byte) value;
376   }
377
378   /**
379    * Reads a short argument.
380    */

381   public int getShortArg()
382   {
383     return getShort(_offset + 1);
384   }
385
386   /**
387    * Sets a short value.
388    */

389   public int getShortArg(int offset)
390   {
391     return getShort(_offset + offset);
392   }
393
394   /**
395    * Sets a short value.
396    */

397   public void setShortArg(int offset, int value)
398   {
399     setShort(_offset + offset, value);
400   }
401
402   /**
403    * Sets a short value.
404    */

405   public void setShort(int offset, int value)
406   {
407     byte []code = getCode();
408     
409     code[offset + 0] = (byte) (value >> 8);
410     code[offset + 1] = (byte) (value);
411   }
412
413   /**
414    * Reads an integer.
415    */

416   public int getIntArg()
417   {
418     return getInt(_offset + 1);
419   }
420
421   /**
422    * Sets a short value.
423    */

424   public void setInt(int offset, int value)
425   {
426     byte []code = getCode();
427     
428     code[offset + 0] = (byte) (value >> 24);
429     code[offset + 1] = (byte) (value >> 16);
430     code[offset + 2] = (byte) (value >> 8);
431     code[offset + 3] = (byte) (value);
432   }
433
434   /**
435    * Reads a byte value.
436    */

437   public int getByte(int offset)
438   {
439     return getCode()[offset + 0] & 0xff;
440   }
441
442   /**
443    * Reads a short value.
444    */

445   public int getShort(int offset)
446   {
447     int b0 = getCode()[offset + 0] & 0xff;
448     int b1 = getCode()[offset + 1] & 0xff;
449     
450     return (short) ((b0 << 8) + b1);
451   }
452
453   /**
454    * Reads an int argument.
455    */

456   public int getInt(int offset)
457   {
458     byte []code = getCode();
459     
460     int b0 = code[offset + 0] & 0xff;
461     int b1 = code[offset + 1] & 0xff;
462     int b2 = code[offset + 2] & 0xff;
463     int b3 = code[offset + 3] & 0xff;
464     
465     return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
466   }
467
468   /**
469    * Analyzes the code for a method
470    */

471   public void analyze(Analyzer analyzer)
472     throws Exception JavaDoc
473   {
474     analyze(analyzer, true);
475   }
476
477   /**
478    * Analyzes the code for a method
479    */

480   public void analyze(Analyzer analyzer, boolean allowFlow)
481     throws Exception JavaDoc
482   {
483     analyzeImpl(analyzer, allowFlow, new IntArray(), new IntArray());
484   }
485
486   /**
487    * Analyzes the code for a method
488    */

489   protected void analyzeImpl(Analyzer analyzer, boolean allowFlow,
490                  IntArray pendingTargets,
491                  IntArray completedTargets)
492     throws Exception JavaDoc
493   {
494     setOffset(0);
495     
496     pendingTargets.add(0);
497
498     ArrayList JavaDoc<CodeAttribute.ExceptionItem> exns;
499     exns = getExceptions();
500
501     for (int i = 0; i < exns.size(); i++) {
502       CodeAttribute.ExceptionItem exn = exns.get(i);
503
504       pendingTargets.add(exn.getHandler());
505     }
506     
507     analyze(analyzer, allowFlow, pendingTargets, completedTargets);
508   }
509   
510   /**
511    * Analyzes the code for a basic block.
512    */

513   private void analyze(Analyzer analyzer,
514                boolean allowFlow,
515                IntArray pendingTargets,
516                IntArray completedTargets)
517     throws Exception JavaDoc
518   {
519     pending:
520     while (pendingTargets.size() > 0) {
521       int pc = pendingTargets.pop();
522
523       if (allowFlow) {
524     if (completedTargets.contains(pc))
525       continue pending;
526
527     completedTargets.add(pc);
528       }
529
530       setOffset(pc);
531
532       flow:
533       do {
534     pc = getOffset();
535
536     if (pc < 0)
537       throw new IllegalStateException JavaDoc();
538     
539     if (! allowFlow) {
540       if (completedTargets.contains(pc))
541         break flow;
542
543       completedTargets.add(pc);
544     }
545
546     if (isBranch()) {
547       int targetPC = getBranchTarget();
548
549       if (! pendingTargets.contains(targetPC))
550         pendingTargets.add(targetPC);
551     }
552     else if (isSwitch()) {
553       int []switchTargets = getSwitchTargets();
554
555       for (int i = 0; i < switchTargets.length; i++) {
556         if (! pendingTargets.contains(switchTargets[i]))
557           pendingTargets.add(switchTargets[i]);
558       }
559     }
560
561     analyzer.analyze(this);
562       } while (next());
563     }
564   }
565
566   public static final int NOP = 0x00;
567   public static final int ACONST_NULL = 0x01;
568   public static final int ICONST_M1 = 0x02;
569   public static final int ICONST_0 = 0x03;
570   public static final int ICONST_1 = 0x04;
571   public static final int ICONST_2 = 0x05;
572   public static final int ICONST_3 = 0x06;
573   public static final int ICONST_4 = 0x07;
574   public static final int ICONST_5 = 0x08;
575   public static final int LCONST_0 = 0x09;
576   public static final int LCONST_1 = 0x0a;
577   public static final int FCONST_0 = 0x0b;
578   public static final int FCONST_1 = 0x0c;
579   public static final int FCONST_2 = 0x0d;
580   public static final int DCONST_0 = 0x0e;
581   public static final int DCONST_1 = 0x0f;
582   
583   public static final int BIPUSH = 0x10;
584   public static final int SIPUSH = 0x11;
585   public static final int LDC = 0x12;
586   public static final int LDC_W = 0x13;
587   public static final int LDC2_W = 0x14;
588   public static final int ILOAD = 0x15;
589   public static final int LLOAD = 0x16;
590   public static final int FLOAD = 0x17;
591   public static final int DLOAD = 0x18;
592   public static final int ALOAD = 0x19;
593   public static final int ILOAD_0 = 0x1a;
594   public static final int ILOAD_1 = 0x1b;
595   public static final int ILOAD_2 = 0x1c;
596   public static final int ILOAD_3 = 0x1d;
597   public static final int LLOAD_0 = 0x1e;
598   public static final int LLOAD_1 = 0x1f;
599   
600   public static final int LLOAD_2 = 0x20;
601   public static final int LLOAD_3 = 0x21;
602   public static final int FLOAD_0 = 0x22;
603   public static final int FLOAD_1 = 0x23;
604   public static final int FLOAD_2 = 0x24;
605   public static final int FLOAD_3 = 0x25;
606   public static final int DLOAD_0 = 0x26;
607   public static final int DLOAD_1 = 0x27;
608   public static final int DLOAD_2 = 0x28;
609   public static final int DLOAD_3 = 0x29;
610   public static final int ALOAD_0 = 0x2a;
611   public static final int ALOAD_1 = 0x2b;
612   public static final int ALOAD_2 = 0x2c;
613   public static final int ALOAD_3 = 0x2d;
614   public static final int IALOAD = 0x2e;
615   public static final int LALOAD = 0x2f;
616   
617   public static final int FALOAD = 0x30;
618   public static final int DALOAD = 0x31;
619   public static final int AALOAD = 0x32;
620   public static final int BALOAD = 0x33;
621   public static final int CALOAD = 0x34;
622   public static final int SALOAD = 0x35;
623   public static final int ISTORE = 0x36;
624   public static final int LSTORE = 0x37;
625   public static final int FSTORE = 0x38;
626   public static final int DSTORE = 0x39;
627   public static final int ASTORE = 0x3a;
628   public static final int ISTORE_0 = 0x3b;
629   public static final int ISTORE_1 = 0x3c;
630   public static final int ISTORE_2 = 0x3d;
631   public static final int ISTORE_3 = 0x3e;
632   public static final int LSTORE_0 = 0x3f;
633   
634   public static final int LSTORE_1 = 0x40;
635   public static final int LSTORE_2 = 0x41;
636   public static final int LSTORE_3 = 0x42;
637   public static final int FSTORE_0 = 0x43;
638   public static final int FSTORE_1 = 0x44;
639   public static final int FSTORE_2 = 0x45;
640   public static final int FSTORE_3 = 0x46;
641   public static final int DSTORE_0 = 0x47;
642   public static final int DSTORE_1 = 0x48;
643   public static final int DSTORE_2 = 0x49;
644   public static final int DSTORE_3 = 0x4a;
645   public static final int ASTORE_0 = 0x4b;
646   public static final int ASTORE_1 = 0x4c;
647   public static final int ASTORE_2 = 0x4d;
648   public static final int ASTORE_3 = 0x4e;
649   public static final int IASTORE = 0x4f;
650   
651   public static final int LASTORE = 0x50;
652   public static final int FASTORE = 0x51;
653   public static final int DASTORE = 0x52;
654   public static final int AASTORE = 0x53;
655   public static final int BASTORE = 0x54;
656   public static final int CASTORE = 0x55;
657   public static final int SASTORE = 0x56;
658   public static final int POP = 0x57;
659   public static final int POP2 = 0x58;
660   public static final int DUP = 0x59;
661   public static final int DUP_X1 = 0x5a;
662   public static final int DUP_X2 = 0x5b;
663   public static final int DUP2 = 0x5c;
664   public static final int DUP2_X1 = 0x5d;
665   public static final int DUP2_X2 = 0x5e;
666   public static final int SWAP = 0x5f;
667   
668   public static final int IADD = 0x60;
669   public static final int LADD = 0x61;
670   public static final int FADD = 0x62;
671   public static final int DADD = 0x63;
672   public static final int ISUB = 0x64;
673   public static final int LSUB = 0x65;
674   public static final int FSUB = 0x66;
675   public static final int DSUB = 0x67;
676   public static final int IMUL = 0x68;
677   public static final int LMUL = 0x69;
678   public static final int FMUL = 0x6a;
679   public static final int DMUL = 0x6b;
680   public static final int IDIV = 0x6c;
681   public static final int LDIV = 0x6d;
682   public static final int FDIV = 0x6e;
683   public static final int DDIV = 0x6f;
684   
685   public static final int IREM = 0x70;
686   public static final int LREM = 0x71;
687   public static final int FREM = 0x72;
688   public static final int DREM = 0x73;
689   public static final int INEG = 0x74;
690   public static final int LNEG = 0x75;
691   public static final int FNEG = 0x76;
692   public static final int DNEG = 0x77;
693   public static final int ISHL = 0x78;
694   public static final int LSHL = 0x79;
695   public static final int ISHR = 0x7a;
696   public static final int LSHR = 0x7b;
697   public static final int IUSHR = 0x7c;
698   public static final int LUSHR = 0x7d;
699   public static final int IAND = 0x7e;
700   public static final int LAND = 0x7f;
701   
702   public static final int IOR = 0x80;
703   public static final int LOR = 0x81;
704   public static final int IXOR = 0x82;
705   public static final int LXOR = 0x83;
706   public static final int IINC = 0x84;
707   public static final int I2L = 0x85;
708   public static final int I2F = 0x86;
709   public static final int I2D = 0x87;
710   public static final int L2I = 0x88;
711   public static final int L2F = 0x89;
712   public static final int L2D = 0x8a;
713   public static final int F2I = 0x8b;
714   public static final int F2L = 0x8c;
715   public static final int F2D = 0x8d;
716   public static final int D2I = 0x8e;
717   public static final int D2L = 0x8f;
718   
719   public static final int D2F = 0x90;
720   public static final int I2B = 0x91;
721   public static final int I2C = 0x92;
722   public static final int I2S = 0x93;
723   public static final int LCMP = 0x94;
724   public static final int FCMPL = 0x95;
725   public static final int FCMPG = 0x96;
726   public static final int DCMPL = 0x97;
727   public static final int DCMPG = 0x98;
728   public static final int IFEQ = 0x99;
729   public static final int IFNE = 0x9a;
730   public static final int IFLT = 0x9b;
731   public static final int IFGE = 0x9c;
732   public static final int IFGT = 0x9d;
733   public static final int IFLE = 0x9e;
734   public static final int IF_ICMPEQ = 0x9f;
735   
736   public static final int IF_ICMPNE = 0xa0;
737   public static final int IF_ICMPLT = 0xa1;
738   public static final int IF_ICMPGE = 0xa2;
739   public static final int IF_ICMPGT = 0xa3;
740   public static final int IF_ICMPLE = 0xa4;
741   public static final int IF_ACMPEQ = 0xa5;
742   public static final int IF_ACMPNE = 0xa6;
743   public static final int GOTO = 0xa7;
744   public static final int JSR = 0xa8;
745   public static final int RET = 0xa9;
746   public static final int TABLESWITCH = 0xaa;
747   public static final int LOOKUPSWITCH = 0xab;
748   public static final int IRETURN = 0xac;
749   public static final int LRETURN = 0xad;
750   public static final int FRETURN = 0xae;
751   public static final int DRETURN = 0xaf;
752   
753   public static final int ARETURN = 0xb0;
754   public static final int RETURN = 0xb1;
755   public static final int GETSTATIC = 0xb2;
756   public static final int PUTSTATIC = 0xb3;
757   public static final int GETFIELD = 0xb4;
758   public static final int PUTFIELD = 0xb5;
759   public static final int INVOKEVIRTUAL = 0xb6;
760   public static final int INVOKESPECIAL = 0xb7;
761   public static final int INVOKESTATIC = 0xb8;
762   public static final int INVOKEINTERFACE = 0xb9;
763   public static final int RESERVED_0 = 0xba;
764   public static final int NEW = 0xbb;
765   public static final int NEWARRAY = 0xbc;
766   public static final int ANEWARRAY = 0xbd;
767   public static final int ARRAYLENGTH = 0xbe;
768   public static final int ATHROW = 0xbf;
769   
770   public static final int CHECKCAST = 0xc0;
771   public static final int INSTANCEOF = 0xc1;
772   public static final int MONITORENTER = 0xc2;
773   public static final int MONITOREXIT = 0xc3;
774   public static final int WIDE = 0xc4;
775   public static final int MULTIANEWARRAY = 0xc5;
776   public static final int IFNULL = 0xc6;
777   public static final int IFNONNULL = 0xc7;
778   public static final int GOTO_W = 0xc8;
779   public static final int JSR_W = 0xc9;
780
781   // the reset are reserved
782

783   private static final int OP_LEN[] = {
784      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */
785      1, 2, 1, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 10 */
786      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 */
787      0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 30 */
788     
789      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 */
790      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 */
791      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 */
792      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 */
793     
794      0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */
795      0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, /* 90 */
796      2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 99, 99, 0, 0, 0, 0, /* a0 */
797      0, 0, 2, 2, 2, 2, 2, 2, 2, 4, -1, 2, 1, 2, 0, 0, /* b0 */
798     
799      2, 2, 0, 0, 99, 3, 2, 2, 4, 4, -1, -1, -1, -1, -1, -1, /* c0 */
800     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* d0 */
801     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* e0 */
802     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* f0 */
803   };
804 }
805
Popular Tags