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 public String toString() { StringBuffer sb = new StringBuffer(); toString(sb, "<init>"); return sb.toString(); }
33 public void toString(StringBuffer sb, String constructorName) {
34 sb.append(ClassGen.flagsToString(flags));
38 if (name.equals("<clinit>")) sb.append("static ");
40 if (name.equals("<init>")) sb.append(constructorName);
43 for(int i=0; i<args.length; i++)
44 sb.append((i==0?"":", ")+args[i]);
52 MethodGen(CPGen cp, DataInput in) throws IOException {
54 flags = in.readShort();
55 name = cp.getUtf8ByIndex(in.readShort());
56 String descriptor = cp.getUtf8ByIndex(in.readShort());
57 String ret = descriptor.substring(descriptor.indexOf(')')+1);
58 this.ret = Type.instance(ret);
59 //String args = descriptor.substring(1, descriptor.indexOf(')'));
60 args = new Type[0]; // FIXME
62 attrs = new ClassGen.AttrGen(cp, in);
65 MethodGen(ClassGen owner, String name, Type ret, Type[] args, int flags) {
66 if((flags & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) != 0)
67 throw new IllegalArgumentException("invalid flags");
74 attrs = new ClassGen.AttrGen(cp);
75 codeAttrs = new ClassGen.AttrGen(cp);
78 cp.addUtf8(getDescriptor());
80 if((owner.flags & ACC_INTERFACE) != 0 || (flags & (ACC_ABSTRACT|ACC_NATIVE)) != 0) size = capacity = -1;
82 maxLocals = Math.max(args.length + (flags&ACC_STATIC)==0 ? 1 : 0, 4);
85 /** Returns the descriptor string for this method */
86 public String getDescriptor() { return MethodRef.getDescriptor(ret, args); }
88 private class ExnTableEnt {
92 public CPGen.Ent typeEnt;
93 public ExnTableEnt(int start, int end, int handler, CPGen.Ent typeEnt) {
96 this.handler = handler;
97 this.typeEnt = typeEnt;
99 public void dump(DataOutput o, int[] pc, int endPC) throws IOException {
100 o.writeShort(pc[start]);
101 o.writeShort(end==pc.length ? endPC : pc[end]);
102 o.writeShort(pc[handler]);
103 o.writeShort(cp.getIndex(typeEnt));
107 /** Adds an exception handler for the range [<i>start</i>, <i>end</i>) pointing to <i>handler</i>
108 @param start The instruction to start at (inclusive)
109 @param end The instruction to end at (exclusive)
110 @param handler The instruction of the excepton handler
111 @param type The type of exception that is to be handled (MUST inherit from Throwable)
113 public final void addExceptionHandler(int start, int end, int handler, Type.Class type) {
114 exnTable.put(type, new ExnTableEnt(start, end, handler, cp.add(type)));
117 /** Adds a exception type that can be thrown from this method
118 NOTE: This isn't enforced by the JVM. This is for reference only. A method can throw exceptions not declared to be thrown
119 @param type The type of exception that can be thrown
121 public final void addThrow(Type.Class type) {
122 thrownExceptions.put(type, cp.add(type));
125 private final void grow() { if(size == capacity) grow(size+1); }
126 private final void grow(int newCap) {
127 if(capacity == NO_CODE) throw new IllegalStateException("method can't have code");
128 if(capacity == FINISHED) throw new IllegalStateException("method has been finished");
129 if(newCap <= capacity) return;
130 newCap = Math.max(newCap, capacity == 0 ? 256 : capacity*2);
132 byte[] op2 = new byte[newCap];
133 if(capacity != 0) System.arraycopy(op, 0, op2, 0, size);
136 Object[] arg2 = new Object[newCap];
137 if(capacity != 0) System.arraycopy(arg, 0, arg2, 0, size);
143 /** Returns the size (in instructions) of this method
144 @return The size of the method (in instructions)
146 public final int size() { return size; }
148 // These two are optimized for speed, they don't call set() below
149 /** Add a bytecode (with no argument) to the method */
150 public final int add(byte op) {
152 if(s == capacity) grow();
157 /** Set the bytecode at position <i>pos</i> to <i>op</i> */
158 public final void set(int pos, byte op) { this.op[pos] = op; }
160 /** Adds a bytecode, <i>op</i>, with argument <i>arg</i> to the method
161 @return The position of the new bytecode
163 public final int add(byte op, Object arg) { if(capacity == size) grow(); set(size, op, arg); return size++; }
164 /** Adds a bytecode with a boolean argument - equivalent to add(op, arg?1:0);
165 @return The position of the new bytecode
168 public final int add(byte op, boolean arg) { if(capacity == size) grow(); set(size, op, arg); return size++; }
169 /** Adds a bytecode with an integer argument. This is equivalent to add(op, new Integer(arg)), but optimized to prevent the allocation when possible
170 @return The position of the new bytecode
171 @see #add(byte, Object)
173 public final int add(byte op, int arg) { if(capacity == size) grow(); set(size, op, arg); return size++; }
175 /** Gets the bytecode at position <i>pos</i>
176 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
178 public final byte get(int pos) { return op[pos]; }
180 /** Gets the bytecode at position <i>pos</i>. NOTE: This isn't necessarily the same object that was set with add or set.
181 Arguments for instructions which access the constant pool (LDC, INVOKEVIRTUAL, etc) are converted to a more efficient
182 interal form when they are added. The value returned from this method for these instruction can be reused, but there
183 is no way to retrieve the original object
184 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
186 public final Object getArg(int pos) { return arg[pos]; }
188 /** 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.
189 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
190 @see #setArg(int, Object) */
191 public final void setArg(int pos, int arg) { set(pos, op[pos], N(arg)); }
192 /** Sets the argument for <i>pos</i> to <i>arg</i>.
193 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
195 public final void setArg(int pos, Object arg) { set(pos, op[pos], arg); }
197 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>arg</i> respectivly.
198 This is equivalent to set(pos, op, arg?1:0)
199 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
201 public final void set(int pos, byte op, boolean arg) { set(pos, op, arg?1:0); }
203 // This MUST handle x{LOAD, STORE} and LDC with an int arg WITHOUT falling back to set(int, byte, Object)
204 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>n</i> respectivly.
205 This is equivalent to set(pos, op, new Integer(n)), but optimized to prevent the allocation when possible.
206 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
208 public final void set(int pos, byte op, int n) {
213 case -1: op = ICONST_M1; break OUTER;
214 case 0: op = ICONST_0; break OUTER;
215 case 1: op = ICONST_1; break OUTER;
216 case 2: op = ICONST_2; break OUTER;
217 case 3: op = ICONST_3; break OUTER;
218 case 4: op = ICONST_4; break OUTER;
219 case 5: op = ICONST_5; break OUTER;
221 if(n >= -128 && n <= 127) { op = BIPUSH; arg = N(n); }
222 else if(n >= -32768 && n <= 32767) { op = SIPUSH; arg = N(n); }
223 else { arg = cp.add(N(n)); }
225 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
226 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
227 if(n >= maxLocals) maxLocals = n + 1;
228 if(n >= 0 && n <= 3) {
231 case ILOAD: base = ILOAD_0; break;
232 case ISTORE: base = ISTORE_0; break;
233 case LLOAD: base = LLOAD_0; break;
234 case LSTORE: base = LSTORE_0; break;
235 case FLOAD: base = FLOAD_0; break;
236 case FSTORE: base = FSTORE_0; break;
237 case DLOAD: base = DLOAD_0; break;
238 case DSTORE: base = DSTORE_0; break;
239 case ALOAD: base = ALOAD_0; break;
240 case ASTORE: base = ASTORE_0; break;
242 op = (byte)((base&0xff) + n);
255 /** Sets the bytecode and argument at <i>pos</i> to <i>op</i> and <i>arg</i> respectivly.
256 @exception ArrayIndexOutOfBoundException if pos < 0 || pos >= size()
258 public final void set(int pos, byte op, Object arg) {
260 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
261 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
262 // set(int, byte, int) always handles these ops itself
263 set(pos, op, ((Integer)arg).intValue());
266 // set(int, byte, int) always handles these opts itself
267 if(arg instanceof Integer) { set(pos, op, ((Integer)arg).intValue()); return; }
268 if(arg instanceof Boolean) { set(pos, op, ((Boolean)arg).booleanValue()); return; }
270 if(arg instanceof Long) {
271 long l = ((Long)arg).longValue();
272 if(l == 0L) { this.op[pos] = LCONST_0; return; }
273 if(l == 1L) { this.op[pos] = LCONST_1; return; }
276 if(arg instanceof Long || arg instanceof Double) op = LDC2_W;
278 case INVOKEINTERFACE:
279 if(arg instanceof MethodRef) arg = new MethodRef.I((MethodRef)arg);
282 int opdata = OP_DATA[op&0xff];
283 if((opdata&OP_CPENT_FLAG) != 0 && !(arg instanceof CPGen.Ent))
285 else if((opdata&OP_VALID_FLAG) == 0)
286 throw new IllegalArgumentException("unknown bytecode");
291 /** This class represents the arguments to the TABLESWITH and LOOKUPSWITCH bytecodes
295 public static abstract class SI {
296 public final Object[] targets;
297 public Object defaultTarget;
299 SI(int size) { targets = new Object[size]; }
300 public void setTarget(int pos, Object val) { targets[pos] = val; }
301 public void setTarget(int pos, int val) { targets[pos] = N(val); }
302 public void setDefaultTarget(int val) { setDefaultTarget(N(val)); }
303 public void setDefaultTarget(Object o) { defaultTarget = o; }
304 public int size() { return targets.length; }
306 public int getTarget(int pos) { return ((Integer)targets[pos]).intValue(); }
307 public int getDefaultTarget() { return ((Integer)defaultTarget).intValue(); }
309 abstract int length();
312 /** This class represents the arguments to the TABLESWITCH bytecode */
313 public static class TSI extends SI {
316 public TSI(int lo, int hi) {
321 public void setTargetForVal(int val, Object o) { setTarget(val-lo, o); }
322 public void setTargetForVal(int val, int n) { setTarget(val-lo, n); }
324 int length() { return 12 + targets.length * 4; } // 4bytes/target, hi, lo, default
327 /** This class represents the arguments to the LOOKUPSWITCH bytecode */
328 public static class LSI extends SI {
329 public final int[] vals;
330 public LSI(int size) {
332 this.vals = new int[size];
334 public final void setVal(int pos, int val) { vals[pos] = val; }
336 int length() { return 8 + targets.length * 8; } // key/val per target, default, count
339 /** This class represents the arguments to byecodes that take two integer arguments. */
340 public static class Pair {
343 public Pair(int i1, int i2) { this.i1 = i1; this.i2 = i2; }
346 public static class Wide {
347 public final byte op;
348 public final int varNum;
350 Wide(byte op, int varNum) { this(op, varNum, 0); }
351 Wide(byte op, int varNum, int n) { this.op = op; this.varNum = varNum; this.n = n; }
354 /** Sets the maximum number of locals in the function to <i>maxLocals</i>. NOTE: This defaults to 0 and is automatically increased as
355 necessary when *LOAD/*STORE bytecodes are added. You do not need to call this function in most cases */
356 public void setMaxLocals(int maxLocals) { this.maxLocals = maxLocals; }
357 /** Sets the maxinum size of th stack for this function to <i>maxStack</i>. This defaults to 16< */
358 public void setMaxStack(int maxStack) { this.maxStack = maxStack; }
360 /** Computes the final bytecode for this method.
361 @exception IllegalStateException if the data for a method is in an inconsistent state (required arguments missing, etc)
362 @exception Exn if the byteocode could not be generated for any other reason (constant pool full, etc)
364 public void finish() {
367 } catch(IOException e) {
368 throw new Error("should never happen");
372 private Object resolveTarget(Object arg) {
374 if(arg instanceof PhantomTarget) {
375 target = ((PhantomTarget)arg).getTarget();
376 if(target == -1) throw new IllegalStateException("unresolved phantom target");
379 target = ((Integer)arg).intValue();
381 if(target < 0 || target >= size)
382 throw new IllegalStateException("invalid target address");
386 private void _finish() throws IOException {
387 if(size == FINISHED) return;
391 ByteArrayOutputStream baos = new ByteArrayOutputStream();
392 DataOutput o = new DataOutputStream(baos);
394 int[] pc = new int[size];
398 // Pass1 - Calculate maximum pc of each bytecode, widen some insns, resolve any unresolved jumps, etc
399 for(i=0, p=0;i<size;i++) {
400 byte op = this.op[i];
401 int opdata = OP_DATA[op&0xff];
405 if((opdata & OP_BRANCH_FLAG)!= 0) {
407 arg[i] = resolveTarget(arg[i]);
408 } catch(RuntimeException e) {
409 System.err.println("WARNING: Error resolving target for " + Integer.toHexString(op&0xff));
415 // Speical caculations
418 int arg = ((Integer)this.arg[i]).intValue();
419 if(arg < i && p - maxpc[arg] <= 32768) p += 3;
429 Object[] targets = si.targets;
430 for(j=0;j<targets.length;j++) targets[j] = resolveTarget(targets[j]);
431 si.defaultTarget = resolveTarget(si.defaultTarget);
432 p += 1 + 3 + si.length(); // opcode itself, padding, data
433 if(op == LOOKUPSWITCH) { // verify sanity of lookupswitch vals
434 int[] vals = ((LSI)si).vals;
435 for(j=1;j<vals.length;j++)
436 if(vals[j] <= vals[j-1])
437 throw new IllegalStateException("out of order/duplicate lookupswitch values");
442 case ILOAD: case ISTORE: case LLOAD: case LSTORE: case FLOAD:
443 case FSTORE: case DLOAD: case DSTORE: case ALOAD: case ASTORE:
445 int arg = ((Integer)this.arg[i]).intValue();
448 this.arg[i] = new Wide(op, arg);
453 Pair pair = (Pair) this.arg[i];
454 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) {
456 this.arg[i] = new Wide(IINC, pair.i1, pair.i2);
461 j = cp.getIndex((CPGen.Ent)arg[i]);
462 if(j >= 256) this.op[i] = op = LDC_W;
466 if((j = (opdata&OP_ARG_LENGTH_MASK)) == 7) throw new Error("shouldn't be here");
470 // Pass2 - Widen instructions if they can possibly be too short
471 for(i=0;i<size;i++) {
475 int arg = ((Integer)this.arg[i]).intValue();
476 int diff = maxpc[arg] - maxpc[i];
477 if(diff < -32768 || diff > 32767)
478 op[i] = op[i] == GOTO ? GOTO_W : JSR_W;
484 // Pass3 - Calculate actual pc
485 for(i=0, p=0;i<size;i++) {
486 byte op = this.op[i];
495 p++; // opcode itself
496 p = (p + 3) & ~3; // padding
498 if(op == TABLESWITCH) p += 4 + 4 + si.size() * 4; // lo, hi, targets
499 else p += 4 + si.size() * 4 * 2; // count, key, val * targets
503 p += 2 + (((Wide)arg[i]).op == IINC ? 4 : 2);
506 int l = OP_DATA[op&0xff] & OP_ARG_LENGTH_MASK;
507 if(l == 7) throw new Error("shouldn't be here");
514 if(codeSize >= 65536) throw new ClassGen.Exn("method too large in size");
516 o.writeShort(maxStack);
517 o.writeShort(maxLocals);
518 o.writeInt(codeSize);
520 // Pass 4 - Actually write the bytecodes
521 for(i=0;i<size;i++) {
522 byte op = this.op[i];
523 int opdata = OP_DATA[op&0xff];
524 if(op == NOP && !EMIT_NOPS) continue;
526 int argLength = opdata & OP_ARG_LENGTH_MASK;
528 if(argLength == 0) continue; // skip if no args
531 Object arg = this.arg[i];
535 Pair pair = (Pair) arg;
536 if(pair.i1 > 255 || pair.i2 < -128 || pair.i2 > 127) throw new ClassGen.Exn("overflow of iinc arg");
537 o.writeByte(pair.i1);
538 o.writeByte(pair.i2);
545 for(p = pc[i]+1;(p&3)!=0;p++) o.writeByte(0);
546 o.writeInt(pc[si.getDefaultTarget()] - mypc);
547 if(op == LOOKUPSWITCH) {
548 int[] vals = ((LSI)si).vals;
549 o.writeInt(si.size());
550 for(int j=0;j<si.size();j++) {
552 o.writeInt(pc[si.getTarget(j)] - mypc);
558 for(int j=0;j<tsi.size();j++) o.writeInt(pc[tsi.getTarget(j)] - mypc);
563 Wide wide = (Wide) arg;
564 o.writeByte(wide.op);
565 o.writeShort(wide.varNum);
566 if(wide.op == IINC) o.writeShort(wide.n);
571 if((opdata & OP_BRANCH_FLAG) != 0) {
572 int v = pc[((Integer)arg).intValue()] - pc[i];
574 if(v < -32768 || v > 32767) throw new ClassGen.Exn("overflow of s2 offset");
576 } else if(argLength == 4) {
579 throw new Error("should never happen");
581 } else if((opdata & OP_CPENT_FLAG) != 0) {
582 int v = cp.getIndex((CPGen.Ent)arg);
583 if(argLength == 1) o.writeByte(v);
584 else if(argLength == 2) o.writeShort(v);
585 else throw new Error("should never happen");
586 } else if(argLength == 7) {
587 throw new Error("should never happen - variable length instruction not explicitly handled");
589 int iarg = ((Integer)arg).intValue();
591 if(iarg < -128 || iarg >= 256) throw new ClassGen.Exn("overflow of s/u1 option");
593 } else if(argLength == 2) {
594 if(iarg < -32768 || iarg >= 65536) throw new ClassGen.Exn("overflow of s/u2 option");
597 throw new Error("should never happen");
604 //if(baos.size() - 8 != codeSize) throw new Error("we didn't output what we were supposed to");
606 o.writeShort(exnTable.size());
607 for(Enumeration e = exnTable.keys();e.hasMoreElements();)
608 ((ExnTableEnt)exnTable.get(e.nextElement())).dump(o, pc, codeSize);
610 o.writeShort(codeAttrs.size());
615 byte[] codeAttribute = baos.toByteArray();
616 attrs.add("Code", codeAttribute);
619 o.writeShort(thrownExceptions.size());
620 for(Enumeration e = thrownExceptions.keys();e.hasMoreElements();)
621 o.writeShort(cp.getIndex((CPGen.Ent)thrownExceptions.get(e.nextElement())));
622 attrs.add("Exceptions", baos.toByteArray());
624 size = capacity = FINISHED;
627 void dump(DataOutput o) throws IOException {
629 o.writeShort(cp.getUtf8Index(name));
630 o.writeShort(cp.getUtf8Index(getDescriptor()));
631 o.writeShort(attrs.size());
635 /** Negates the IF* instruction, <i>op</i> (IF_ICMPGT -> IF_ICMPLE, IFNE -> IFEQ, etc)
636 @exception IllegalArgumentException if <i>op</i> isn't an IF* instruction */
637 public static byte negate(byte op) {
639 case IFEQ: return IFNE;
640 case IFNE: return IFEQ;
641 case IFLT: return IFGE;
642 case IFGE: return IFLT;
643 case IFGT: return IFLE;
644 case IFLE: return IFGT;
645 case IF_ICMPEQ: return IF_ICMPNE;
646 case IF_ICMPNE: return IF_ICMPEQ;
647 case IF_ICMPLT: return IF_ICMPGE;
648 case IF_ICMPGE: return IF_ICMPLT;
649 case IF_ICMPGT: return IF_ICMPLE;
650 case IF_ICMPLE: return IF_ICMPGT;
651 case IF_ACMPEQ: return IF_ACMPNE;
652 case IF_ACMPNE: return IF_ACMPEQ;
655 throw new IllegalArgumentException("Can't negate " + Integer.toHexString(op));
659 /** Class that represents a target that isn't currently know. The target MUST be set with setTarget() before the classfile is written.
660 This class is more or less a mutable integer */
661 public static class PhantomTarget {
662 private int target = -1;
663 public void setTarget(int target) { this.target = target; }
664 public int getTarget() { return target; }
667 private static Integer N(int n) { return new Integer(n); }
668 private static Long N(long n) { return new Long(n); }
669 private static Float N(float f) { return new Float(f); }
670 private static Double N(double d) { return new Double(d); }
671 private static int max(int a, int b) { return a > b ? a : b; }
673 private static final int OP_BRANCH_FLAG = 1<<3;
674 private static final int OP_CPENT_FLAG = 1<<4;
675 private static final int OP_VALID_FLAG = 1<<5;
676 private static final int OP_ARG_LENGTH_MASK = 7;
677 private static final boolean OP_VALID(byte op) { return (OP_DATA[op&0xff] & OP_VALID_FLAG) != 0; }
678 private static final int OP_ARG_LENGTH(byte op) { return (OP_DATA[op&0xff]&OP_ARG_LENGTH_MASK); }
679 private static final boolean OP_CPENT(byte op) { return (OP_DATA[op&0xff]&OP_CPENT_FLAG) != 0; }
680 private static final boolean OP_BRANCH(byte op) { return (OP_DATA[op&0xff]&OP_BRANCH_FLAG ) != 0; }
682 // Run perl -x src/org/ibex/classgen/CGConst.java to generate this
683 private static final byte[] OP_DATA = {
684 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
685 0x21, 0x22, 0x31, 0x32, 0x32, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
686 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
687 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
688 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
689 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
690 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
691 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
692 0x20, 0x20, 0x20, 0x20, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
693 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a,
694 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x21, 0x27, 0x27, 0x20, 0x20, 0x20, 0x20,
695 0x20, 0x20, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x01, 0x32, 0x21, 0x32, 0x20, 0x20,
696 0x32, 0x32, 0x20, 0x20, 0x27, 0x23, 0x2a, 0x2a, 0x2c, 0x2c, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
697 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
698 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
699 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01