View Javadoc

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