View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software 
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License.
16   */
17  
18  package org.apache.jdo.impl.enhancer.core;
19  
20  import java.util.HashMap;
21  import java.util.ArrayList;
22  import java.util.Iterator;
23  import java.util.Enumeration;
24  
25  import org.apache.jdo.impl.enhancer.classfile.AttributeVector;
26  import org.apache.jdo.impl.enhancer.classfile.ClassField;
27  import org.apache.jdo.impl.enhancer.classfile.ClassFile;
28  import org.apache.jdo.impl.enhancer.classfile.CodeAttribute;
29  import org.apache.jdo.impl.enhancer.classfile.ConstClass;
30  import org.apache.jdo.impl.enhancer.classfile.ConstFieldRef;
31  import org.apache.jdo.impl.enhancer.classfile.ConstNameAndType;
32  import org.apache.jdo.impl.enhancer.classfile.ConstUtf8;
33  import org.apache.jdo.impl.enhancer.classfile.ConstantPool;
34  import org.apache.jdo.impl.enhancer.classfile.Descriptor;
35  import org.apache.jdo.impl.enhancer.classfile.ExceptionRange;
36  import org.apache.jdo.impl.enhancer.classfile.ExceptionTable;
37  import org.apache.jdo.impl.enhancer.classfile.ExceptionsAttribute;
38  import org.apache.jdo.impl.enhancer.classfile.Insn;
39  import org.apache.jdo.impl.enhancer.classfile.InsnIInc;
40  import org.apache.jdo.impl.enhancer.classfile.InsnInterfaceInvoke;
41  import org.apache.jdo.impl.enhancer.classfile.InsnLookupSwitch;
42  import org.apache.jdo.impl.enhancer.classfile.InsnTableSwitch;
43  import org.apache.jdo.impl.enhancer.classfile.InsnTarget;
44  import org.apache.jdo.impl.enhancer.classfile.InsnUtils;
45  import org.apache.jdo.impl.enhancer.classfile.VMConstants;
46  import org.apache.jdo.impl.enhancer.util.InternalError;
47  import org.apache.jdo.impl.enhancer.util.Support;
48  
49  /***
50   * Helper object to create the generic JDO methods for a class.
51   */
52  class Builder
53      extends Support
54      implements VMConstants, JDOConstants, EnhancerConstants
55  {
56      /***
57       * The augmentation controller for this class.
58       */
59      private final Augmenter augmenter;
60  
61      /***
62       * The class analyzer for this class.
63       */
64      private final Analyzer analyzer;
65  
66      /***
67       * The classfile to be annotated.
68       */
69      private final ClassFile classFile;
70  
71      /***
72       * The class name in VM form.
73       */
74      private final String className;
75  
76      /***
77       * The class name in user ('.' delimited) form.
78       */
79      private final String userClassName;
80  
81      /***
82       * The classfile's constant pool.
83       */
84      private final ConstantPool pool;
85  
86      /***
87       * Repository for the enhancement options.
88       */
89      private final Environment env;
90  
91      /***
92       * The constant utf8 string for the CodeAttribute.
93       */
94      private ConstUtf8 codeAttributeUtf8;
95      /***
96  
97       * The constant field ref for the jdoStateManager field.
98       */
99      private ConstFieldRef jdoStateManagerFieldRef;
100 
101     /***
102      * The constant field ref for the jdoFlags field.
103      */
104     private ConstFieldRef jdoFlagsFieldRef;
105 
106     /***
107      * The constant field ref for the jdoFieldNames field.
108      */
109     private ConstFieldRef jdoFieldNamesFieldRef;
110 
111     /***
112      * The constant field ref for the jdoFieldTypes field.
113      */
114     private ConstFieldRef jdoFieldTypesFieldRef;
115 
116     /***
117      * The constant field ref for the jdoFieldFlags field.
118      */
119     private ConstFieldRef jdoFieldFlagsFieldRef;
120 
121     /***
122      * The constant field ref for the jdoPersistenceCapableSuperclass field.
123      */
124     private ConstFieldRef jdoPersistenceCapableSuperclassFieldRef;
125 
126     /***
127      * The constant field refs for the annotated fields sorted by their
128      * relative field index.
129      */
130     private ConstFieldRef[] annotatedFieldRefs;
131 
132     /***
133      * The constant field refs for the key fields sorted by
134      * ascending relative field index.
135      */
136     private ConstFieldRef[] keyFieldRefs;
137 
138     /***
139      * The constant field refs on the key class for the key fields sorted by
140      * ascending relative field index.
141      */
142     private ConstFieldRef[] keyClassKeyFieldRefs;
143 
144     /***
145      * Constructor.
146      */
147     public Builder(Analyzer analyzer,
148                    Augmenter augmenter,
149                    Environment env)
150     {
151         affirm(analyzer != null);
152         affirm(augmenter != null);
153         affirm(env != null);
154 
155         this.analyzer = analyzer;
156         this.augmenter = augmenter;
157         this.classFile = analyzer.getClassFile();
158         this.className = classFile.classNameString();
159         this.userClassName = classFile.userClassName();
160         this.pool = classFile.pool();
161         this.env = env;
162 
163         affirm(classFile != null);
164         affirm(className != null);
165         affirm(userClassName != null);
166         affirm(pool != null);
167     }
168 
169     // ----------------------------------------------------------------------
170     // Internal Helper Methods
171     // ----------------------------------------------------------------------
172 
173     /***
174      * Holder object for returning a size info from a code generation method.
175      */
176     static private class SizeHolder
177     {
178         int size;
179     }
180 
181     /***
182      * Returns the minimum of two numbers.
183      */
184     static private int min(int i, int j) {
185         return (i < j ? i : j);
186     }
187 
188     /***
189      * Returns the maximum of two numbers.
190      */
191     static private int max(int i, int j) {
192         return (i < j ? j : i);
193     }
194 
195     /***
196      * Count the size of the arguments to an invokevirtual method call.
197      */
198     static private int countMethodArgWords(String sig) 
199     {
200         // the 'this' pointer is to be accounted too
201         return Descriptor.countMethodArgWords(sig) + 1;
202     }    
203 
204     /***
205      * Returns the utf8 string for the CodeAttribute.
206      */
207     private ConstUtf8 getCodeAttributeUtf8()
208     {
209         // create utf8 in constant pool if not done yet
210         if (codeAttributeUtf8 == null) {
211             codeAttributeUtf8 = pool.addUtf8(CodeAttribute.expectedAttrName);
212         }
213         return codeAttributeUtf8;
214     }
215 
216     /***
217      * Returns the constant field ref for the jdoStateManager field.
218      */
219     private ConstFieldRef getjdoStateManagerFieldRef()
220     {
221         //^olsen: javac uses the truelly declaring class
222         final String pcRootName = analyzer.getPCRootClassName();
223         affirm(pcRootName != null);
224 
225         // create field reference in constant pool if not done yet
226         if (jdoStateManagerFieldRef == null) {
227             jdoStateManagerFieldRef
228                 = pool.addFieldRef(pcRootName, //className,
229                                    JDO_PC_jdoStateManager_Name,
230                                    JDO_PC_jdoStateManager_Sig);
231         }
232         return jdoStateManagerFieldRef;
233     }
234 
235     /***
236      * Returns the constant field ref for the jdoFlags field.
237      */
238     private ConstFieldRef getjdoFlagsFieldRef()
239     {
240         //^olsen: javac uses the truelly declaring class
241         final String pcRootName = analyzer.getPCRootClassName();
242         affirm(pcRootName != null);
243 
244         // create field reference in constant pool if not done yet
245         if (jdoFlagsFieldRef == null) {
246             jdoFlagsFieldRef
247                 = pool.addFieldRef(pcRootName, //className,
248                                    JDO_PC_jdoFlags_Name,
249                                    JDO_PC_jdoFlags_Sig);
250         }
251         return jdoFlagsFieldRef;
252     }
253 
254     /***
255      * Returns the constant field ref for the jdoFieldNames field.
256      */
257     private ConstFieldRef getjdoFieldNamesFieldRef()
258     {
259         // create field reference in constant pool if not done yet
260         if (jdoFieldNamesFieldRef == null) {
261             jdoFieldNamesFieldRef
262                 = pool.addFieldRef(className,
263                                    JDO_PC_jdoFieldNames_Name,
264                                    JDO_PC_jdoFieldNames_Sig);
265         }
266         return jdoFieldNamesFieldRef;
267     }
268 
269     /***
270      * Returns the constant field ref for the jdoFieldTypes field.
271      */
272     private ConstFieldRef getjdoFieldTypesFieldRef()
273     {
274         // create field reference in constant pool if not done yet
275         if (jdoFieldTypesFieldRef == null) {
276             jdoFieldTypesFieldRef
277                 = pool.addFieldRef(className,
278                                    JDO_PC_jdoFieldTypes_Name,
279                                    JDO_PC_jdoFieldTypes_Sig);
280         }
281         return jdoFieldTypesFieldRef;
282     }
283 
284     /***
285      * Returns the constant field ref for the jdoFieldFlags field.
286      */
287     private ConstFieldRef getjdoFieldFlagsFieldRef()
288     {
289         // create field reference in constant pool if not done yet
290         if (jdoFieldFlagsFieldRef == null) {
291             jdoFieldFlagsFieldRef
292                 = pool.addFieldRef(className,
293                                    JDO_PC_jdoFieldFlags_Name,
294                                    JDO_PC_jdoFieldFlags_Sig);
295         }
296         return jdoFieldFlagsFieldRef;
297     }
298 
299     /***
300      * Returns the constant field ref for the jdoPersistenceCapableSuperclass field.
301      */
302     private ConstFieldRef getjdoPersistenceCapableSuperclassFieldRef()
303     {
304         // create field reference in constant pool if not done yet
305         if (jdoPersistenceCapableSuperclassFieldRef == null) {
306             jdoPersistenceCapableSuperclassFieldRef
307                 = pool.addFieldRef(className,
308                                    JDO_PC_jdoPersistenceCapableSuperclass_Name,
309                                    JDO_PC_jdoPersistenceCapableSuperclass_Sig);
310         }
311         return jdoPersistenceCapableSuperclassFieldRef;
312     }
313 
314     /***
315      * Returns the constant field refs for the annotated fields.
316      */
317     private ConstFieldRef[] getAnnotatedFieldRefs()
318     {
319         // create field references in constant pool if not done yet
320         if (annotatedFieldRefs == null) {
321             final int annotatedFieldCount = analyzer.getAnnotatedFieldCount();
322             final String[] annotatedFieldNames
323                 = analyzer.getAnnotatedFieldNames();
324             final String[] annotatedFieldSigs
325                 = analyzer.getAnnotatedFieldSigs();
326             affirm(annotatedFieldNames.length == annotatedFieldCount);
327             affirm(annotatedFieldSigs.length == annotatedFieldCount);
328             
329             // add field references to constant pool
330             annotatedFieldRefs = new ConstFieldRef[annotatedFieldCount];
331             for (int i = 0; i < annotatedFieldCount; i++) {
332                 final String name = annotatedFieldNames[i];
333                 final String sig = annotatedFieldSigs[i];
334                 annotatedFieldRefs[i] = pool.addFieldRef(className, name, sig);
335                 affirm(annotatedFieldRefs[i] != null);
336             }
337         }
338         affirm(annotatedFieldRefs != null);
339         return annotatedFieldRefs;
340     }
341 
342     /***
343      * Returns the constant field refs for the key fields.
344      */
345     private ConstFieldRef[] getKeyFieldRefs()
346     {
347         // get field references if not done yet
348         if (keyFieldRefs == null) {
349             final ConstFieldRef[] annotatedFieldRefs = getAnnotatedFieldRefs();
350             final int keyFieldCount = analyzer.getKeyFieldCount();
351             final int[] keyFieldIndexes = analyzer.getKeyFieldIndexes();
352             affirm(keyFieldIndexes.length == keyFieldCount);
353             
354             // add field references
355             keyFieldRefs = new ConstFieldRef[keyFieldCount];
356             for (int i = 0; i < keyFieldCount; i++) {
357                 keyFieldRefs[i] = annotatedFieldRefs[keyFieldIndexes[i]];
358                 affirm(keyFieldRefs[i] != null);
359             }
360         }
361         affirm(keyFieldRefs != null);
362         return keyFieldRefs;
363     }
364 
365     /***
366      * Returns the constant field refs for the key fields of the key class.
367      */
368     private ConstFieldRef[] getKeyClassKeyFieldRefs()
369     {
370         // get field references if not done yet
371         if (keyClassKeyFieldRefs == null) {
372             final String keyClassName = analyzer.getKeyClassName();
373             affirm(keyClassName != null);
374             final int keyFieldCount = analyzer.getKeyFieldCount();
375             final ConstFieldRef[] keyFieldRefs = getKeyFieldRefs();
376             affirm(keyFieldRefs.length == keyFieldCount);
377             
378             // add field references
379             keyClassKeyFieldRefs = new ConstFieldRef[keyFieldCount];
380             for (int i = 0; i < keyFieldCount; i++) {
381                 final ConstNameAndType nt = keyFieldRefs[i].nameAndType();
382                 final String name = nt.name().asString();
383                 final String sig = nt.signature().asString();
384                 keyClassKeyFieldRefs[i]
385                     = pool.addFieldRef(keyClassName, name, sig);
386                 affirm(keyClassKeyFieldRefs[i] != null);
387             }
388         }
389         affirm(keyClassKeyFieldRefs != null);
390         return keyClassKeyFieldRefs;
391     }
392 
393     /***
394      * Adds the code for throwing a IllegalArgumentException.
395      */
396     private Insn appendThrowJavaException(Insn insn,
397                                           String exceptionName,
398                                           String exceptionText)
399     {
400         affirm(insn != null);
401         affirm(exceptionName != null);
402         affirm(exceptionText != null);
403 
404         // throw exception
405         final String exceptionCtorName
406             = NameHelper.constructorName();
407         final String exceptionCtorSig
408             = NameHelper.constructorSig(JAVA_String_Sig);
409         insn = insn.append(
410             Insn.create(opc_new,
411                         pool.addClass(exceptionName)));
412         insn = insn.append(Insn.create(opc_dup));
413         insn = insn.append(
414             InsnUtils.stringConstant(
415                 exceptionText, pool));
416         insn = insn.append(
417             Insn.create(opc_invokespecial,
418                         pool.addMethodRef(
419                             exceptionName,
420                             exceptionCtorName,
421                             exceptionCtorSig)));
422         insn = insn.append(Insn.create(opc_athrow));
423 
424         affirm(insn != null);
425         return insn;
426     }
427 
428     /***
429      * Adds the code for handling if jdoStateManager field is null.
430      */
431     private Insn appendCheckStateManager(Insn insn,
432                                          int argStart,
433                                          String exceptionName,
434                                          String exceptionText)
435     {
436         affirm(insn != null);
437         affirm(exceptionName != null);
438         affirm(exceptionText != null);
439         
440         // throw exception if sm == null
441         final InsnTarget body = new InsnTarget();
442         insn = insn.append(InsnUtils.aLoad(argStart, pool));
443         insn = insn.append(
444             Insn.create(
445                 opc_getfield,
446                 getjdoStateManagerFieldRef()));
447         insn = insn.append(Insn.create(opc_ifnonnull, body));
448         insn = appendThrowJavaException(insn, exceptionName, exceptionText);
449         insn = insn.append(body);
450 
451         affirm(insn != null);
452         return insn;
453     }
454 
455     /***
456      * Adds the code for handling if an argument is null.
457      */
458     private Insn appendCheckVarNonNull(Insn insn,
459                                        int argStart,
460                                        String exceptionName,
461                                        String exceptionText)
462     {
463         affirm(insn != null);
464         affirm(exceptionName != null);
465         affirm(exceptionText != null);
466 
467         // throw exception if obj == null
468         final InsnTarget body = new InsnTarget();
469         insn = insn.append(InsnUtils.aLoad(argStart, pool));
470         insn = insn.append(Insn.create(opc_ifnonnull, body));
471         insn = appendThrowJavaException(insn, exceptionName, exceptionText);
472         insn = insn.append(body);
473 
474         affirm(insn != null);
475         return insn;
476     }
477 
478     /***
479      * Adds the code for handling if an argument is instance of a class.
480      */
481     private Insn appendCheckVarInstanceOf(Insn insn,
482                                           int argStart,
483                                           ConstClass constClass,
484                                           String exceptionName,
485                                           String exceptionText)
486     {
487         affirm(insn != null);
488         affirm(constClass != null);
489         affirm(exceptionName != null);
490         affirm(exceptionText != null);
491 
492         // throw exception if obj not instance of class
493         final InsnTarget body = new InsnTarget();
494         insn = insn.append(InsnUtils.aLoad(argStart, pool));
495         insn = insn.append(Insn.create(opc_instanceof, constClass));
496         insn = insn.append(Insn.create(opc_ifne, body));
497         insn = appendThrowJavaException(insn, exceptionName, exceptionText);
498         insn = insn.append(body);
499 
500         affirm(insn != null);
501         return insn;
502     }
503 
504     // ----------------------------------------------------------------------
505 
506     /***
507      * Builds an empty method (for debugging).
508      *
509      * public void XXX() {
510      * }
511      */
512     public void addNullMethod(final String methodName,
513                               final String methodSig,
514                               final int accessFlags)
515     {
516         // assumed nonstatic call; otherwise subtract 'this' from maxStack
517         affirm((accessFlags & ACCStatic) == 0);
518         final ExceptionsAttribute exceptAttr = null;
519 
520         // begin of method body
521         final InsnTarget begin = new InsnTarget();
522         Insn insn = begin;
523 
524         // end of method body
525         insn = insn.append(Insn.create(opc_return));
526 
527         final CodeAttribute codeAttr
528             = new CodeAttribute(getCodeAttributeUtf8(),
529                                 0, // maxStack
530                                 countMethodArgWords(methodSig), // maxLocals
531                                 begin,
532                                 new ExceptionTable(),
533                                 new AttributeVector());
534         augmenter.addMethod(methodName, methodSig, accessFlags,
535                             codeAttr, exceptAttr);
536     }
537 
538     // ----------------------------------------------------------------------
539     // Generic Augmentation
540     // ----------------------------------------------------------------------
541 
542     /***
543      * Build the jdoSetStateManager method for the class.
544      *
545      * public final synchronized void jdoReplaceStateManager(javax.jdo.StateManager sm)
546      * {
547      *     final javax.jdo.StateManager s = this.jdoStateManager;
548      *     if (s != null) {
549      *         this.jdoStateManager = s.replacingStateManager(this, sm);
550      *         return;
551      *     }
552      *     // throws exception if not authorized
553      *     JDOImplHelper.checkAuthorizedStateManager(sm);
554      *     this.jdoStateManager = sm;
555      *     this.jdoFlags = LOAD_REQUIRED;
556      * }
557      */
558     public void addJDOReplaceStateManager()
559     {
560         final String methodName = JDO_PC_jdoReplaceStateManager_Name;
561         final String methodSig = JDO_PC_jdoReplaceStateManager_Sig;
562         final int accessFlags = JDO_PC_jdoReplaceStateManager_Mods;
563         final ExceptionsAttribute exceptAttr = null;
564 
565         //^olsen: exceptAttr != null ???
566 
567         // begin of method body
568         final InsnTarget begin = new InsnTarget();
569         Insn insn = begin;
570 
571         // store the sm field into local var
572         insn = insn.append(Insn.create(opc_aload_0));
573         insn = insn.append(
574             Insn.create(
575                 opc_getfield,
576                 getjdoStateManagerFieldRef()));
577         insn = insn.append(Insn.create(opc_astore_2));
578 
579         // test the sm field and call the sm if nonnull
580         final InsnTarget check = new InsnTarget();
581         insn = insn.append(Insn.create(opc_aload_2));
582         insn = insn.append(Insn.create(opc_ifnull, check));
583 
584         // load 'this' on the stack
585         insn = insn.append(Insn.create(opc_aload_0));
586 
587         // call the sm's method with 'this' and 'sm' arguments
588         insn = insn.append(Insn.create(opc_aload_2));
589         insn = insn.append(Insn.create(opc_aload_0));
590         insn = insn.append(Insn.create(opc_aload_1));
591         insn = insn.append(
592             new InsnInterfaceInvoke(
593                 pool.addInterfaceMethodRef(
594                     JDO_StateManager_Path,
595                     JDO_SM_replacingStateManager_Name,
596                     JDO_SM_replacingStateManager_Sig),
597                 countMethodArgWords(JDO_SM_replacingStateManager_Sig)));
598 
599         // put result value to sm field and return
600         insn = insn.append(
601             Insn.create(opc_putfield,
602                         getjdoStateManagerFieldRef()));
603         insn = insn.append(Insn.create(opc_return));
604 
605         // invoke JDOImplHelper.checkAuthorizedStateManager with 'sm' argument
606         insn = insn.append(check);
607         insn = insn.append(Insn.create(opc_aload_1));
608         insn = insn.append(
609             Insn.create(opc_invokestatic,
610                         pool.addMethodRef(
611                             JDO_JDOImplHelper_Path,
612                             JDO_JDOImplHelper_checkAuthorizedStateManager_Name,
613                             JDO_JDOImplHelper_checkAuthorizedStateManager_Sig)));
614 
615         // put argument value to jdoStateManager field
616         insn = insn.append(Insn.create(opc_aload_0));
617         insn = insn.append(Insn.create(opc_aload_1));
618         insn = insn.append(
619             Insn.create(opc_putfield,
620                         getjdoStateManagerFieldRef()));
621 
622         // reset flags to LOAD_REQUIRED
623         insn = insn.append(Insn.create(opc_aload_0));
624         insn = insn.append(Insn.create(opc_iconst_1));
625         insn = insn.append(
626             Insn.create(opc_putfield,
627                         getjdoFlagsFieldRef()));
628 
629         // end of method body
630         insn = insn.append(Insn.create(opc_return));
631 
632         final CodeAttribute codeAttr
633             = new CodeAttribute(getCodeAttributeUtf8(),
634                                 4, // maxStack
635                                 3, // maxLocals
636                                 begin,
637                                 new ExceptionTable(),
638                                 new AttributeVector());
639         augmenter.addMethod(methodName, methodSig, accessFlags,
640                             codeAttr, exceptAttr);
641     }
642 
643     // ----------------------------------------------------------------------
644 
645     /***
646      * Build the jdoReplaceFlags method for the class.
647      *
648      * public final void jdoReplaceFlags()
649      * {
650      *     final StateManager sm = this.jdoStateManager;
651      *     if (sm != null) {
652      *         this.jdoFlags = sm.replacingFlags(this);
653      *     }
654      * }
655      */
656     public void addJDOReplaceFlags()
657     {
658         final String methodName = JDO_PC_jdoReplaceFlags_Name;
659         final String methodSig = JDO_PC_jdoReplaceFlags_Sig;
660         final int accessFlags = JDO_PC_jdoReplaceFlags_Mods;
661         final ExceptionsAttribute exceptAttr = null;
662 
663         // begin of method body
664         final InsnTarget begin = new InsnTarget();
665         Insn insn = begin;
666 
667         // store the sm field into local var
668         insn = insn.append(Insn.create(opc_aload_0));
669         insn = insn.append(
670             Insn.create(
671                 opc_getfield,
672                 getjdoStateManagerFieldRef()));
673         insn = insn.append(Insn.create(opc_astore_1));
674 
675         // test the sm field and goto end if null
676         final InsnTarget end = new InsnTarget();
677         insn = insn.append(Insn.create(opc_aload_1));
678         insn = insn.append(Insn.create(opc_ifnull, end));
679 
680         // load 'this' on the stack
681         insn = insn.append(Insn.create(opc_aload_0));
682 
683         // call the sm's method with 'this' argument
684         insn = insn.append(Insn.create(opc_aload_1));
685         insn = insn.append(Insn.create(opc_aload_0));
686         insn = insn.append(
687             new InsnInterfaceInvoke(
688                 pool.addInterfaceMethodRef(
689                     JDO_StateManager_Path,
690                     JDO_SM_replacingFlags_Name,
691                     JDO_SM_replacingFlags_Sig),
692                 countMethodArgWords(JDO_SM_replacingFlags_Sig)));
693 
694         // put result value to flags field
695         insn = insn.append(
696             Insn.create(opc_putfield,
697                         getjdoFlagsFieldRef()));
698 
699         // end of method body
700         insn = insn.append(end);
701         insn = insn.append(Insn.create(opc_return));
702 
703         final CodeAttribute codeAttr
704             = new CodeAttribute(getCodeAttributeUtf8(),
705                                 3, // maxStack
706                                 2, // maxLocals
707                                 begin,
708                                 new ExceptionTable(),
709                                 new AttributeVector());
710         augmenter.addMethod(methodName, methodSig, accessFlags,
711                             codeAttr, exceptAttr);
712     }
713 
714     // ----------------------------------------------------------------------
715 
716     /***
717      * Build the jdoMakeDirty method for the class.
718      *
719      * public final void jdoMakeDirty(java.lang.String fieldname)
720      * {
721      *     final javax.jdo.StateManager sm = this.jdoStateManager;
722      *     if (sm != null) {
723      *         sm.makeDirty(this, fieldname);
724      *     }
725      * }
726      */
727     public void addJDOMakeDirtyMethod()
728     {
729         final String methodName = JDO_PC_jdoMakeDirty_Name;
730         final String methodSig = JDO_PC_jdoMakeDirty_Sig;
731         final int accessFlags = JDO_PC_jdoMakeDirty_Mods;
732         final ExceptionsAttribute exceptAttr = null;
733 
734         // begin of method body
735         final InsnTarget begin = new InsnTarget();
736         Insn insn = begin;
737 
738         // store the sm field into local var
739         insn = insn.append(Insn.create(opc_aload_0));
740         insn = insn.append(
741             Insn.create(
742                 opc_getfield,
743                 getjdoStateManagerFieldRef()));
744         insn = insn.append(Insn.create(opc_astore_2));
745 
746         // test the sm field and goto end if null
747         final InsnTarget end = new InsnTarget();
748         insn = insn.append(Insn.create(opc_aload_2));
749         insn = insn.append(Insn.create(opc_ifnull, end));
750 
751         // call the sm's method with 'this' and 'fieldname' arguments
752         insn = insn.append(Insn.create(opc_aload_2));
753         insn = insn.append(Insn.create(opc_aload_0));
754         insn = insn.append(Insn.create(opc_aload_1));
755         insn = insn.append(
756             new InsnInterfaceInvoke(
757                 pool.addInterfaceMethodRef(
758                     JDO_StateManager_Path,
759                     JDO_SM_makeDirty_Name,
760                     JDO_SM_makeDirty_Sig),
761                 countMethodArgWords(JDO_SM_makeDirty_Sig)));
762 
763         // end of method body
764         insn = insn.append(end);
765         insn = insn.append(Insn.create(opc_return));
766 
767         final CodeAttribute codeAttr
768             = new CodeAttribute(getCodeAttributeUtf8(),
769                                 3, // maxStack
770                                 3, // maxLocals
771                                 begin,
772                                 new ExceptionTable(),
773                                 new AttributeVector());
774         augmenter.addMethod(methodName, methodSig, accessFlags,
775                             codeAttr, exceptAttr);
776     }
777 
778     // ----------------------------------------------------------------------
779 
780     /***
781      * Build the jdoPreSerialize method for the class.
782      *
783      * protected final void jdoPreSerialize()
784      * {
785      *     final javax.jdo.StateManager sm = this.jdoStateManager;
786      *     if (sm != null) {
787      *         sm.preSerialize(this);
788      *     }
789      * }
790      */
791     public void addJDOPreSerializeMethod()
792     {
793         final String methodName = JDO_PC_jdoPreSerialize_Name;
794         final String methodSig = JDO_PC_jdoPreSerialize_Sig;
795         final int accessFlags = JDO_PC_jdoPreSerialize_Mods;
796         final ExceptionsAttribute exceptAttr = null;
797 
798         // begin of method body
799         final InsnTarget begin = new InsnTarget();
800         Insn insn = begin;
801 
802         // store the sm field into local var
803         insn = insn.append(Insn.create(opc_aload_0));
804         insn = insn.append(
805             Insn.create(
806                 opc_getfield,
807                 getjdoStateManagerFieldRef()));
808         insn = insn.append(Insn.create(opc_astore_1));
809 
810         // test the sm field and goto end if null
811         final InsnTarget end = new InsnTarget();
812         insn = insn.append(Insn.create(opc_aload_1));
813         insn = insn.append(Insn.create(opc_ifnull, end));
814 
815         // call the sm's method with 'this' argument
816         insn = insn.append(Insn.create(opc_aload_1));
817         insn = insn.append(Insn.create(opc_aload_0));
818         insn = insn.append(
819             new InsnInterfaceInvoke(
820                 pool.addInterfaceMethodRef(
821                     JDO_StateManager_Path,
822                     JDO_SM_preSerialize_Name,
823                     JDO_SM_preSerialize_Sig),
824                 countMethodArgWords(JDO_SM_preSerialize_Sig)));
825 
826         // end of method body
827         insn = insn.append(end);
828         insn = insn.append(Insn.create(opc_return));
829 
830         final CodeAttribute codeAttr
831             = new CodeAttribute(getCodeAttributeUtf8(),
832                                 2, // maxStack
833                                 2, // maxLocals
834                                 begin,
835                                 new ExceptionTable(),
836                                 new AttributeVector());
837         augmenter.addMethod(methodName, methodSig, accessFlags,
838                             codeAttr, exceptAttr);
839     }
840 
841     // ----------------------------------------------------------------------
842 
843     /***
844      * Build the writeObject method for the class.
845      *
846      * private void writeObject(java.io.ObjectOutputStream out) 
847      *    throws java.io.IOException
848      * {
849      *    jdoPreSerialize();
850      *    out.defaultWriteObject();
851      * }
852      */
853     public void addWriteObjectMethod()
854     {
855         final String methodName = JAVA_Object_writeObject_Name;
856         final String methodSig = JAVA_Object_writeObject_Sig;
857         final int accessFlags = JAVA_Object_writeObject_Mods;
858         final ExceptionsAttribute exceptAttr
859             = new ExceptionsAttribute(
860                 pool.addUtf8(ExceptionsAttribute.expectedAttrName),
861                 pool.addClass("java/io/IOException"));
862         
863         // begin of method body
864         final InsnTarget begin = new InsnTarget();
865         Insn insn = begin;
866 
867         // call jdoPreSerialize 
868         insn = insn.append(Insn.create(opc_aload_0));
869         insn = insn.append(
870             Insn.create(opc_invokevirtual,
871                         pool.addMethodRef(
872                             className,
873                             JDO_PC_jdoPreSerialize_Name,
874                             JDO_PC_jdoPreSerialize_Sig)));
875 
876         // call out.defaultWriteObject();
877         insn = insn.append(Insn.create(opc_aload_1));
878         insn = insn.append(
879             Insn.create(opc_invokevirtual,
880                         pool.addMethodRef(
881                             JAVA_ObjectOutputStream_Path,
882                             JAVA_ObjectOutputStream_defaultWriteObject_Name,
883                             JDO_PC_jdoPreSerialize_Sig)));
884         
885         // end of method body
886         insn = insn.append(Insn.create(opc_return));
887 
888         final CodeAttribute codeAttr
889             = new CodeAttribute(getCodeAttributeUtf8(),
890                                 1, // maxStack
891                                 2, // maxLocals
892                                 begin,
893                                 new ExceptionTable(),
894                                 new AttributeVector());
895         augmenter.addMethod(methodName, methodSig, accessFlags,
896                             codeAttr, exceptAttr);
897         
898     }
899 
900     // ----------------------------------------------------------------------
901 
902     /***
903      * Adds a call to jdoPreSerialize as first statement to the existing method.
904      */
905     public void addJDOPreSerializeCall(String methodName, String methodSig)
906     {
907         final ExceptionsAttribute exceptAttr = null;
908 
909         // begin of method body
910         final InsnTarget begin = new InsnTarget();
911         Insn insn = begin;
912         
913         // invoke jdoPreSerialize
914         insn = insn.append(Insn.create(opc_aload_0));
915         insn = insn.append(
916             Insn.create(opc_invokevirtual,
917                         pool.addMethodRef(
918                             className,
919                             JDO_PC_jdoPreSerialize_Name,
920                             JDO_PC_jdoPreSerialize_Sig)));
921 
922         // create code block to be added
923         final CodeAttribute codeAttr
924             = new CodeAttribute(getCodeAttributeUtf8(),
925                                 1, // maxStack
926                                 0, // maxLocals
927                                 begin,
928                                 new ExceptionTable(),
929                                 new AttributeVector());
930 
931         augmenter.prependMethod(methodName, methodSig, codeAttr, exceptAttr);
932     }
933 
934     // ----------------------------------------------------------------------
935 
936     /***
937      * Build an interrogative method for the class.
938      */
939     public void addJDOIsPersistentMethod()
940     {
941         addJDOInterrogativeMethod(JDO_PC_jdoIsPersistent_Name,
942                                   JDO_PC_jdoIsPersistent_Sig,
943                                   JDO_PC_jdoIsPersistent_Mods,
944                                   JDO_SM_isPersistent_Name,
945                                   JDO_SM_isPersistent_Sig);
946     }
947     
948     /***
949      * Build an interrogative method for the class.
950      */
951     public void addJDOIsTransactionalMethod()
952     {
953         addJDOInterrogativeMethod(JDO_PC_jdoIsTransactional_Name,
954                                   JDO_PC_jdoIsTransactional_Sig,
955                                   JDO_PC_jdoIsTransactional_Mods,
956                                   JDO_SM_isTransactional_Name,
957                                   JDO_SM_isTransactional_Sig);
958     }
959     
960     /***
961      * Build an interrogative method for the class.
962      */
963     public void addJDOIsNewMethod()
964     {
965         addJDOInterrogativeMethod(JDO_PC_jdoIsNew_Name,
966                                   JDO_PC_jdoIsNew_Sig,
967                                   JDO_PC_jdoIsNew_Mods,
968                                   JDO_SM_isNew_Name,
969                                   JDO_SM_isNew_Sig);
970     }
971     
972     /***
973      * Build an interrogative method for the class.
974      */
975     public void addJDOIsDeletedMethod()
976     {
977         addJDOInterrogativeMethod(JDO_PC_jdoIsDeleted_Name,
978                                   JDO_PC_jdoIsDeleted_Sig,
979                                   JDO_PC_jdoIsDeleted_Mods,
980                                   JDO_SM_isDeleted_Name,
981                                   JDO_SM_isDeleted_Sig);
982     }
983     
984     /***
985      * Build an interrogative method for the class.
986      */
987     public void addJDOIsDirtyMethod()
988     {
989         addJDOInterrogativeMethod(JDO_PC_jdoIsDirty_Name,
990                                   JDO_PC_jdoIsDirty_Sig,
991                                   JDO_PC_jdoIsDirty_Mods,
992                                   JDO_SM_isDirty_Name,
993                                   JDO_SM_isDirty_Sig);
994     }
995     
996     /***
997      * Build an interrogative method for the class.
998      */
999     public void addJDOIsDetachedMethod()
1000     {
1001         // TODO: generate real method body
1002         addNotYetImplementedMethod(JDO_PC_jdoIsDetached_Name,
1003                                    JDO_PC_jdoIsDetached_Sig,
1004                                    JDO_PC_jdoIsDetached_Mods);
1005     }
1006     
1007     /***
1008      * Build an interrogative method named methodName for the class.
1009      *
1010      * public boolean isXXX() {
1011      *     final StateManager sm = this.jdoStateManager;
1012      *     if (sm == null)
1013      *         return false;
1014      *     return sm.isXXXX(this);
1015      * }
1016      */
1017     private void addJDOInterrogativeMethod(final String methodName,
1018                                            final String methodSig,
1019                                            final int accessFlags,
1020                                            final String delegateName,
1021                                            final String delegateSig)
1022     {
1023         final ExceptionsAttribute exceptAttr = null;
1024 
1025         // begin of method body
1026         final InsnTarget begin = new InsnTarget();
1027         Insn insn = begin;
1028 
1029         // store the sm field into local var
1030         insn = insn.append(Insn.create(opc_aload_0));
1031         insn = insn.append(
1032             Insn.create(
1033                 opc_getfield,
1034                 getjdoStateManagerFieldRef()));
1035         insn = insn.append(Insn.create(opc_astore_1));
1036 
1037         // test the sm field and do the call if nonnull
1038         InsnTarget noncall = new InsnTarget();
1039         insn = insn.append(Insn.create(opc_aload_1));
1040         insn = insn.append(Insn.create(opc_ifnull, noncall));
1041 
1042         // call the sm's method with 'this' argument and return
1043         insn = insn.append(Insn.create(opc_aload_1));
1044         insn = insn.append(Insn.create(opc_aload_0));
1045         insn = insn.append(
1046             new InsnInterfaceInvoke(
1047                 pool.addInterfaceMethodRef(
1048                     JDO_StateManager_Path,
1049                     delegateName,
1050                     delegateSig),
1051                 countMethodArgWords(delegateSig)));
1052         insn = insn.append(Insn.create(opc_ireturn));
1053 
1054         // return false
1055         insn = insn.append(noncall);
1056         insn = insn.append(Insn.create(opc_iconst_0));
1057 
1058         // end of method body
1059         insn = insn.append(Insn.create(opc_ireturn));
1060 
1061         final CodeAttribute codeAttr
1062             = new CodeAttribute(getCodeAttributeUtf8(),
1063                                 2, // maxStack
1064                                 2, // maxLocals
1065                                 begin,
1066                                 new ExceptionTable(),
1067                                 new AttributeVector());
1068         augmenter.addMethod(methodName, methodSig, accessFlags,
1069                             codeAttr, exceptAttr);
1070     }
1071 
1072     // ----------------------------------------------------------------------
1073 
1074     /***
1075      * Build an object query method for the class.
1076      */
1077     public void addJDOGetPersistenceManagerMethod()
1078     {
1079         addJDOObjectQueryMethod(JDO_PC_jdoGetPersistenceManager_Name,
1080                                 JDO_PC_jdoGetPersistenceManager_Sig,
1081                                 JDO_PC_jdoGetPersistenceManager_Mods,
1082                                 JDO_SM_getPersistenceManager_Name,
1083                                 JDO_SM_getPersistenceManager_Sig);
1084     }
1085 
1086     /***
1087      * Build an object query method for the class.
1088      */
1089     public void addJDOGetObjectIdMethod()
1090     {
1091         addJDOObjectQueryMethod(JDO_PC_jdoGetObjectId_Name,
1092                                 JDO_PC_jdoGetObjectId_Sig,
1093                                 JDO_PC_jdoGetObjectId_Mods,
1094                                 JDO_SM_getObjectId_Name,
1095                                 JDO_SM_getObjectId_Sig);
1096     }
1097 
1098     /***
1099      * Build an object query method for the class.
1100      */
1101     public void addJDOGetTransactionalObjectIdMethod()
1102     {
1103         addJDOObjectQueryMethod(JDO_PC_jdoGetTransactionalObjectId_Name,
1104                                 JDO_PC_jdoGetTransactionalObjectId_Sig,
1105                                 JDO_PC_jdoGetTransactionalObjectId_Mods,
1106                                 JDO_SM_getTransactionalObjectId_Name,
1107                                 JDO_SM_getTransactionalObjectId_Sig);
1108     }
1109 
1110     /***
1111      * Build an object query method for the class.
1112      */
1113     public void addJDOGetVersionMethod()
1114     {
1115         // TODO: generate real method body
1116         addNotYetImplementedMethod(JDO_PC_jdoGetVersion_Name,
1117                                    JDO_PC_jdoGetVersion_Sig,
1118                                    JDO_PC_jdoGetVersion_Mods);
1119     }
1120 
1121     /***
1122      * Build an object query method for the class.
1123      *
1124      * public final XXX jdoGetYYY()
1125      * {
1126      *     final javax.jdo.StateManager sm = this.jdoStateManager;
1127      *     if (sm != null) {
1128      *         return sm.getYYY(this);
1129      *     }
1130      *     return null;
1131      * }
1132      */
1133     private void addJDOObjectQueryMethod(final String methodName,
1134                                          final String methodSig,
1135                                          final int accessFlags,
1136                                          final String delegateName,
1137                                          final String delegateSig)
1138     {
1139         final ExceptionsAttribute exceptAttr = null;
1140 
1141         // begin of method body
1142         final InsnTarget begin = new InsnTarget();
1143         Insn insn = begin;
1144 
1145         // store the sm field into local var
1146         insn = insn.append(Insn.create(opc_aload_0));
1147         insn = insn.append(
1148             Insn.create(
1149                 opc_getfield,
1150                 getjdoStateManagerFieldRef()));
1151         insn = insn.append(Insn.create(opc_astore_1));
1152 
1153         // test the sm field and do the call if nonnull
1154         InsnTarget noncall = new InsnTarget();
1155         insn = insn.append(Insn.create(opc_aload_1));
1156         insn = insn.append(Insn.create(opc_ifnull, noncall));
1157 
1158         // call the sm's method with 'this' argument and return
1159         insn = insn.append(Insn.create(opc_aload_1));
1160         insn = insn.append(Insn.create(opc_aload_0));
1161         insn = insn.append(
1162             new InsnInterfaceInvoke(
1163                 pool.addInterfaceMethodRef(
1164                     JDO_StateManager_Path,
1165                     delegateName,
1166                     delegateSig),
1167                 countMethodArgWords(delegateSig)));
1168         insn = insn.append(Insn.create(opc_areturn));
1169 
1170         // return null
1171         insn = insn.append(noncall);
1172         insn = insn.append(Insn.create(opc_aconst_null));
1173 
1174         // end of method body
1175         insn = insn.append(Insn.create(opc_areturn));
1176 
1177         final CodeAttribute codeAttr
1178             = new CodeAttribute(getCodeAttributeUtf8(),
1179                                 2, // maxStack
1180                                 2, // maxLocals
1181                                 begin,
1182                                 new ExceptionTable(),
1183                                 new AttributeVector());
1184         augmenter.addMethod(methodName, methodSig, accessFlags,
1185                             codeAttr, exceptAttr);
1186     }
1187 
1188     // ----------------------------------------------------------------------
1189 
1190     /***
1191      * Build the jdoArrayArgumentIteration method for the class.
1192      */
1193     public void addJDOProvideFieldsMethod()
1194     {
1195         addJDOArrayArgumentIterationMethod(JDO_PC_jdoProvideFields_Name,
1196                                            JDO_PC_jdoProvideFields_Sig,
1197                                            JDO_PC_jdoProvideFields_Mods,
1198                                            JDO_PC_jdoProvideField_Name,
1199                                            JDO_PC_jdoProvideField_Sig);
1200     }
1201 
1202     /***
1203      * Build the jdoArrayArgumentIteration method for the class.
1204      */
1205     public void addJDOReplaceFieldsMethod()
1206     {
1207         addJDOArrayArgumentIterationMethod(JDO_PC_jdoReplaceFields_Name,
1208                                            JDO_PC_jdoReplaceFields_Sig,
1209                                            JDO_PC_jdoReplaceFields_Mods,
1210                                            JDO_PC_jdoReplaceField_Name,
1211                                            JDO_PC_jdoReplaceField_Sig);
1212     }
1213 
1214     /***
1215      * Build the jdoArrayArgumentIteration method for the class.
1216      *
1217      * public final void jdoXXXFields(int[] fieldnumbers)
1218      * {
1219      *     final int n = fieldnumbers.length;
1220      *     for (int i = 0; i < n; i++) {
1221      *         this.jdoXXXField(fieldnumbers[i]);
1222      *     }
1223      * }
1224      */
1225     public void addJDOArrayArgumentIterationMethod(final String methodName,
1226                                                    final String methodSig,
1227                                                    final int accessFlags,
1228                                                    final String delegateName,
1229                                                    final String delegateSig)
1230     {
1231         final ExceptionsAttribute exceptAttr = null;
1232 
1233         // begin of method body
1234         final InsnTarget begin = new InsnTarget();
1235         Insn insn = begin;
1236 
1237         // check arg
1238         insn = appendCheckVarNonNull(insn, 1,
1239                                      JAVA_IllegalArgumentException_Path,
1240                                      "arg1");
1241 
1242         // store the array argument length into local var
1243         insn = insn.append(Insn.create(opc_aload_1));
1244         insn = insn.append(Insn.create(opc_arraylength));
1245         insn = insn.append(Insn.create(opc_istore_2));
1246 
1247         // init loop counter and goto loop check
1248         final InsnTarget loopcheck = new InsnTarget();
1249         insn = insn.append(Insn.create(opc_iconst_0));
1250         insn = insn.append(Insn.create(opc_istore_3));
1251         insn = insn.append(Insn.create(opc_goto, loopcheck));
1252 
1253         // loop body: call self-delegating method with array element
1254         final InsnTarget loopbody = new InsnTarget();
1255         insn = insn.append(loopbody);
1256         insn = insn.append(Insn.create(opc_aload_0));
1257 
1258         // select element from array argument at loop counter
1259         insn = insn.append(Insn.create(opc_aload_1));
1260         insn = insn.append(Insn.create(opc_iload_3));
1261         insn = insn.append(Insn.create(opc_iaload));
1262 
1263         // call self-delegating method
1264         insn = insn.append(
1265             Insn.create(opc_invokevirtual,
1266                         pool.addMethodRef(
1267                             className,
1268                             delegateName,
1269                             delegateSig)));
1270 
1271         // loop counter increment
1272         insn = insn.append(new InsnIInc(3, 1));
1273 
1274         // loop termination check
1275         insn = insn.append(loopcheck);
1276         insn = insn.append(Insn.create(opc_iload_3));
1277         insn = insn.append(Insn.create(opc_iload_2));
1278         insn = insn.append(Insn.create(opc_if_icmplt, loopbody));
1279 
1280         // end of method body
1281         insn = insn.append(Insn.create(opc_return));
1282 
1283         final CodeAttribute codeAttr
1284             = new CodeAttribute(getCodeAttributeUtf8(),
1285                                 3, // maxStack
1286                                 4, // maxLocals
1287                                 begin,
1288                                 new ExceptionTable(),
1289                                 new AttributeVector());
1290         augmenter.addMethod(methodName, methodSig, accessFlags,
1291                             codeAttr, exceptAttr);
1292     }
1293 
1294     // ----------------------------------------------------------------------
1295 
1296     /***
1297      * Build the sunjdoClassForName method for the class.
1298      *
1299      * public final Class sunjdoClassForName(java.lang.String classname)
1300      * {
1301      *     try {
1302      *         return Class.forName(classname);
1303      *     catch (ClassNotFoundException ex) {
1304      *         throw new NoClassDefFoundError(ex.getMessage());
1305      *     }
1306      * }
1307      */
1308     public void addSunJDOClassForNameMethod()
1309     {
1310         final String methodName = SUNJDO_PC_sunjdoClassForName_Name;
1311         final String methodSig = SUNJDO_PC_sunjdoClassForName_Sig;
1312         final int accessFlags = SUNJDO_PC_sunjdoClassForName_Mods;
1313         final ExceptionsAttribute exceptAttr = null;
1314 
1315         // begin of method body
1316         final InsnTarget begin = new InsnTarget();
1317         Insn insn = begin;
1318 
1319         // invoke the Class.forName(String) method with argument
1320         insn = insn.append(Insn.create(opc_aload_0));
1321         insn = insn.append(
1322             Insn.create(opc_invokestatic,
1323                         pool.addMethodRef(
1324                             JAVA_Class_Path,
1325                             JAVA_Class_forName_Name,
1326                             JAVA_Class_forName_Sig)));
1327 
1328         // end of method body
1329         insn = insn.append(Insn.create(opc_areturn));
1330 
1331         // begin of exception handler
1332         final InsnTarget end = new InsnTarget();
1333         final InsnTarget beginHandler = end;
1334         insn = insn.append(beginHandler);
1335 
1336         // create NoClassDefFoundError with message from caught exception
1337         insn = insn.append(Insn.create(opc_astore_1));
1338         insn = insn.append(
1339             Insn.create(opc_new,
1340                         pool.addClass(JAVA_NoClassDefFoundError_Path)));
1341         insn = insn.append(Insn.create(opc_dup));
1342         insn = insn.append(Insn.create(opc_aload_1));
1343         insn = insn.append(
1344             Insn.create(
1345                 opc_invokevirtual,
1346                 pool.addMethodRef(
1347                     JAVA_Throwable_Path,
1348                     JAVA_Throwable_getMessage_Name,
1349                     JAVA_Throwable_getMessage_Sig)));
1350         insn = insn.append(
1351             Insn.create(
1352                 opc_invokespecial,
1353                 pool.addMethodRef(
1354                     JAVA_NoClassDefFoundError_Path,
1355                     JAVA_NoClassDefFoundError_NoClassDefFoundError_Name,
1356                     JAVA_NoClassDefFoundError_NoClassDefFoundError_Sig)));
1357 
1358         // end of exception handler
1359         insn = insn.append(Insn.create(opc_athrow));
1360 
1361         // create exception table
1362         final ConstClass catchType
1363             = pool.addClass(JAVA_ClassNotFoundException_Path);
1364         final ExceptionRange exceptionRange
1365             = new ExceptionRange(begin, end, beginHandler, catchType);
1366         final ExceptionTable exceptionTable
1367             = new ExceptionTable();
1368         exceptionTable.addElement(exceptionRange);
1369 
1370         final CodeAttribute codeAttr
1371             = new CodeAttribute(getCodeAttributeUtf8(),
1372                                 3, // maxStack
1373                                 3, // maxLocals
1374                                 begin,
1375                                 exceptionTable,
1376                                 new AttributeVector());
1377         augmenter.addMethod(methodName, methodSig, accessFlags,
1378                             codeAttr, exceptAttr);
1379     }
1380 
1381     // ----------------------------------------------------------------------
1382     // Specific Augmentation
1383     // ----------------------------------------------------------------------
1384     
1385     /***
1386      * Build the jdoGetManagedFieldCount method for the class.
1387      *
1388      * protected static int jdoGetManagedFieldCount()
1389      * {
1390      *     return jdoInheritedFieldCount + X;
1391      * }
1392      */
1393     public void addJDOGetManagedFieldCountMethod()
1394     {
1395         final String methodName = JDO_PC_jdoGetManagedFieldCount_Name;
1396         final String methodSig = JDO_PC_jdoGetManagedFieldCount_Sig;
1397         final int accessFlags = JDO_PC_jdoGetManagedFieldCount_Mods;
1398         final ExceptionsAttribute exceptAttr = null;
1399 
1400         final int managedFieldCount = analyzer.getManagedFieldCount();
1401         affirm(managedFieldCount >= 0);
1402 
1403         // begin of method body
1404         final InsnTarget begin = new InsnTarget();
1405         Insn insn = begin;
1406 
1407         // push total (absolute) number of managed fields
1408         final boolean isPCRoot = analyzer.isAugmentableAsRoot();
1409         if (isPCRoot) {
1410             insn = insn.append(InsnUtils.integerConstant(managedFieldCount, pool));
1411         }
1412         else {
1413             final ConstClass superConstClass = classFile.superName();
1414             affirm(superConstClass != null);
1415             final String superClassName = superConstClass.asString();
1416             affirm(superClassName != null);
1417             // call the superclass' jdoGetManagedFieldCount method
1418             insn = insn.append(
1419                 Insn.create(opc_invokestatic,
1420                             pool.addMethodRef(
1421                                 superClassName,
1422                                 JDO_PC_jdoGetManagedFieldCount_Name,
1423                                 JDO_PC_jdoGetManagedFieldCount_Sig)));
1424             insn = insn.append(InsnUtils.integerConstant(managedFieldCount, pool));
1425             insn = insn.append(Insn.create(opc_iadd));
1426         }
1427 
1428         // end of method body
1429         insn = insn.append(Insn.create(opc_ireturn));
1430 
1431         final CodeAttribute codeAttr
1432             = new CodeAttribute(getCodeAttributeUtf8(),
1433                                 isPCRoot ? 1 : 2, // maxStack
1434                                 0, // maxLocals
1435                                 begin,
1436                                 new ExceptionTable(),
1437                                 new AttributeVector());
1438         augmenter.addMethod(methodName, methodSig, accessFlags,
1439                             codeAttr, exceptAttr);
1440     }
1441 
1442     // ----------------------------------------------------------------------
1443 
1444     /***
1445      * Adds the initialization code for the jdoInheritedFieldCount field.
1446      */
1447     private Insn initJdoInheritedFieldCount(Insn insn) 
1448     {
1449         affirm(insn != null);
1450 
1451         // invoke jdoGetManagedFieldCount if not PCRoot class
1452         final boolean isPCRoot = analyzer.isAugmentableAsRoot();
1453         if (isPCRoot) {
1454             insn = insn.append(Insn.create(opc_iconst_0));
1455         } else {
1456             final ConstClass superConstClass = classFile.superName();
1457             affirm(superConstClass != null);
1458             final String superClassName = superConstClass.asString();
1459             affirm(superClassName != null);
1460             insn = insn.append(
1461                 Insn.create(opc_invokestatic,
1462                             pool.addMethodRef(
1463                                 superClassName,
1464                                 JDO_PC_jdoGetManagedFieldCount_Name,
1465                                 JDO_PC_jdoGetManagedFieldCount_Sig)));
1466         }
1467 
1468         // store to field
1469         insn = insn.append(
1470             Insn.create(opc_putstatic,
1471                         pool.addFieldRef(
1472                             className,
1473                             JDO_PC_jdoInheritedFieldCount_Name,
1474                             JDO_PC_jdoInheritedFieldCount_Sig)));
1475 
1476         affirm(insn != null);
1477         return insn;
1478     }
1479     
1480     /***
1481      * Adds the initialization code for the jdoFieldNames field.
1482      */
1483     private Insn initJdoFieldNames(Insn insn)
1484     {
1485         affirm(insn != null);
1486 
1487         final int managedFieldCount = analyzer.getManagedFieldCount();
1488         final String[] managedFieldNames = analyzer.getAnnotatedFieldNames();
1489         affirm(managedFieldNames.length >= managedFieldCount);
1490         
1491         // create array
1492         affirm(NameHelper.elementPathForSig(JDO_PC_jdoFieldNames_Sig)
1493                .equals(JAVA_String_Path));
1494         insn = insn.append(InsnUtils.integerConstant(managedFieldCount, pool));
1495         insn = insn.append(
1496             Insn.create(opc_anewarray,
1497                         pool.addClass(JAVA_String_Path)));
1498 
1499         // initialize elements
1500         for (int i = 0; i < managedFieldCount; i++) {
1501             insn = insn.append(Insn.create(opc_dup));
1502             insn = insn.append(InsnUtils.integerConstant(i, pool));
1503             final String name = managedFieldNames[i];
1504             affirm(name != null);
1505             insn = insn.append(
1506                 InsnUtils.stringConstant(name, pool));
1507             insn = insn.append(Insn.create(opc_aastore));
1508         }
1509 
1510         // store to field
1511         insn = insn.append(
1512             Insn.create(opc_putstatic,
1513                         getjdoFieldNamesFieldRef()));
1514 
1515         affirm(insn != null);
1516         return insn;
1517     }
1518     
1519     /***
1520      * Adds the initialization code for the jdoFieldTypes field.
1521      */
1522     private Insn initJdoFieldTypes(Insn insn) 
1523     {
1524         affirm(insn != null);
1525 
1526         final int managedFieldCount = analyzer.getManagedFieldCount();
1527         final String[] managedFieldSigs = analyzer.getAnnotatedFieldSigs();
1528         affirm(managedFieldSigs.length >= managedFieldCount);
1529         
1530         // create array
1531         affirm(NameHelper.elementPathForSig(JDO_PC_jdoFieldTypes_Sig)
1532                .equals(JAVA_Class_Path));
1533         insn = insn.append(InsnUtils.integerConstant(managedFieldCount, pool));
1534         insn = insn.append(
1535             Insn.create(opc_anewarray,
1536                         pool.addClass(JAVA_Class_Path)));
1537 
1538         // initialize elements
1539         for (int i = 0; i < managedFieldCount; i++) {
1540             insn = insn.append(Insn.create(opc_dup));
1541             insn = insn.append(InsnUtils.integerConstant(i, pool));
1542             final String sig = managedFieldSigs[i];
1543             affirm(sig != null && sig.length() > 0);
1544 
1545             // push the class object
1546             // If the field is of primitive type then access the
1547             // corresponding wrapper class' static 'TYPE' field;
1548             // otherwise call generated, static method sunjdoClassForName.
1549             switch (sig.charAt(0)) {
1550             case 'Z':
1551                 // for primitive types, the wrapper's TYPE field is pushed
1552                 insn = insn.append(
1553                     Insn.create(opc_getstatic,
1554                                 pool.addFieldRef(
1555                                     JAVA_Boolean_Path,
1556                                     JAVA_Boolean_TYPE_Name,
1557                                     JAVA_Boolean_TYPE_Sig)));
1558                 break;
1559             case 'C':
1560                 // for primitive types, the wrapper's TYPE field is pushed
1561                 insn = insn.append(
1562                     Insn.create(opc_getstatic,
1563                                 pool.addFieldRef(
1564                                     JAVA_Character_Path,
1565                                     JAVA_Character_TYPE_Name,
1566                                     JAVA_Character_TYPE_Sig)));
1567                 break;
1568             case 'B':
1569                 // for primitive types, the wrapper's TYPE field is pushed
1570                 insn = insn.append(
1571                     Insn.create(opc_getstatic,
1572                                 pool.addFieldRef(
1573                                     JAVA_Byte_Path,
1574                                     JAVA_Byte_TYPE_Name,
1575                                     JAVA_Byte_TYPE_Sig)));
1576                 break;
1577             case 'S':
1578                 // for primitive types, the wrapper's TYPE field is pushed
1579                 insn = insn.append(
1580                     Insn.create(opc_getstatic,
1581                                 pool.addFieldRef(
1582                                     JAVA_Short_Path,
1583                                     JAVA_Short_TYPE_Name,
1584                                     JAVA_Short_TYPE_Sig)));
1585                 break;
1586             case 'I':
1587                 // for primitive types, the wrapper's TYPE field is pushed
1588                 insn = insn.append(
1589                     Insn.create(opc_getstatic,
1590                                 pool.addFieldRef(
1591                                     JAVA_Integer_Path,
1592                                     JAVA_Integer_TYPE_Name,
1593                                     JAVA_Integer_TYPE_Sig)));
1594                 break;
1595             case 'J':
1596                 // for primitive types, the wrapper's TYPE field is pushed
1597                 insn = insn.append(
1598                     Insn.create(opc_getstatic,
1599                                 pool.addFieldRef(
1600                                     JAVA_Long_Path,
1601                                     JAVA_Long_TYPE_Name,
1602                                     JAVA_Long_TYPE_Sig)));
1603                 break;
1604             case 'F':
1605                 // for primitive types, the wrapper's TYPE field is pushed
1606                 insn = insn.append(
1607                     Insn.create(opc_getstatic,
1608                                 pool.addFieldRef(
1609                                     JAVA_Float_Path,
1610                                     JAVA_Float_TYPE_Name,
1611                                     JAVA_Float_TYPE_Sig)));
1612                 break;
1613             case 'D':
1614                 // for primitive types, the wrapper's TYPE field is pushed
1615                 insn = insn.append(
1616                     Insn.create(opc_getstatic,
1617                                 pool.addFieldRef(
1618                                     JAVA_Double_Path,
1619                                     JAVA_Double_TYPE_Name,
1620                                     JAVA_Double_TYPE_Sig)));
1621                 break;
1622             case 'L':
1623                 // for object types, the signature is simply converted 
1624                 // into a type name, e.g.:
1625                 //     ldc #13 <String "java.lang.String">
1626                 insn = insn.append(
1627                     InsnUtils.stringConstant(
1628                         NameHelper.typeForSig(sig), pool));
1629 
1630                 // push class object using the generated helper method
1631                 insn = insn.append(
1632                     Insn.create(opc_invokestatic,
1633                                 pool.addMethodRef(
1634                                     className,
1635                                     SUNJDO_PC_sunjdoClassForName_Name,
1636                                     SUNJDO_PC_sunjdoClassForName_Sig)));
1637                 break;
1638             case '[':
1639                 // for array types, the element's signature is simply
1640                 // converted into a type name, e.g.:
1641                 //     ldc #10 <String "[I">
1642                 //     ldc #15 <String "[Ljava.lang.String;">
1643                 insn = insn.append(
1644                     InsnUtils.stringConstant(
1645                         NameHelper.typeForPath(sig), pool));
1646 
1647                 // push class object using the generated helper method
1648                 insn = insn.append(
1649                     Insn.create(opc_invokestatic,
1650                                 pool.addMethodRef(
1651                                     className,
1652                                     SUNJDO_PC_sunjdoClassForName_Name,
1653                                     SUNJDO_PC_sunjdoClassForName_Sig)));
1654                 break;
1655             default:
1656                 affirm(false, "Illegal field type: " + sig);
1657             }
1658 
1659             insn = insn.append(Insn.create(opc_aastore));
1660         }
1661 
1662         // store to field
1663         insn = insn.append(
1664             Insn.create(opc_putstatic,
1665                         getjdoFieldTypesFieldRef()));
1666 
1667         affirm(insn != null);
1668         return insn;
1669     }
1670     
1671     /***
1672      * Adds the initialization code for the jdoFieldFlags field.
1673      */
1674     private Insn initJdoFieldFlags(Insn insn)
1675     {
1676         affirm(insn != null);
1677 
1678         final int managedFieldCount = analyzer.getManagedFieldCount();
1679         final int[] managedFieldFlags = analyzer.getAnnotatedFieldFlags();
1680         affirm(managedFieldFlags.length >= managedFieldCount);
1681         
1682         // create array
1683         affirm(NameHelper.elementSigForSig(JDO_PC_jdoFieldFlags_Sig)
1684                .equals("B"));
1685         insn = insn.append(InsnUtils.integerConstant(managedFieldCount, pool));
1686         insn = insn.append(
1687             Insn.create(opc_newarray, T_BYTE));
1688 
1689         // initialize elements
1690         for (int i = 0; i < managedFieldCount; i++) {
1691             insn = insn.append(Insn.create(opc_dup));
1692             insn = insn.append(InsnUtils.integerConstant(i, pool));
1693             final int flags = managedFieldFlags[i];
1694 
1695             // ensure we're using [opc_iconst_x .. opc_bipush]
1696             affirm(-128 <= flags && flags < 128);
1697             insn = insn.append(InsnUtils.integerConstant(flags, pool));
1698             insn = insn.append(Insn.create(opc_bastore));
1699         }
1700 
1701         // store to field
1702         insn = insn.append(
1703             Insn.create(opc_putstatic,
1704                         getjdoFieldFlagsFieldRef()));
1705 
1706         affirm(insn != null);
1707         return insn;
1708     }
1709     
1710     /***
1711      * Adds the initialization code for the jdoPersistenceCapableSuperclass
1712      * field.
1713      */
1714     private Insn initJdoPersistenceCapableSuperclass(Insn insn) 
1715     {
1716         affirm(insn != null);
1717 
1718         final String pcSuperName = analyzer.getPCSuperClassName();
1719         final String pcRootName = analyzer.getPCRootClassName();
1720         affirm(pcSuperName == null || pcRootName != null);
1721         //final ConstClass superConstClass = classFile.superName();
1722         //affirm(pcSuperName == null || superConstClass != null);
1723         //affirm(pcRootName == null || superConstClass != null);
1724 
1725         if (pcSuperName == null) {
1726             insn = insn.append(Insn.create(opc_aconst_null));
1727         } else {
1728             // the type name is used for loading, e.g.:
1729             //     ldc #13 <String "java.lang.String">
1730             insn = insn.append(
1731                 InsnUtils.stringConstant(
1732                     NameHelper.typeForPath(pcSuperName), pool));
1733             
1734             //^olsen: decide on whether to use PCRoot class or superclass
1735             // push class object using the generated helper method
1736             insn = insn.append(
1737                 Insn.create(opc_invokestatic,
1738                             pool.addMethodRef(
1739                                 pcRootName, //superConstClass.asString(),
1740                                 SUNJDO_PC_sunjdoClassForName_Name,
1741                                 SUNJDO_PC_sunjdoClassForName_Sig)));
1742         }
1743         
1744         // store to field
1745         insn = insn.append(
1746             Insn.create(opc_putstatic,
1747                         getjdoPersistenceCapableSuperclassFieldRef()));
1748         
1749         affirm(insn != null);
1750         return insn;
1751     }
1752     
1753     /***
1754      * Adds the code for the jdoPersistenceCapableSuperclass
1755      * field.
1756      */
1757     private Insn registerClass(Insn insn) 
1758     {
1759         affirm(insn != null);
1760 
1761         final String pcRootName = analyzer.getPCRootClassName();
1762         //final ConstClass superConstClass = classFile.superName();
1763         //affirm(pcRootName == null || superConstClass != null);
1764 
1765         // push the class object for this class
1766         // the type name is used for loading, e.g.:
1767         //     ldc #13 <String "java.lang.String">
1768         insn = insn.append(
1769             InsnUtils.stringConstant(
1770                 NameHelper.typeForPath(className), pool));
1771         
1772         //^olsen: decide on whether to use PCRoot class or superclass
1773         // push class object using the generated helper method
1774         insn = insn.append(
1775             Insn.create(opc_invokestatic,
1776                         pool.addMethodRef(
1777                             pcRootName, //superConstClass.asString(),
1778                             SUNJDO_PC_sunjdoClassForName_Name,
1779                             SUNJDO_PC_sunjdoClassForName_Sig)));
1780 
1781         // push the jdoFieldNames field
1782         insn = insn.append(
1783             Insn.create(opc_getstatic,
1784                         getjdoFieldNamesFieldRef()));
1785 
1786         // push the jdoFieldTypes field
1787         insn = insn.append(
1788             Insn.create(opc_getstatic,
1789                         getjdoFieldTypesFieldRef()));
1790 
1791         // push the jdoFieldFlags field
1792         insn = insn.append(
1793             Insn.create(opc_getstatic,
1794                         getjdoFieldFlagsFieldRef()));
1795 
1796         // push the jdoPersistenceCapableSuperclass field
1797         insn = insn.append(
1798             Insn.create(opc_getstatic,
1799                         getjdoPersistenceCapableSuperclassFieldRef()));
1800 
1801         // push a newly created an instance of this class or null if
1802         // class is abstract
1803         if (classFile.isAbstract()) {
1804             insn = insn.append(Insn.create(opc_aconst_null));
1805         } else {
1806             final ConstClass thisConstClass = classFile.className();
1807             affirm(thisConstClass != null);
1808             insn = insn.append(Insn.create(opc_new, thisConstClass));
1809             insn = insn.append(Insn.create(opc_dup));
1810             insn = insn.append(
1811                 Insn.create(opc_invokespecial,
1812                             pool.addMethodRef(
1813                                 className,
1814                                 NameHelper.constructorName(),
1815                                 NameHelper.constructorSig())));
1816         }
1817         
1818         // invoke registerClass
1819         insn = insn.append(
1820             Insn.create(opc_invokestatic,
1821                         pool.addMethodRef(
1822                             JDO_JDOImplHelper_Path,
1823                             JDO_JDOImplHelper_registerClass_Name,
1824                             JDO_JDOImplHelper_registerClass_Sig)));
1825         
1826         affirm(insn != null);
1827         return insn;
1828     }
1829     
1830     /***
1831      * Build the static initialization code for the class.
1832      *
1833      * static
1834      * {
1835      *     jdoInheritedFieldCount = 0 | super.jdoGetManagedFieldCount();
1836      *     jdoFieldNames = new String[]{ ... };
1837      *     jdoFieldTypes = new Class[]{ ... };
1838      *     jdoFieldFlags = new byte[]{ ... };
1839      *     jdoPersistenceCapableSuperclass = ...;
1840      *     javax.jdo.JDOImplHelper.registerClass(
1841      *         XXX.class, 
1842      *         jdoFieldNames, 
1843      *         jdoFieldTypes, 
1844      *         jdoFieldFlags, 
1845      *         jdoPersistenceCapableSuperclass, 
1846      *         new XXX()
1847      *     );
1848      * }
1849      */
1850     public void addStaticInitialization()
1851     {
1852         final String methodName = JAVA_clinit_Name;
1853         final String methodSig = JAVA_clinit_Sig;
1854         final int accessFlags = JAVA_clinit_Mods;
1855         final ExceptionsAttribute exceptAttr = null;
1856 
1857         // begin of method body
1858         final InsnTarget begin = new InsnTarget();
1859         Insn insn = begin;
1860 
1861         // initialize jdo fields
1862         insn = initJdoInheritedFieldCount(insn);
1863         insn = initJdoFieldNames(insn);
1864         insn = initJdoFieldTypes(insn);
1865         insn = initJdoFieldFlags(insn);
1866         insn = initJdoPersistenceCapableSuperclass(insn);
1867 
1868         // invoke registerClass
1869         insn = registerClass(insn);
1870 
1871         // add or extend the static initializer
1872         final CodeAttribute codeAttr
1873             = new CodeAttribute(getCodeAttributeUtf8(),
1874                                 7, // maxStack
1875                                 0, // maxLocals
1876                                 begin,
1877                                 new ExceptionTable(),
1878                                 new AttributeVector());
1879 
1880         if (analyzer.hasStaticInitializer()) {
1881             // not end of method body
1882             augmenter.prependMethod(methodName, methodSig, 
1883                                     codeAttr, exceptAttr);
1884         } else {
1885             // end of method body
1886             insn = insn.append(Insn.create(opc_return));
1887             augmenter.addMethod(methodName, methodSig, accessFlags,
1888                                 codeAttr, exceptAttr);
1889         }
1890     }
1891 
1892     // ----------------------------------------------------------------------
1893 
1894     /***
1895      * Build the jdoNewInstance method for the class.
1896      *
1897      * public PersistenceCapable jdoNewInstance(StateManager sm)
1898      * {
1899      *     final XXX pc = new XXX();
1900      *     pc.jdoFlags = 1; // == LOAD_REQUIRED
1901      *     pc.jdoStateManager = sm;
1902      *     return pc;
1903      * }
1904      */
1905     public void addJDONewInstanceMethod()
1906     {
1907         final String methodName = JDO_PC_jdoNewInstance_Name;
1908         final String methodSig = JDO_PC_jdoNewInstance_Sig;
1909         final int accessFlags = JDO_PC_jdoNewInstance_Mods;
1910         final ExceptionsAttribute exceptAttr = null;
1911 
1912         // begin of method body
1913         final InsnTarget begin = new InsnTarget();
1914         Insn insn = begin;
1915 
1916         // push a newly created an instance of this class
1917         final ConstClass thisConstClass = classFile.className();
1918         affirm(thisConstClass != null);
1919         insn = insn.append(Insn.create(opc_new, thisConstClass));
1920         insn = insn.append(Insn.create(opc_dup));
1921         insn = insn.append(
1922             Insn.create(opc_invokespecial,
1923                         pool.addMethodRef(
1924                             className,
1925                             NameHelper.constructorName(),
1926                             NameHelper.constructorSig())));
1927         insn = insn.append(Insn.create(opc_astore_2));
1928 
1929         // init jdo flags and assign argument to sm
1930         insn = insn.append(Insn.create(opc_aload_2));
1931         insn = insn.append(Insn.create(opc_iconst_1));
1932         insn = insn.append(
1933             Insn.create(opc_putfield,
1934                         getjdoFlagsFieldRef()));
1935         insn = insn.append(Insn.create(opc_aload_2));
1936         insn = insn.append(Insn.create(opc_aload_1));
1937         insn = insn.append(
1938             Insn.create(opc_putfield,
1939                         getjdoStateManagerFieldRef()));
1940 
1941         // end of method body
1942         insn = insn.append(Insn.create(opc_aload_2));
1943         insn = insn.append(Insn.create(opc_areturn));
1944 
1945         final CodeAttribute codeAttr
1946             = new CodeAttribute(getCodeAttributeUtf8(),
1947                                 2, // maxStack
1948                                 3, // maxLocals
1949                                 begin,
1950                                 new ExceptionTable(),
1951                                 new AttributeVector());
1952         augmenter.addMethod(methodName, methodSig, accessFlags,
1953                             codeAttr, exceptAttr);
1954     }
1955 
1956     /***
1957      * Build the jdoNewInstance method for the class.
1958      *
1959      * public PersistenceCapable jdoNewInstance(StateManager sm, Object oid)
1960      * {
1961      *     final XXX pc = new XXX();
1962      *     pc.jdoCopyKeyFieldsFromObjectId(oid);
1963      *     pc.jdoFlags = 1; // == LOAD_REQUIRED
1964      *     pc.jdoStateManager = sm;
1965      *     return pc;
1966      * }
1967      */
1968     public void addJDONewInstanceOidMethod()
1969     {
1970         final String methodName = JDO_PC_jdoNewInstance_Object_Name;
1971         final String methodSig = JDO_PC_jdoNewInstance_Object_Sig;
1972         final int accessFlags = JDO_PC_jdoNewInstance_Object_Mods;
1973         final ExceptionsAttribute exceptAttr = null;
1974 
1975         // begin of method body
1976         final InsnTarget begin = new InsnTarget();
1977         Insn insn = begin;
1978 
1979         // push a newly created an instance of this class
1980         final ConstClass thisConstClass = classFile.className();
1981         affirm(thisConstClass != null);
1982         insn = insn.append(Insn.create(opc_new, thisConstClass));
1983         insn = insn.append(Insn.create(opc_dup));
1984         insn = insn.append(
1985             Insn.create(opc_invokespecial,
1986                         pool.addMethodRef(
1987                             className,
1988                             NameHelper.constructorName(),
1989                             NameHelper.constructorSig())));
1990         insn = insn.append(Insn.create(opc_astore_3));
1991 
1992         // class on instance pc.jdoCopyKeyFieldsFromObjectId(oid)
1993         //^olsen: javac uses the truelly declaring class
1994         final String pcKeyOwnerClassName = analyzer.getPCKeyOwnerClassName();
1995         affirm(pcKeyOwnerClassName != null);
1996         insn = insn.append(Insn.create(opc_aload_3));
1997         insn = insn.append(Insn.create(opc_aload_2));
1998         insn = insn.append(
1999             Insn.create(opc_invokevirtual,
2000                         pool.addMethodRef(
2001                             pcKeyOwnerClassName,
2002                             JDO_PC_jdoCopyKeyFieldsFromObjectId_Name,
2003                             JDO_PC_jdoCopyKeyFieldsFromObjectId_Sig)));
2004 
2005         // init jdo flags and assign argument to sm
2006         insn = insn.append(Insn.create(opc_aload_3));
2007         insn = insn.append(Insn.create(opc_iconst_1));
2008         insn = insn.append(
2009             Insn.create(opc_putfield,
2010                         getjdoFlagsFieldRef()));
2011         insn = insn.append(Insn.create(opc_aload_3));
2012         insn = insn.append(Insn.create(opc_aload_1));
2013         insn = insn.append(
2014             Insn.create(opc_putfield,
2015                         getjdoStateManagerFieldRef()));
2016 
2017         // end of method body
2018         insn = insn.append(Insn.create(opc_aload_3));
2019         insn = insn.append(Insn.create(opc_areturn));
2020 
2021         final CodeAttribute codeAttr
2022             = new CodeAttribute(getCodeAttributeUtf8(),
2023                                 2, // maxStack
2024                                 4, // maxLocals
2025                                 begin,
2026                                 new ExceptionTable(),
2027                                 new AttributeVector());
2028         augmenter.addMethod(methodName, methodSig, accessFlags,
2029                             codeAttr, exceptAttr);
2030     }
2031 
2032     // ----------------------------------------------------------------------
2033 
2034     /***
2035      * Adds the code for the begin of the jdoProvideField and
2036      * jdoReplaceField methods.
2037      */
2038     private Insn appendBeginProvideReplaceField(Insn insn)
2039     {
2040         affirm(insn != null);
2041 
2042         // store the sm field into local var
2043         insn = insn.append(Insn.create(opc_aload_0));
2044         insn = insn.append(
2045             Insn.create(opc_getfield,
2046                         getjdoStateManagerFieldRef()));
2047         insn = insn.append(Insn.create(opc_astore_2));
2048 
2049         // push (fieldnumber - jdoInheritedFieldCount)
2050         insn = insn.append(Insn.create(opc_iload_1));
2051         insn = insn.append(
2052             Insn.create(opc_getstatic,
2053                         pool.addFieldRef(
2054                             className,
2055                             JDO_PC_jdoInheritedFieldCount_Name,
2056                             JDO_PC_jdoInheritedFieldCount_Sig)));
2057         insn = insn.append(Insn.create(opc_isub));
2058         affirm(insn != null);
2059         return insn;
2060     }
2061     
2062     /***
2063      * Adds the default-branch code for the jdoProvideField and
2064      * jdoReplaceField methods.
2065      */
2066     private Insn appendEndProvideReplaceField(Insn insn,
2067                                               String provideReplaceField_Name,
2068                                               String provideReplaceField_Sig)
2069     {
2070         affirm(insn != null);
2071         affirm(provideReplaceField_Name);
2072         affirm(provideReplaceField_Sig);
2073 
2074         // throw exception or delegate to PC superclass
2075         final boolean isPCRoot = analyzer.isAugmentableAsRoot();
2076         if (isPCRoot) {
2077             insn = appendThrowJavaException(insn,
2078                                             JAVA_IllegalArgumentException_Path,
2079                                             "arg1");
2080         } else {
2081             // call super.jdoProvideField(int)
2082             final ConstClass superConstClass = classFile.superName();
2083             affirm(superConstClass != null);
2084             final String superClassName = superConstClass.asString();
2085             affirm(superClassName != null);
2086             insn = insn.append(Insn.create(opc_aload_0));
2087             insn = insn.append(Insn.create(opc_iload_1));
2088             insn = insn.append(
2089                 Insn.create(opc_invokespecial,
2090                             pool.addMethodRef(
2091                                 superClassName,
2092                                 provideReplaceField_Name,
2093                                 provideReplaceField_Sig)));
2094             insn = insn.append(Insn.create(opc_return));
2095         }        
2096 
2097         affirm(insn != null);
2098         return insn;
2099     }
2100     
2101     /***
2102      * Adds the code for one case-branch in the jdoProvideField method.
2103      */
2104     private Insn appendCaseBranchForProvideField(Insn insn,
2105                                                  String providedXXXField_Name,
2106                                                  String providedXXXField_Sig,
2107                                                  ConstFieldRef managedFieldRef)
2108     {
2109         affirm(insn != null);
2110         affirm(providedXXXField_Name != null);
2111         affirm(providedXXXField_Sig != null);
2112         affirm(managedFieldRef != null);
2113 
2114         // check sm
2115         insn = appendCheckVarNonNull(insn, 2,
2116                                      JAVA_IllegalStateException_Path,
2117                                      "arg0." + JDO_PC_jdoStateManager_Name);
2118 
2119         // push sm and args: this, fieldnumber, and field
2120         insn = insn.append(Insn.create(opc_aload_2));
2121         insn = insn.append(Insn.create(opc_aload_0));
2122         insn = insn.append(Insn.create(opc_iload_1));
2123         insn = insn.append(Insn.create(opc_aload_0));
2124         insn = insn.append(Insn.create(opc_getfield, managedFieldRef));
2125 
2126         // call providedXXXField
2127         insn = insn.append(
2128             new InsnInterfaceInvoke(
2129                 pool.addInterfaceMethodRef(
2130                     JDO_StateManager_Path,
2131                     providedXXXField_Name,
2132                     providedXXXField_Sig),
2133                 countMethodArgWords(providedXXXField_Sig)));
2134 
2135         // return
2136         insn = insn.append(Insn.create(opc_return));
2137         
2138         affirm(insn != null);
2139         return insn;
2140     }
2141     
2142     /***
2143      * Adds the switch code for the jdoProvideField method.
2144      */
2145     private Insn appendSwitchForProvideField(Insn insn,
2146                                              SizeHolder sizeHolder)
2147     {
2148         affirm(insn != null);
2149         affirm(sizeHolder != null);
2150 
2151         // generate the switch-statement only if more than zero fields
2152         final int managedFieldCount = analyzer.getManagedFieldCount();
2153         //if (managedFieldCount == 0) {
2154         //    return insn;
2155         //}        
2156 
2157         // get types of and field references of the managed fields
2158         final String[] managedFieldSigs = analyzer.getAnnotatedFieldSigs();
2159         final ConstFieldRef[] managedFieldRefs = getAnnotatedFieldRefs();
2160         affirm(managedFieldSigs.length >= managedFieldCount);
2161         affirm(managedFieldRefs.length >= managedFieldCount);
2162 
2163         // generate the switch
2164         final int lowOp = 0;
2165         final InsnTarget defaultOp = new InsnTarget();
2166         final InsnTarget[] targetsOp = new InsnTarget[managedFieldCount];
2167         for (int i = 0; i < managedFieldCount; i++) {
2168             targetsOp[i] = new InsnTarget();
2169         }            
2170 
2171         // javac prefers lookup switches for 1-element tables
2172         if (managedFieldCount <= 1) {
2173             final int[] matchesOp
2174                 = (managedFieldCount == 0 ? new int[]{} : new int[]{ lowOp });
2175             insn = insn.append(
2176                 new InsnLookupSwitch(defaultOp, matchesOp, targetsOp));
2177         } else {
2178             insn = insn.append(
2179                 new InsnTableSwitch(lowOp, defaultOp, targetsOp));
2180         }
2181         
2182         // generate the case-targets for the method calls
2183         for (int i = 0; i < managedFieldCount; i++) {
2184             // target for accessing field [i]
2185             insn = insn.append(targetsOp[i]);
2186 
2187             // get signature and constant field reference for field
2188             final String sig = managedFieldSigs[i];
2189             final ConstFieldRef ref = managedFieldRefs[i];
2190             affirm(sig != null && sig.length() > 0);
2191             affirm(ref != null);
2192 
2193             // compute stack demand
2194             sizeHolder.size = max(sizeHolder.size,
2195                                   Descriptor.countFieldWords(sig));
2196 
2197             // generate the case-branch for a field depending on its type
2198             switch (sig.charAt(0)) {
2199             case 'Z':
2200                 insn = appendCaseBranchForProvideField(
2201                     insn,
2202                     JDO_SM_providedBooleanField_Name,
2203                     JDO_SM_providedBooleanField_Sig,
2204                     ref);
2205                 break;
2206             case 'C':
2207                 insn = appendCaseBranchForProvideField(
2208                     insn,
2209                     JDO_SM_providedCharField_Name,
2210                     JDO_SM_providedCharField_Sig,
2211                     ref);
2212                 break;
2213             case 'B':
2214                 insn = appendCaseBranchForProvideField(
2215                     insn,
2216                     JDO_SM_providedByteField_Name,
2217                     JDO_SM_providedByteField_Sig,
2218                     ref);
2219                 break;
2220             case 'S':
2221                 insn = appendCaseBranchForProvideField(
2222                     insn,
2223                     JDO_SM_providedShortField_Name,
2224                     JDO_SM_providedShortField_Sig,
2225                     ref);
2226                 break;
2227             case 'I':
2228                 insn = appendCaseBranchForProvideField(
2229                     insn,
2230                     JDO_SM_providedIntField_Name,
2231                     JDO_SM_providedIntField_Sig,
2232                     ref);
2233                 break;
2234             case 'J':
2235                 insn = appendCaseBranchForProvideField(
2236                     insn,
2237                     JDO_SM_providedLongField_Name,
2238                     JDO_SM_providedLongField_Sig,
2239                     ref);
2240                 break;
2241             case 'F':
2242                 insn = appendCaseBranchForProvideField(
2243                     insn,
2244                     JDO_SM_providedFloatField_Name,
2245                     JDO_SM_providedFloatField_Sig,
2246                     ref);
2247                 break;
2248             case 'D':
2249                 insn = appendCaseBranchForProvideField(
2250                     insn,
2251                     JDO_SM_providedDoubleField_Name,
2252                     JDO_SM_providedDoubleField_Sig,
2253                     ref);
2254                 break;
2255             case 'L':
2256             case '[':
2257                 if (sig.equals(JAVA_String_Sig)) {
2258                     insn = appendCaseBranchForProvideField(
2259                         insn,
2260                         JDO_SM_providedStringField_Name,
2261                         JDO_SM_providedStringField_Sig,
2262                         ref);
2263                 } else {
2264                     insn = appendCaseBranchForProvideField(
2265                         insn,
2266                         JDO_SM_providedObjectField_Name,
2267                         JDO_SM_providedObjectField_Sig,
2268                         ref);
2269                 }
2270                 break;
2271             default:
2272                 affirm(false, "Illegal field type: " + sig);
2273             }
2274         }
2275         
2276         // the default branch target comes next
2277         insn = insn.append(defaultOp);        
2278 
2279         affirm(insn != null);
2280         return insn;
2281     }
2282 
2283     /***
2284      * Build the jdoProvideField method for the class.
2285      *
2286      * public void jdoProvideField(int fieldnumber)
2287      * {
2288      *     final javax.jdo.StateManager sm = this.jdoStateManager;
2289      *     switch(fieldnumber - jdoInheritedFieldCount) {
2290      *     case 0:
2291      *         sm.providedXXXField(this, fieldnumber, this.yyy);
2292      *         return;
2293      *     case 1:
2294      *         ...
2295      *     default:
2296      *         <if (isPCRoot) {>
2297      *             throw new javax.jdo.JDOFatalInternalException();
2298      *         <} else {>
2299      *             super.jdoProvideField(fieldnumber);
2300      *         <}>
2301      *     }
2302      * }
2303      */
2304     public void addJDOProvideFieldMethod()
2305     {
2306         final String methodName = JDO_PC_jdoProvideField_Name;
2307         final String methodSig = JDO_PC_jdoProvideField_Sig;
2308         final int accessFlags = JDO_PC_jdoProvideField_Mods;
2309         final ExceptionsAttribute exceptAttr = null;
2310 
2311         // begin of method body
2312         final InsnTarget begin = new InsnTarget();
2313         Insn insn = begin;
2314 
2315         // generate the begin code
2316         insn = appendBeginProvideReplaceField(insn);
2317         
2318         // generate the switch code
2319         final SizeHolder sizeHolder = new SizeHolder();
2320         insn = appendSwitchForProvideField(insn, sizeHolder);
2321         
2322         // generate the default-branch code with throw/return
2323         insn = appendEndProvideReplaceField(insn,
2324                                             JDO_PC_jdoProvideField_Name,
2325                                             JDO_PC_jdoProvideField_Sig);
2326 
2327         // end of method body
2328         affirm(insn.opcode() == opc_athrow || insn.opcode() == opc_return);
2329         
2330         affirm(0 <= sizeHolder.size && sizeHolder.size <= 2);
2331         //System.out.println("sizeHolder.size = " + sizeHolder.size);
2332         final int maxStack = (sizeHolder.size == 0
2333                               ? 3 : (sizeHolder.size == 1 ? 4 : 5));
2334         final CodeAttribute codeAttr
2335             = new CodeAttribute(getCodeAttributeUtf8(),
2336                                 maxStack, // maxStack
2337                                 3, // maxLocals
2338                                 begin,
2339                                 new ExceptionTable(),
2340                                 new AttributeVector());
2341         augmenter.addMethod(methodName, methodSig, accessFlags,
2342                             codeAttr, exceptAttr);
2343     }
2344 
2345     /***
2346      * Adds the code for one case-branch in the jdoReplaceField method.
2347      */
2348     private Insn appendCaseBranchForReplaceField(Insn insn,
2349                                                  String replacingXXXField_Name,
2350                                                  String replacingXXXField_Sig,
2351                                                  ConstFieldRef managedFieldRef,
2352                                                  String managedFieldSig)
2353     {
2354         affirm(insn != null);
2355         affirm(replacingXXXField_Name != null);
2356         affirm(replacingXXXField_Sig != null);
2357         affirm(managedFieldRef != null);
2358         affirm(managedFieldSig != null);
2359 
2360         // check sm
2361         insn = appendCheckVarNonNull(insn, 2,
2362                                      JAVA_IllegalStateException_Path,
2363                                      "arg0." + JDO_PC_jdoStateManager_Name);
2364 
2365         // push this, sm and args: this and fieldnumber
2366         insn = insn.append(Insn.create(opc_aload_0));
2367         insn = insn.append(Insn.create(opc_aload_2));
2368         insn = insn.append(Insn.create(opc_aload_0));
2369         insn = insn.append(Insn.create(opc_iload_1));
2370 
2371         // call replacingXXXField
2372         insn = insn.append(
2373             new InsnInterfaceInvoke(
2374                 pool.addInterfaceMethodRef(
2375                     JDO_StateManager_Path,
2376                     replacingXXXField_Name,
2377                     replacingXXXField_Sig),
2378                 countMethodArgWords(replacingXXXField_Sig)));
2379 
2380         // put to field with downcast for Object return types
2381         if (replacingXXXField_Name.equals(JDO_SM_replacingObjectField_Name)) {
2382             final String fieldType = NameHelper.pathForSig(managedFieldSig);
2383             insn = insn.append(
2384                 Insn.create(opc_checkcast,
2385                             pool.addClass(fieldType)));
2386         }
2387         insn = insn.append(Insn.create(opc_putfield, managedFieldRef));
2388 
2389         // return
2390         insn = insn.append(Insn.create(opc_return));
2391         
2392         affirm(insn != null);
2393         return insn;
2394     }
2395     
2396     /***
2397      * Adds the switch code for the jdoReplaceField method.
2398      */
2399     private Insn appendSwitchForReplaceField(Insn insn,
2400                                              SizeHolder sizeHolder)
2401     {
2402         affirm(insn != null);
2403         affirm(sizeHolder != null);
2404 
2405         // generate the switch-statement only if more than zero fields
2406         final int managedFieldCount = analyzer.getManagedFieldCount();
2407         //if (managedFieldCount == 0) {
2408         //    return insn;
2409         //}        
2410 
2411         // get types of and field references of the managed fields
2412         final String[] managedFieldSigs = analyzer.getAnnotatedFieldSigs();
2413         final ConstFieldRef[] managedFieldRefs = getAnnotatedFieldRefs();
2414         affirm(managedFieldSigs.length >= managedFieldCount);
2415         affirm(managedFieldRefs.length >= managedFieldCount);
2416 
2417         // generate the switch
2418         final int lowOp = 0;
2419         final InsnTarget defaultOp = new InsnTarget();
2420         final InsnTarget[] targetsOp = new InsnTarget[managedFieldCount];
2421         for (int i = 0; i < managedFieldCount; i++) {
2422             targetsOp[i] = new InsnTarget();
2423         }            
2424 
2425         // javac prefers lookup switches for 1-element tables
2426         if (managedFieldCount <= 1) {
2427             final int[] matchesOp
2428                 = (managedFieldCount == 0 ? new int[]{} : new int[]{ lowOp });
2429             insn = insn.append(
2430                 new InsnLookupSwitch(defaultOp, matchesOp, targetsOp));
2431         } else {
2432             insn = insn.append(
2433                 new InsnTableSwitch(lowOp, defaultOp, targetsOp));
2434         }
2435         
2436         // generate the case-targets for the method calls
2437         for (int i = 0; i < managedFieldCount; i++) {
2438             // target for accessing field [i]
2439             insn = insn.append(targetsOp[i]);
2440 
2441             // get signature and constant field reference for field
2442             final String sig = managedFieldSigs[i];
2443             final ConstFieldRef ref = managedFieldRefs[i];
2444             affirm(sig != null && sig.length() > 0);
2445             affirm(ref != null);
2446 
2447             // compute stack demand
2448             sizeHolder.size = max(sizeHolder.size,
2449                                   Descriptor.countFieldWords(sig));
2450 
2451             // generate the case-branch for a field depending on its type
2452             switch (sig.charAt(0)) {
2453             case 'Z':
2454                 insn = appendCaseBranchForReplaceField(
2455                     insn,
2456                     JDO_SM_replacingBooleanField_Name,
2457                     JDO_SM_replacingBooleanField_Sig,
2458                     ref, sig);
2459                 break;
2460             case 'C':
2461                 insn = appendCaseBranchForReplaceField(
2462                     insn,
2463                     JDO_SM_replacingCharField_Name,
2464                     JDO_SM_replacingCharField_Sig,
2465                     ref, sig);
2466                 break;
2467             case 'B':
2468                 insn = appendCaseBranchForReplaceField(
2469                     insn,
2470                     JDO_SM_replacingByteField_Name,
2471                     JDO_SM_replacingByteField_Sig,
2472                     ref, sig);
2473                 break;
2474             case 'S':
2475                 insn = appendCaseBranchForReplaceField(
2476                     insn,
2477                     JDO_SM_replacingShortField_Name,
2478                     JDO_SM_replacingShortField_Sig,
2479                     ref, sig);
2480                 break;
2481             case 'I':
2482                 insn = appendCaseBranchForReplaceField(
2483                     insn,
2484                     JDO_SM_replacingIntField_Name,
2485                     JDO_SM_replacingIntField_Sig,
2486                     ref, sig);
2487                 break;
2488             case 'J':
2489                 insn = appendCaseBranchForReplaceField(
2490                     insn,
2491                     JDO_SM_replacingLongField_Name,
2492                     JDO_SM_replacingLongField_Sig,
2493                     ref, sig);
2494                 break;
2495             case 'F':
2496                 insn = appendCaseBranchForReplaceField(
2497                     insn,
2498                     JDO_SM_replacingFloatField_Name,
2499                     JDO_SM_replacingFloatField_Sig,
2500                     ref, sig);
2501                 break;
2502             case 'D':
2503                 insn = appendCaseBranchForReplaceField(
2504                     insn,
2505                     JDO_SM_replacingDoubleField_Name,
2506                     JDO_SM_replacingDoubleField_Sig,
2507                     ref, sig);
2508                 break;
2509             case 'L':
2510             case '[':
2511                 if (sig.equals(JAVA_String_Sig)) {
2512                     insn = appendCaseBranchForReplaceField(
2513                         insn,
2514                         JDO_SM_replacingStringField_Name,
2515                         JDO_SM_replacingStringField_Sig,
2516                         ref, sig);
2517                 } else {
2518                     insn = appendCaseBranchForReplaceField(
2519                         insn,
2520                         JDO_SM_replacingObjectField_Name,
2521                         JDO_SM_replacingObjectField_Sig,
2522                         ref, sig);
2523                 }
2524                 break;
2525             default:
2526                 affirm(false, "Illegal field type: " + sig);
2527             }
2528         }
2529         
2530         // the default branch target comes next
2531         insn = insn.append(defaultOp);        
2532 
2533         affirm(insn != null);
2534         return insn;
2535     }
2536 
2537     /***
2538      * Build the jdoReplaceField method for the class.
2539      *
2540      * public void jdoReplaceField(int fieldnumber)
2541      * {
2542      *     final javax.jdo.StateManager sm = this.jdoStateManager;
2543      *     switch(fieldnumber - jdoInheritedFieldCount) {
2544      *     case 0:
2545      *         this.yyy = (XXX)sm.replacingXXXField(this, fieldnumber);
2546      *         return;
2547      *     case 1:
2548      *         ...
2549      *     default:
2550      *         <if (isPCRoot) {>
2551      *             throw new javax.jdo.JDOFatalInternalException();
2552      *         <} else {>
2553      *             super.jdoReplaceField(fieldnumber);
2554      *         <}>
2555      *     }
2556      * }
2557      */
2558     public void addJDOReplaceFieldMethod()
2559     {
2560         final String methodName = JDO_PC_jdoReplaceField_Name;
2561         final String methodSig = JDO_PC_jdoReplaceField_Sig;
2562         final int accessFlags = JDO_PC_jdoReplaceField_Mods;
2563         final ExceptionsAttribute exceptAttr = null;
2564 
2565         // begin of method body
2566         final InsnTarget begin = new InsnTarget();
2567         Insn insn = begin;
2568 
2569         // generate the begin code
2570         insn = appendBeginProvideReplaceField(insn);
2571         
2572         // generate the switch code
2573         final SizeHolder sizeHolder = new SizeHolder();
2574         insn = appendSwitchForReplaceField(insn, sizeHolder);
2575         
2576         // generate the default-branch code with throw/return
2577         insn = appendEndProvideReplaceField(insn,
2578                                             JDO_PC_jdoReplaceField_Name,
2579                                             JDO_PC_jdoReplaceField_Sig);
2580 
2581         // end of method body
2582         affirm(insn.opcode() == opc_athrow || insn.opcode() == opc_return);
2583 
2584         affirm(0 <= sizeHolder.size && sizeHolder.size <= 2);
2585         //System.out.println("sizeHolder.size = " + sizeHolder.size);
2586         final int maxStack = (sizeHolder.size == 0 ? 3 : 4);
2587         final CodeAttribute codeAttr
2588             = new CodeAttribute(getCodeAttributeUtf8(),
2589                                 maxStack, // maxStack
2590                                 3, // maxLocals
2591                                 begin,
2592                                 new ExceptionTable(),
2593                                 new AttributeVector());
2594         augmenter.addMethod(methodName, methodSig, accessFlags,
2595                             codeAttr, exceptAttr);
2596     }
2597 
2598     // ----------------------------------------------------------------------
2599 
2600     /***
2601      * Adds the code for the begin of the jdoCopyField method.
2602      */
2603     private Insn appendBeginCopyField(Insn insn)
2604     {
2605         affirm(insn != null);
2606 
2607         // push (fieldnumber - jdoInheritedFieldCount)
2608         insn = insn.append(Insn.create(opc_iload_2));
2609         insn = insn.append(
2610             Insn.create(opc_getstatic,
2611                         pool.addFieldRef(
2612                             className,
2613                             JDO_PC_jdoInheritedFieldCount_Name,
2614                             JDO_PC_jdoInheritedFieldCount_Sig)));
2615         insn = insn.append(Insn.create(opc_isub));
2616 
2617         affirm(insn != null);
2618         return insn;
2619     }
2620     
2621     /***
2622      * Adds the default-branch code for the jdoCopyField method.
2623      */
2624     private Insn appendEndCopyField(Insn insn)
2625     {
2626         affirm(insn != null);
2627 
2628         // throw exception or delegate to PC superclass
2629         final boolean isPCRoot = analyzer.isAugmentableAsRoot();
2630         if (isPCRoot) {
2631             insn = appendThrowJavaException(insn,
2632                                             JAVA_IllegalArgumentException_Path,
2633                                             "arg2");
2634         } else {
2635             // call super.jdoCopyField(XXX, int)
2636 
2637             //^olsen: javac uses the truelly declaring class
2638             //final ConstClass superConstClass = classFile.superName();
2639             //affirm(superConstClass != null);
2640             //final String superClassName = superConstClass.asString();
2641             //affirm(superClassName != null);
2642 
2643             // must use pcSuperClass (not the immediate superclass) in order
2644             // to match formal parameter of jdoCopyField
2645             final String superClassName = analyzer.getPCSuperClassName();
2646             affirm(superClassName != null);
2647             final String jdo_PC_jdoCopyField_Sig
2648                 = JDONameHelper.getJDO_PC_jdoCopyField_Sig(superClassName);
2649             insn = insn.append(Insn.create(opc_aload_0));
2650             insn = insn.append(Insn.create(opc_aload_1));
2651             insn = insn.append(Insn.create(opc_iload_2));
2652             insn = insn.append(
2653                 Insn.create(opc_invokespecial,
2654                             pool.addMethodRef(
2655                                 superClassName,
2656                                 JDO_PC_jdoCopyField_Name,
2657                                 jdo_PC_jdoCopyField_Sig)));
2658             insn = insn.append(Insn.create(opc_return));
2659         }
2660 
2661         affirm(insn != null);
2662         return insn;
2663     }
2664     
2665     /***
2666      * Adds the code for one case-branch in the jdoCopyField method.
2667      */
2668     private Insn appendCaseBranchForCopyField(Insn insn,
2669                                               ConstFieldRef managedFieldRef)
2670     {
2671         affirm(insn != null);
2672         affirm(managedFieldRef != null);
2673 
2674         // check arg
2675         insn = appendCheckVarNonNull(insn, 1,
2676                                      JAVA_IllegalArgumentException_Path,
2677                                      "arg1");
2678 
2679         // assign argument's field to this instance's field
2680         insn = insn.append(Insn.create(opc_aload_0));
2681         insn = insn.append(Insn.create(opc_aload_1));
2682         insn = insn.append(Insn.create(opc_getfield, managedFieldRef));
2683         insn = insn.append(Insn.create(opc_putfield, managedFieldRef));
2684 
2685         // return
2686         insn = insn.append(Insn.create(opc_return));
2687         
2688         affirm(insn != null);
2689         return insn;
2690     }
2691     
2692     /***
2693      * Adds the switch code for the jdoCopyField method.
2694      */
2695     private Insn appendSwitchForCopyField(Insn insn)
2696     {
2697         affirm(insn != null);
2698 
2699         // generate the switch-statement only if more than zero fields
2700         final int managedFieldCount = analyzer.getManagedFieldCount();
2701         //if (managedFieldCount == 0) {
2702         //    return insn;
2703         //}        
2704 
2705         // get types of and field references of the managed fields
2706         final String[] managedFieldSigs = analyzer.getAnnotatedFieldSigs();
2707         final ConstFieldRef[] managedFieldRefs = getAnnotatedFieldRefs();
2708         affirm(managedFieldSigs.length >= managedFieldCount);
2709         affirm(managedFieldRefs.length >= managedFieldCount);
2710 
2711         // generate the switch
2712         final int lowOp = 0;
2713         final InsnTarget defaultOp = new InsnTarget();
2714         final InsnTarget[] targetsOp = new InsnTarget[managedFieldCount];
2715         for (int i = 0; i < managedFieldCount; i++) {
2716             targetsOp[i] = new InsnTarget();
2717         }            
2718 
2719         // javac prefers lookup switches for 1-element tables
2720         if (managedFieldCount <= 1) {
2721             final int[] matchesOp
2722                 = (managedFieldCount == 0 ? new int[]{} : new int[]{ lowOp });
2723             insn = insn.append(
2724                 new InsnLookupSwitch(defaultOp, matchesOp, targetsOp));
2725         } else {
2726             insn = insn.append(
2727                 new InsnTableSwitch(lowOp, defaultOp, targetsOp));
2728         }
2729         
2730         // generate the case-targets for the method calls
2731         for (int i = 0; i < managedFieldCount; i++) {
2732             // target for accessing field [i]
2733             insn = insn.append(targetsOp[i]);
2734 
2735             // get signature and constant field reference for field
2736             final String sig = managedFieldSigs[i];
2737             final ConstFieldRef ref = managedFieldRefs[i];
2738             affirm(sig != null && sig.length() > 0);
2739             affirm(ref != null);
2740 
2741             // generate the case-branch for a field depending on its type
2742             switch (sig.charAt(0)) {
2743             case 'Z':
2744                 insn = appendCaseBranchForCopyField(insn, ref);
2745                 break;
2746             case 'C':
2747                 insn = appendCaseBranchForCopyField(insn, ref);
2748                 break;
2749             case 'B':
2750                 insn = appendCaseBranchForCopyField(insn, ref);
2751                 break;
2752             case 'S':
2753                 insn = appendCaseBranchForCopyField(insn, ref);
2754                 break;
2755             case 'I':
2756                 insn = appendCaseBranchForCopyField(insn, ref);
2757                 break;
2758             case 'J':
2759                 insn = appendCaseBranchForCopyField(insn, ref);
2760                 break;
2761             case 'F':
2762                 insn = appendCaseBranchForCopyField(insn, ref);
2763                 break;
2764             case 'D':
2765                 insn = appendCaseBranchForCopyField(insn, ref);
2766                 break;
2767             case 'L':
2768             case '[':
2769                 insn = appendCaseBranchForCopyField(insn, ref);
2770                 break;
2771             default:
2772                 affirm(false, "Illegal field type: " + sig);
2773             }
2774         }
2775         
2776         // the default branch target comes next
2777         insn = insn.append(defaultOp);        
2778 
2779         affirm(insn != null);
2780         return insn;
2781     }
2782 
2783     /***
2784      * Build the jdoCopyField method for the class.
2785      *
2786      * protected final void jdoCopyField(XXX pc, int fieldnumber)
2787      * {
2788      *     switch(fieldnumber - jdoInheritedFieldCount) {
2789      *     case 0:
2790      *         this.yyy = pc.yyy;
2791      *         return;
2792      *     case 1:
2793      *         ...
2794      *     default:
2795      *         <if (isPCRoot) {>
2796      *             throw new javax.jdo.JDOFatalInternalException();
2797      *         <} else {>
2798      *             super.jdoCopyField(pc, fieldnumber);
2799      *         <}>
2800      *     }
2801      * }
2802      */
2803     public void addJDOCopyFieldMethod()
2804     {
2805         final String methodName = JDO_PC_jdoCopyField_Name;
2806         final String methodSig
2807             = JDONameHelper.getJDO_PC_jdoCopyField_Sig(className);
2808         final int accessFlags = JDO_PC_jdoCopyField_Mods;
2809         final ExceptionsAttribute exceptAttr = null;
2810         
2811         // begin of method body
2812         final InsnTarget begin = new InsnTarget();
2813         Insn insn = begin;
2814 
2815         // generate the begin code
2816         insn = appendBeginCopyField(insn);
2817         
2818         // generate the switch code
2819         insn = appendSwitchForCopyField(insn);
2820         
2821         // generate the default-branch code with throw/return
2822         insn = appendEndCopyField(insn);
2823 
2824         // end of method body
2825         affirm(insn.opcode() == opc_athrow || insn.opcode() == opc_return);
2826         
2827         final CodeAttribute codeAttr
2828             = new CodeAttribute(getCodeAttributeUtf8(),
2829                                 3, // maxStack
2830                                 3, // maxLocals
2831                                 begin,
2832                                 new ExceptionTable(),
2833                                 new AttributeVector());
2834         augmenter.addMethod(methodName, methodSig, accessFlags,
2835                             codeAttr, exceptAttr);
2836     }
2837 
2838     // ----------------------------------------------------------------------
2839 
2840     /***
2841      * Build the jdoArrayArgumentIteration method for the class.
2842      *
2843      * public void jdoCopyFields(java.lang.Object pc, int[] fieldnumbers)
2844      * {
2845      *     final XXX other = (XXX)pc;
2846      *     if (other.jdoStateManager != this.jdoStateManager
2847      *         || this.jdoStateManager == null) {
2848      *         throw new javax.jdo.JDOFatalInternalException();
2849      *     }
2850      *     final int n = fieldnumbers.length;
2851      *     for (int i = 0; i < n; i++) {
2852      *         this.jdoCopyField(other, fieldnumbers[i]);
2853      *     }
2854      * }
2855      */
2856     public void addJDOCopyFieldsMethod()
2857     {
2858         final String methodName = JDO_PC_jdoCopyFields_Name;
2859         final String methodSig = JDO_PC_jdoCopyFields_Sig;
2860         final int accessFlags = JDO_PC_jdoCopyFields_Mods;        
2861         final ExceptionsAttribute exceptAttr = null;
2862 
2863         // begin of method body
2864         final InsnTarget begin = new InsnTarget();
2865         Insn insn = begin;
2866 
2867         // check sm
2868         insn = appendCheckStateManager(insn, 0,
2869                                        JAVA_IllegalStateException_Path,
2870                                        "arg0." + JDO_PC_jdoStateManager_Name);
2871 
2872         // check pc argument
2873         final ConstClass thisConstClass = classFile.className();
2874         affirm(thisConstClass != null);
2875         insn = appendCheckVarInstanceOf(insn, 1, thisConstClass,
2876                                         JAVA_IllegalArgumentException_Path,
2877                                         "arg1");
2878 
2879         // check fieldnumbers argument
2880         insn = appendCheckVarNonNull(insn, 2,
2881                                      JAVA_IllegalArgumentException_Path,
2882                                      "arg2");
2883 
2884         // downcast argument
2885         insn = insn.append(Insn.create(opc_aload_1));
2886         insn = insn.append(Insn.create(opc_checkcast, thisConstClass));
2887         insn = insn.append(Insn.create(opc_astore_3));
2888 
2889         // check this and argument's sm for equality
2890         final InsnTarget endcheck = new InsnTarget();
2891         insn = insn.append(Insn.create(opc_aload_3));
2892         insn = insn.append(
2893             Insn.create(
2894                 opc_getfield,
2895                 getjdoStateManagerFieldRef()));
2896         insn = insn.append(Insn.create(opc_aload_0));
2897         insn = insn.append(
2898             Insn.create(
2899                 opc_getfield,
2900                 getjdoStateManagerFieldRef()));
2901         insn = insn.append(Insn.create(opc_if_acmpeq, endcheck));
2902         insn = appendThrowJavaException(insn,
2903                                         JAVA_IllegalArgumentException_Path,
2904                                         "arg1." + JDO_PC_jdoStateManager_Name);
2905 
2906         // store the array argument length into local var
2907         insn = insn.append(endcheck);
2908         insn = insn.append(Insn.create(opc_aload_2));
2909         insn = insn.append(Insn.create(opc_arraylength));
2910         insn = insn.append(Insn.create(opc_istore, 4));
2911 
2912         // init loop counter and goto loop check
2913         final InsnTarget loopcheck = new InsnTarget();
2914         insn = insn.append(Insn.create(opc_iconst_0));
2915         insn = insn.append(Insn.create(opc_istore, 5));
2916         insn = insn.append(Insn.create(opc_goto, loopcheck));
2917 
2918         // loop body: call self-delegating method with arguments
2919         final InsnTarget loopbody = new InsnTarget();
2920         insn = insn.append(loopbody);
2921         insn = insn.append(Insn.create(opc_aload_0));
2922         insn = insn.append(Insn.create(opc_aload_3));
2923 
2924         // select element from array argument at loop counter
2925         insn = insn.append(Insn.create(opc_aload_2));
2926         insn = insn.append(Insn.create(opc_iload, 5));
2927         insn = insn.append(Insn.create(opc_iaload));
2928 
2929         // call self-delegating method
2930         final String delegateName = JDO_PC_jdoCopyField_Name;
2931         final String delegateSig
2932             = JDONameHelper.getJDO_PC_jdoCopyField_Sig(className);
2933         insn = insn.append(
2934             Insn.create(opc_invokevirtual,
2935                         pool.addMethodRef(
2936                             className,
2937                             delegateName,
2938                             delegateSig)));
2939 
2940         // loop counter increment
2941         insn = insn.append(new InsnIInc(5, 1));
2942 
2943         // loop termination check
2944         insn = insn.append(loopcheck);
2945         insn = insn.append(Insn.create(opc_iload, 5));
2946         insn = insn.append(Insn.create(opc_iload, 4));
2947         insn = insn.append(Insn.create(opc_if_icmplt, loopbody));
2948 
2949         // end of method body
2950         insn = insn.append(Insn.create(opc_return));
2951 
2952         final CodeAttribute codeAttr
2953             = new CodeAttribute(getCodeAttributeUtf8(),
2954                                 4, // maxStack
2955                                 6, // maxLocals
2956                                 begin,
2957                                 new ExceptionTable(),
2958                                 new AttributeVector());
2959         augmenter.addMethod(methodName, methodSig, accessFlags,
2960                             codeAttr, exceptAttr);
2961     }
2962 
2963     // ----------------------------------------------------------------------
2964 
2965     /***
2966      * Build the jdoNewObjectIdInstance method for the class.
2967      *
2968      * public java.lang.Object jdoNewObjectIdInstance()
2969      * {
2970      *     return new XXX();
2971      * }
2972      */
2973     public void addJDONewObjectIdInstanceMethod()
2974     {
2975         final String methodName = JDO_PC_jdoNewObjectIdInstance_Name;
2976         final String methodSig = JDO_PC_jdoNewObjectIdInstance_Sig;
2977         final int accessFlags = JDO_PC_jdoNewObjectIdInstance_Mods;
2978         final ExceptionsAttribute exceptAttr = null;
2979 
2980         // begin of method body
2981         final InsnTarget begin = new InsnTarget();
2982         Insn insn = begin;
2983 
2984         // generate empty method in case of datastore identity
2985         final String keyClassName = analyzer.getKeyClassName();
2986         if (keyClassName == null){
2987             // end of method body
2988             insn = insn.append(Insn.create(opc_aconst_null));
2989             insn = insn.append(Insn.create(opc_areturn));
2990 
2991             final CodeAttribute codeAttr
2992                 = new CodeAttribute(getCodeAttributeUtf8(),
2993                                     1, // maxStack
2994                                     1, // maxLocals
2995                                     begin,
2996                                     new ExceptionTable(),
2997                                     new AttributeVector());
2998             augmenter.addMethod(methodName, methodSig, accessFlags,
2999                                 codeAttr, exceptAttr);
3000             return;
3001         }
3002         affirm(keyClassName != null);
3003 
3004         // push a newly created an instance of this class
3005         insn = insn.append(
3006             Insn.create(opc_new,
3007                         pool.addClass(keyClassName)));
3008         insn = insn.append(Insn.create(opc_dup));
3009         insn = insn.append(
3010             Insn.create(opc_invokespecial,
3011                         pool.addMethodRef(
3012                             keyClassName,
3013                             NameHelper.constructorName(),
3014                             NameHelper.constructorSig())));
3015 
3016         // end of method body
3017         insn = insn.append(Insn.create(opc_areturn));
3018 
3019         final CodeAttribute codeAttr
3020             = new CodeAttribute(getCodeAttributeUtf8(),
3021                                 2, // maxStack
3022                                 1, // maxLocals
3023                                 begin,
3024                                 new ExceptionTable(),
3025                                 new AttributeVector());
3026         augmenter.addMethod(methodName, methodSig, accessFlags,
3027                             codeAttr, exceptAttr);
3028     }
3029 
3030     /***
3031      * Build the jdoNewObjectIdInstance method for the class.
3032      *
3033      * public java.lang.Object jdoNewObjectIdInstance(Object o)
3034      * {
3035      *     throw new UnsupportedOperationException(
3036      *        "Method jdoNewObjectIdInstance not yet implemented");
3037      * }
3038      */
3039     public void addJDONewObjectIdInstanceObjectMethod()
3040     {
3041         final String methodName = JDO_PC_jdoNewObjectIdInstance_Object_Name;
3042         final String methodSig = JDO_PC_jdoNewObjectIdInstance_Object_Sig;
3043         final int accessFlags = JDO_PC_jdoNewObjectIdInstance_Object_Mods;
3044         final ExceptionsAttribute exceptAttr = null;
3045 
3046         // begin of method body
3047         final InsnTarget begin = new InsnTarget();
3048         Insn insn = begin;
3049 
3050         // generate empty method in case of datastore identity
3051         final String keyClassName = analyzer.getKeyClassName();
3052         if (keyClassName == null){
3053             // end of method body
3054             insn = insn.append(Insn.create(opc_aconst_null));
3055             insn = insn.append(Insn.create(opc_areturn));
3056 
3057             final CodeAttribute codeAttr
3058                 = new CodeAttribute(getCodeAttributeUtf8(),
3059                                     1, // maxStack
3060                                     2, // maxLocals
3061                                     begin,
3062                                     new ExceptionTable(),
3063                                     new AttributeVector());
3064             augmenter.addMethod(methodName, methodSig, accessFlags,
3065                                 codeAttr, exceptAttr);
3066             return;
3067         }
3068         affirm(keyClassName != null);
3069 
3070         // TODO: support for single field identity
3071 
3072         // push a newly created an instance of this class
3073         insn = insn.append(
3074             Insn.create(opc_new,
3075                         pool.addClass(keyClassName)));
3076         insn = insn.append(Insn.create(opc_dup));
3077         insn = insn.append(Insn.create(opc_aload_1));
3078         insn = insn.append(Insn.create(opc_checkcast, 
3079                                        pool.addClass(JAVA_String_Path)));
3080         insn = insn.append(
3081             Insn.create(opc_invokespecial,
3082                         pool.addMethodRef(
3083                             keyClassName,
3084                             NameHelper.constructorName(),
3085                             NameHelper.constructorSig(JAVA_String_Sig))));
3086 
3087         // end of method body
3088         insn = insn.append(Insn.create(opc_areturn));
3089 
3090         final CodeAttribute codeAttr
3091             = new CodeAttribute(getCodeAttributeUtf8(),
3092                                 3, // maxStack
3093                                 2, // maxLocals
3094                                 begin,
3095                                 new ExceptionTable(),
3096                                 new AttributeVector());
3097         augmenter.addMethod(methodName, methodSig, accessFlags,
3098                             codeAttr, exceptAttr);
3099     }
3100 
3101     // ----------------------------------------------------------------------
3102 
3103     /***
3104      * Build the jdoCopyKeyFieldsToObjectId method for the class.
3105      */
3106     public void addJDOCopyKeyFieldsToObjectIdMethod()
3107     {
3108         addJDOCopyKeyFieldsToFromObjectIdMethod(true);
3109     }
3110     
3111     /***
3112      * Build the jdoCopyKeyFieldsFromObjectId method for the class.
3113      */
3114     public void addJDOCopyKeyFieldsFromObjectIdMethod()
3115     {
3116         addJDOCopyKeyFieldsToFromObjectIdMethod(false);
3117     }
3118     
3119     /***
3120      * Build the jdoCopyKeyFieldsTo/FromObjectId method for the class.
3121      *
3122      * public void jdoCopyKeyFieldsTo/FromObjectId(Object oid)
3123      * {
3124      *     if (!(oid instanceof XXX)) {
3125      *         throw new IllegalArgumentException("arg0");
3126      *     }
3127      *     final XXX _oid = (XXX)oid;
3128      *     <if (superKeyClassname != null) {>
3129      *         super.jdoCopyKeyFieldsToObjectId(oid);
3130      *     <}>
3131      *     _oid.yyy = this.yyy;
3132      *     ...
3133      * }
3134      */
3135     private void addJDOCopyKeyFieldsToFromObjectIdMethod(boolean isToOid)
3136     {
3137         final String methodName;
3138         final String methodSig;
3139         final int accessFlags;
3140         if (isToOid) {
3141             methodName = JDO_PC_jdoCopyKeyFieldsToObjectId_Name;
3142             methodSig = JDO_PC_jdoCopyKeyFieldsToObjectId_Sig;
3143             accessFlags = JDO_PC_jdoCopyKeyFieldsToObjectId_Mods;        
3144         } else {
3145             methodName = JDO_PC_jdoCopyKeyFieldsFromObjectId_Name;
3146             methodSig = JDO_PC_jdoCopyKeyFieldsFromObjectId_Sig;
3147             accessFlags = JDO_PC_jdoCopyKeyFieldsFromObjectId_Mods;
3148         }
3149         final ExceptionsAttribute exceptAttr = null;
3150 
3151         // begin of method body
3152         final InsnTarget begin = new InsnTarget();
3153         Insn insn = begin;
3154 
3155         // generate empty method in case of datastore identity
3156         final String keyClassName = analyzer.getKeyClassName();
3157         if (keyClassName == null){
3158             // end of method body
3159             insn = insn.append(Insn.create(opc_return));
3160 
3161             final CodeAttribute codeAttr
3162                 = new CodeAttribute(getCodeAttributeUtf8(),
3163                                     0, // maxStack
3164                                     2, // maxLocals
3165                                     begin,
3166                                     new ExceptionTable(),
3167                                     new AttributeVector());
3168             augmenter.addMethod(methodName, methodSig, accessFlags,
3169                                 codeAttr, exceptAttr);
3170             return;
3171         }
3172         affirm(keyClassName != null);
3173 
3174         // check oid argument
3175         final ConstClass keyConstClass = pool.addClass(keyClassName);
3176         affirm(keyConstClass != null);
3177         insn = appendCheckVarInstanceOf(insn, 1, keyConstClass,
3178                                         JAVA_IllegalArgumentException_Path,
3179                                         "arg1");
3180 
3181         // downcast argument
3182         insn = insn.append(Insn.create(opc_aload_1));
3183         insn = insn.append(Insn.create(opc_checkcast, keyConstClass));
3184         insn = insn.append(Insn.create(opc_astore_2));
3185 
3186         // check argument or delegate to superclass
3187         final boolean isPCRoot = analyzer.isAugmentableAsRoot();
3188         if (!isPCRoot) {
3189             // call super.jdoCopyKeyFieldsToObjectId(oid)
3190 
3191             //^olsen: javac uses the truelly declaring class
3192             //final ConstClass superConstClass = classFile.superName();
3193             //affirm(superConstClass != null);
3194             //final String superClassName = superConstClass.asString();
3195             //affirm(superClassName != null);
3196 
3197             final String superClassName
3198                 = analyzer.getPCSuperKeyOwnerClassName();
3199             affirm(superClassName != null);
3200             insn = insn.append(Insn.create(opc_aload_0));
3201             insn = insn.append(Insn.create(opc_aload_2));
3202             insn = insn.append(
3203                 Insn.create(opc_invokespecial,
3204                             pool.addMethodRef(
3205                                 superClassName,
3206                                 methodName,
3207                                 methodSig)));
3208         }
3209         
3210         // get types of and field references of the key fields
3211         final int keyFieldCount = analyzer.getKeyFieldCount();
3212         final ConstFieldRef[] keyFieldRefs = getKeyFieldRefs();
3213         final ConstFieldRef[] keyClassKeyFieldRefs = getKeyClassKeyFieldRefs();
3214         affirm(keyFieldRefs.length == keyFieldCount);
3215         affirm(keyClassKeyFieldRefs.length == keyFieldCount);
3216 
3217         // generate the assignment statements
3218         int maxFieldSize = 0;
3219         for (int i = 0; i < keyFieldCount; i++) {
3220             // assign key field
3221             final ConstFieldRef thisClassKeyRef = keyFieldRefs[i];
3222             final ConstFieldRef keyClassKeyRef = keyClassKeyFieldRefs[i];
3223             affirm(thisClassKeyRef != null);
3224             affirm(keyClassKeyRef != null);
3225             if (isToOid) {
3226                 insn = insn.append(Insn.create(opc_aload_2));
3227                 insn = insn.append(Insn.create(opc_aload_0));
3228                 insn = insn.append(Insn.create(opc_getfield, thisClassKeyRef));
3229                 insn = insn.append(Insn.create(opc_putfield, keyClassKeyRef));
3230             } else {
3231                 insn = insn.append(Insn.create(opc_aload_0));
3232                 insn = insn.append(Insn.create(opc_aload_2));
3233                 insn = insn.append(Insn.create(opc_getfield, keyClassKeyRef));
3234                 insn = insn.append(Insn.create(opc_putfield, thisClassKeyRef));
3235             }
3236 
3237             // compute stack demand
3238             final String sig
3239                 = thisClassKeyRef.nameAndType().signature().asString();
3240             affirm(sig != null && sig.length() > 0);
3241             maxFieldSize = max(maxFieldSize, Descriptor.countFieldWords(sig));
3242         }
3243 
3244         // end of method body
3245         insn = insn.append(Insn.create(opc_return));
3246 
3247         final CodeAttribute codeAttr
3248             = new CodeAttribute(getCodeAttributeUtf8(),
3249                                 max(maxFieldSize + 1, 3), // maxStack
3250                                 3, // maxLocals
3251                                 begin,
3252                                 new ExceptionTable(),
3253                                 new AttributeVector());
3254         augmenter.addMethod(methodName, methodSig, accessFlags,
3255                             codeAttr, exceptAttr);
3256     }
3257 
3258     /***
3259      * Adds the code for one case-branch in the jdoCopyKeyFieldsToObjectId.
3260      */
3261     private Insn appendCopyKeyFieldToOid(Insn insn,
3262                                          String fetchXXXField_Name,
3263                                          String fetchXXXField_Sig,
3264                                          int keyFieldNo,
3265                                          ConstFieldRef keyFieldRef,
3266                                          String keyFieldSig)
3267     {
3268         affirm(insn != null);
3269         affirm(fetchXXXField_Name != null);
3270         affirm(fetchXXXField_Sig != null);
3271         affirm(keyFieldNo >= 0);
3272         affirm(keyFieldRef != null);
3273         affirm(keyFieldSig != null && keyFieldSig.length() > 0);
3274 
3275         // push oid, ofs
3276         insn = insn.append(Insn.create(opc_aload_3));
3277         insn = insn.append(Insn.create(opc_aload_1));
3278 
3279         // push absolute field index
3280         insn = insn.append(
3281             Insn.create(opc_getstatic,
3282                         pool.addFieldRef(
3283                             className,
3284                             JDO_PC_jdoInheritedFieldCount_Name,
3285                             JDO_PC_jdoInheritedFieldCount_Sig)));
3286         insn = insn.append(InsnUtils.integerConstant(keyFieldNo, pool));
3287         insn = insn.append(Insn.create(opc_iadd));
3288 
3289         // call fetchXXXField
3290         insn = insn.append(
3291             new InsnInterfaceInvoke(
3292                 pool.addInterfaceMethodRef(
3293                     JDO_ObjectIdFieldSupplier_Path,
3294                     fetchXXXField_Name,
3295                     fetchXXXField_Sig),
3296                 countMethodArgWords(fetchXXXField_Sig)));
3297 
3298         // downcast an Object value to actual field type if neccessary
3299         if (fetchXXXField_Name.equals(JDO_OIFS_fetchObjectField_Name)
3300             && !keyFieldSig.equals(JAVA_Object_Sig)) {
3301             final String fieldType = NameHelper.pathForSig(keyFieldSig);
3302             insn = insn.append(
3303                 Insn.create(opc_checkcast,
3304                             pool.addClass(fieldType)));
3305         }
3306 
3307         // assign
3308         insn = insn.append(Insn.create(opc_putfield, keyFieldRef));
3309         
3310         affirm(insn != null);
3311         return insn;
3312     }
3313     
3314     /***
3315      * Adds the field assignment code for the jdoCopyKeyFieldsToObjectId.
3316      */
3317     private Insn appendStatementsForCopyKeyFieldsToOid(Insn insn,
3318                                                        SizeHolder sizeHolder)
3319     {
3320         affirm(insn != null);
3321         affirm(sizeHolder != null);
3322 
3323         // get field references of the key fields
3324         final int keyFieldCount = analyzer.getKeyFieldCount();
3325         final ConstFieldRef[] keyFieldRefs = getKeyClassKeyFieldRefs();
3326         final int[] keyFieldIndexes = analyzer.getKeyFieldIndexes();
3327         affirm(keyFieldRefs.length == keyFieldCount);
3328         affirm(keyFieldIndexes.length == keyFieldCount);
3329 
3330         // generate the field access statements
3331         for (int i = 0; i < keyFieldCount; i++) {
3332             // get field no, constant field ref, and signature for field
3333             final int no = keyFieldIndexes[i];
3334             final ConstFieldRef ref = keyFieldRefs[i];
3335             affirm(ref != null);
3336             final String sig = ref.nameAndType().signature().asString();
3337             affirm(sig != null && sig.length() > 0);
3338 
3339             // compute stack demand
3340             sizeHolder.size = max(sizeHolder.size,
3341                                   Descriptor.countFieldWords(sig));
3342 
3343             // generate the field copying depending on its type
3344             switch (sig.charAt(0)) {
3345             case 'Z':
3346                 insn = appendCopyKeyFieldToOid(
3347                     insn,
3348                     JDO_OIFS_fetchBooleanField_Name,
3349                     JDO_OIFS_fetchBooleanField_Sig,
3350                     no, ref, sig);
3351                 break;
3352             case 'C':
3353                 insn = appendCopyKeyFieldToOid(
3354                     insn,
3355                     JDO_OIFS_fetchCharField_Name,
3356                     JDO_OIFS_fetchCharField_Sig,
3357                     no, ref, sig);
3358                 break;
3359             case 'B':
3360                 insn = appendCopyKeyFieldToOid(
3361                     insn,
3362                     JDO_OIFS_fetchByteField_Name,
3363                     JDO_OIFS_fetchByteField_Sig,
3364                     no, ref, sig);
3365                 break;
3366             case 'S':
3367                 insn = appendCopyKeyFieldToOid(
3368                     insn,
3369                     JDO_OIFS_fetchShortField_Name,
3370                     JDO_OIFS_fetchShortField_Sig,
3371                     no, ref, sig);
3372                 break;
3373             case 'I':
3374                 insn = appendCopyKeyFieldToOid(
3375                     insn,
3376                     JDO_OIFS_fetchIntField_Name,
3377                     JDO_OIFS_fetchIntField_Sig,
3378                     no, ref, sig);
3379                 break;
3380             case 'J':
3381                 insn = appendCopyKeyFieldToOid(
3382                     insn,
3383                     JDO_OIFS_fetchLongField_Name,
3384                     JDO_OIFS_fetchLongField_Sig,
3385                     no, ref, sig);
3386                 break;
3387             case 'F':
3388                 insn = appendCopyKeyFieldToOid(
3389                     insn,
3390                     JDO_OIFS_fetchFloatField_Name,
3391                     JDO_OIFS_fetchFloatField_Sig,
3392                     no, ref, sig);
3393                 break;
3394             case 'D':
3395                 insn = appendCopyKeyFieldToOid(
3396                     insn,
3397                     JDO_OIFS_fetchDoubleField_Name,
3398                     JDO_OIFS_fetchDoubleField_Sig,
3399                     no, ref, sig);
3400                 break;
3401             case 'L':
3402             case '[':
3403                 if (sig.equals(JAVA_String_Sig)) {
3404                     insn = appendCopyKeyFieldToOid(
3405                         insn,
3406                         JDO_OIFS_fetchStringField_Name,
3407                         JDO_OIFS_fetchStringField_Sig,
3408                         no, ref, sig);
3409                 } else {
3410                     insn = appendCopyKeyFieldToOid(
3411                         insn,
3412                         JDO_OIFS_fetchObjectField_Name,
3413                         JDO_OIFS_fetchObjectField_Sig,
3414                         no, ref, sig);
3415                 }
3416                 break;
3417             default:
3418                 affirm(false, "Illegal field type: " + sig);
3419             }
3420         }
3421 
3422         affirm(insn != null);
3423         return insn;
3424     }
3425  
3426     /***
3427      * Adds the code for one case-branch in the jdoCopyKeyFieldsFromObjectId.
3428      */
3429     private Insn appendCopyKeyFieldFromOid(Insn insn,
3430                                            String storeXXXField_Name,
3431                                            String storeXXXField_Sig,
3432                                            int keyFieldNo,
3433                                            ConstFieldRef keyFieldRef)
3434     {
3435         affirm(insn != null);
3436         affirm(storeXXXField_Name != null);
3437         affirm(storeXXXField_Sig != null);
3438         affirm(keyFieldNo >= 0);
3439         affirm(keyFieldRef != null);
3440 
3441         // push ofc
3442         insn = insn.append(Insn.create(opc_aload_1));
3443 
3444         // push absolute field index
3445         insn = insn.append(
3446             Insn.create(opc_getstatic,
3447                         pool.addFieldRef(
3448                             className,
3449                             JDO_PC_jdoInheritedFieldCount_Name,
3450                             JDO_PC_jdoInheritedFieldCount_Sig)));
3451         insn = insn.append(InsnUtils.integerConstant(keyFieldNo, pool));
3452         insn = insn.append(Insn.create(opc_iadd));
3453 
3454         // push oid field
3455         insn = insn.append(Insn.create(opc_aload_3));
3456         insn = insn.append(Insn.create(opc_getfield, keyFieldRef));
3457 
3458         // call storeXXXField
3459         insn = insn.append(
3460             new InsnInterfaceInvoke(
3461                 pool.addInterfaceMethodRef(
3462                     JDO_ObjectIdFieldConsumer_Path,
3463                     storeXXXField_Name,
3464                     storeXXXField_Sig),
3465                 countMethodArgWords(storeXXXField_Sig)));
3466 
3467         affirm(insn != null);
3468         return insn;
3469     }
3470     
3471     /***
3472      * Adds the field assignment code for the jdoCopyKeyFieldsFromObjectId.
3473      */
3474     private Insn appendStatementsForCopyKeyFieldsFromOid(Insn insn,
3475                                                          SizeHolder sizeHolder)
3476     {
3477         affirm(insn != null);
3478         affirm(sizeHolder != null);
3479 
3480         // get field references of the key fields
3481         final int keyFieldCount = analyzer.getKeyFieldCount();
3482         final ConstFieldRef[] keyFieldRefs = getKeyClassKeyFieldRefs();
3483         final int[] keyFieldIndexes = analyzer.getKeyFieldIndexes();
3484         affirm(keyFieldRefs.length == keyFieldCount);
3485         affirm(keyFieldIndexes.length == keyFieldCount);
3486 
3487         // generate the field access statements
3488         for (int i = 0; i < keyFieldCount; i++) {
3489             // get field no, constant field ref, and signature for field
3490             final int no = keyFieldIndexes[i];
3491             final ConstFieldRef ref = keyFieldRefs[i];
3492             affirm(ref != null);
3493             final String sig = ref.nameAndType().signature().asString();
3494             affirm(sig != null && sig.length() > 0);
3495 
3496             // compute stack demand
3497             sizeHolder.size = max(sizeHolder.size,
3498                                   Descriptor.countFieldWords(sig));
3499 
3500             // generate the field copying depending on its type
3501             switch (sig.charAt(0)) {
3502             case 'Z':
3503                 insn = appendCopyKeyFieldFromOid(
3504                     insn,
3505                     JDO_OIFC_storeBooleanField_Name,
3506                     JDO_OIFC_storeBooleanField_Sig,
3507                     no, ref);
3508                 break;
3509             case 'C':
3510                 insn = appendCopyKeyFieldFromOid(
3511                     insn,
3512                     JDO_OIFC_storeCharField_Name,
3513                     JDO_OIFC_storeCharField_Sig,
3514                     no, ref);
3515                 break;
3516             case 'B':
3517                 insn = appendCopyKeyFieldFromOid(
3518                     insn,
3519                     JDO_OIFC_storeByteField_Name,
3520                     JDO_OIFC_storeByteField_Sig,
3521                     no, ref);
3522                 break;
3523             case 'S':
3524                 insn = appendCopyKeyFieldFromOid(
3525                     insn,
3526                     JDO_OIFC_storeShortField_Name,
3527                     JDO_OIFC_storeShortField_Sig,
3528                     no, ref);
3529                 break;
3530             case 'I':
3531                 insn = appendCopyKeyFieldFromOid(
3532                     insn,
3533                     JDO_OIFC_storeIntField_Name,
3534                     JDO_OIFC_storeIntField_Sig,
3535                     no, ref);
3536                 break;
3537             case 'J':
3538                 insn = appendCopyKeyFieldFromOid(
3539                     insn,
3540                     JDO_OIFC_storeLongField_Name,
3541                     JDO_OIFC_storeLongField_Sig,
3542                     no, ref);
3543                 break;
3544             case 'F':
3545                 insn = appendCopyKeyFieldFromOid(
3546                     insn,
3547                     JDO_OIFC_storeFloatField_Name,
3548                     JDO_OIFC_storeFloatField_Sig,
3549                     no, ref);
3550                 break;
3551             case 'D':
3552                 insn = appendCopyKeyFieldFromOid(
3553                     insn,
3554                     JDO_OIFC_storeDoubleField_Name,
3555                     JDO_OIFC_storeDoubleField_Sig,
3556                     no, ref);
3557                 break;
3558             case 'L':
3559             case '[':
3560                 if (sig.equals(JAVA_String_Sig)) {
3561                     insn = appendCopyKeyFieldFromOid(
3562                         insn,
3563                         JDO_OIFC_storeStringField_Name,
3564                         JDO_OIFC_storeStringField_Sig,
3565                         no, ref);
3566                 } else {
3567                     insn = appendCopyKeyFieldFromOid(
3568                         insn,
3569                         JDO_OIFC_storeObjectField_Name,
3570                         JDO_OIFC_storeObjectField_Sig,
3571                         no, ref);
3572                 }
3573                 break;
3574             default:
3575                 affirm(false, "Illegal field type: " + sig);
3576             }
3577         }
3578 
3579         affirm(insn != null);
3580         return insn;
3581     }
3582  
3583    /***
3584     * Build the jdoCopyKeyFieldsToObjectId method for the class.
3585     */
3586     public void addJDOCopyKeyFieldsToObjectIdOIFSMethod()
3587     {
3588         addJDOCopyKeyFieldsToFromObjectIdOIFSMethod(true);
3589     }
3590     
3591    /***
3592     * Build the jdoCopyKeyFieldsFromObjectId method for the class.
3593     */
3594     public void addJDOCopyKeyFieldsFromObjectIdOIFCMethod()
3595     {
3596         addJDOCopyKeyFieldsToFromObjectIdOIFSMethod(false);
3597     }
3598     
3599     /***
3600      * Build the jdoCopyKeyFieldsTo/FromObjectId method for the class.
3601      *
3602      * public void jdoCopyKeyFieldsTo/FromObjectId(
3603      *     ObjectIdFieldSupplier/Consumer fm,
3604      *     Object oid)
3605      * {
3606      *     if (fm == null) {
3607      *         throw new IllegalArgumentException("arg0");
3608      *     }
3609      *     if (!(oid instanceof XXX)) {
3610      *         throw new IllegalArgumentException("arg1");
3611      *     }
3612      *     final XXX _oid = (XXX)oid;
3613      *     <if (superKeyClassname != null) {>
3614      *         super.jdoCopyKeyFieldsTo/FromObjectId(fm, _oid);
3615      *     <}>
3616      *     _oid.yyy = ofs.fetchIntField(jdoInheritedFieldCount + 0);
3617      *   / ofc.storeIntField(jdoInheritedFieldCount + 0, _oid.yyy);
3618      *     ...
3619      * }
3620      */
3621     private void addJDOCopyKeyFieldsToFromObjectIdOIFSMethod(boolean isToOid)
3622     {
3623         final String methodName;
3624         final String methodSig;
3625         final int accessFlags;
3626         if (isToOid) {
3627             methodName = JDO_PC_jdoCopyKeyFieldsToObjectId_OIFS_Name;
3628             methodSig = JDO_PC_jdoCopyKeyFieldsToObjectId_OIFS_Sig;
3629             accessFlags = JDO_PC_jdoCopyKeyFieldsToObjectId_OIFS_Mods;        
3630         } else {
3631             methodName = JDO_PC_jdoCopyKeyFieldsFromObjectId_OIFC_Name;
3632             methodSig = JDO_PC_jdoCopyKeyFieldsFromObjectId_OIFC_Sig;
3633             accessFlags = JDO_PC_jdoCopyKeyFieldsFromObjectId_OIFC_Mods;
3634         }
3635         final ExceptionsAttribute exceptAttr = null;
3636 
3637         // begin of method body
3638         final InsnTarget begin = new InsnTarget();
3639         Insn insn = begin;
3640 
3641         // generate empty method in case of datastore identity
3642         final String keyClassName = analyzer.getKeyClassName();
3643         if (keyClassName == null){
3644             // end of method body
3645             insn = insn.append(Insn.create(opc_return));
3646 
3647             final CodeAttribute codeAttr
3648                 = new CodeAttribute(getCodeAttributeUtf8(),
3649                                     0, // maxStack
3650                                     3, // maxLocals
3651                                     begin,
3652                                     new ExceptionTable(),
3653                                     new AttributeVector());
3654             augmenter.addMethod(methodName, methodSig, accessFlags,
3655                                 codeAttr, exceptAttr);
3656             return;
3657         }
3658         affirm(keyClassName != null);
3659 
3660         // check fm argument
3661         insn = appendCheckVarNonNull(insn, 1,
3662                                      JAVA_IllegalArgumentException_Path,
3663                                      "arg1");
3664         
3665         // check oid argument
3666         final ConstClass keyConstClass = pool.addClass(keyClassName);
3667         affirm(keyConstClass != null);
3668         insn = appendCheckVarInstanceOf(insn, 2, keyConstClass,
3669                                         JAVA_IllegalArgumentException_Path,
3670                                         "arg2");
3671 
3672         // downcast argument
3673         insn = insn.append(Insn.create(opc_aload_2));
3674         insn = insn.append(Insn.create(opc_checkcast, keyConstClass));
3675         insn = insn.append(Insn.create(opc_astore_3));
3676 
3677         // call super.jdoCopyKeyFieldsToObjectId(oid)
3678         final boolean isPCRoot = analyzer.isAugmentableAsRoot();
3679         if (!isPCRoot) {
3680             // call super.jdoCopyKeyFieldsToObjectId(oid)
3681 
3682             //^olsen: javac uses the truelly declaring class
3683             //final ConstClass superConstClass = classFile.superName();
3684             //affirm(superConstClass != null);
3685             //final String superClassName = superConstClass.asString();
3686             //affirm(superClassName != null);
3687 
3688             final String superClassName
3689                 = analyzer.getPCSuperKeyOwnerClassName();
3690             insn = insn.append(Insn.create(opc_aload_0));
3691             insn = insn.append(Insn.create(opc_aload_1));
3692             insn = insn.append(Insn.create(opc_aload_3));
3693             insn = insn.append(
3694                 Insn.create(opc_invokespecial,
3695                             pool.addMethodRef(
3696                                 superClassName,
3697                                 methodName,
3698                                 methodSig)));
3699         }
3700         
3701         // get types of and field references of the key fields
3702         final int keyFieldCount = analyzer.getKeyFieldCount();
3703         final ConstFieldRef[] keyFieldRefs = getKeyFieldRefs();
3704         final ConstFieldRef[] keyClassKeyFieldRefs = getKeyClassKeyFieldRefs();
3705         affirm(keyFieldRefs.length == keyFieldCount);
3706         affirm(keyClassKeyFieldRefs.length == keyFieldCount);
3707 
3708         // generate the case-targets for the method calls
3709         final SizeHolder sizeHolder = new SizeHolder();
3710         if (isToOid) {
3711             insn = appendStatementsForCopyKeyFieldsToOid(insn, sizeHolder);
3712         } else {
3713             insn = appendStatementsForCopyKeyFieldsFromOid(insn, sizeHolder);
3714         }
3715 
3716         // end of method body
3717         insn = insn.append(Insn.create(opc_return));
3718 
3719         final CodeAttribute codeAttr
3720             = new CodeAttribute(getCodeAttributeUtf8(),
3721                                 max(sizeHolder.size
3722                                     + (isToOid ? 3 : 2), 3), // maxStack
3723                                 4, // maxLocals
3724                                 begin,
3725                                 new ExceptionTable(),
3726                                 new AttributeVector());
3727         augmenter.addMethod(methodName, methodSig, accessFlags,
3728                             codeAttr, exceptAttr);
3729     }
3730 
3731     // ----------------------------------------------------------------------
3732 
3733     /***
3734      * Append the code for returning the value from a direct read access.
3735      */
3736     private Insn appendDirectReadReturn(Insn insn,
3737                                         ConstFieldRef fieldRef)
3738     {
3739         affirm(insn != null);
3740         affirm(fieldRef != null);
3741 
3742         final String sig = fieldRef.nameAndType().signature().asString();
3743         affirm(sig != null && sig.length() > 0);
3744 
3745         // read field
3746         insn = insn.append(Insn.create(opc_aload_0));
3747         insn = insn.append(Insn.create(opc_getfield, fieldRef));
3748         switch (sig.charAt(0)) {
3749         case 'Z':
3750         case 'C':
3751         case 'B':
3752         case 'S':
3753         case 'I':
3754             insn = insn.append(Insn.create(opc_ireturn));
3755             break;
3756         case 'J':
3757             insn = insn.append(Insn.create(opc_lreturn));
3758             break;
3759         case 'F':
3760             insn = insn.append(Insn.create(opc_freturn));
3761             break;
3762         case 'D':
3763             insn = insn.append(Insn.create(opc_dreturn));
3764             break;
3765         case 'L':
3766         case '[':
3767             insn = insn.append(Insn.create(opc_areturn));
3768             break;
3769         default:
3770             affirm(false, "Illegal field type: " + sig);
3771         }
3772 
3773         affirm(insn != null);
3774         return insn;
3775     }
3776 
3777     /***
3778      * Build an accessor method for direct read access.
3779      *
3780      * static xxx final YYY jdoGetyyy(XXX instance)
3781      * {
3782      *     // augmentation: grant direct read access
3783      *     return instance.yyy;
3784      * }
3785      */
3786     public void addJDODirectReadAccessMethod(String methodName,
3787                                              String methodSig,
3788                                              int accessFlags,
3789                                              int fieldIndex)
3790     {
3791         affirm(methodName != null);      
3792         affirm(methodSig != null);      
3793         final ExceptionsAttribute exceptAttr = null;
3794 
3795         // begin of method body
3796         final InsnTarget begin = new InsnTarget();
3797         Insn insn = begin;
3798 
3799         final ConstFieldRef fieldRef = getAnnotatedFieldRefs()[fieldIndex];
3800         affirm(fieldRef != null);
3801         final String sig = fieldRef.nameAndType().signature().asString();
3802         affirm(sig != null && sig.length() > 0);
3803         final int fieldSize = ((sig.equals("J") || sig.equals("D")) ? 2 : 1);
3804 
3805         // return direct read
3806         insn = appendDirectReadReturn(insn, fieldRef);
3807 
3808         // end of method body
3809 
3810         final CodeAttribute codeAttr
3811             = new CodeAttribute(getCodeAttributeUtf8(),
3812                                 fieldSize, // maxStack
3813                                 1, // maxLocals
3814                                 begin,
3815                                 new ExceptionTable(),
3816                                 new AttributeVector());
3817         augmenter.addMethod(methodName, methodSig, accessFlags,
3818                             codeAttr, exceptAttr);
3819     }
3820 
3821     /***
3822      * Append the code for mediated read access.
3823      */
3824     public Insn appendMediatedReadAccess(Insn insn,
3825                                          int fieldIndex,
3826                                          ConstFieldRef fieldRef,
3827                                          int varStart)
3828     {
3829         affirm(insn != null);      
3830         affirm(fieldRef != null);
3831 
3832         final String sig = fieldRef.nameAndType().signature().asString();
3833         affirm(sig != null && sig.length() > 0);
3834 
3835         // store the sm field into local var
3836         insn = insn.append(Insn.create(opc_aload_0));
3837         insn = insn.append(
3838             Insn.create(
3839                 opc_getfield,
3840                 getjdoStateManagerFieldRef()));
3841         insn = insn.append(InsnUtils.aStore(varStart, pool));
3842 
3843         // test the sm field and return field if null
3844         final InsnTarget callIsLoaded = new InsnTarget();
3845         insn = insn.append(InsnUtils.aLoad(varStart, pool));
3846         insn = insn.append(Insn.create(opc_ifnonnull, callIsLoaded));
3847         insn = appendDirectReadReturn(insn, fieldRef);
3848 
3849         // call sm for isLoaded
3850         insn = insn.append(callIsLoaded);
3851         insn = insn.append(InsnUtils.aLoad(varStart, pool));
3852 
3853         // push instance
3854         insn = insn.append(Insn.create(opc_aload_0));
3855 
3856         // push absolute field index
3857         insn = insn.append(
3858             Insn.create(opc_getstatic,
3859                         pool.addFieldRef(
3860                             className,
3861                             JDO_PC_jdoInheritedFieldCount_Name,
3862                             JDO_PC_jdoInheritedFieldCount_Sig)));
3863         insn = insn.append(InsnUtils.integerConstant(fieldIndex, pool));
3864         insn = insn.append(Insn.create(opc_iadd));
3865 
3866         // test result of isLoaded and return field if nonzero
3867         final InsnTarget mediate = new InsnTarget();
3868         insn = insn.append(
3869             new InsnInterfaceInvoke(
3870                 pool.addInterfaceMethodRef(
3871                     JDO_StateManager_Path,
3872                     JDO_SM_isLoaded_Name,
3873                     JDO_SM_isLoaded_Sig),
3874                 countMethodArgWords(JDO_SM_isLoaded_Sig)));
3875         insn = insn.append(Insn.create(opc_ifeq, mediate));
3876         insn = appendDirectReadReturn(insn, fieldRef);
3877 
3878         // call sm for mediation
3879         insn = insn.append(mediate);
3880         insn = insn.append(InsnUtils.aLoad(varStart, pool));
3881 
3882         // push instance
3883         insn = insn.append(Insn.create(opc_aload_0));
3884 
3885         // push absolute field index
3886         insn = insn.append(
3887             Insn.create(opc_getstatic,
3888                         pool.addFieldRef(
3889                             className,
3890                             JDO_PC_jdoInheritedFieldCount_Name,
3891                             JDO_PC_jdoInheritedFieldCount_Sig)));
3892         insn = insn.append(InsnUtils.integerConstant(fieldIndex, pool));
3893         insn = insn.append(Insn.create(opc_iadd));
3894 
3895         // push field
3896         insn = insn.append(Insn.create(opc_aload_0));
3897         insn = insn.append(Insn.create(opc_getfield, fieldRef));
3898 
3899         // call the sm's get field method
3900         switch (sig.charAt(0)) {
3901         case 'Z':
3902             insn = insn.append(
3903                 new InsnInterfaceInvoke(
3904                     pool.addInterfaceMethodRef(
3905                         JDO_StateManager_Path,
3906                         JDO_SM_getBooleanField_Name,
3907                         JDO_SM_getBooleanField_Sig),
3908                     countMethodArgWords(JDO_SM_getBooleanField_Sig)));
3909             insn = insn.append(Insn.create(opc_ireturn));
3910             break;
3911         case 'C':
3912             insn = insn.append(
3913                 new InsnInterfaceInvoke(
3914                     pool.addInterfaceMethodRef(
3915                         JDO_StateManager_Path,
3916                         JDO_SM_getCharField_Name,
3917                         JDO_SM_getCharField_Sig),
3918                     countMethodArgWords(JDO_SM_getCharField_Sig)));
3919             insn = insn.append(Insn.create(opc_ireturn));
3920             break;
3921         case 'B':
3922             insn = insn.append(
3923                 new InsnInterfaceInvoke(
3924                     pool.addInterfaceMethodRef(
3925                         JDO_StateManager_Path,
3926                         JDO_SM_getByteField_Name,
3927                         JDO_SM_getByteField_Sig),
3928                     countMethodArgWords(JDO_SM_getByteField_Sig)));
3929             insn = insn.append(Insn.create(opc_ireturn));
3930             break;
3931         case 'S':
3932             insn = insn.append(
3933                 new InsnInterfaceInvoke(
3934                     pool.addInterfaceMethodRef(
3935                         JDO_StateManager_Path,
3936                         JDO_SM_getShortField_Name,
3937                         JDO_SM_getShortField_Sig),
3938                     countMethodArgWords(JDO_SM_getShortField_Sig)));
3939             insn = insn.append(Insn.create(opc_ireturn));
3940             break;
3941         case 'I':
3942             insn = insn.append(
3943                 new InsnInterfaceInvoke(
3944                     pool.addInterfaceMethodRef(
3945                         JDO_StateManager_Path,
3946                         JDO_SM_getIntField_Name,
3947                         JDO_SM_getIntField_Sig),
3948                     countMethodArgWords(JDO_SM_getIntField_Sig)));
3949             insn = insn.append(Insn.create(opc_ireturn));
3950             break;
3951         case 'J':
3952             insn = insn.append(
3953                 new InsnInterfaceInvoke(
3954                     pool.addInterfaceMethodRef(
3955                         JDO_StateManager_Path,
3956                         JDO_SM_getLongField_Name,
3957                         JDO_SM_getLongField_Sig),
3958                     countMethodArgWords(JDO_SM_getLongField_Sig)));
3959             insn = insn.append(Insn.create(opc_lreturn));
3960             break;
3961         case 'F':
3962             insn = insn.append(
3963                 new InsnInterfaceInvoke(
3964                     pool.addInterfaceMethodRef(
3965                         JDO_StateManager_Path,
3966                         JDO_SM_getFloatField_Name,
3967                         JDO_SM_getFloatField_Sig),
3968                     countMethodArgWords(JDO_SM_getFloatField_Sig)));
3969             insn = insn.append(Insn.create(opc_freturn));
3970             break;
3971         case 'D':
3972             insn = insn.append(
3973                 new InsnInterfaceInvoke(
3974                     pool.addInterfaceMethodRef(
3975                         JDO_StateManager_Path,
3976                         JDO_SM_getDoubleField_Name,
3977                         JDO_SM_getDoubleField_Sig),
3978                     countMethodArgWords(JDO_SM_getDoubleField_Sig)));
3979             insn = insn.append(Insn.create(opc_dreturn));
3980             break;
3981         case 'L':
3982         case '[':
3983             if (sig.equals(JAVA_String_Sig)) {
3984                 insn = insn.append(
3985                     new InsnInterfaceInvoke(
3986                         pool.addInterfaceMethodRef(
3987                             JDO_StateManager_Path,
3988                             JDO_SM_getStringField_Name,
3989                             JDO_SM_getStringField_Sig),
3990                         countMethodArgWords(JDO_SM_getStringField_Sig)));
3991                 insn = insn.append(Insn.create(opc_areturn));
3992             } else {
3993                 insn = insn.append(
3994                     new InsnInterfaceInvoke(
3995                         pool.addInterfaceMethodRef(
3996                             JDO_StateManager_Path,
3997                             JDO_SM_getObjectField_Name,
3998                             JDO_SM_getObjectField_Sig),
3999                         countMethodArgWords(JDO_SM_getObjectField_Sig)));
4000                 if (!sig.equals(JAVA_Object_Sig)) {
4001                     final String fieldType = NameHelper.pathForSig(sig);
4002                     insn = insn.append(
4003                         Insn.create(opc_checkcast,
4004                                     pool.addClass(fieldType)));
4005                 }
4006                 insn = insn.append(Insn.create(opc_areturn));
4007             }
4008             break;
4009         default:
4010             affirm(false, "Illegal field type: " + sig);
4011         }
4012 
4013         affirm(insn != null);
4014         return insn;
4015     }
4016 
4017     /***
4018      * Build an accessor method for mediated read access.
4019      *
4020      * static xxx final YYY jdoGetyyy(XXX instance)
4021      * {
4022      *     // augmentation: mediate read access
4023      *     final javax.jdo.StateManager sm = instance.jdoStateManager;
4024      *     if (sm == null) {
4025      *         return instance.yyy;
4026      *     }
4027      *     if (sm.isLoaded(instance, instance.jdoInheritedFieldCount + y)) {
4028      *         return instance.yyy;
4029      *     }
4030      *     return (YYY)sm.getYYYField(instance,
4031      *                                instance.jdoInheritedFieldCount + x,
4032      *                                instance.yyy);
4033      * }
4034      */
4035     public void addJDOMediatedReadAccessMethod(String methodName,
4036                                                String methodSig,
4037                                                int accessFlags,
4038                                                int fieldIndex)
4039     {
4040         affirm(methodName != null);      
4041         affirm(methodSig != null);      
4042         final ExceptionsAttribute exceptAttr = null;
4043 
4044         // begin of method body
4045         final InsnTarget begin = new InsnTarget();
4046         Insn insn = begin;
4047 
4048         // get field's sig and compute first non-parameter slot
4049         final ConstFieldRef fieldRef = getAnnotatedFieldRefs()[fieldIndex];
4050         affirm(fieldRef != null);
4051         final String sig = fieldRef.nameAndType().signature().asString();
4052         affirm(sig != null && sig.length() > 0);
4053         final int fieldSize = ((sig.equals("J") || sig.equals("D")) ? 2 : 1);
4054         final int varStart = 1;
4055 
4056         // mediate access
4057         insn = appendMediatedReadAccess(insn, fieldIndex, fieldRef, varStart);
4058 
4059         // end of method body
4060 
4061         final CodeAttribute codeAttr
4062             = new CodeAttribute(getCodeAttributeUtf8(),
4063                                 fieldSize + 3, // maxStack
4064                                 2, // maxLocals
4065                                 begin,
4066                                 new ExceptionTable(),
4067                                 new AttributeVector());
4068 
4069         augmenter.addMethod(methodName, methodSig, accessFlags,
4070                             codeAttr, exceptAttr);
4071     }
4072 
4073     /***
4074      * Build an accessor method for checked read access.
4075      *
4076      * static xxx final YYY jdoGetyyy(XXX instance)
4077      * {
4078      *     // augmentation: check read access
4079      *     if (instance.jdoFlags <= 0) {
4080      *         return instance.yyy;
4081      *     }
4082      *     final javax.jdo.StateManager sm = instance.jdoStateManager;
4083      *     if (sm == null) {
4084      *         return instance.yyy;
4085      *     }
4086      *     if (sm.isLoaded(instance, instance.jdoInheritedFieldCount + y)) {
4087      *         return instance.yyy;
4088      *     }
4089      *     return (YYY)instance.jdoStateManager
4090      *         .getYYYField(instance,
4091      *                      instance.jdoInheritedFieldCount + y,
4092      *                      instance.yyy);
4093      * }
4094      */
4095     public void addJDOCheckedReadAccessMethod(String methodName,
4096                                               String methodSig,
4097                                               int accessFlags,
4098                                               int fieldIndex)
4099     {
4100         affirm(methodName != null);      
4101         affirm(methodSig != null);      
4102         final ExceptionsAttribute exceptAttr = null;
4103 
4104         // begin of method body
4105         final InsnTarget begin = new InsnTarget();
4106         Insn insn = begin;
4107 
4108         // get field's sig and compute first non-parameter slot
4109         final ConstFieldRef fieldRef = getAnnotatedFieldRefs()[fieldIndex];
4110         affirm(fieldRef != null);
4111         final String sig = fieldRef.nameAndType().signature().asString();
4112         affirm(sig != null && sig.length() > 0);
4113         final int fieldSize = ((sig.equals("J") || sig.equals("D")) ? 2 : 1);
4114         final int varStart = 1;
4115 
4116         // directly return field if flags are <= LOAD_REQUIRED
4117         final InsnTarget mediate = new InsnTarget();
4118         insn = insn.append(Insn.create(opc_aload_0));
4119         insn = insn.append(
4120             Insn.create(opc_getfield,
4121                         getjdoFlagsFieldRef()));
4122         insn = insn.append(Insn.create(opc_ifgt, mediate));
4123         insn = appendDirectReadReturn(insn, fieldRef);
4124 
4125         // mediate access
4126         insn = insn.append(mediate);
4127         insn = appendMediatedReadAccess(insn, fieldIndex, fieldRef, varStart);
4128 
4129         // end of method body
4130 
4131         final CodeAttribute codeAttr
4132             = new CodeAttribute(getCodeAttributeUtf8(),
4133                                 fieldSize + 3, // maxStack
4134                                 2, // maxLocals
4135                                 begin,
4136                                 new ExceptionTable(),
4137                                 new AttributeVector());
4138         augmenter.addMethod(methodName, methodSig, accessFlags,
4139                             codeAttr, exceptAttr);
4140     }
4141 
4142     /***
4143      * Append the code for assigning the argument to the field and return.
4144      */
4145     private Insn appendDirectWriteReturn(Insn insn,
4146                                          ConstFieldRef fieldRef)
4147     {
4148         affirm(insn != null);
4149         affirm(fieldRef != null);
4150 
4151         final String sig = fieldRef.nameAndType().signature().asString();
4152         affirm(sig != null && sig.length() > 0);
4153 
4154         // write argument to field and return
4155         insn = insn.append(Insn.create(opc_aload_0));
4156         switch (sig.charAt(0)) {
4157         case 'Z':
4158         case 'C':
4159         case 'B':
4160         case 'S':
4161         case 'I':
4162             insn = insn.append(Insn.create(opc_iload_1));
4163             break;
4164         case 'J':
4165             insn = insn.append(Insn.create(opc_lload_1));
4166             break;
4167         case 'F':
4168             insn = insn.append(Insn.create(opc_fload_1));
4169             break;
4170         case 'D':
4171             insn = insn.append(Insn.create(opc_dload_1));
4172             break;
4173         case 'L':
4174         case '[':
4175             insn = insn.append(Insn.create(opc_aload_1));
4176             break;
4177         default:
4178             affirm(false, "Illegal field type: " + sig);
4179         }
4180         insn = insn.append(Insn.create(opc_putfield, fieldRef));
4181         insn = insn.append(Insn.create(opc_return));
4182 
4183         affirm(insn != null);
4184         return insn;
4185     }
4186 
4187     /***
4188      * Build a mutator method for direct write access.
4189      *
4190      * static xxx void jdoSetyyy(XXX instance, YYY yyy)
4191      * {
4192      *     // augmentation: grant direct write access
4193      *     instance.yyy = yyy;
4194      * }
4195      */
4196     public void addJDODirectWriteAccessMethod(String methodName,
4197                                               String methodSig,
4198                                               int accessFlags,
4199                                               int fieldIndex)
4200     {
4201         affirm(methodName != null);      
4202         affirm(methodSig != null);      
4203         final ExceptionsAttribute exceptAttr = null;
4204 
4205         // begin of method body
4206         final InsnTarget begin = new InsnTarget();
4207         Insn insn = begin;
4208 
4209         final ConstFieldRef fieldRef = getAnnotatedFieldRefs()[fieldIndex];
4210         affirm(fieldRef != null);
4211 
4212         // write argument to field and return
4213         insn = appendDirectWriteReturn(insn, fieldRef);
4214 
4215         final CodeAttribute codeAttr
4216             = new CodeAttribute(getCodeAttributeUtf8(),
4217                                 3, // maxStack: allow for long/double
4218                                 3, // maxLocals: allow for long/double
4219                                 begin,
4220                                 new ExceptionTable(),
4221                                 new AttributeVector());
4222         augmenter.addMethod(methodName, methodSig, accessFlags,
4223                             codeAttr, exceptAttr);
4224     }
4225 
4226     /***
4227      * Append the code for mediated write access.
4228      */
4229     private Insn appendMediatedWriteAccess(Insn insn,
4230                                            int fieldIndex,
4231                                            ConstFieldRef fieldRef,
4232                                            int varStart)
4233     {
4234         affirm(insn != null);
4235         affirm(fieldRef != null);
4236 
4237         final String sig = fieldRef.nameAndType().signature().asString();
4238         affirm(sig != null && sig.length() > 0);
4239 
4240         // store the sm field into local var
4241         insn = insn.append(Insn.create(opc_aload_0));
4242         insn = insn.append(
4243             Insn.create(
4244                 opc_getfield,
4245                 getjdoStateManagerFieldRef()));
4246         insn = insn.append(InsnUtils.aStore(varStart, pool));
4247 
4248         // test the sm field and assign field if null
4249         final InsnTarget mediate = new InsnTarget();
4250         insn = insn.append(InsnUtils.aLoad(varStart, pool));
4251         insn = insn.append(Insn.create(opc_ifnonnull, mediate));
4252 
4253         // write argument to field and return
4254         insn = appendDirectWriteReturn(insn, fieldRef);
4255 
4256         // call sm for mediation
4257         insn = insn.append(mediate);
4258         insn = insn.append(InsnUtils.aLoad(varStart, pool));
4259 
4260         // push instance
4261         insn = insn.append(Insn.create(opc_aload_0));
4262 
4263         // push absolute field index
4264         insn = insn.append(
4265             Insn.create(opc_getstatic,
4266                         pool.addFieldRef(
4267                             className,
4268                             JDO_PC_jdoInheritedFieldCount_Name,
4269                             JDO_PC_jdoInheritedFieldCount_Sig)));
4270         insn = insn.append(InsnUtils.integerConstant(fieldIndex, pool));
4271         insn = insn.append(Insn.create(opc_iadd));
4272 
4273         // push field
4274         insn = insn.append(Insn.create(opc_aload_0));
4275         insn = insn.append(Insn.create(opc_getfield, fieldRef));
4276 
4277         // push passed argument value
4278         switch (sig.charAt(0)) {
4279         case 'Z':
4280         case 'C':
4281         case 'B':
4282         case 'S':
4283         case 'I':
4284             insn = insn.append(Insn.create(opc_iload_1));
4285             break;
4286         case 'J':
4287             insn = insn.append(Insn.create(opc_lload_1));
4288             break;
4289         case 'F':
4290             insn = insn.append(Insn.create(opc_fload_1));
4291             break;
4292         case 'D':
4293             insn = insn.append(Insn.create(opc_dload_1));
4294             break;
4295         case 'L':
4296         case '[':
4297             insn = insn.append(Insn.create(opc_aload_1));
4298             break;
4299         default:
4300             affirm(false, "Illegal field type: " + sig);
4301         }
4302 
4303         // call the sm's set field method
4304         switch (sig.charAt(0)) {
4305         case 'Z':
4306             insn = insn.append(
4307                 new InsnInterfaceInvoke(
4308                     pool.addInterfaceMethodRef(
4309                         JDO_StateManager_Path,
4310                         JDO_SM_setBooleanField_Name,
4311                         JDO_SM_setBooleanField_Sig),
4312                     countMethodArgWords(JDO_SM_setBooleanField_Sig)));
4313             break;
4314         case 'C':
4315             insn = insn.append(
4316                 new InsnInterfaceInvoke(
4317                     pool.addInterfaceMethodRef(
4318                         JDO_StateManager_Path,
4319                         JDO_SM_setCharField_Name,
4320                         JDO_SM_setCharField_Sig),
4321                     countMethodArgWords(JDO_SM_setCharField_Sig)));
4322             break;
4323         case 'B':
4324             insn = insn.append(
4325                 new InsnInterfaceInvoke(
4326                     pool.addInterfaceMethodRef(
4327                         JDO_StateManager_Path,
4328                         JDO_SM_setByteField_Name,
4329                         JDO_SM_setByteField_Sig),
4330                     countMethodArgWords(JDO_SM_setByteField_Sig)));
4331             break;
4332         case 'S':
4333             insn = insn.append(
4334                 new InsnInterfaceInvoke(
4335                     pool.addInterfaceMethodRef(
4336                         JDO_StateManager_Path,
4337                         JDO_SM_setShortField_Name,
4338                         JDO_SM_setShortField_Sig),
4339                     countMethodArgWords(JDO_SM_setShortField_Sig)));
4340             break;
4341         case 'I':
4342             insn = insn.append(
4343                 new InsnInterfaceInvoke(
4344                     pool.addInterfaceMethodRef(
4345                         JDO_StateManager_Path,
4346                         JDO_SM_setIntField_Name,
4347                         JDO_SM_setIntField_Sig),
4348                     countMethodArgWords(JDO_SM_setIntField_Sig)));
4349             break;
4350         case 'J':
4351             insn = insn.append(
4352                 new InsnInterfaceInvoke(
4353                     pool.addInterfaceMethodRef(
4354                         JDO_StateManager_Path,
4355                         JDO_SM_setLongField_Name,
4356                         JDO_SM_setLongField_Sig),
4357                     countMethodArgWords(JDO_SM_setLongField_Sig)));
4358             break;
4359         case 'F':
4360             insn = insn.append(
4361                 new InsnInterfaceInvoke(
4362                     pool.addInterfaceMethodRef(
4363                         JDO_StateManager_Path,
4364                         JDO_SM_setFloatField_Name,
4365                         JDO_SM_setFloatField_Sig),
4366                     countMethodArgWords(JDO_SM_setFloatField_Sig)));
4367             break;
4368         case 'D':
4369             insn = insn.append(
4370                 new InsnInterfaceInvoke(
4371                     pool.addInterfaceMethodRef(
4372                         JDO_StateManager_Path,
4373                         JDO_SM_setDoubleField_Name,
4374                         JDO_SM_setDoubleField_Sig),
4375                     countMethodArgWords(JDO_SM_setDoubleField_Sig)));
4376             break;
4377         case 'L':
4378         case '[':
4379             if (sig.equals(JAVA_String_Sig)) {
4380                 insn = insn.append(
4381                     new InsnInterfaceInvoke(
4382                         pool.addInterfaceMethodRef(
4383                             JDO_StateManager_Path,
4384                             JDO_SM_setStringField_Name,
4385                             JDO_SM_setStringField_Sig),
4386                         countMethodArgWords(JDO_SM_setStringField_Sig)));
4387             } else {
4388                 insn = insn.append(
4389                     new InsnInterfaceInvoke(
4390                         pool.addInterfaceMethodRef(
4391                             JDO_StateManager_Path,
4392                             JDO_SM_setObjectField_Name,
4393                             JDO_SM_setObjectField_Sig),
4394                         countMethodArgWords(JDO_SM_setObjectField_Sig)));
4395             }
4396             break;
4397         default:
4398             affirm(false, "Illegal field type: " + sig);
4399         }
4400 
4401         insn = insn.append(Insn.create(opc_return));
4402 
4403         affirm(insn != null);
4404         return insn;
4405     }
4406 
4407     /***
4408      * Build a mutator method for mediated write access.
4409      *
4410      * static xxx void jdoSetyyy(XXX instance, YYY yyy)
4411      * {
4412      *     // augmentation: mediate write access
4413      *     final javax.jdo.StateManager sm = instance.jdoStateManager;
4414      *     if (sm == null) {
4415      *         instance.yyy = yyy;
4416      *         return;
4417      *     }
4418      *     sm.setYYYField(instance,
4419      *                    instance.jdoInheritedFieldCount + y,
4420      *                    instance.yyy,
4421      *                    yyy);
4422      * }
4423      */
4424     public void addJDOMediatedWriteAccessMethod(String methodName,
4425                                                 String methodSig,
4426                                                 int accessFlags,
4427                                                 int fieldIndex)
4428     {
4429         affirm(methodName != null);      
4430         affirm(methodSig != null);      
4431         final ExceptionsAttribute exceptAttr = null;
4432 
4433         // begin of method body
4434         final InsnTarget begin = new InsnTarget();
4435         Insn insn = begin;
4436 
4437         // get field's sig and compute first non-parameter slot
4438         final ConstFieldRef fieldRef = getAnnotatedFieldRefs()[fieldIndex];
4439         affirm(fieldRef != null);
4440         final String sig = fieldRef.nameAndType().signature().asString();
4441         affirm(sig != null && sig.length() > 0);
4442         final int fieldSize = ((sig.equals("J") || sig.equals("D")) ? 2 : 1);
4443         final int varStart = fieldSize + 1;
4444 
4445         // mediate access
4446         insn = appendMediatedWriteAccess(insn, fieldIndex, fieldRef, varStart);
4447 
4448         // end of method body
4449 
4450         final CodeAttribute codeAttr
4451             = new CodeAttribute(getCodeAttributeUtf8(),
4452                                 (2 * fieldSize) + 3, // maxStack
4453                                 fieldSize + 2, // maxLocals
4454                                 begin,
4455                                 new ExceptionTable(),
4456                                 new AttributeVector());
4457         augmenter.addMethod(methodName, methodSig, accessFlags,
4458                             codeAttr, exceptAttr);
4459     }
4460 
4461     /***
4462      * Build a mutator method for checked write access.
4463      *
4464      * static xxx void jdoSetyyy(XXX instance, YYY yyy)
4465      * {
4466      *     // augmentation: check write access
4467      *     if (instance.jdoFlags == 0) {
4468      *         instance.yyy = yyy;
4469      *         return;
4470      *     }
4471      *     instance.yyy = (YYY)instance.jdoStateManager
4472      *         .setYYYField(instance,
4473      *                      instance.jdoInheritedFieldCount + y,
4474      *                      instance.yyy, yyy);
4475      * }
4476      */
4477     public void addJDOCheckedWriteAccessMethod(String methodName,
4478                                                String methodSig,
4479                                                int accessFlags,
4480                                                int fieldIndex)
4481     {
4482         affirm(methodName != null);      
4483         affirm(methodSig != null);      
4484         final ExceptionsAttribute exceptAttr = null;
4485 
4486         // begin of method body
4487         final InsnTarget begin = new InsnTarget();
4488         Insn insn = begin;
4489 
4490         // get field's sig and compute first non-parameter slot
4491         final ConstFieldRef fieldRef = getAnnotatedFieldRefs()[fieldIndex];
4492         affirm(fieldRef != null);
4493         final String sig = fieldRef.nameAndType().signature().asString();
4494         affirm(sig != null && sig.length() > 0);
4495         final int fieldSize = ((sig.equals("J") || sig.equals("D")) ? 2 : 1);
4496         final int varStart = fieldSize + 1;
4497 
4498         // directly write argument and retrurn if flags are != READ_WRITE_OK
4499         final InsnTarget mediate = new InsnTarget();
4500         insn = insn.append(Insn.create(opc_aload_0));
4501         insn = insn.append(
4502             Insn.create(opc_getfield,
4503                         getjdoFlagsFieldRef()));
4504         insn = insn.append(Insn.create(opc_ifne, mediate));
4505         insn = appendDirectWriteReturn(insn, fieldRef);
4506 
4507         // mediate access
4508         insn = insn.append(mediate);
4509         insn = appendMediatedWriteAccess(insn, fieldIndex, fieldRef, varStart);
4510 
4511         // end of method body
4512 
4513         final CodeAttribute codeAttr
4514             = new CodeAttribute(getCodeAttributeUtf8(),
4515                                 (2 * fieldSize) + 3, // maxStack
4516                                 fieldSize + 2, // maxLocals
4517                                 begin,
4518                                 new ExceptionTable(),
4519                                 new AttributeVector());
4520         augmenter.addMethod(methodName, methodSig, accessFlags,
4521                             codeAttr, exceptAttr);
4522     }
4523 
4524     // ----------------------------------------------------------------------
4525 
4526     /***
4527      * Build the jdoClear method for the class.
4528      *
4529      * public void jdoClear() {
4530      *     ...
4531      * }
4532      */
4533     public void addJDOClearMethod()
4534     {
4535         final String methodName = "";
4536         final String methodSig = "()V";
4537         final int accessFlags = 0;
4538         final ExceptionsAttribute exceptAttr = null;
4539 
4540         // begin of method body
4541         final InsnTarget begin = new InsnTarget();
4542         Insn insn = begin;
4543 
4544         //@olsen: disabled code
4545         if (false) {
4546             // reset jdoFlags = LOAD_REQUIRED
4547             insn = insn.append(Insn.create(opc_aload_0));
4548             insn = insn.append(Insn.create(opc_iconst_1));
4549             insn = insn.append(
4550                 Insn.create(opc_putfield,
4551                             pool.addFieldRef(className,
4552                                              JDO_PC_jdoFlags_Name,
4553                                              JDO_PC_jdoFlags_Sig)));
4554         }
4555 
4556         // iterate over all declared fields of the class
4557         final ClassField[] managedFields = null; //analyzer.annotatedFields();
4558         final int managedFieldCount = managedFields.length;
4559         for (int i = 0; i < managedFieldCount; i++) {
4560             final ClassField field = managedFields[i];
4561             final String fieldName = field.name().asString();
4562             final String fieldSig = field.signature().asString();
4563 
4564 /*
4565             // ignore primary managed fields
4566             if (field.isManaged())
4567                 continue;
4568 */
4569 
4570 /*
4571             //@olsen: disconnect mutable SCOs before clear
4572             if (field.isMutableSCO()) {
4573                 // fetch field
4574                 insn = insn.append(Insn.create(opc_aload_0));
4575                 insn = insn.append(
4576                     Insn.create(opc_getfield,
4577                                 pool.addFieldRef(
4578                                     className,
4579                                     fieldName,
4580                                     fieldSig)));
4581 
4582                 // test whether instanceof SCO base type
4583                 // skip disconnecting if == 0
4584                 final ConstClass cc
4585                     = pool.addClass(JDO_SecondClassObjectBase_Path);
4586                 InsnTarget disconnect = new InsnTarget();
4587                 InsnTarget afterDisconnect = new InsnTarget();
4588                 insn = insn.append(
4589                     Insn.create(opc_dup));
4590                 insn = insn.append(
4591                     Insn.create(opc_instanceof,
4592                                 cc));
4593                 insn = insn.append(
4594                     Insn.create(opc_ifne,
4595                                 disconnect));
4596 
4597                 // pop field and skip disconnecting
4598                 insn = insn.append(
4599                     Insn.create(opc_pop));
4600                 insn = insn.append(
4601                     Insn.create(opc_goto, afterDisconnect));
4602 
4603                 // disconnect SCO field's object
4604                 insn = insn.append(disconnect);
4605 
4606                 // cast to SCO base type
4607                 insn = insn.append(
4608                     Insn.create(opc_checkcast,
4609                                 cc));
4610 
4611                 // call method: void unsetOwner();
4612                 final int requiredStack = 1;
4613                 insn = insn.append(
4614                     new InsnInterfaceInvoke(
4615                         pool.addInterfaceMethodRef(
4616                             JDO_SecondClassObjectBase_Path,
4617                             "unsetOwner",
4618                             "()V"),
4619                         requiredStack));
4620 
4621                 insn = insn.append(afterDisconnect);
4622             }
4623 */
4624 
4625             // get this
4626             insn = insn.append(Insn.create(opc_aload_0));
4627 
4628             // use the getMethodReturn type to decide how to clear field
4629             switch (fieldSig.charAt(0)) {
4630             case 'D':
4631                 insn = insn.append(Insn.create(opc_dconst_0));
4632                 break;
4633             case 'F':
4634                 insn = insn.append(Insn.create(opc_fconst_0));
4635                 break;
4636             case 'J':
4637                 insn = insn.append(Insn.create(opc_lconst_0));
4638                 break;
4639             case 'Z':
4640             case 'C':
4641             case 'B':
4642             case 'S':
4643             case 'I':
4644                 insn = insn.append(Insn.create(opc_iconst_0));
4645                 break;
4646             case 'L':
4647             case '[':
4648                 insn = insn.append(Insn.create(opc_aconst_null));
4649                 break;
4650             default:
4651                 throw new InternalError("Illegal field type: " + fieldSig);
4652             }
4653 
4654             // put default value to field
4655             insn = insn.append(
4656                 Insn.create(opc_putfield,
4657                             pool.addFieldRef(className,
4658                                              fieldName,
4659                                              fieldSig)));
4660         }
4661 
4662         // end of method body
4663         insn = insn.append(Insn.create(opc_return));
4664 
4665         final CodeAttribute codeAttr
4666             = new CodeAttribute(getCodeAttributeUtf8(),
4667                                 3, // maxStack
4668                                 1, // maxLocals
4669                                 begin,
4670                                 new ExceptionTable(),
4671                                 new AttributeVector());
4672         augmenter.addMethod(methodName, methodSig, accessFlags,
4673                             codeAttr, exceptAttr);
4674     }
4675 
4676     /***
4677      * Build the clone method for the class.
4678      */
4679     public void addJDOClone()
4680     {
4681         final String methodName = "";
4682         final String methodSig = "()Ljava/lang/Object;";
4683         final int accessFlags = 0;
4684         final ExceptionsAttribute exceptAttr
4685             = new ExceptionsAttribute(
4686                 pool.addUtf8(ExceptionsAttribute.expectedAttrName),
4687                 pool.addClass("java/lang/CloneNotSupportedException"));
4688 
4689         // begin of method body
4690         final InsnTarget begin = new InsnTarget();
4691         Insn insn = begin;
4692 
4693         // THISCLASS newObject = (THISCLASS) super.clone();
4694         final ConstClass superConstClass = classFile.superName();
4695         final ConstClass thisConstClass = classFile.className();
4696         affirm(thisConstClass != null);
4697         insn = insn.append(Insn.create(opc_aload_0));
4698         insn = insn.append(
4699             Insn.create(opc_invokespecial,
4700                         pool.addMethodRef(superConstClass.asString(),
4701                                           methodName,
4702                                           methodSig)));
4703         insn = insn.append(Insn.create(opc_checkcast, thisConstClass));
4704 
4705         // newObject.jdoStateManager = null;
4706         if (false)
4707         {
4708             insn = insn.append(Insn.create(opc_dup));
4709             insn = insn.append(Insn.create(opc_aconst_null));
4710             insn = insn.append(
4711                 Insn.create(opc_putfield,
4712                             pool.addFieldRef(className,
4713                                              JDO_PC_jdoStateManager_Name,
4714                                              JDO_PC_jdoStateManager_Sig)));
4715         }
4716 
4717         // newObject.jdoFlags = 0;
4718         if (false)
4719         {
4720             insn = insn.append(Insn.create(opc_dup));
4721             insn = insn.append(Insn.create(opc_iconst_0));
4722             insn = insn.append(
4723                 Insn.create(opc_putfield,
4724                             pool.addFieldRef(className,
4725                                              JDO_PC_jdoFlags_Name,
4726                                              JDO_PC_jdoFlags_Sig)));
4727         }
4728 
4729         // return newObject;
4730 
4731         // end of method body
4732         insn = insn.append(Insn.create(opc_areturn));
4733 
4734         final CodeAttribute codeAttr
4735             = new CodeAttribute(getCodeAttributeUtf8(),
4736                                 1, //3, //3, // maxStack
4737                                 1, //2, // maxLocals
4738                                 begin,
4739                                 new ExceptionTable(),
4740                                 new AttributeVector());
4741         augmenter.addMethod(methodName, methodSig, accessFlags,
4742                             codeAttr, exceptAttr);
4743     }
4744 
4745     /***
4746      * Builds a method throwing an UnsupportedOperationException.
4747      *
4748      * public void XXX() {
4749      *    throw new UnsupportedOperationException(
4750      *        "Method XXX not yet implemented");
4751      * }
4752      */
4753     public void addNotYetImplementedMethod(final String methodName,
4754                                            final String methodSig,
4755                                            final int accessFlags)
4756     {
4757         // assumed nonstatic call; otherwise subtract 'this' from maxStack
4758         affirm((accessFlags & ACCStatic) == 0);
4759         final ExceptionsAttribute exceptAttr = null;
4760 
4761         // begin of method body
4762         final InsnTarget begin = new InsnTarget();
4763         Insn insn = begin;
4764 
4765         insn = appendThrowJavaException(
4766             insn, JAVA_UnsupportedOperationException_Path, 
4767             "Method " + methodName + " not yet implemented");
4768 
4769         final CodeAttribute codeAttr
4770             = new CodeAttribute(getCodeAttributeUtf8(),
4771                                 3, // maxStack
4772                                 countMethodArgWords(methodSig), // maxLocals
4773                                 begin,
4774                                 new ExceptionTable(),
4775                                 new AttributeVector());
4776         augmenter.addMethod(methodName, methodSig, accessFlags,
4777                             codeAttr, exceptAttr);
4778     }
4779     
4780 }