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(DataInput in) { throw new Error("Brian is lame"); }
33 MethodGen(ClassGen owner, String name, Type ret, Type[] args, int flags) {
34 if((flags & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) != 0)
35 throw new IllegalArgumentException("invalid flags");
42 attrs = new ClassGen.AttrGen(cp);
43 codeAttrs = new ClassGen.AttrGen(cp);
46 cp.addUtf8(getDescriptor());
48 if((owner.flags & ACC_INTERFACE) != 0 || (flags & (ACC_ABSTRACT|ACC_NATIVE)) != 0) size = capacity = -1;
50 maxLocals = Math.max(args.length + (flags&ACC_STATIC)==0 ? 1 : 0, 4);
53 /** Returns the descriptor string for this method */
54 public String getDescriptor() { return MethodRef.getDescriptor(ret, args); }
56 private class ExnTableEnt {
60 public CPGen.Ent typeEnt;
61 public ExnTableEnt(int start, int end, int handler, CPGen.Ent typeEnt) {
64 this.handler = handler;
65 this.typeEnt = typeEnt;
67 public void dump(DataOutput o, int[] pc, int endPC) throws IOException {
68 o.writeShort(pc[start]);
69 o.writeShort(end==pc.length ? endPC : pc[end]);
70 o.writeShort(pc[handler]);
71 o.writeShort(cp.getIndex(typeEnt));
75 /** Adds an exception handler for the range [<i>start</i>, <i>end</i>) pointing to <i>handler</i>
76 @param start The instruction to start at (inclusive)
77 @param end The instruction to end at (exclusive)
78 @param handler The instruction of the excepton handler
79 @param type The type of exception that is to be handled (MUST inherit from Throwable)
81 public final void addExceptionHandler(int start, int end, int handler, Type.Object type) {
82 exnTable.put(type, new ExnTableEnt(start, end, handler, cp.add(type)));
85 /** Adds a exception type that can be thrown from this method
86 NOTE: This isn't enforced by the JVM. This is for reference only. A method can throw exceptions not declared to be thrown
87 @param type The type of exception that can be thrown
89 public final void addThrow(Type.Object type) {
90 thrownExceptions.put(type, cp.add(type));
93 private final void grow() { if(size == capacity) grow(size+1); }
94 private final void grow(int newCap) {
95 if(capacity == NO_CODE) throw new IllegalStateException("method can't have code");
96 if(capacity == FINISHED) throw new IllegalStateException("method has been finished");
97 if(newCap <= capacity) return;
98 newCap = Math.max(newCap, capacity == 0 ? 256 : capacity*2);
100 byte[] op2 = new byte[newCap];
101 if(capacity != 0) System.arraycopy(op, 0, op2, 0, size);
104 Object[] arg2 = new Object[newCap];
105 if(capacity != 0) System.arraycopy(arg, 0, arg2, 0, size);
111 /** Returns the size (in instructions) of this method
112 @return The size of the method (in instructions)
114 public final int size() { return size; }
116 // These two are optimized for speed, they don't call set() below
117 /** Add a bytecode (with no argument) to the method */
118 public final int add(byte op) {
120 if(s == capacity) grow();
125 /** Set the bytecode at position <i>pos</i> to <i>op</i> */
126 public final void set(int pos, byte op) { this.op[pos] = op; }
128 /** Adds a bytecode, <i>op</i>, with argument <i>arg</i> to the method
129 @return The position of the new bytecode
131 public final int add(byte op, Object arg) { if(capacity == size) grow(); set(size, op, arg); return size++; }
132 /** Adds a bytecode with a boolean argument - equivalent to add(op, arg?1:0);
133 @return The position of the new bytecode
136 public final int add(byte op, boolean arg) { if(capacity == size) grow(); set(size, op, arg); return size++; }
137 /** Adds a bytecode with an integer argument. This is equivalent to add(op, new Integer(arg)), but optimized to prevent the allocation when possible
138 @return The position of the new bytecode
139 @see #add(byte, Object)
141 public final int add(byte op, int arg) { if(capacity == size) grow(); set(size, op, arg); return size++; }
143 /** Gets the bytecode at position <i>pos</i>
144 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
146 public final byte get(int pos) { return op[pos]; }
148 /** Gets the bytecode at position <i>pos</i>. NOTE: This isn't necessarily the same object that was set with add or set.
149 Arguments for instructions which access the constant pool (LDC, INVOKEVIRTUAL, etc) are converted to a more efficient
150 interal form when they are added. The value returned from this method for these instruction can be reused, but there
151 is no way to retrieve the original object
152 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
154 public final Object getArg(int pos) { return arg[pos]; }
156 /** 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.
157 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
158 @see #setArg(int, Object) */
159 public final void setArg(int pos, int arg) { set(pos, op[pos], N(arg)); }
160 /** Sets the argument for <i>pos</i> to <i>arg</i>.
161 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
163 public final void setArg(int pos, Object arg) { set(pos, op[pos], arg); }
165 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>arg</i> respectivly.
166 This is equivalent to set(pos, op, arg?1:0)
167 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
169 public final void set(int pos, byte op, boolean arg) { set(pos, op, arg?1:0); }
171 // This MUST handle x{LOAD, STORE} and LDC with an int arg WITHOUT falling back to set(int, byte, Object)
172 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>n</i> respectivly.
173 This is equivalent to set(pos, op, new Integer(n)), but optimized to prevent the allocation when possible.
174 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
176 public final void set(int pos, byte op, int n) {
181 case -1: op = ICONST_M1; break OUTER;
182 case 0: op = ICONST_0; break OUTER;
183 case 1: op = ICONST_1; break OUTER;
184 case 2: op = ICONST_2; break OUTER;
185 case 3: op = ICONST_3; break OUTER;
186 case 4: op = ICONST_4; break OUTER;
187 case 5: op = ICONST_5; break OUTER;
189 if(n >= -128 && n <= 127) { op = BIPUSH; arg = N(n); }
190 else if(n >= -32768 && n <= 32767) { op = SIPUSH; arg = N(n); }
191 else { arg = cp.add(N(n)); }
193 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
194 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
195 if(n >= maxLocals) maxLocals = n + 1;
196 if(n >= 0 && n <= 3) {
199 case ILOAD: base = ILOAD_0; break;
200 case ISTORE: base = ISTORE_0; break;
201 case LLOAD: base = LLOAD_0; break;
202 case LSTORE: base = LSTORE_0; break;
203 case FLOAD: base = FLOAD_0; break;
204 case FSTORE: base = FSTORE_0; break;
205 case DLOAD: base = DLOAD_0; break;
206 case DSTORE: base = DSTORE_0; break;
207 case ALOAD: base = ALOAD_0; break;
208 case ASTORE: base = ASTORE_0; break;
210 op = (byte)((base&0xff) + n);
223 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>arg</i> respectivly.
224 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
226 public final void set(int pos, byte op, Object arg) {
228 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
229 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
230 // set(int, byte, int) always handles these ops itself
231 set(pos, op, ((Integer)arg).intValue());
234 // set(int, byte, int) always handles these opts itself
235 if(arg instanceof Integer) { set(pos, op, ((Integer)arg).intValue()); return; }
236 if(arg instanceof Boolean) { set(pos, op, ((Boolean)arg).booleanValue()); return; }
238 if(arg instanceof Long) {
239 long l = ((Long)arg).longValue();
240 if(l == 0L) { this.op[pos] = LCONST_0; return; }
241 if(l == 1L) { this.op[pos] = LCONST_1; return; }
244 if(arg instanceof Long || arg instanceof Double) op = LDC2_W;
246 case INVOKEINTERFACE:
247 if(arg instanceof MethodRef) arg = new MethodRef.I((MethodRef)arg);
250 int opdata = OP_DATA[op&0xff];
251 if((opdata&OP_CPENT_FLAG) != 0 && !(arg instanceof CPGen.Ent))
253 else if((opdata&OP_VALID_FLAG) == 0)
254 throw new IllegalArgumentException("unknown bytecode");
259 /** This class represents the arguments to the TABLESWITH and LOOKUPSWITCH bytecodes
263 public static abstract class SI {
264 public final Object[] targets;
265 public Object defaultTarget;
267 SI(int size) { targets = new Object[size]; }
268 public void setTarget(int pos, Object val) { targets[pos] = val; }
269 public void setTarget(int pos, int val) { targets[pos] = N(val); }
270 public void setDefaultTarget(int val) { setDefaultTarget(N(val)); }
271 public void setDefaultTarget(Object o) { defaultTarget = o; }
272 public int size() { return targets.length; }
274 public int getTarget(int pos) { return ((Integer)targets[pos]).intValue(); }
275 public int getDefaultTarget() { return ((Integer)defaultTarget).intValue(); }
277 abstract int length();
280 /** This class represents the arguments to the TABLESWITCH bytecode */
281 public static class TSI extends SI {
284 public TSI(int lo, int hi) {
289 public void setTargetForVal(int val, Object o) { setTarget(val-lo, o); }
290 public void setTargetForVal(int val, int n) { setTarget(val-lo, n); }
292 int length() { return 12 + targets.length * 4; } // 4bytes/target, hi, lo, default
295 /** This class represents the arguments to the LOOKUPSWITCH bytecode */
296 public static class LSI extends SI {
297 public final int[] vals;
298 public LSI(int size) {
300 this.vals = new int[size];
302 public final void setVal(int pos, int val) { vals[pos] = val; }
304 int length() { return 8 + targets.length * 8; } // key/val per target, default, count
307 /** This class represents the arguments to byecodes that take two integer arguments. */
308 public static class Pair {
311 public Pair(int i1, int i2) { this.i1 = i1; this.i2 = i2; }
314 public static class Wide {
315 public final byte op;
316 public final int varNum;
318 Wide(byte op, int varNum) { this(op, varNum, 0); }
319 Wide(byte op, int varNum, int n) { this.op = op; this.varNum = varNum; this.n = n; }
322 /** Sets the maximum number of locals in the function to <i>maxLocals</i>. NOTE: This defaults to 0 and is automatically increased as
323 necessary when *LOAD/*STORE bytecodes are added. You do not need to call this function in most cases */
324 public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; }
325 /** Sets the maxinum size of th stack for this function to <i>maxStack</i>. This defaults to 16< */
326 public void setMaxStack(int maxStack) { this.maxStack = maxStack; }
328 /** Computes the final bytecode for this method.
329 @exception IllegalStateException if the data for a method is in an inconsistent state (required arguments missing, etc)
330 @exception Exn if the byteocode could not be generated for any other reason (constant pool full, etc)
332 public void finish() {
335 } catch(IOException e) {
336 throw new Error("should never happen");
340 private Object resolveTarget(Object arg) {
342 if(arg instanceof PhantomTarget) {
343 target = ((PhantomTarget)arg).getTarget();
344 if(target == -1) throw new IllegalStateException("unresolved phantom target");
347 target = ((Integer)arg).intValue();
349 if(target < 0 || target >= size)
350 throw new IllegalStateException("invalid target address");
354 private void _finish() throws IOException {
355 if(size == FINISHED) return;
359 ByteArrayOutputStream baos = new ByteArrayOutputStream();
360 DataOutput o = new DataOutputStream(baos);
362 int[] pc = new int[size];
366 // Pass1 - Calculate maximum pc of each bytecode, widen some insns, resolve any unresolved jumps, etc
367 for(i=0, p=0;i<size;i++) {
368 byte op = this.op[i];
369 int opdata = OP_DATA[op&0xff];
373 if((opdata & OP_BRANCH_FLAG)!= 0) {
375 arg[i] = resolveTarget(arg[i]);
376 } catch(RuntimeException e) {
377 System.err.println("WARNING: Error resolving target for " + Integer.toHexString(op&0xff));
383 // Speical caculations
386 int arg = ((Integer)this.arg[i]).intValue();
387 if(arg < i && p - maxpc[arg] <= 32768) p += 3;
397 Object[] targets = si.targets;
398 for(j=0;j<targets.length;j++) targets[j] = resolveTarget(targets[j]);
399 si.defaultTarget = resolveTarget(si.defaultTarget);
400 p += 1 + 3 + si.length(); // opcode itself, padding, data
401 if(op == LOOKUPSWITCH) { // verify sanity of lookupswitch vals
402 int[] vals = ((LSI)si).vals;
403 for(j=1;j<vals.length;j++)
404 if(vals[j] <= vals[j-1])
405 throw new IllegalStateException("out of order/duplicate lookupswitch values");
410 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
411 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
413 int arg = ((Integer)this.arg[i]).intValue();
416 this.arg[i] = new Wide(op, arg);
421 Pair pair = (Pair) this.arg[i];
422 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) {
424 this.arg[i] = new Wide(IINC, pair.i1, pair.i2);
429 j = cp.getIndex((CPGen.Ent)arg[i]);
430 if(j >= 256) this.op[i] = op = LDC_W;
434 if((j = (opdata&OP_ARG_LENGTH_MASK)) == 7) throw new Error("shouldn't be here");
438 // Pass2 - Widen instructions if they can possibly be too short
439 for(i=0;i<size;i++) {
443 int arg = ((Integer)this.arg[i]).intValue();
444 int diff = maxpc[arg] - maxpc[i];
445 if(diff < -32768 || diff > 32767)
446 op[i] = op[i] == GOTO ? GOTO_W : JSR_W;
452 // Pass3 - Calculate actual pc
453 for(i=0, p=0;i<size;i++) {
454 byte op = this.op[i];
463 p++; // opcode itself
464 p = (p + 3) & ~3; // padding
466 if(op == TABLESWITCH) p += 4 + 4 + si.size() * 4; // lo, hi, targets
467 else p += 4 + si.size() * 4 * 2; // count, key, val * targets
471 p += 2 + (((Wide)arg[i]).op == IINC ? 4 : 2);
474 int l = OP_DATA[op&0xff] & OP_ARG_LENGTH_MASK;
475 if(l == 7) throw new Error("shouldn't be here");
482 if(codeSize >= 65536) throw new ClassGen.Exn("method too large in size");
484 o.writeShort(maxStack);
485 o.writeShort(maxLocals);
486 o.writeInt(codeSize);
488 // Pass 4 - Actually write the bytecodes
489 for(i=0;i<size;i++) {
490 byte op = this.op[i];
491 int opdata = OP_DATA[op&0xff];
492 if(op == NOP && !EMIT_NOPS) continue;
494 int argLength = opdata & OP_ARG_LENGTH_MASK;
496 if(argLength == 0) continue; // skip if no args
499 Object arg = this.arg[i];
503 Pair pair = (Pair) arg;
504 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) throw new ClassGen.Exn("overflow of iinc arg");
505 o.writeByte(pair.i1);
506 o.writeByte(pair.i2);
513 for(p = pc[i]+1;(p&3)!=0;p++) o.writeByte(0);
514 o.writeInt(pc[si.getDefaultTarget()] - mypc);
515 if(op == LOOKUPSWITCH) {
516 int[] vals = ((LSI)si).vals;
517 o.writeInt(si.size());
518 for(int j=0;j<si.size();j++) {
520 o.writeInt(pc[si.getTarget(j)] - mypc);
526 for(int j=0;j<tsi.size();j++) o.writeInt(pc[tsi.getTarget(j)] - mypc);
531 Wide wide = (Wide) arg;
532 o.writeByte(wide.op);
533 o.writeShort(wide.varNum);
534 if(wide.op == IINC) o.writeShort(wide.n);
539 if((opdata & OP_BRANCH_FLAG) != 0) {
540 int v = pc[((Integer)arg).intValue()] - pc[i];
542 if(v < -32768 || v > 32767) throw new ClassGen.Exn("overflow of s2 offset");
544 } else if(argLength == 4) {
547 throw new Error("should never happen");
549 } else if((opdata & OP_CPENT_FLAG) != 0) {
550 int v = cp.getIndex((CPGen.Ent)arg);
551 if(argLength == 1) o.writeByte(v);
552 else if(argLength == 2) o.writeShort(v);
553 else throw new Error("should never happen");
554 } else if(argLength == 7) {
555 throw new Error("should never happen - variable length instruction not explicitly handled");
557 int iarg = ((Integer)arg).intValue();
559 if(iarg < -128 || iarg >= 256) throw new ClassGen.Exn("overflow of s/u1 option");
561 } else if(argLength == 2) {
562 if(iarg < -32768 || iarg >= 65536) throw new ClassGen.Exn("overflow of s/u2 option");
565 throw new Error("should never happen");
572 //if(baos.size() - 8 != codeSize) throw new Error("we didn't output what we were supposed to");
574 o.writeShort(exnTable.size());
575 for(Enumeration e = exnTable.keys();e.hasMoreElements();)
576 ((ExnTableEnt)exnTable.get(e.nextElement())).dump(o, pc, codeSize);
578 o.writeShort(codeAttrs.size());
583 byte[] codeAttribute = baos.toByteArray();
584 attrs.add("Code", codeAttribute);
587 o.writeShort(thrownExceptions.size());
588 for(Enumeration e = thrownExceptions.keys();e.hasMoreElements();)
589 o.writeShort(cp.getIndex((CPGen.Ent)thrownExceptions.get(e.nextElement())));
590 attrs.add("Exceptions", baos.toByteArray());
592 size = capacity = FINISHED;
595 void dump(DataOutput o) throws IOException {
597 o.writeShort(cp.getUtf8Index(name));
598 o.writeShort(cp.getUtf8Index(getDescriptor()));
599 o.writeShort(attrs.size());
603 /** Negates the IF* instruction, <i>op</i> (IF_ICMPGT -> IF_ICMPLE, IFNE -> IFEQ, etc)
604 @exception IllegalArgumentException if <i>op</i> isn't an IF* instruction */
605 public static byte negate(byte op) {
607 case IFEQ: return IFNE;
608 case IFNE: return IFEQ;
609 case IFLT: return IFGE;
610 case IFGE: return IFLT;
611 case IFGT: return IFLE;
612 case IFLE: return IFGT;
613 case IF_ICMPEQ: return IF_ICMPNE;
614 case IF_ICMPNE: return IF_ICMPEQ;
615 case IF_ICMPLT: return IF_ICMPGE;
616 case IF_ICMPGE: return IF_ICMPLT;
617 case IF_ICMPGT: return IF_ICMPLE;
618 case IF_ICMPLE: return IF_ICMPGT;
619 case IF_ACMPEQ: return IF_ACMPNE;
620 case IF_ACMPNE: return IF_ACMPEQ;
623 throw new IllegalArgumentException("Can't negate " + Integer.toHexString(op));
627 /** Class that represents a target that isn't currently know. The target MUST be set with setTarget() before the classfile is written.
628 This class is more or less a mutable integer */
629 public static class PhantomTarget {
630 private int target = -1;
631 public void setTarget(int target) { this.target = target; }
632 public int getTarget() { return target; }
635 private static Integer N(int n) { return new Integer(n); }
636 private static Long N(long n) { return new Long(n); }
637 private static Float N(float f) { return new Float(f); }
638 private static Double N(double d) { return new Double(d); }
639 private static int max(int a, int b) { return a > b ? a : b; }
641 private static final int OP_BRANCH_FLAG = 1<<3;
642 private static final int OP_CPENT_FLAG = 1<<4;
643 private static final int OP_VALID_FLAG = 1<<5;
644 private static final int OP_ARG_LENGTH_MASK = 7;
645 private static final boolean OP_VALID(byte op) { return (OP_DATA[op&0xff] & OP_VALID_FLAG) != 0; }
646 private static final int OP_ARG_LENGTH(byte op) { return (OP_DATA[op&0xff]&OP_ARG_LENGTH_MASK); }
647 private static final boolean OP_CPENT(byte op) { return (OP_DATA[op&0xff]&OP_CPENT_FLAG) != 0; }
648 private static final boolean OP_BRANCH(byte op) { return (OP_DATA[op&0xff]&OP_BRANCH_FLAG ) != 0; }
650 // Run perl -x src/org/ibex/classgen/CGConst.java to generate this
651 private static final byte[] OP_DATA = {
652 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
653 0x21, 0x22, 0x31, 0x32, 0x32, 0x21, 0x21, 0x21, 0x21, 0x21, 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, 0x21, 0x21, 0x21, 0x21, 0x21, 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, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
660 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
661 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
662 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x21, 0x27, 0x27, 0x20, 0x20, 0x20, 0x20,
663 0x20, 0x20, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x01, 0x32, 0x21, 0x32, 0x20, 0x20,
664 0x32, 0x32, 0x20, 0x20, 0x27, 0x23, 0x2a, 0x2a, 0x2c, 0x2c, 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,
667 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01