1 package org.ibex.classgen;
6 /** A class representing a method in a generated classfile
7 @see ClassGen#addMethod */
8 public class MethodGen implements CGConst {
9 private final static boolean EMIT_NOPS = false;
11 private static final int NO_CODE = -1;
12 private static final int FINISHED = -2;
14 private final CPGen cp;
15 private final String name;
16 private final Type ret;
17 private final Type[] args;
18 private final int flags;
19 private final ClassGen.AttrGen attrs;
20 private final ClassGen.AttrGen codeAttrs;
21 private final Hashtable exnTable = new Hashtable();
22 private final Hashtable thrownExceptions = new Hashtable();
24 private int maxStack = 16;
25 private int maxLocals;
32 MethodGen(ClassGen owner, String name, Type ret, Type[] args, int flags) {
33 if((flags & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) != 0)
34 throw new IllegalArgumentException("invalid flags");
41 attrs = new ClassGen.AttrGen(cp);
42 codeAttrs = new ClassGen.AttrGen(cp);
45 cp.addUtf8(getDescriptor());
47 if((owner.flags & ACC_INTERFACE) != 0 || (flags & (ACC_ABSTRACT|ACC_NATIVE)) != 0) size = capacity = -1;
49 maxLocals = Math.max(args.length + (flags&ACC_STATIC)==0 ? 1 : 0,4);
52 /** Returns the descriptor string for this method */
53 public String getDescriptor() { return MethodRef.getDescriptor(ret,args); }
55 private class ExnTableEnt {
59 public CPGen.Ent typeEnt;
60 public ExnTableEnt(int start, int end, int handler, CPGen.Ent typeEnt) {
63 this.handler = handler;
64 this.typeEnt = typeEnt;
66 public void dump(DataOutput o, int[] pc, int endPC) throws IOException {
67 o.writeShort(pc[start]);
68 o.writeShort(end==pc.length ? endPC : pc[end]);
69 o.writeShort(pc[handler]);
70 o.writeShort(cp.getIndex(typeEnt));
74 /** Adds an exception handler for the range [<i>start</i>,<i>end</i>) pointing to <i>handler</i>
75 @param start The instruction to start at (inclusive)
76 @param end The instruction to end at (exclusive)
77 @param handler The instruction of the excepton handler
78 @param type The type of exception that is to be handled (MUST inherit from Throwable)
80 public final void addExceptionHandler(int start, int end, int handler, Type.Object type) {
81 exnTable.put(type, new ExnTableEnt(start,end,handler,cp.add(type)));
84 /** Adds a exception type that can be thrown from this method
85 NOTE: This isn't enforced by the JVM. This is for reference only. A method can throw exceptions not declared to be thrown
86 @param type The type of exception that can be thrown
88 public final void addThrow(Type.Object type) {
89 thrownExceptions.put(type,cp.add(type));
92 private final void grow() { if(size == capacity) grow(size+1); }
93 private final void grow(int newCap) {
94 if(capacity == NO_CODE) throw new IllegalStateException("method can't have code");
95 if(capacity == FINISHED) throw new IllegalStateException("method has been finished");
96 if(newCap <= capacity) return;
97 newCap = Math.max(newCap,capacity == 0 ? 256 : capacity*2);
99 byte[] op2 = new byte[newCap];
100 if(capacity != 0) System.arraycopy(op,0,op2,0,size);
103 Object[] arg2 = new Object[newCap];
104 if(capacity != 0) System.arraycopy(arg,0,arg2,0,size);
110 /** Returns the size (in instructions) of this method
111 @return The size of the method (in instructions)
113 public final int size() { return size; }
115 // These two are optimized for speed, they don't call set() below
116 /** Add a bytecode (with no argument) to the method */
117 public final int add(byte op) {
119 if(s == capacity) grow();
124 /** Set the bytecode at position <i>pos</i> to <i>op</i> */
125 public final void set(int pos, byte op) { this.op[pos] = op; }
127 /** Adds a bytecode, <i>op</i>, with argument <i>arg</i> to the method
128 @return The position of the new bytecode
130 public final int add(byte op, Object arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
131 /** Adds a bytecode with a boolean argument - equivalent to add(op,arg?1:0);
132 @return The position of the new bytecode
135 public final int add(byte op, boolean arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
136 /** Adds a bytecode with an integer argument. This is equivalent to add(op,new Integer(arg)), but optimized to prevent the allocation when possible
137 @return The position of the new bytecode
138 @see #add(byte,Object)
140 public final int add(byte op, int arg) { if(capacity == size) grow(); set(size,op,arg); return size++; }
142 /** Gets the bytecode at position <i>pos</i>
143 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
145 public final byte get(int pos) { return op[pos]; }
147 /** Gets the bytecode at position <i>pos</i>. NOTE: This isn't necessarily the same object that was set with add or set.
148 Arguments for instructions which access the constant pool (LDC, INVOKEVIRTUAL, etc) are converted to a more efficient
149 interal form when they are added. The value returned from this method for these instruction can be reused, but there
150 is no way to retrieve the original object
151 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
153 public final Object getArg(int pos) { return arg[pos]; }
155 /** 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.
156 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
157 @see #setArg(int,Object) */
158 public final void setArg(int pos, int arg) { set(pos,op[pos],N(arg)); }
159 /** Sets the argument for <i>pos</i> to <i>arg</i>.
160 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
162 public final void setArg(int pos, Object arg) { set(pos,op[pos],arg); }
164 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>arg</i> respectivly.
165 This is equivalent to set(pos,op,arg?1:0)
166 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
168 public final void set(int pos, byte op, boolean arg) { set(pos,op,arg?1:0); }
170 // This MUST handle x{LOAD,STORE} and LDC with an int arg WITHOUT falling back to set(int,byte,Object)
171 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>n</i> respectivly.
172 This is equivalent to set(pos,op, new Integer(n)), but optimized to prevent the allocation when possible.
173 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
175 public final void set(int pos, byte op, int n) {
180 case -1: op = ICONST_M1; break OUTER;
181 case 0: op = ICONST_0; break OUTER;
182 case 1: op = ICONST_1; break OUTER;
183 case 2: op = ICONST_2; break OUTER;
184 case 3: op = ICONST_3; break OUTER;
185 case 4: op = ICONST_4; break OUTER;
186 case 5: op = ICONST_5; break OUTER;
188 if(n >= -128 && n <= 127) { op = BIPUSH; arg = N(n); }
189 else if(n >= -32768 && n <= 32767) { op = SIPUSH; arg = N(n); }
190 else { arg = cp.add(N(n)); }
192 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
193 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
194 if(n >= maxLocals) maxLocals = n + 1;
195 if(n >= 0 && n <= 3) {
198 case ILOAD: base = ILOAD_0; break;
199 case ISTORE: base = ISTORE_0; break;
200 case LLOAD: base = LLOAD_0; break;
201 case LSTORE: base = LSTORE_0; break;
202 case FLOAD: base = FLOAD_0; break;
203 case FSTORE: base = FSTORE_0; break;
204 case DLOAD: base = DLOAD_0; break;
205 case DSTORE: base = DSTORE_0; break;
206 case ALOAD: base = ALOAD_0; break;
207 case ASTORE: base = ASTORE_0; break;
209 op = (byte)((base&0xff) + n);
222 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>arg</i> respectivly.
223 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
225 public final void set(int pos, byte op, Object arg) {
227 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
228 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
229 // set(int,byte,int) always handles these ops itself
230 set(pos,op,((Integer)arg).intValue());
233 // set(int,byte,int) always handles these opts itself
234 if(arg instanceof Integer) { set(pos,op,((Integer)arg).intValue()); return; }
235 if(arg instanceof Boolean) { set(pos,op,((Boolean)arg).booleanValue()); return; }
237 if(arg instanceof Long) {
238 long l = ((Long)arg).longValue();
239 if(l == 0L) { this.op[pos] = LCONST_0; return; }
240 if(l == 1L) { this.op[pos] = LCONST_1; return; }
243 if(arg instanceof Long || arg instanceof Double) op = LDC2_W;
245 case INVOKEINTERFACE:
246 if(arg instanceof MethodRef) arg = new MethodRef.I((MethodRef)arg);
249 int opdata = OP_DATA[op&0xff];
250 if((opdata&OP_CPENT_FLAG) != 0 && !(arg instanceof CPGen.Ent))
252 else if((opdata&OP_VALID_FLAG) == 0)
253 throw new IllegalArgumentException("unknown bytecode");
258 /** This class represents the arguments to the TABLESWITH and LOOKUPSWITCH bytecodes
262 public static abstract class SI {
263 public final Object[] targets;
264 public Object defaultTarget;
266 SI(int size) { targets = new Object[size]; }
267 public void setTarget(int pos, Object val) { targets[pos] = val; }
268 public void setTarget(int pos, int val) { targets[pos] = N(val); }
269 public void setDefaultTarget(int val) { setDefaultTarget(N(val)); }
270 public void setDefaultTarget(Object o) { defaultTarget = o; }
271 public int size() { return targets.length; }
273 public int getTarget(int pos) { return ((Integer)targets[pos]).intValue(); }
274 public int getDefaultTarget() { return ((Integer)defaultTarget).intValue(); }
276 abstract int length();
279 /** This class represents the arguments to the TABLESWITCH bytecode */
280 public static class TSI extends SI {
283 public TSI(int lo, int hi) {
288 public void setTargetForVal(int val, Object o) { setTarget(val-lo,o); }
289 public void setTargetForVal(int val, int n) { setTarget(val-lo,n); }
291 int length() { return 12 + targets.length * 4; } // 4bytes/target, hi, lo, default
294 /** This class represents the arguments to the LOOKUPSWITCH bytecode */
295 public static class LSI extends SI {
296 public final int[] vals;
297 public LSI(int size) {
299 this.vals = new int[size];
301 public final void setVal(int pos, int val) { vals[pos] = val; }
303 int length() { return 8 + targets.length * 8; } // key/val per target, default, count
306 /** This class represents the arguments to byecodes that take two integer arguments. */
307 public static class Pair {
310 public Pair(int i1, int i2) { this.i1 = i1; this.i2 = i2; }
313 public static class Wide {
314 public final byte op;
315 public final int varNum;
317 Wide(byte op, int varNum) { this(op,varNum,0); }
318 Wide(byte op, int varNum, int n) { this.op = op; this.varNum = varNum; this.n = n; }
321 /** Sets the maximum number of locals in the function to <i>maxLocals</i>. NOTE: This defaults to 0 and is automatically increased as
322 necessary when *LOAD/*STORE bytecodes are added. You do not need to call this function in most cases */
323 public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; }
324 /** Sets the maxinum size of th stack for this function to <i>maxStack</i>. This defaults to 16< */
325 public void setMaxStack(int maxStack) { this.maxStack = maxStack; }
327 /** Computes the final bytecode for this method.
328 @exception IllegalStateException if the data for a method is in an inconsistent state (required arguments missing, etc)
329 @exception Exn if the byteocode could not be generated for any other reason (constant pool full, etc)
331 public void finish() {
334 } catch(IOException e) {
335 throw new Error("should never happen");
339 private Object resolveTarget(Object arg) {
341 if(arg instanceof PhantomTarget) {
342 target = ((PhantomTarget)arg).getTarget();
343 if(target == -1) throw new IllegalStateException("unresolved phantom target");
346 target = ((Integer)arg).intValue();
348 if(target < 0 || target >= size)
349 throw new IllegalStateException("invalid target address");
353 private void _finish() throws IOException {
354 if(size == FINISHED) return;
358 ByteArrayOutputStream baos = new ByteArrayOutputStream();
359 DataOutput o = new DataOutputStream(baos);
361 int[] pc = new int[size];
365 // Pass1 - Calculate maximum pc of each bytecode, widen some insns, resolve any unresolved jumps, etc
366 for(i=0,p=0;i<size;i++) {
367 byte op = this.op[i];
368 int opdata = OP_DATA[op&0xff];
372 if((opdata & OP_BRANCH_FLAG)!= 0) {
374 arg[i] = resolveTarget(arg[i]);
375 } catch(RuntimeException e) {
376 System.err.println("WARNING: Error resolving target for " + Integer.toHexString(op&0xff));
382 // Speical caculations
385 int arg = ((Integer)this.arg[i]).intValue();
386 if(arg < i && p - maxpc[arg] <= 32768) p += 3;
396 Object[] targets = si.targets;
397 for(j=0;j<targets.length;j++) targets[j] = resolveTarget(targets[j]);
398 si.defaultTarget = resolveTarget(si.defaultTarget);
399 p += 1 + 3 + si.length(); // opcode itself, padding, data
400 if(op == LOOKUPSWITCH) { // verify sanity of lookupswitch vals
401 int[] vals = ((LSI)si).vals;
402 for(j=1;j<vals.length;j++)
403 if(vals[j] <= vals[j-1])
404 throw new IllegalStateException("out of order/duplicate lookupswitch values");
409 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
410 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
412 int arg = ((Integer)this.arg[i]).intValue();
415 this.arg[i] = new Wide(op,arg);
420 Pair pair = (Pair) this.arg[i];
421 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) {
423 this.arg[i] = new Wide(IINC,pair.i1,pair.i2);
428 j = cp.getIndex((CPGen.Ent)arg[i]);
429 if(j >= 256) this.op[i] = op = LDC_W;
433 if((j = (opdata&OP_ARG_LENGTH_MASK)) == 7) throw new Error("shouldn't be here");
437 // Pass2 - Widen instructions if they can possibly be too short
438 for(i=0;i<size;i++) {
442 int arg = ((Integer)this.arg[i]).intValue();
443 int diff = maxpc[arg] - maxpc[i];
444 if(diff < -32768 || diff > 32767)
445 op[i] = op[i] == GOTO ? GOTO_W : JSR_W;
451 // Pass3 - Calculate actual pc
452 for(i=0,p=0;i<size;i++) {
453 byte op = this.op[i];
462 p++; // opcode itself
463 p = (p + 3) & ~3; // padding
465 if(op == TABLESWITCH) p += 4 + 4 + si.size() * 4; // lo, hi, targets
466 else p += 4 + si.size() * 4 * 2; // count, key,val * targets
470 p += 2 + (((Wide)arg[i]).op == IINC ? 4 : 2);
473 int l = OP_DATA[op&0xff] & OP_ARG_LENGTH_MASK;
474 if(l == 7) throw new Error("shouldn't be here");
481 if(codeSize >= 65536) throw new ClassGen.Exn("method too large in size");
483 o.writeShort(maxStack);
484 o.writeShort(maxLocals);
485 o.writeInt(codeSize);
487 // Pass 4 - Actually write the bytecodes
488 for(i=0;i<size;i++) {
489 byte op = this.op[i];
490 int opdata = OP_DATA[op&0xff];
491 if(op == NOP && !EMIT_NOPS) continue;
493 int argLength = opdata & OP_ARG_LENGTH_MASK;
495 if(argLength == 0) continue; // skip if no args
498 Object arg = this.arg[i];
502 Pair pair = (Pair) arg;
503 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) throw new ClassGen.Exn("overflow of iinc arg");
504 o.writeByte(pair.i1);
505 o.writeByte(pair.i2);
512 for(p = pc[i]+1;(p&3)!=0;p++) o.writeByte(0);
513 o.writeInt(pc[si.getDefaultTarget()] - mypc);
514 if(op == LOOKUPSWITCH) {
515 int[] vals = ((LSI)si).vals;
516 o.writeInt(si.size());
517 for(int j=0;j<si.size();j++) {
519 o.writeInt(pc[si.getTarget(j)] - mypc);
525 for(int j=0;j<tsi.size();j++) o.writeInt(pc[tsi.getTarget(j)] - mypc);
530 Wide wide = (Wide) arg;
531 o.writeByte(wide.op);
532 o.writeShort(wide.varNum);
533 if(wide.op == IINC) o.writeShort(wide.n);
538 if((opdata & OP_BRANCH_FLAG) != 0) {
539 int v = pc[((Integer)arg).intValue()] - pc[i];
541 if(v < -32768 || v > 32767) throw new ClassGen.Exn("overflow of s2 offset");
543 } else if(argLength == 4) {
546 throw new Error("should never happen");
548 } else if((opdata & OP_CPENT_FLAG) != 0) {
549 int v = cp.getIndex((CPGen.Ent)arg);
550 if(argLength == 1) o.writeByte(v);
551 else if(argLength == 2) o.writeShort(v);
552 else throw new Error("should never happen");
553 } else if(argLength == 7) {
554 throw new Error("should never happen - variable length instruction not explicitly handled");
556 int iarg = ((Integer)arg).intValue();
558 if(iarg < -128 || iarg >= 256) throw new ClassGen.Exn("overflow of s/u1 option");
560 } else if(argLength == 2) {
561 if(iarg < -32768 || iarg >= 65536) throw new ClassGen.Exn("overflow of s/u2 option");
564 throw new Error("should never happen");
571 //if(baos.size() - 8 != codeSize) throw new Error("we didn't output what we were supposed to");
573 o.writeShort(exnTable.size());
574 for(Enumeration e = exnTable.keys();e.hasMoreElements();)
575 ((ExnTableEnt)exnTable.get(e.nextElement())).dump(o,pc,codeSize);
577 o.writeShort(codeAttrs.size());
582 byte[] codeAttribute = baos.toByteArray();
583 attrs.add("Code",codeAttribute);
586 o.writeShort(thrownExceptions.size());
587 for(Enumeration e = thrownExceptions.keys();e.hasMoreElements();)
588 o.writeShort(cp.getIndex((CPGen.Ent)thrownExceptions.get(e.nextElement())));
589 attrs.add("Exceptions",baos.toByteArray());
591 size = capacity = FINISHED;
594 void dump(DataOutput o) throws IOException {
596 o.writeShort(cp.getUtf8Index(name));
597 o.writeShort(cp.getUtf8Index(getDescriptor()));
598 o.writeShort(attrs.size());
602 /** Negates the IF* instruction, <i>op</i> (IF_ICMPGT -> IF_ICMPLE, IFNE -> IFEQ, etc)
603 @exception IllegalArgumentException if <i>op</i> isn't an IF* instruction */
604 public static byte negate(byte op) {
606 case IFEQ: return IFNE;
607 case IFNE: return IFEQ;
608 case IFLT: return IFGE;
609 case IFGE: return IFLT;
610 case IFGT: return IFLE;
611 case IFLE: return IFGT;
612 case IF_ICMPEQ: return IF_ICMPNE;
613 case IF_ICMPNE: return IF_ICMPEQ;
614 case IF_ICMPLT: return IF_ICMPGE;
615 case IF_ICMPGE: return IF_ICMPLT;
616 case IF_ICMPGT: return IF_ICMPLE;
617 case IF_ICMPLE: return IF_ICMPGT;
618 case IF_ACMPEQ: return IF_ACMPNE;
619 case IF_ACMPNE: return IF_ACMPEQ;
622 throw new IllegalArgumentException("Can't negate " + Integer.toHexString(op));
626 /** Class that represents a target that isn't currently know. The target MUST be set with setTarget() before the classfile is written.
627 This class is more or less a mutable integer */
628 public static class PhantomTarget {
629 private int target = -1;
630 public void setTarget(int target) { this.target = target; }
631 public int getTarget() { return target; }
634 private static Integer N(int n) { return new Integer(n); }
635 private static Long N(long n) { return new Long(n); }
636 private static Float N(float f) { return new Float(f); }
637 private static Double N(double d) { return new Double(d); }
638 private static int max(int a, int b) { return a > b ? a : b; }
640 private static final int OP_BRANCH_FLAG = 1<<3;
641 private static final int OP_CPENT_FLAG = 1<<4;
642 private static final int OP_VALID_FLAG = 1<<5;
643 private static final int OP_ARG_LENGTH_MASK = 7;
644 private static final boolean OP_VALID(byte op) { return (OP_DATA[op&0xff] & OP_VALID_FLAG) != 0; }
645 private static final int OP_ARG_LENGTH(byte op) { return (OP_DATA[op&0xff]&OP_ARG_LENGTH_MASK); }
646 private static final boolean OP_CPENT(byte op) { return (OP_DATA[op&0xff]&OP_CPENT_FLAG) != 0; }
647 private static final boolean OP_BRANCH(byte op) { return (OP_DATA[op&0xff]&OP_BRANCH_FLAG ) != 0; }
649 // Run perl -x src/org/ibex/classgen/CGConst.java to generate this
650 private static final byte[] OP_DATA = {
651 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
652 0x21, 0x22, 0x31, 0x32, 0x32, 0x21, 0x21, 0x21, 0x21, 0x21, 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, 0x21, 0x21, 0x21, 0x21, 0x21, 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, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
657 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
658 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
659 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
660 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
661 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x21, 0x27, 0x27, 0x20, 0x20, 0x20, 0x20,
662 0x20, 0x20, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x01, 0x32, 0x21, 0x32, 0x20, 0x20,
663 0x32, 0x32, 0x20, 0x20, 0x27, 0x23, 0x2a, 0x2a, 0x2c, 0x2c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
664 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
665 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
666 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01