1 package org.ibex.classgen;
6 // FEATURE: Support WIDE bytecodes
8 /** A class representing a method in a generated classfile
9 @see ClassGen#addMethod */
10 public class MethodGen implements CGConst {
11 private final static boolean EMIT_NOPS = false;
13 private static final int NO_CODE = -1;
14 private static final int FINISHED = -2;
16 private final CPGen cp;
17 private final String name;
18 private final Type ret;
19 private final Type[] args;
20 private final int flags;
21 private final ClassGen.AttrGen attrs;
22 private final ClassGen.AttrGen codeAttrs;
23 private final Hashtable exnTable = new Hashtable();
24 private final Hashtable thrownExceptions = new Hashtable();
26 private int maxStack = 16;
27 private int maxLocals;
34 MethodGen(ClassGen owner, String name, Type ret, Type[] args, int flags) {
35 if((flags & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) != 0)
36 throw new IllegalArgumentException("invalid flags");
43 attrs = new ClassGen.AttrGen(cp);
44 codeAttrs = new ClassGen.AttrGen(cp);
47 cp.addUtf8(getDescriptor());
49 if((owner.flags & ACC_INTERFACE) != 0 || (flags & (ACC_ABSTRACT|ACC_NATIVE)) != 0) size = capacity = -1;
51 maxLocals = Math.max(args.length + (flags&ACC_STATIC)==0 ? 1 : 0,4);
54 /** Returns the descriptor string for this method */
55 public String getDescriptor() { return MethodRef.getDescriptor(ret,args); }
57 private class ExnTableEnt {
61 public CPGen.Ent typeEnt;
62 public ExnTableEnt(int start, int end, int handler, CPGen.Ent typeEnt) {
65 this.handler = handler;
66 this.typeEnt = typeEnt;
68 public void dump(DataOutput o, int[] pc, int endPC) throws IOException {
69 o.writeShort(pc[start]);
70 o.writeShort(end==pc.length ? endPC : pc[end]);
71 o.writeShort(pc[handler]);
72 o.writeShort(typeEnt.getIndex());
76 /** Adds an exception handler for the range [<i>start</i>,<i>end</i>) pointing to <i>handler</i>
77 @param start The instruction to start at (inclusive)
78 @param end The instruction to end at (exclusive)
79 @param handler The instruction of the excepton handler
80 @param type The type of exception that is to be handled (MUST inherit from Throwable)
82 public final void addExceptionHandler(int start, int end, int handler, Type.Object type) {
83 exnTable.put(type, new ExnTableEnt(start,end,handler,cp.add(type)));
86 /** Adds a exception type that can be thrown from this method
87 NOTE: This isn't enforced by the JVM. This is for reference only. A method can throw exceptions not declared to be thrown
88 @param type The type of exception that can be thrown
90 public final void addThrow(Type.Object type) {
91 thrownExceptions.put(type,cp.add(type));
94 private final void grow() { if(size == capacity) grow(size+1); }
95 private final void grow(int newCap) {
96 if(capacity == NO_CODE) throw new IllegalStateException("method can't have code");
97 if(capacity == FINISHED) throw new IllegalStateException("method has been finished");
98 if(newCap <= capacity) return;
99 newCap = Math.max(newCap,capacity == 0 ? 256 : capacity*2);
101 byte[] op2 = new byte[newCap];
102 if(capacity != 0) System.arraycopy(op,0,op2,0,size);
105 Object[] arg2 = new Object[newCap];
106 if(capacity != 0) System.arraycopy(arg,0,arg2,0,size);
112 /** Returns the size (in instructions) of this method
113 @return The size of the method (in instructions)
115 public final int size() { return size; }
117 // These two are optimized for speed, they don't call set() below
118 /** Add a bytecode (with no argument) to the method */
119 public final int add(byte op) {
121 if(s == capacity) grow();
126 /** Set the bytecode at position <i>pos</i> to <i>op</i> */
127 public final void set(int pos, byte op) { this.op[pos] = op; }
129 /** Adds a bytecode, <i>op</i>, with argument <i>arg</i> to the method
130 @return The position of the new bytecode
132 public final int add(byte op, Object arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
133 /** Adds a bytecode with a boolean argument - equivalent to add(op,arg?1:0);
134 @return The position of the new bytecode
137 public final int add(byte op, boolean arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
138 /** Adds a bytecode with an integer argument. This is equivalent to add(op,new Integer(arg)), but optimized to prevent the allocation when possible
139 @return The position of the new bytecode
140 @see #add(byte,Object)
142 public final int add(byte op, int arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
144 /** Gets the bytecode at position <i>pos</i>
145 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
147 public final byte get(int pos) { return op[pos]; }
149 /** Gets the bytecode at position <i>pos</i>. NOTE: This isn't necessarily the same object that was set with add or set.
150 Arguments for instructions which access the constant pool (LDC, INVOKEVIRTUAL, etc) are converted to a more efficient
151 interal form when they are added. The value returned from this method for these instruction can be reused, but there
152 is no way to retrieve the original object
153 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
155 public final Object getArg(int pos) { return arg[pos]; }
157 /** Sets the argument for <i>pos</i> to <i>arg</i>. This is equivalent to set(pos,op,new Integer(arg)), but optimized to prevent the allocation when possible.
158 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
159 @see #setArg(int,Object) */
160 public final void setArg(int pos, int arg) { set(pos,op[pos],N(arg)); }
161 /** Sets the argument for <i>pos</i> to <i>arg</i>.
162 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
164 public final void setArg(int pos, Object arg) { set(pos,op[pos],arg); }
166 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>arg</i> respectivly.
167 This is equivalent to set(pos,op,arg?1:0)
168 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
170 public final void set(int pos, byte op, boolean arg) { set(pos,op,arg?1:0); }
172 // This MUST handle x{LOAD,STORE} and LDC with an int arg WITHOUT falling back to set(int,byte,Object)
173 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>n</i> respectivly.
174 This is equivalent to set(pos,op, new Integer(n)), but optimized to prevent the allocation when possible.
175 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
177 public final void set(int pos, byte op, int n) {
182 case -1: op = ICONST_M1; break OUTER;
183 case 0: op = ICONST_0; break OUTER;
184 case 1: op = ICONST_1; break OUTER;
185 case 2: op = ICONST_2; break OUTER;
186 case 3: op = ICONST_3; break OUTER;
187 case 4: op = ICONST_4; break OUTER;
188 case 5: op = ICONST_5; break OUTER;
190 if(n >= -128 && n <= 127) { op = BIPUSH; arg = N(n); }
191 else if(n >= -32768 && n <= 32767) { op = SIPUSH; arg = N(n); }
192 else { arg = cp.add(N(n)); }
194 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
195 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
196 if(n >= maxLocals) maxLocals = n + 1;
197 if(n >= 0 && n <= 3) {
200 case ILOAD: base = ILOAD_0; break;
201 case ISTORE: base = ISTORE_0; break;
202 case LLOAD: base = LLOAD_0; break;
203 case LSTORE: base = LSTORE_0; break;
204 case FLOAD: base = FLOAD_0; break;
205 case FSTORE: base = FSTORE_0; break;
206 case DLOAD: base = DLOAD_0; break;
207 case DSTORE: base = DSTORE_0; break;
208 case ALOAD: base = ALOAD_0; break;
209 case ASTORE: base = ASTORE_0; break;
211 op = (byte)((base&0xff) + n);
212 } else if(n >= 256) {
213 arg = new Wide(op,n);
227 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>arg</i> respectivly.
228 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
230 public final void set(int pos, byte op, Object arg) {
232 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
233 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
234 // set(int,byte,int) always handles these ops itself
235 set(pos,op,((Integer)arg).intValue());
238 if(((Integer)arg).intValue() > 255) {
240 arg = new Wide(RET,((Integer)arg).intValue());
244 Pair pair = (Pair) arg;
245 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) {
247 arg = new Wide(IINC,pair.i1,pair.i2);
252 // set(int,byte,int) always handles these opts itself
253 if(arg instanceof Integer) { set(pos,op,((Integer)arg).intValue()); return; }
254 if(arg instanceof Boolean) { set(pos,op,((Boolean)arg).booleanValue()); return; }
256 if(arg instanceof Long) {
257 long l = ((Long)arg).longValue();
258 if(l == 0L) { this.op[pos] = LCONST_0; return; }
259 if(l == 1L) { this.op[pos] = LCONST_1; return; }
262 if(arg instanceof Long || arg instanceof Double) op = LDC2_W;
264 case INVOKEINTERFACE:
265 if(arg instanceof MethodRef) arg = new MethodRef.I((MethodRef)arg);
268 int opdata = OP_DATA[op&0xff];
269 if((opdata&OP_CPENT_FLAG) != 0 && !(arg instanceof CPGen.Ent))
271 else if((opdata&OP_VALID_FLAG) == 0)
272 throw new IllegalArgumentException("unknown bytecode");
277 /** This class represents the arguments to the TABLESWITH and LOOKUPSWITCH bytecodes
281 public static class SI {
282 public final Object[] targets;
283 public Object defaultTarget;
285 SI(int size) { targets = new Object[size]; }
286 public void setTarget(int pos, Object val) { targets[pos] = val; }
287 public void setTarget(int pos, int val) { targets[pos] = N(val); }
288 public void setDefaultTarget(int val) { setDefaultTarget(N(val)); }
289 public void setDefaultTarget(Object o) { defaultTarget = o; }
290 public int size() { return targets.length; }
292 public int getTarget(int pos) { return ((Integer)targets[pos]).intValue(); }
293 public int getDefaultTarget() { return ((Integer)defaultTarget).intValue(); }
296 /** This class represents the arguments to the TABLESWITCH bytecode */
297 public static class TSI extends SI {
300 public TSI(int lo, int hi) {
305 public void setTargetForVal(int val, Object o) { setTarget(val-lo,o); }
306 public void setTargetForVal(int val, int n) { setTarget(val-lo,n); }
309 /** This class represents the arguments to the LOOKUPSWITCH bytecode */
310 public static class LSI extends SI {
311 public final int[] vals;
312 public LSI(int size) {
314 this.vals = new int[size];
316 public final void setVal(int pos, int val) { vals[pos] = val; }
319 /** This class represents the arguments to byecodes that take two integer arguments. */
320 public static class Pair {
323 public Pair(int i1, int i2) { this.i1 = i1; this.i2 = i2; }
326 public static class Wide {
327 public final byte op;
328 public final int varNum;
330 Wide(byte op, int varNum) { this(op,varNum,0); }
331 Wide(byte op, int varNum, int n) { this.op = op; this.varNum = varNum; this.n = n; }
334 /** Sets the maximum number of locals in the function to <i>maxLocals</i>. NOTE: This defaults to 0 and is automatically increased as
335 necessary when *LOAD/*STORE bytecodes are added. You do not need to call this function in most cases */
336 public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; }
337 /** Sets the maxinum size of th stack for this function to <i>maxStack</i>. This defaults to 16< */
338 public void setMaxStack(int maxStack) { this.maxStack = maxStack; }
340 /** Computes the final bytecode for this method.
341 @exception IllegalStateException if the data for a method is in an inconsistent state (required arguments missing, etc)
342 @exception Exn if the byteocode could not be generated for any other reason (constant pool full, etc)
344 public void finish() {
347 } catch(IOException e) {
348 throw new Error("should never happen");
352 private Object resolveTarget(Object arg) {
354 if(arg instanceof PhantomTarget) {
355 target = ((PhantomTarget)arg).getTarget();
356 if(target == -1) throw new IllegalStateException("unresolved phantom target");
359 target = ((Integer)arg).intValue();
361 if(target < 0 || target >= size)
362 throw new IllegalStateException("invalid target address");
366 private void _finish() throws IOException {
367 if(size == FINISHED) return;
369 ByteArrayOutputStream baos = new ByteArrayOutputStream();
370 DataOutput o = new DataOutputStream(baos);
372 int[] pc = new int[size];
376 // Pass1 - Calculate maximum pc of each bytecode, widen some insns, resolve any unresolved jumps, etc
377 for(i=0,p=0;i<size;i++) {
378 byte op = this.op[i];
379 int opdata = OP_DATA[op&0xff];
383 if((opdata & OP_BRANCH_FLAG)!= 0) {
385 arg[i] = resolveTarget(arg[i]);
386 } catch(RuntimeException e) {
387 System.err.println("WARNING: Error resolving target for " + Integer.toHexString(op&0xff));
395 int arg = ((Integer)this.arg[i]).intValue();
396 if(arg < i && p - maxpc[arg] <= 32768) p += 3;
406 Object[] targets = si.targets;
407 for(j=0;j<targets.length;j++) targets[j] = resolveTarget(targets[j]);
408 si.defaultTarget = resolveTarget(si.defaultTarget);
409 p += 1 + 3 + 4; // opcode itself, padding, default
410 if(op == TABLESWITCH) p += 4 + 4 + targets.length * 4; // lo, hi, targets
411 else p += 4 + targets.length * 4 * 2; // count, key,val * targets
412 if(op == LOOKUPSWITCH) {
413 int[] vals = ((LSI)si).vals;
414 for(j=1;j<vals.length;j++)
415 if(vals[j] <= vals[j-1])
416 throw new IllegalStateException("out of order/duplicate lookupswitch values");
421 p += 2 + (((Wide)arg[i]).op == IINC ? 4 : 2);
424 j = ((CPGen.Ent)arg[i]).getIndex();
425 if(j >= 256) this.op[i] = op = LDC_W;
428 if((j = (opdata&OP_ARG_LENGTH_MASK)) == 7) throw new Error("shouldn't be here");
434 // Pass2 - Widen instructions if they can possibly be too short
435 for(i=0;i<size;i++) {
439 int arg = ((Integer)this.arg[i]).intValue();
440 int diff = maxpc[arg] - maxpc[i];
441 if(diff < -32768 || diff > 32767)
442 op[i] = op[i] == GOTO ? GOTO_W : JSR_W;
448 // Pass3 - Calculate actual pc
449 for(i=0,p=0;i<size;i++) {
450 byte op = this.op[i];
459 p++; // opcode itself
460 p = (p + 3) & ~3; // padding
462 if(op == TABLESWITCH) p += 4 + 4 + si.size() * 4; // lo, hi, targets
463 else p += 4 + si.size() * 4 * 2; // count, key,val * targets
467 p += 2 + (((Wide)arg[i]).op == IINC ? 4 : 2);
470 int l = OP_DATA[op&0xff] & OP_ARG_LENGTH_MASK;
471 if(l == 7) throw new Error("shouldn't be here");
478 if(codeSize >= 65536) throw new ClassGen.Exn("method too large in size");
480 o.writeShort(maxStack);
481 o.writeShort(maxLocals);
482 o.writeInt(codeSize);
484 // Pass 4 - Actually write the bytecodes
485 for(i=0;i<size;i++) {
486 byte op = this.op[i];
487 int opdata = OP_DATA[op&0xff];
488 if(op == NOP && !EMIT_NOPS) continue;
490 int argLength = opdata & OP_ARG_LENGTH_MASK;
492 if(argLength == 0) continue; // skip if no args
495 Object arg = this.arg[i];
499 Pair pair = (Pair) arg;
500 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) throw new ClassGen.Exn("overflow of iinc arg");
501 o.writeByte(pair.i1);
502 o.writeByte(pair.i2);
509 for(p = pc[i]+1;(p&3)!=0;p++) o.writeByte(0);
510 o.writeInt(pc[si.getDefaultTarget()] - mypc);
511 if(op == LOOKUPSWITCH) {
512 int[] vals = ((LSI)si).vals;
513 o.writeInt(si.size());
514 for(int j=0;j<si.size();j++) {
516 o.writeInt(pc[si.getTarget(j)] - mypc);
522 for(int j=0;j<tsi.size();j++) o.writeInt(pc[tsi.getTarget(j)] - mypc);
527 Wide wide = (Wide) arg;
528 o.writeByte(wide.op);
529 o.writeShort(wide.varNum);
530 if(wide.op == IINC) o.writeShort(wide.n);
535 if((opdata & OP_BRANCH_FLAG) != 0) {
536 int v = pc[((Integer)arg).intValue()] - pc[i];
538 if(v < -32768 || v > 32767) throw new ClassGen.Exn("overflow of s2 offset");
540 } else if(argLength == 4) {
543 throw new Error("should never happen");
545 } else if((opdata & OP_CPENT_FLAG) != 0) {
546 int v = ((CPGen.Ent)arg).getIndex();
547 if(argLength == 1) o.writeByte(v);
548 else if(argLength == 2) o.writeShort(v);
549 else throw new Error("should never happen");
550 } else if(argLength == 7) {
551 throw new Error("should never happen - variable length instruction not explicitly handled");
553 int iarg = ((Integer)arg).intValue();
555 if(iarg < -128 || iarg >= 256) throw new ClassGen.Exn("overflow of s/u1 option");
557 } else if(argLength == 2) {
558 if(iarg < -32768 || iarg >= 65536) throw new ClassGen.Exn("overflow of s/u2 option");
561 throw new Error("should never happen");
568 //if(baos.size() - 8 != codeSize) throw new Error("we didn't output what we were supposed to");
570 o.writeShort(exnTable.size());
571 for(Enumeration e = exnTable.keys();e.hasMoreElements();)
572 ((ExnTableEnt)exnTable.get(e.nextElement())).dump(o,pc,codeSize);
574 o.writeShort(codeAttrs.size());
579 byte[] codeAttribute = baos.toByteArray();
580 attrs.add("Code",codeAttribute);
583 o.writeShort(thrownExceptions.size());
584 for(Enumeration e = thrownExceptions.keys();e.hasMoreElements();)
585 o.writeShort(((CPGen.Ent)thrownExceptions.get(e.nextElement())).getIndex());
586 attrs.add("Exceptions",baos.toByteArray());
588 size = capacity = FINISHED;
591 void dump(DataOutput o) throws IOException {
593 o.writeShort(cp.getUtf8Index(name));
594 o.writeShort(cp.getUtf8Index(getDescriptor()));
595 o.writeShort(attrs.size());
599 /** Negates the IF* instruction, <i>op</i> (IF_ICMPGT -> IF_ICMPLE, IFNE -> IFEQ, etc)
600 @exception IllegalArgumentException if <i>op</i> isn't an IF* instruction */
601 public static byte negate(byte op) {
603 case IFEQ: return IFNE;
604 case IFNE: return IFEQ;
605 case IFLT: return IFGE;
606 case IFGE: return IFLT;
607 case IFGT: return IFLE;
608 case IFLE: return IFGT;
609 case IF_ICMPEQ: return IF_ICMPNE;
610 case IF_ICMPNE: return IF_ICMPEQ;
611 case IF_ICMPLT: return IF_ICMPGE;
612 case IF_ICMPGE: return IF_ICMPLT;
613 case IF_ICMPGT: return IF_ICMPLE;
614 case IF_ICMPLE: return IF_ICMPGT;
615 case IF_ACMPEQ: return IF_ACMPNE;
616 case IF_ACMPNE: return IF_ACMPEQ;
619 throw new IllegalArgumentException("Can't negate " + Integer.toHexString(op));
623 /** Class that represents a target that isn't currently know. The target MUST be set with setTarget() before the classfile is written.
624 This class is more or less a mutable integer */
625 public static class PhantomTarget {
626 private int target = -1;
627 public void setTarget(int target) { this.target = target; }
628 public int getTarget() { return target; }
631 private static Integer N(int n) { return new Integer(n); }
632 private static Long N(long n) { return new Long(n); }
633 private static Float N(float f) { return new Float(f); }
634 private static Double N(double d) { return new Double(d); }
635 private static int max(int a, int b) { return a > b ? a : b; }
637 private static final int OP_BRANCH_FLAG = 1<<3;
638 private static final int OP_CPENT_FLAG = 1<<4;
639 private static final int OP_VALID_FLAG = 1<<5;
640 private static final int OP_ARG_LENGTH_MASK = 7;
641 private static final boolean OP_VALID(byte op) { return (OP_DATA[op&0xff] & OP_VALID_FLAG) != 0; }
642 private static final int OP_ARG_LENGTH(byte op) { return (OP_DATA[op&0xff]&OP_ARG_LENGTH_MASK); }
643 private static final boolean OP_CPENT(byte op) { return (OP_DATA[op&0xff]&OP_CPENT_FLAG) != 0; }
644 private static final boolean OP_BRANCH(byte op) { return (OP_DATA[op&0xff]&OP_BRANCH_FLAG ) != 0; }
646 // Run perl -x src/org/ibex/classgen/CGConst.java to generate this
647 private static final byte[] OP_DATA = {
648 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
649 0x21, 0x22, 0x31, 0x32, 0x32, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
650 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
651 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
652 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
653 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
654 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
655 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
656 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
657 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
658 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x21, 0x27, 0x27, 0x20, 0x20, 0x20, 0x20,
659 0x20, 0x20, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x01, 0x32, 0x21, 0x32, 0x20, 0x20,
660 0x32, 0x32, 0x20, 0x20, 0x27, 0x23, 0x2a, 0x2a, 0x2c, 0x2c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
661 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
662 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
663 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01