Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/VMOp.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/VMOp.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/VMOp.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/classfile/VMOp.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,546 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jdo.impl.enhancer.classfile; + +/** + * Description of the VM opcodes + */ +public class VMOp implements VMConstants { + /* The opcode value */ + private int opcodeValue; + + /* The name of the opcode */ + private String opcodeName; + + /* The number of stack argument words */ + private int stackArgs; + + /* The number of stack result words */ + private int stackResults; + + /* The "type" signature of the stack argument words */ + private String stackArgTypes; + + /* The "type" signature of the stack result words */ + private String stackResultTypes; + + /* public accessors */ + + /** + * Return the opcode value + */ + final public int opcode() { + return opcodeValue; + } + + /** + * Return the opcode name + */ + final public String name() { + return opcodeName; + } + + /** + * Return the number of words of stack arguments expected by this operation. + * If the number is not a fixed value, return -1; + */ + final public int nStackArgs() { + return stackArgs; + } + + /** + * Return the number of words of stack results produced by this operation. + * If the number is not a fixed value, return -1; + */ + final public int nStackResults() { + return stackResults; + } + + /** + * Return the type descriptor for the stack arguments to the operation. + */ + final public String argTypes() { + return stackArgTypes; + } + + /** + * Return the type descriptor for the stack results of the operation. + */ + final public String resultTypes() { + return stackResultTypes; + } + + /** + * constructor for a VMOp + */ + + public VMOp(int theOpcode, String theOpcodeName, int nArgs, int nResults, + String argDescr, String resultDescr) { + opcodeValue = theOpcode; + opcodeName = theOpcodeName; + stackArgs = nArgs; + stackResults = nResults; + stackArgTypes = argDescr; + stackResultTypes = resultDescr; + } + + /* package local methods */ + + static VMOp[] ops = { + /* | no change*/ + new VMOp(opc_nop, "nop", 0, 0, "", ""), + /* | ... -> ..., null */ + new VMOp(opc_aconst_null, "aconst_null", 0, 1, "", "A"), + /* | ... -> ..., -1 */ + new VMOp(opc_iconst_m1, "iconst_m1", 0, 1, "", "I"), + /* | ... -> ..., 0 */ + new VMOp(opc_iconst_0, "iconst_0", 0, 1, "", "I"), + /* | ... -> ..., 1 */ + new VMOp(opc_iconst_1, "iconst_1", 0, 1, "", "I"), + /* | ... -> ..., 2 */ + new VMOp(opc_iconst_2, "iconst_2", 0, 1, "", "I"), + /* | ... -> ..., 3 */ + new VMOp(opc_iconst_3, "iconst_3", 0, 1, "", "I"), + /* | ... -> ..., 4 */ + new VMOp(opc_iconst_4, "iconst_4", 0, 1, "", "I"), + /* | ... -> ..., 5 */ + new VMOp(opc_iconst_5, "iconst_5", 0, 1, "", "I"), + /* | ... -> ..., 0<high/low>, 0<high/low> */ + new VMOp(opc_lconst_0, "lconst_0", 0, 2, "", "J"), + /* | ... -> ..., 1<high/low>, 1<high/low> */ + new VMOp(opc_lconst_1, "lconst_1", 0, 2, "", "J"), + /* | ... -> ..., 0.0f */ + new VMOp(opc_fconst_0, "fconst_0", 0, 1, "", "F"), + /* | ... -> ..., 1.0f */ + new VMOp(opc_fconst_1, "fconst_1", 0, 1, "", "F"), + /* | ... -> ..., 2.0f */ + new VMOp(opc_fconst_2, "fconst_2", 0, 1, "", "F"), + /* | ... -> ..., 0.0<high/low>, 0.0<high/low> */ + new VMOp(opc_dconst_0, "dconst_0", 0, 2, "", "D"), + /* | ... -> ..., 1.0<high/low>, 1.0<high/low> */ + new VMOp(opc_dconst_1, "dconst_1", 0, 2, "", "D"), + /* byte1 | ... => ..., value */ + new VMOp(opc_bipush, "bipush", 0, 1, "", "I"), + /* byte1 byte2 | ... => ..., value */ + new VMOp(opc_sipush, "sipush", 0, 1, "", "I"), + /* indexbyte1 | ... => ..., item */ + new VMOp(opc_ldc, "ldc", 0, 1, "", "W"), + /* indexbyte1 indexbyte2 | ... => ..., item */ + new VMOp(opc_ldc_w, "ldc_w", 0, 1, "", "W"), + /* indexbyte1 indexbyte2 | ... => ..., item1, item2 */ + new VMOp(opc_ldc2_w, "ldc2_w", 0, 2, "", "X"), + /* vindex | ... => ..., value<vindex> */ + new VMOp(opc_iload, "iload", 0, 1, "", "I"), + /* vindex | ... => ..., value<vindex><h/l>, value<vindex><h/l> */ + new VMOp(opc_lload, "lload", 0, 2, "", "J"), + /* vindex | ... => ..., value<vindex> */ + new VMOp(opc_fload, "fload", 0, 1, "", "F"), + /* vindex | ... => ..., value<vindex><h/l>, value<vindex><h/l> */ + new VMOp(opc_dload, "dload", 0, 2, "", "D"), + /* vindex | ... => ..., value<vindex> */ + new VMOp(opc_aload, "aload", 0, 1, "", "A"), + /* | ... => ..., value<0> */ + new VMOp(opc_iload_0, "iload_0", 0, 1, "", "I"), + /* | ... => ..., value<1> */ + new VMOp(opc_iload_1, "iload_1", 0, 1, "", "I"), + /* | ... => ..., value<2> */ + new VMOp(opc_iload_2, "iload_2", 0, 1, "", "I"), + /* | ... => ..., value<3> */ + new VMOp(opc_iload_3, "iload_3", 0, 1, "", "I"), + /* | ... => ..., value<0><h/l>, value<0><h/l> */ + new VMOp(opc_lload_0, "lload_0", 0, 2, "", "J"), + /* | ... => ..., value<1><h/l>, value<1><h/l> */ + new VMOp(opc_lload_1, "lload_1", 0, 2, "", "J"), + /* | ... => ..., value<2><h/l>, value<2><h/l> */ + new VMOp(opc_lload_2, "lload_2", 0, 2, "", "J"), + /* | ... => ..., value<3><h/l>, value<3><h/l> */ + new VMOp(opc_lload_3, "lload_3", 0, 2, "", "J"), + /* | ... => ..., value<0> */ + new VMOp(opc_fload_0, "fload_0", 0, 1, "", "F"), + /* | ... => ..., value<1> */ + new VMOp(opc_fload_1, "fload_1", 0, 1, "", "F"), + /* | ... => ..., value<2> */ + new VMOp(opc_fload_2, "fload_2", 0, 1, "", "F"), + /* | ... => ..., value<3> */ + new VMOp(opc_fload_3, "fload_3", 0, 1, "", "F"), + /* | ... => ..., value<0><h/l>, value<0><h/l> */ + new VMOp(opc_dload_0, "dload_0", 0, 2, "", "D"), + /* | ... => ..., value<1><h/l>, value<1><h/l> */ + new VMOp(opc_dload_1, "dload_1", 0, 2, "", "D"), + /* | ... => ..., value<2><h/l>, value<2><h/l> */ + new VMOp(opc_dload_2, "dload_2", 0, 2, "", "D"), + /* | ... => ..., value<3><h/l>, value<3><h/l> */ + new VMOp(opc_dload_3, "dload_3", 0, 2, "", "D"), + /* | ... => ..., value<0> */ + new VMOp(opc_aload_0, "aload_0", 0, 1, "", "A"), + /* | ... => ..., value<1> */ + new VMOp(opc_aload_1, "aload_1", 0, 1, "", "A"), + /* | ... => ..., value<2> */ + new VMOp(opc_aload_2, "aload_2", 0, 1, "", "A"), + /* | ... => ..., value<3> */ + new VMOp(opc_aload_3, "aload_3", 0, 1, "", "A"), + /* | ..., arrayref, index => ..., value */ + new VMOp(opc_iaload, "iaload", 2, 1, "AI", "I"), + /* | ..., arrayref, index => ..., value<h/l>, value<h/l> */ + new VMOp(opc_laload, "laload", 2, 2, "AI", "J"), + /* | ..., arrayref, index => ..., value */ + new VMOp(opc_faload, "faload", 2, 1, "AI", "F"), + /* | ..., arrayref, index => ..., value<h/l>, value<h/l> */ + new VMOp(opc_daload, "daload", 2, 2, "AI", "D"), + /* | ..., arrayref, index => ..., value */ + new VMOp(opc_aaload, "aaload", 2, 1, "AI", "A"), + /* | ..., arrayref, index => ..., value */ + new VMOp(opc_baload, "baload", 2, 1, "AI", "I"), + /* | ..., arrayref, index => ..., value */ + new VMOp(opc_caload, "caload", 2, 1, "AI", "I"), + /* | ..., arrayref, index => ..., value */ + new VMOp(opc_saload, "saload", 2, 1, "AI", "I"), + /* vindex | ..., value => ... */ + new VMOp(opc_istore, "istore", 1, 0, "I", ""), + /* vindex | ..., value<h/l>, value<h/l> => ... */ + new VMOp(opc_lstore, "lstore", 2, 0, "J", ""), + /* vindex | ..., value => ... */ + new VMOp(opc_fstore, "fstore", 1, 0, "F", ""), + /* vindex | ..., value<h/l>, value<h/l> => ... */ + new VMOp(opc_dstore, "dstore", 2, 0, "D", ""), + /* vindex | ..., value => ... */ + new VMOp(opc_astore, "astore", 1, 0, "A", ""), + /* | ..., value => ... */ + new VMOp(opc_istore_0, "istore_0", 1, 0, "I", ""), + /* | ..., value => ... */ + new VMOp(opc_istore_1, "istore_1", 1, 0, "I", ""), + /* | ..., value => ... */ + new VMOp(opc_istore_2, "istore_2", 1, 0, "I", ""), + /* | ..., value => ... */ + new VMOp(opc_istore_3, "istore_3", 1, 0, "I", ""), + /* | ..., value<h/l>, value<h/l> => ... */ + new VMOp(opc_lstore_0, "lstore_0", 2, 0, "J", ""), + /* | ..., value<h/l>, value<h/l> => ... */ + new VMOp(opc_lstore_1, "lstore_1", 2, 0, "J", ""), + /* | ..., value<h/l>, value<h/l> => ... */ + new VMOp(opc_lstore_2, "lstore_2", 2, 0, "J", ""), + /* | ..., value<h/l>, value<h/l> => ... */ + new VMOp(opc_lstore_3, "lstore_3", 2, 0, "J", ""), + /* | ..., value => ... */ + new VMOp(opc_fstore_0, "fstore_0", 1, 0, "F", ""), + /* | ..., value => ... */ + new VMOp(opc_fstore_1, "fstore_1", 1, 0, "F", ""), + /* | ..., value => ... */ + new VMOp(opc_fstore_2, "fstore_2", 1, 0, "F", ""), + /* | ..., value => ... */ + new VMOp(opc_fstore_3, "fstore_3", 1, 0, "F", ""), + /* | ..., value<h/l>, value<h/l> => ... */ + new VMOp(opc_dstore_0, "dstore_0", 2, 0, "D", ""), + /* | ..., value<h/l>, value<h/l> => ... */ + new VMOp(opc_dstore_1, "dstore_1", 2, 0, "D", ""), + /* | ..., value<h/l>, value<h/l> => ... */ + new VMOp(opc_dstore_2, "dstore_2", 2, 0, "D", ""), + /* | ..., value<h/l>, value<h/l> => ... */ + new VMOp(opc_dstore_3, "dstore_3", 2, 0, "D", ""), + /* | ..., value => ... */ + new VMOp(opc_astore_0, "astore_0", 1, 0, "A", ""), + /* | ..., value => ... */ + new VMOp(opc_astore_1, "astore_1", 1, 0, "A", ""), + /* | ..., value => ... */ + new VMOp(opc_astore_2, "astore_2", 1, 0, "A", ""), + /* | ..., value => ... */ + new VMOp(opc_astore_3, "astore_3", 1, 0, "A", ""), + /* | ..., arrayref, index, value => ... */ + new VMOp(opc_iastore, "iastore", 3, 0, "AII", ""), + /* | ..., arrayref, index, value<h/l>, value<h/l> => ... */ + new VMOp(opc_lastore, "lastore", 4, 0, "AIJ", ""), + /* | ..., arrayref, index, value => ... */ + new VMOp(opc_fastore, "fastore", 3, 0, "AIF", ""), + /* | ..., arrayref, index, value<h/l>, value<h/l> => ... */ + new VMOp(opc_dastore, "dastore", 4, 0, "AID", ""), + /* | ..., arrayref, index, value => ... */ + new VMOp(opc_aastore, "aastore", 3, 0, "AIA", ""), + /* | ..., arrayref, index, value => ... */ + new VMOp(opc_bastore, "bastore", 3, 0, "AII", ""), + /* | ..., arrayref, index, value => ... */ + new VMOp(opc_castore, "castore", 3, 0, "AII", ""), + /* | ..., arrayref, index, value => ... */ + new VMOp(opc_sastore, "sastore", 3, 0, "AII", ""), + /* | ..., any => ... */ + new VMOp(opc_pop, "pop", 1, 0, "W", ""), + /* | ..., any1, any2 => ... */ + new VMOp(opc_pop2, "pop2", 2, 0, "WW", ""), + /* | ..., any => ..., any, any */ + new VMOp(opc_dup, "dup", 1, 2, "W", "WW"), + /* | ..., any1, any2 => ..., any2, any1, any2 */ + new VMOp(opc_dup_x1, "dup_x1", 2, 3, "WW", "WWW"), + /* | ..., any1, any2, any3 => ..., any3, any1, any2, any3 */ + new VMOp(opc_dup_x2, "dup_x2", 3, 4, "WWW", "WWWW"), + /* | ..., any1, any2 => ..., any1, any2, any1, any2 */ + new VMOp(opc_dup2, "dup2", 2, 4, "WW", "WWWW"), + /* | ..., any1, any2, any3 => ..., any2, any3, any1, any2, any3 */ + new VMOp(opc_dup2_x1, "dup2_x1", 3, 5, "WWW", "WWWWW"), + /* | ..., any1, any2, any3, any4 => ..., any3, any4, any1, any2, any3, any4 */ + new VMOp(opc_dup2_x2, "dup2_x2", 4, 6, "WWWW", "WWWWWW"), + /* | ..., any1, any2 => ..., any2, any1 */ + new VMOp(opc_swap, "swap", 2, 2, "WW", "WW"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_iadd, "iadd", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_ladd, "ladd", 4, 2, "JJ", "J"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_fadd, "fadd", 2, 1, "FF", "F"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_dadd, "dadd", 4, 2, "DD", "D"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_isub, "isub", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_lsub, "lsub", 4, 2, "JJ", "J"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_fsub, "fsub", 2, 1, "FF", "F"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_dsub, "dsub", 4, 2, "DD", "D"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_imul, "imul", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_lmul, "lmul", 4, 2, "JJ", "J"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_fmul, "fmul", 2, 1, "FF", "F"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_dmul, "dmul", 4, 2, "DD", "D"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_idiv, "idiv", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_ldiv, "ldiv", 4, 2, "JJ", "J"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_fdiv, "fdiv", 2, 1, "FF", "F"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_ddiv, "ddiv", 4, 2, "DD", "D"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_irem, "irem", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_lrem, "lrem", 4, 2, "JJ", "J"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_frem, "frem", 2, 1, "FF", "F"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_drem, "drem", 4, 2, "DD", "D"), + /* | ..., value => ..., result */ + new VMOp(opc_ineg, "ineg", 1, 1, "I", "I"), + /* | ..., value<h/l>, value<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_lneg, "lneg", 2, 2, "J", "J"), + /* | ..., value => ..., result */ + new VMOp(opc_fneg, "fneg", 1, 1, "F", "F"), + /* | ..., value<h/l>, value<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_dneg, "dneg", 2, 2, "D", "D"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_ishl, "ishl", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2 => ..., result */ + new VMOp(opc_lshl, "lshl", 3, 2, "JI", "J"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_ishr, "ishr", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2 => ..., result<h/l>, result<h/l> */ + new VMOp(opc_lshr, "lshr", 3, 2, "JI", "J"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_iushr, "iushr", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2 => ..., result<h/l>, result<h/l> */ + new VMOp(opc_lushr, "lushr", 3, 2, "JI", "J"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_iand, "iand", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_land, "land", 4, 2, "JJ", "J"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_ior, "ior", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_lor, "lor", 4, 2, "JJ", "J"), + /* | ..., value1, value2 => ..., result */ + new VMOp(opc_ixor, "ixor", 2, 1, "II", "I"), + /* | ..., value1<h/l>, value1<h/l>, value2<h/l>, value2<h/l> => ..., result<h/l>, result<h/l> */ + new VMOp(opc_lxor, "lxor", 4, 2, "JJ", "J"), + /* vindex, const | no change */ + new VMOp(opc_iinc, "iinc", 0, 0, "", ""), + /* | ..., value => ..., value<h/l>, value<h/l> */ + new VMOp(opc_i2l, "i2l", 1, 2, "I", "J"), + /* | ..., value => ..., value */ + new VMOp(opc_i2f, "i2f", 1, 1, "I", "F"), + /* | ..., value => ..., value<h/l>, value<h/l> */ + new VMOp(opc_i2d, "i2d", 1, 2, "I", "D"), + /* | ..., value<h/l>, value<h/l> => ..., value */ + new VMOp(opc_l2i, "l2i", 2, 1, "J", "I"), + /* | ..., value<h/l>, value<h/l> => ..., value */ + new VMOp(opc_l2f, "l2f", 2, 1, "J", "F"), + /* | ..., value<h/l>, value<h/l> => ..., value<h/l>, value<h/l> */ + new VMOp(opc_l2d, "l2d", 2, 2, "J", "D"), + /* | ..., value => ..., value */ + new VMOp(opc_f2i, "f2i", 1, 1, "F", "I"), + /* | ..., value => ..., value<h/l>, value<h/l> */ + new VMOp(opc_f2l, "f2l", 1, 2, "F", "J"), + /* | ..., value => ..., value<h/l>, value<h/l> */ + new VMOp(opc_f2d, "f2d", 1, 2, "F", "D"), + /* | ..., value<h/l>, value<h/l> => ..., value */ + new VMOp(opc_d2i, "d2i", 2, 1, "D", "I"), + /* | ..., value<h/l>, value<h/l> => ..., value<h/l>, value<h/l> */ + new VMOp(opc_d2l, "d2l", 2, 2, "D", "J"), + /* | ..., value<h/l>, value<h/l> => ..., value */ + new VMOp(opc_d2f, "d2f", 2, 1, "D", "F"), + /* | ..., value => ..., result */ + new VMOp(opc_i2b, "i2b", 1, 1, "I", "I"), + /* | ..., value => ..., result */ + new VMOp(opc_i2c, "i2c", 1, 1, "I", "I"), + /* | ..., value => ..., result */ + new VMOp(opc_i2s, "i2s", 1, 1, "I", "I"), + /* | ..., v1<h/l>, v1<h/l>, v2<h/l>, v2<h/l> => ..., result */ + new VMOp(opc_lcmp, "lcmp", 4, 1, "JJ", "I"), + /* | ..., v1<h/l>, v1<h/l>, v2<h/l>, v2<h/l> => ..., result */ + new VMOp(opc_fcmpl, "fcmpl", 2, 1, "FF", "I"), + /* | ..., v1, v2 => ..., result */ + new VMOp(opc_fcmpg, "fcmpg", 2, 1, "FF", "I"), + /* | ..., v1<h/l>, v1<h/l>, v2<h/l>, v2<h/l> => ..., result */ + new VMOp(opc_dcmpl, "dcmpl", 4, 1, "DD", "I"), + /* | ..., v1<h/l>, v1<h/l>, v2<h/l>, v2<h/l> => ..., result */ + new VMOp(opc_dcmpg, "dcmpg", 4, 1, "DD", "I"), + /* brbyte1, brbyte2 | ..., value => ... */ + new VMOp(opc_ifeq, "ifeq", 1, 0, "I", ""), + /* brbyte1, brbyte2 | ..., value => ... */ + new VMOp(opc_ifne, "ifne", 1, 0, "I", ""), + /* brbyte1, brbyte2 | ..., value => ... */ + new VMOp(opc_iflt, "iflt", 1, 0, "I", ""), + /* brbyte1, brbyte2 | ..., value => ... */ + new VMOp(opc_ifge, "ifge", 1, 0, "I", ""), + /* brbyte1, brbyte2 | ..., value => ... */ + new VMOp(opc_ifgt, "ifgt", 1, 0, "I", ""), + /* brbyte1, brbyte2 | ..., value => ... */ + new VMOp(opc_ifle, "ifle", 1, 0, "I", ""), + /* brbyte1, brbyte2 | ..., value1, value2 => ... */ + new VMOp(opc_if_icmpeq, "if_icmpeq", 2, 0, "II", ""), + /* brbyte1, brbyte2 | ..., value1, value2 => ... */ + new VMOp(opc_if_icmpne, "if_icmpne", 2, 0, "II", ""), + /* brbyte1, brbyte2 | ..., value1, value2 => ... */ + new VMOp(opc_if_icmplt, "if_icmplt", 2, 0, "II", ""), + /* brbyte1, brbyte2 | ..., value1, value2 => ... */ + new VMOp(opc_if_icmpge, "if_icmpge", 2, 0, "II", ""), + /* brbyte1, brbyte2 | ..., value1, value2 => ... */ + new VMOp(opc_if_icmpgt, "if_icmpgt", 2, 0, "II", ""), + /* brbyte1, brbyte2 | ..., value1, value2 => ... */ + new VMOp(opc_if_icmple, "if_icmple", 2, 0, "II", ""), + /* brbyte1, brbyte2 | ..., value1, value2 => ... */ + new VMOp(opc_if_acmpeq, "if_acmpeq", 2, 0, "AA", ""), + /* brbyte1, brbyte2 | ..., value1, value2 => ... */ + new VMOp(opc_if_acmpne, "if_acmpne", 2, 0, "AA", ""), + /* brbyte1, brbyte2 | no change */ + new VMOp(opc_goto, "goto", 0, 0, "", ""), + /* brbyte1, brbyte2 | ... => ..., return_addr */ + new VMOp(opc_jsr, "jsr", 0, 1, "", "W"), + /* vindex | no change */ + new VMOp(opc_ret, "ret", 0, 0, "", ""), + /* ??? | ..., index => ... */ + new VMOp(opc_tableswitch, "tableswitch", 1, 0, "I", ""), + /* ??? | ..., key => ... */ + new VMOp(opc_lookupswitch, "lookupswitch", 1, 0, "I", ""), + /* | ..., value => [empty] */ + new VMOp(opc_ireturn, "ireturn", 1, 0, "I", ""), + /* | ..., value<h/l>, value<h/l> => [empty] */ + new VMOp(opc_lreturn, "lreturn", 2, 0, "J", ""), + /* | ..., value => [empty] */ + new VMOp(opc_freturn, "freturn", 1, 0, "F", ""), + /* | ..., value<h/l>, value<h/l> => [empty] */ + new VMOp(opc_dreturn, "dreturn", 2, 0, "D", ""), + /* | ..., value => [empty] */ + new VMOp(opc_areturn, "areturn", 1, 0, "A", ""), + /* | ... => [empty] */ + new VMOp(opc_return, "return", 0, 0, "", ""), + /* idxbyte1, idxbyte2 | ... => ..., value [ value2 ] */ + new VMOp(opc_getstatic, "getstatic", 0, -1, "", "?"), + /* idxbyte1, idxbyte2 | ..., value [ value2 ] => ... */ + new VMOp(opc_putstatic, "putstatic", -1, 0, "?", ""), + /* idxbyte1, idxbyte2 | ..., objectref => ..., value [ value2 ] */ + new VMOp(opc_getfield, "getfield", 1, -1, "A", "?"), + /* idxbyte1, idxbyte2 | ..., objectref, value [ value2 ] => ... */ + new VMOp(opc_putfield, "putfield", -1, 0, "A?", ""), + /* idxbyte1, idxbyte2 | ..., objectref, [args] => ... */ + new VMOp(opc_invokevirtual, "invokevirtual", -1, -1, "A?", "?"), + /* idxbyte1, idxbyte2 | ..., objectref, [args] => ... */ + new VMOp(opc_invokespecial, "invokespecial", -1, -1, "A?", "?"), + /* idxbyte1, idxbyte2 | ..., [args] => ... */ + new VMOp(opc_invokestatic, "invokestatic", -1, -1, "?", "?"), + /* idxbyte1, idxbyte2, nargs, rsvd | ..., objectref, [args] => ... */ + new VMOp(opc_invokeinterface, "invokeinterface", -1, -1, "A?", "?"), + /* */ + new VMOp(opc_xxxunusedxxx, "xxxunusedxxx", 0, 0, "", ""), + /* idxbyte1, idxbyte2 | ... => ..., objectref */ + new VMOp(opc_new, "new", 0, 1, "", "A"), + /* atype | ..., size => ..., result */ + new VMOp(opc_newarray, "newarray", 1, 1, "I", "A"), + /* indexbyte1, indexbyte2 | ..., size => ..., result */ + new VMOp(opc_anewarray, "anewarray", 1, 1, "I", "A"), + /* | ..., objectref => ..., length */ + new VMOp(opc_arraylength, "arraylength", 1, 1, "A", "I"), + /* | ..., objectref => [undefined] */ + new VMOp(opc_athrow, "athrow", 1, 0, "A", "?"), + /* idxbyte1, idxbyte2 | ..., objectref => ..., objectref */ + new VMOp(opc_checkcast, "checkcast", 1, 1, "A", "A"), + /* idxbyte1, idxbyte2 | ..., objectref => ..., result */ + new VMOp(opc_instanceof, "instanceof", 1, 1, "A", "I"), + /* | ..., objectref => ... */ + new VMOp(opc_monitorenter, "monitorenter", 1, 0, "A", ""), + /* | ..., objectref => ... */ + new VMOp(opc_monitorexit, "monitorexit", 1, 0, "A", ""), + /* an instruction | special */ + new VMOp(opc_wide, "wide", 0, 0, "", ""), + /* indexbyte1, indexbyte2, dimensions | ..., size1, ..., sizen => ..., result*/ + new VMOp(opc_multianewarray, "multianewarray", -1, 1, "?", "A"), + /* brbyte1, brbyte2 | ..., value => ... */ + new VMOp(opc_ifnull, "ifnull", 1, 0, "A", ""), + /* brbyte1, brbyte2 | ..., value => ... */ + new VMOp(opc_ifnonnull, "ifnonnull", 1, 0, "A", ""), + /* brbyte1, brbyte2, brbyte3, brbyte4 | no change */ + new VMOp(opc_goto_w, "goto_w", 0, 0, "", ""), + /* brbyte1, brbyte2, brbyte3, brbyte4 | ... => ..., return_addr */ + new VMOp(opc_jsr_w, "jsr_w", 0, 1, "", "W") }; + + /** + * Check that each entry in the ops array has a valid VMOp entry + */ + private static void check() { + for (int i=0; i<=opc_jsr_w; i++) { + VMOp op = ops[i]; + if (op == null) + throw new InsnError ("null VMOp for " + i); + if (op.opcode() != i) + throw new InsnError ("bad opcode for " + i); + + if (1 == 0) { + /* check arg/result data */ + checkTypes(op.argTypes(), op.nStackArgs(), op); + checkTypes(op.resultTypes(), op.nStackResults(), op); + } + } + } + + private static void checkTypes(String types, int n, VMOp op) { + for (int i=0; i<types.length(); i++) { + char c = types.charAt(i); + if (c == '?') + return; + if (c == 'J' || c == 'X' || c == 'D') + n -= 2; + else + n -= 1; + } + if (n != 0) + throw new InsnError ("Bad arg/result for VMOp " + op.opcodeName); + } + + static { + check(); + } +}
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Analyzer.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Analyzer.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Analyzer.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Analyzer.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,1586 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.impl.enhancer.core; + +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Arrays; +import java.util.Set; +import java.util.HashSet; +import java.util.Map; +import java.util.HashMap; + +import org.apache.jdo.impl.enhancer.classfile.ClassAttribute; +import org.apache.jdo.impl.enhancer.classfile.ClassField; +import org.apache.jdo.impl.enhancer.classfile.ClassFile; +import org.apache.jdo.impl.enhancer.classfile.ClassMethod; +import org.apache.jdo.impl.enhancer.classfile.ConstClass; +import org.apache.jdo.impl.enhancer.classfile.ConstantPool; +import org.apache.jdo.impl.enhancer.classfile.GenericAttribute; +import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData; +import org.apache.jdo.impl.enhancer.util.Support; + + + + + +/** + * Analyzes a class for enhancement. + */ +final class Analyzer + extends Support + implements JDOConstants, EnhancerConstants +{ + /** + * The class is not to be modified by the enahncer. + */ + static public final int CC_Unenhancable = -2; + + /** + * The class is detected to be enhanced already and is not to be modifed. + */ + static public final int CC_PreviouslyEnhanced = -1; + + /** + * The enhancement status of the class hasn't been determined yet. + */ + static public final int CC_PersistenceUnknown = 0; + + /** + * The class is to be enhanced for persistence-awareness. + */ + static public final int CC_PersistenceAware = 1; + + /** + * The class is to be enhanced for specific persistence-capability + * (class does extend another persistence-capable class). + */ + static public final int CC_PersistenceCapable = 2; + + /** + * The class is to be enhanced for generic and specific + * persistence-capability (class does not extend another + * persistence-capable class). + */ + static public final int CC_PersistenceCapableRoot = 3; + + /** + * The names of the jdo fields of persistene-capable classes. + */ + static private final Set jdoFieldNames = new HashSet(); + static + { + jdoFieldNames.add(JDO_PC_jdoStateManager_Name); + jdoFieldNames.add(JDO_PC_jdoFlags_Name); + jdoFieldNames.add(JDO_PC_jdoInheritedFieldCount_Name); + jdoFieldNames.add(JDO_PC_jdoFieldNames_Name); + jdoFieldNames.add(JDO_PC_jdoFieldTypes_Name); + jdoFieldNames.add(JDO_PC_jdoFieldFlags_Name); + jdoFieldNames.add(JDO_PC_jdoPersistenceCapableSuperclass_Name); + } + + /** + * The classfile's enhancement controller. + */ + private final Controller control; + + /** + * The classfile to be enhanced. + */ + private final ClassFile classFile; + + /** + * The class name in VM form. + */ + private final String className; + + /** + * The class name in user ('.' delimited) form. + */ + private final String userClassName; + + /** + * The classfile's constant pool. + */ + private final ConstantPool pool; + + /** + * Repository for the enhancement options. + */ + private final Environment env; + + /** + * Repository for JDO meta-data on classes. + */ + private final EnhancerMetaData meta; + + /** + * What type of class is this with respect to persistence. + */ + private int persistenceType = CC_PersistenceUnknown; + + /** + * The name of the persistence-capable superclass if defined. + */ + private String pcSuperClassName; + + /** + * The name of the persistence-capable rootclass if defined. + */ + private String pcRootClassName; + + /** + * The name of this class or the next persistence-capable superclass + * that owns a key class, or the PC rootclass if none defines a key class. + */ + private String pcKeyOwnerClassName; + + /** + * The name next persistence-capable superclass that owns a key class, + * or the PC rootclass if none defines a key class. + */ + private String pcSuperKeyOwnerClassName; + + /** + * The name of the key class if defined. + */ + private String keyClassName; + + /** + * The name of the key class of the next persistence-capable superclass + * that defines one. + */ + private String superKeyClassName; + + /** + * The number of key fields. + */ + private int keyFieldCount; + + /** + * The indexes of all key fields. + */ + private int[] keyFieldIndexes; + + /** + * The number of managed fields. + */ + private int managedFieldCount; + + /** + * The number of annotated fields. + */ + private int annotatedFieldCount; + + /** + * The names of all annotated fields sorted by relative field index. + */ + private String[] annotatedFieldNames; + + /** + * The type names of all annotated fields sorted by relative field index. + */ + private String[] annotatedFieldSigs; + + /** + * The java access modifiers of all annotated fields sorted by relative + * field index. + */ + private int[] annotatedFieldMods; + + /** + * The jdo flags of all annotated fields sorted by relative field index. + */ + private int[] annotatedFieldFlags; + + /** + * The map of found JDO fields. + */ + private final Map jdoLikeFields = new HashMap(20); + + /** + * The map of found JDO methods + */ + private final Map jdoLikeMethods = new HashMap(50); + + /** + * The map of found JDO methods + */ + private final Map annotatableMethods = new HashMap(100); + + /** + * True if a jdo member has been seen in this class. + */ + private boolean hasImplementsPC = false; + private boolean hasGenericJDOFields = false; + private boolean hasGenericJDOMethods = false; + private boolean hasGenericJDOMembers = false; + private boolean hasSpecificJDOFields = false; + private boolean hasSpecificJDOMethods = false; + private boolean hasSpecificJDOMembers = false; + private boolean hasCallbackJDOMethods = false; + private boolean hasJDOMembers = false; + + /** + * True if the class has a default (no-argument) constructor. + */ + private boolean hasDefaultConstructor = false; + + //^olsen: performance opt.: make these fields of type ClassMethod + + /** + * True if the class has a static initializer block. + */ + private boolean hasStaticInitializer = false; + + /** + * True if the class has a clone() method. + */ + private boolean hasCloneMethod = false; + + /** + * True if the class has a writeObject(java.io.ObjectOutputStream) method. + */ + private boolean hasWriteObjectMethod = false; + + /** + * True if the class has a writeReplace() method. + */ + private boolean hasWriteReplaceMethod = false; + + /** + * True if the class has a readObject(java.io.ObjectInputStream) method. + */ + private boolean hasReadObjectMethod = false; + + // ---------------------------------------------------------------------- + + /** + * Constructor + */ + public Analyzer(Controller control, + Environment env) + { + affirm(control != null); + affirm(env != null); + + this.control = control; + this.classFile = control.getClassFile(); + this.className = classFile.classNameString(); + this.userClassName = classFile.userClassName(); + this.pool = classFile.pool(); + this.env = env; + this.meta = env.getEnhancerMetaData(); + + affirm(classFile != null); + affirm(className != null); + affirm(userClassName != null); + affirm(pool != null); + affirm(meta != null); + } + + /** + * Returns the class file which we are operating on. + */ + public ClassFile getClassFile() + { + return classFile; + } + + /** + * Return the persistence type for this class + */ + public int getPersistenceType() + { + return persistenceType; + } + + /** + * Returns true if the class has been analyzed already. + */ + public boolean isAnalyzed() + { + return (persistenceType != CC_PersistenceUnknown); + } + + /** + * Returns true if the class is one which should be a candidate for + * annotation. + */ + public boolean isAnnotateable() + { + return (persistenceType >= CC_PersistenceUnknown); + } + + /** + * Returns true if the class is to be enhanced for persistence-capability. + */ + public boolean isAugmentable() + { + return (persistenceType >= CC_PersistenceCapable); + } + + /** + * Returns true if the class is to be enhanced as least-derived, + * persistence-capable class. + */ + public boolean isAugmentableAsRoot() + { + return (persistenceType >= CC_PersistenceCapableRoot); + } + + /** + * Returns the methods that are candidates for annotation. + */ + public Collection getAnnotatableMethods() + { + return annotatableMethods.values(); + } + + /** + * Returns the name of the persistence-capable superclass if defined. + */ + public String getPCSuperClassName() + { + return pcSuperClassName; + } + + /** + * Returns the name of the persistence-capable rootclass if defined. + */ + public String getPCRootClassName() + { + return pcRootClassName; + } + + /** + * Returns the name of this class or the next persistence-capable + * superclass that owns a key class. + */ + public String getPCKeyOwnerClassName() + { + return pcKeyOwnerClassName; + } + + /** + * Returns the name of this class or the next persistence-capable + * that owns a key class. + */ + public String getPCSuperKeyOwnerClassName() + { + return pcSuperKeyOwnerClassName; + } + + /** + * Returns the name of the key class if defined. + */ + public String getKeyClassName() + { + return keyClassName; + } + + /** + * Returns the name of the key class of the next persistence-capable + * superclass that defines one. + */ + public String getSuperKeyClassName() + { + return superKeyClassName; + } + + /** + * Returns the number of key field. + */ + public int getKeyFieldCount() + { + return keyFieldCount; + } + + /** + * Returns the names of the key fields. + */ + public int[] getKeyFieldIndexes() + { + return keyFieldIndexes; + } + + /** + * Returns the number of managed field. + */ + public int getManagedFieldCount() + { + return managedFieldCount; + } + + /** + * Returns the number of annotated field. + */ + public int getAnnotatedFieldCount() + { + return annotatedFieldCount; + } + + /** + * Returns the names of the annotated fields. + */ + public String[] getAnnotatedFieldNames() + { + return annotatedFieldNames; + } + + /** + * Returns the types names of the annotated fields. + */ + public String[] getAnnotatedFieldSigs() + { + return annotatedFieldSigs; + } + + /** + * Returns the Java access modifiers of the annotated fields. + */ + public int[] getAnnotatedFieldMods() + { + return annotatedFieldMods; + } + + /** + * Returns the JDO flags of the annotated fields. + */ + public int[] getAnnotatedFieldFlags() + { + return annotatedFieldFlags; + } + + /** + * Returns true if the class has a default (no-argument) constructor. + */ + public boolean hasDefaultConstructor() + { + return hasDefaultConstructor; + } + + /** + * Returns true if the class has a static initializer block. + */ + public boolean hasStaticInitializer() + { + return hasStaticInitializer; + } + + /** + * Returns true if the class has a clone() method. + */ + public boolean hasCloneMethod() + { + return hasCloneMethod; + } + + /** + * Returns true if the class has a writeObject() method. + */ + public boolean hasWriteObjectMethod() + { + return hasWriteObjectMethod; + } + + /** + * Returns true if the class has a writeReplace() method. + */ + public boolean hasWriteReplaceMethod() + { + return hasWriteReplaceMethod; + } + + /** + * Returns true if the class has a readObject() method. + */ + public boolean hasReadObjectMethod() + { + return hasReadObjectMethod; + } + + /** + * Returns true if the class already provides the JDO augmentation. + */ + public boolean hasJDOAugmentation() + { + return hasJDOMembers; + } + + // ---------------------------------------------------------------------- + + /** + * Analyzes the class for existing augmentation. + */ + public void scan() + { + env.message("scanning class " + userClassName); + + // skip previously enhanced files + checkForEnhancedAttribute(); + if (!isAnnotateable()) { + return; + } + + // skip unenhancable files + initPersistenceType(); + if (!isAnnotateable()) { + return; + } + affirm(persistenceType > CC_Unenhancable); + + scanFields(); + scanMethods(); + + if (isAugmentable()) { + checkPCFeasibility(); + checkSpecificAugmentation(); + checkCallbackAugmentation(); + + if (isAugmentableAsRoot()) { + checkGenericAugmentation(); + } + } + + //^olsen: check +/* + //@olsen: check whether member starts with the reserved jdo prefix + if (methodName.startsWith("jdo")) { + //@olsen: issue a warning only + env.warning( + getI18N("enhancer.class_has_jdo_like_member", + userClassName, methodName)); + return; + } + //@olsen: check whether member starts with the reserved jdo prefix + if (fieldName.startsWith("jdo")) { + //@olsen: issue a warning only + env.warning( + getI18N("enhancer.class_has_jdo_like_member", + userClassName, fieldName)); + return; + } +*/ + } + + /** + * Scans the attributes of a ClassFile + */ + private void checkForEnhancedAttribute() + { + for (Enumeration e = classFile.attributes().elements(); + e.hasMoreElements();) { + final ClassAttribute attr = (ClassAttribute)e.nextElement(); + final String attrName = attr.attrName().asString(); + if (SUNJDO_PC_EnhancedAttribute.equals(attrName)) { + persistenceType = CC_PreviouslyEnhanced; + + // At some point we may want to consider stripping old + // annotations and re-annotating, but not yet + env.message("ignoring previously enhanced class " + + userClassName); + return; + } + } + } + + // ---------------------------------------------------------------------- + + /** + * Sets the persistence type of a class according to JDO metadata. + */ + private void initPersistenceType() + { + affirm(persistenceType == CC_PersistenceUnknown); + + // check if class is known not to be changed + final EnhancerMetaData meta = env.getEnhancerMetaData(); + if (meta.isKnownUnenhancableClass(className)) { + persistenceType = CC_Unenhancable; + return; + } + + // check if class is persistence-capable + if (meta.isPersistenceCapableClass(className)) { + pcSuperClassName + = meta.getPersistenceCapableSuperClass(className); + pcRootClassName + = meta.getPersistenceCapableRootClass(className); + affirm(pcSuperClassName == null || pcRootClassName != null); + + persistenceType + = (pcSuperClassName == null + ? CC_PersistenceCapableRoot + : CC_PersistenceCapable); + + //^olsen: assert consistency between Java and JDO metadata + affirm(!classFile.isInterface()); + //affirm(!classFile.isInnerClass()); + + //^olsen: assert consistency between Java and JDO metadata + // disallow enhancing classes not derived from java.lang.Object + final ConstClass superConstClass = classFile.superName(); + affirm(superConstClass != null); + + // non-pc-root classes must not derive from java.lang.Object + affirm(pcSuperClassName == null + || !superConstClass.asString().equals("java/lang/Object")); + + // define the PC key owner class + pcKeyOwnerClassName = className; + while (meta.getKeyClass(pcKeyOwnerClassName) == null) { + final String pcSuperClassName + = meta.getPersistenceCapableSuperClass( + pcKeyOwnerClassName); + if (pcSuperClassName == null) + break; + pcKeyOwnerClassName = pcSuperClassName; + } + affirm(pcKeyOwnerClassName != null); + + // define the PC super key owner class + pcSuperKeyOwnerClassName = pcSuperClassName; + if (pcSuperKeyOwnerClassName != null) { + while (meta.getKeyClass(pcSuperKeyOwnerClassName) == null) { + final String pcSuperClassName + = meta.getPersistenceCapableSuperClass( + pcSuperKeyOwnerClassName); + if (pcSuperClassName == null) + break; + pcSuperKeyOwnerClassName = pcSuperClassName; + } + affirm(pcKeyOwnerClassName != null); + } + + keyClassName + = meta.getKeyClass(className); + superKeyClassName + = meta.getSuperKeyClass(className); + affirm(superKeyClassName == null || pcSuperClassName != null); + } + } + + /** + * Scans the fields. + */ + private void scanFields() + { + // all fields for which accessor/mutator needs to be generated + final Map annotatedFieldMap = new HashMap(); + + if (isAugmentable()) { + // loop over class fields to declare them to the model + for (final Enumeration e = classFile.fields().elements(); + e.hasMoreElements();) { + final ClassField field = (ClassField)e.nextElement(); + final String name = field.name().asString(); + final String sig = field.signature().asString(); + + // skip jdo fields + if (jdoFieldNames.contains(name)) { + continue; + } + + // skip static fields + if (field.isStatic()) { + continue; + } + + // skip known non-managed fields + if (meta.isKnownNonManagedField(className, name, sig)) { + continue; + } + + // remember field requiring accessor/mutator + Object obj = annotatedFieldMap.put(name, field); + affirm(obj == null, + ("Error in classfile: repeated declaration of field: " + + userClassName + "." + name)); + + // skip final, transient fields + if (field.isFinal() + || field.isTransient()) { + continue; + } + + if (false) { + System.out.println("Analyzer.scanFields(): declaring " + + className + "." + name + " : " + sig); + } + meta.declareField(className, name, sig); + } + } + + // nr of fields needing accessor/mutator methods + annotatedFieldCount = annotatedFieldMap.size(); + + // get managed field names from meta data + final String[] managedFieldNames = meta.getManagedFields(className); + affirm(managedFieldNames != null); + managedFieldCount = managedFieldNames.length; + final Set managedFieldNamesSet + = new HashSet(Arrays.asList(managedFieldNames)); + affirm(managedFieldNamesSet.size() == managedFieldCount, + "JDO metadata: returned duplicate managed fields."); + affirm(managedFieldCount <= annotatedFieldCount, + "JDO metadata: managed fields exceed annotated fields."); + + // data structures for key fields + final String[] keyFieldNames = meta.getKeyFields(className); + affirm(keyFieldNames != null); + keyFieldCount = keyFieldNames.length; + affirm(keyFieldCount == 0 || keyClassName != null, + "JDO metadata: returned key fields but no key class."); + final Set keyFieldNamesSet + = new HashSet(Arrays.asList(keyFieldNames)); + affirm(keyFieldNamesSet.size() == keyFieldCount, + "JDO metadata: returned duplicate key fields."); + affirm(keyFieldCount <= managedFieldCount, + "JDO metadata: key fields exceed managed fields."); + + // loop over class fields to compute 'jdo*' and key/managed fields + for (final Enumeration e = classFile.fields().elements(); + e.hasMoreElements();) { + final ClassField field = (ClassField)e.nextElement(); + final String name = field.name().asString(); + final String sig = field.signature().asString(); + final String userFieldName = userClassName + "." + name; + + if (false) { + System.out.println("Analyzer.scanFields(): scanning " + + className + "." + name + " : " + sig); + } + + // map 'jdo*' field names to class fields + if (name.startsWith("jdo")) { + final Object f = jdoLikeFields.put(name, field); + affirm(f == null); + } + + // skip non-managed fields + if (!managedFieldNamesSet.contains(name)) { + affirm(!meta.isManagedField(className, name)); + + // check for non-managed key field + affirm(!keyFieldNamesSet.contains(name), + ("JDO metadata: reported the field " + userFieldName + + " to be non-managed but key.")); + continue; + } + affirm(meta.isManagedField(className, name)); + + // check for managed static field + affirm(!field.isStatic(), + ("JDO metadata: reported the field " + userFieldName + + " to be managed though it's static.")); + + // check for managed final field + affirm(!field.isFinal(), + ("JDO metadata: reported the field " + userFieldName + + " to be managed though it's final.")); + + // allow for managed transient fields + +//^olsen: adopt +/* + r[i++] = hasField( + out, + Modifier.PRIVATE | Modifier.FINAL | Modifier.STATIC, + long.class, + "serialVersionUID"); +*/ + } + + // get the managed field flags ordered by relative index + final int[] managedFieldFlags + = meta.getFieldFlags(className, managedFieldNames); + + // compute the managed field types ordered by relative index + // and key field indexes + int j = 0; + keyFieldIndexes = new int[keyFieldCount]; + final String[] managedFieldSigs = new String[managedFieldCount]; + final int[] managedFieldMods = new int[managedFieldCount]; + for (int i = 0; i < managedFieldCount; i++) { + final String name = managedFieldNames[i]; + affirm(name != null); + + // assert consistency between Java and JDO metadata + final ClassField field = (ClassField)annotatedFieldMap.get(name); + affirm(field != null, + ("The managed field " + userClassName + "." + name + + " is not declared by the class.")); + affirm(!field.isStatic(), + ("The managed field " + userClassName + "." + name + + " is static.")); + affirm(!field.isFinal(), + ("The managed field " + userClassName + "." + name + + " is final.")); + + // mark managed field as taken care of + annotatedFieldMap.remove(name); + + // assign key field index + if (keyFieldNamesSet.contains(name)) { + affirm(meta.isKeyField(className, name)); + keyFieldIndexes[j++] = i; + } + + // add field type and Java access modifers + managedFieldSigs[i] = field.signature().asString(); + managedFieldMods[i] = field.access(); + + // set the serializable bit if field is not (Java) transient + // This code might be removed as soon as the metadata is able + // to retrieve the info as part of meta.getFieldFlags. + if (!field.isTransient()) { + managedFieldFlags[i] |= EnhancerMetaData.SERIALIZABLE; + } + + if (false) { + System.out.println("managed field: " + + className + "." + name + " : {"); + System.out.println(" sigs = " + managedFieldSigs[i]); + System.out.println(" mods = " + + Integer.toHexString(managedFieldMods[i])); + System.out.println(" flags = " + + Integer.toHexString(managedFieldFlags[i])); + } + } + + // post conditions of managed/key field processing + affirm(keyFieldIndexes.length == keyFieldCount); + affirm(keyFieldCount <= managedFieldCount); + affirm(managedFieldNames.length == managedFieldCount); + affirm(managedFieldSigs.length == managedFieldCount); + affirm(managedFieldMods.length == managedFieldCount); + affirm(managedFieldFlags.length == managedFieldCount); + affirm(managedFieldCount <= annotatedFieldCount); + + // assign the annotated field arrays + if (managedFieldCount == annotatedFieldCount) { + // return if the annotated fields are equal to the managed ones + annotatedFieldNames = managedFieldNames; + annotatedFieldSigs = managedFieldSigs; + annotatedFieldMods = managedFieldMods; + annotatedFieldFlags = managedFieldFlags; + } else { + // fill the annotated field arrays with the managed ones + annotatedFieldNames = new String[annotatedFieldCount]; + annotatedFieldSigs = new String[annotatedFieldCount]; + annotatedFieldMods = new int[annotatedFieldCount]; + annotatedFieldFlags = new int[annotatedFieldCount]; + int i = managedFieldCount; + System.arraycopy(managedFieldNames, 0, annotatedFieldNames, 0, i); + System.arraycopy(managedFieldSigs, 0, annotatedFieldSigs, 0, i); + System.arraycopy(managedFieldMods, 0, annotatedFieldMods, 0, i); + System.arraycopy(managedFieldFlags, 0, annotatedFieldFlags, 0, i); + + // append the annotated, non-managed fields + for (Iterator k = annotatedFieldMap.entrySet().iterator(); + k.hasNext();) { + final Map.Entry entry = (Map.Entry)k.next(); + final String name = (String)entry.getKey(); + final ClassField field = (ClassField)entry.getValue(); + affirm(name.equals(field.name().asString())); + + affirm(!field.isStatic(), + ("The managed field " + userClassName + "." + name + + " is static.")); + + // add field type and Java access modifers + annotatedFieldNames[i] = name; + annotatedFieldSigs[i] = field.signature().asString(); + annotatedFieldMods[i] = field.access(); + annotatedFieldFlags[i] = 0x0; // direct read/write access + i++; + } + affirm(i == annotatedFieldCount); + } + + // post conditions + affirm(keyFieldIndexes.length == keyFieldCount); + affirm(keyFieldCount <= managedFieldCount); + affirm(annotatedFieldNames.length == annotatedFieldCount); + affirm(annotatedFieldSigs.length == annotatedFieldCount); + affirm(annotatedFieldMods.length == annotatedFieldCount); + affirm(annotatedFieldFlags.length == annotatedFieldCount); + affirm(managedFieldCount <= annotatedFieldCount); + } + + /** + * Scans the methods of a ClassFile. + */ + private void scanMethods() + { + // check methods + for (final Enumeration e = classFile.methods().elements(); + e.hasMoreElements();) { + final ClassMethod method = (ClassMethod)e.nextElement(); + final String name = method.name().asString(); + final String sig = method.signature().asString(); + affirm(name != null); + affirm(sig != null); + + final String key = methodKey(name, sig); + affirm(key != null); + + // for non-abstract, non-native methods, map names to class methods + if (!method.isAbstract() && !method.isNative()) { + final Object m = annotatableMethods.put(key, method); + affirm(m == null); + } + + // for 'jdo*' like methods, map names to class methods + if (name.startsWith("jdo")) { + final Object m = jdoLikeMethods.put(key, method); + affirm(m == null); + continue; + } + + // check for a default constructor by name and signature + if (name.equals(NameHelper.constructorName()) + && sig.equals(NameHelper.constructorSig())) { + hasDefaultConstructor = true; + continue; + } + + // check for a static initializer block by name and signature + if (name.equals(JAVA_clinit_Name) + && sig.equals(JAVA_clinit_Sig)) { + hasStaticInitializer = true; + continue; + } + + // check for method clone() by name and signature + if (name.equals(JAVA_Object_clone_Name) + && sig.equals(JAVA_Object_clone_Sig)) { + hasCloneMethod = true; + continue; + } + + // check for method writeObject() by name and signature + if (name.equals(JAVA_Object_writeObject_Name) + && sig.equals(JAVA_Object_writeObject_Sig)) { + hasWriteObjectMethod = true; + continue; + } + + // check for method writeReplace() by name and signature + if (name.equals(JAVA_Object_writeReplace_Name) + && sig.equals(JAVA_Object_writeReplace_Sig)) { + hasWriteReplaceMethod = true; + continue; + } + + // check for method readObject() by name and signature + if (name.equals(JAVA_Object_readObject_Name) + && sig.equals(JAVA_Object_readObject_Sig)) { + hasReadObjectMethod = true; + + // remove readObject() method from annotation candidates + Object m = annotatableMethods.remove(key); + affirm(m != null); + continue; + } + } + + // check for a default constructor by name and signature + if (hasDefaultConstructor) { + env.message(getI18N("enhancer.class_has_default_constructor")); + } else { + env.message(getI18N("enhancer.class_has_not_default_constructor")); + } + + // check for a static initializer block by name and signature + if (hasStaticInitializer) { + env.message(getI18N("enhancer.class_has_static_initializer")); + } else { + env.message(getI18N("enhancer.class_has_not_static_initializer")); + } + + // check for method clone() by name and signature + if (hasCloneMethod) { + env.message(getI18N("enhancer.class_has_clone_method")); + } else { + env.message(getI18N("enhancer.class_has_not_clone_method")); + } + + // check for method writeObject() by name and signature + if (hasWriteObjectMethod) { + env.message(getI18N("enhancer.class_has_writeObject_method")); + } else { + env.message(getI18N("enhancer.class_has_not_writeObject_method")); + } + + // check for method writeReplace() by name and signature + if (hasWriteReplaceMethod) { + env.message(getI18N("enhancer.class_has_writeReplace_method")); + } else { + env.message(getI18N("enhancer.class_has_not_writeReplace_method")); + } + + // check for method readObject() by name and signature + if (hasReadObjectMethod) { + env.message(getI18N("enhancer.class_has_readObject_method")); + } else { + env.message(getI18N("enhancer.class_has_not_readObject_method")); + } + } + + private void checkGenericAugmentation() + { + scanForImplementsPC(); + scanForGenericJDOFields(); + scanForGenericJDOMethods(); + + final boolean all + = (hasImplementsPC && hasGenericJDOFields && hasGenericJDOMethods); + //^olsen: check + final boolean none + = !(hasImplementsPC + || hasGenericJDOFields || hasGenericJDOMethods); + + if (all ^ none) { + hasGenericJDOMembers = hasImplementsPC; + env.message( + getI18N("enhancer.class_has_generic_jdo_members", + String.valueOf(hasGenericJDOMembers))); + + //^olsen: check for specific enhancement + + return; + } + + final String key + = "enhancer.class_has_inconsistently_declared_jdo_members"; + if (hasGenericJDOFields && !hasGenericJDOMethods) { + env.error( + getI18N(key, + userClassName, + "<generic jdo fields>", + "<generic jdo methods>")); + } else if (!hasGenericJDOFields && hasGenericJDOMethods) { + env.error( + getI18N(key, + userClassName, + "<generic jdo methods>", + "<generic jdo fields>")); + } else if (!hasGenericJDOFields && !hasGenericJDOMethods) { + env.error( + getI18N(key, + userClassName, + "<implements " + JDO_PersistenceCapable_Name + ">", + "<generic jdo members>")); + } else { + env.error( + getI18N(key, + userClassName, + "<generic jdo members>", + "<implements " + JDO_PersistenceCapable_Name + ">")); + } + } + + private void checkSpecificAugmentation() + { + scanForSpecificJDOFields(); + scanForSpecificJDOMethods(); + + final boolean all + = (hasSpecificJDOFields && hasSpecificJDOMethods); + //^olsen: check + final boolean none + = !(hasSpecificJDOFields || hasSpecificJDOMethods); + + if (all ^ none) { + hasSpecificJDOMembers = hasSpecificJDOFields; + env.message( + getI18N("enhancer.class_has_specific_jdo_members", + String.valueOf(hasSpecificJDOMembers))); + return; + } + + final String key + = "enhancer.class_has_inconsistently_declared_jdo_members"; + if (hasSpecificJDOFields && !hasSpecificJDOMethods) { + env.error( + getI18N(key, + userClassName, + "<specific jdo fields>", + "<specific jdo methods>")); + } else { + env.error( + getI18N(key, + userClassName, + "<specific jdo methods>", + "<specific jdo fields>")); + } + } + + private void checkCallbackAugmentation() + { + scanForCallbackJDOMethods(); + env.message( + getI18N("enhancer.class_has_callback_jdo_methods", + String.valueOf(hasCallbackJDOMethods))); + } + + private void checkPCFeasibility() + { + if (!hasDefaultConstructor) { + env.error( + getI18N("enhancer.class_missing_default_constructor", + userClassName)); + } + } + + /** + * Scans the class for implementing the PC interface. + */ + private void scanForImplementsPC() + { + hasImplementsPC = false; + for (final Iterator ifc = classFile.interfaces().iterator(); + ifc.hasNext();) { + final ConstClass i = (ConstClass)ifc.next(); + if (i.asString().equals(JDO_PersistenceCapable_Path)) { + hasImplementsPC = true; + break; + } + } + env.message( + getI18N("enhancer.class_implements_jdo_pc", + String.valueOf(hasImplementsPC))); + } + + /** + * Scans for JDO fields of generic augmentation. + */ + private void scanForGenericJDOFields() + { + // performance shortcut + if (jdoLikeFields.isEmpty()) { + hasGenericJDOFields = false; + env.message( + getI18N("enhancer.class_has_generic_jdo_fields", + String.valueOf(hasGenericJDOFields))); + return; + } + + // sets of found/missing 'jdo*' members + final Set found = new HashSet(10); + final Set missing = new HashSet(10); + + scanJDOField(JDO_PC_jdoStateManager_Name, + JDO_PC_jdoStateManager_Sig, + JDO_PC_jdoStateManager_Mods, + found, missing); + scanJDOField(JDO_PC_jdoFlags_Name, + JDO_PC_jdoFlags_Sig, + JDO_PC_jdoFlags_Mods, + found, missing); + + if (found.isEmpty() ^ missing.isEmpty()) { + hasGenericJDOFields = missing.isEmpty(); + env.message( + getI18N("enhancer.class_has_generic_jdo_fields", + String.valueOf(hasGenericJDOFields))); + return; + } + + reportInconsistentJDOMembers(found, missing); + } + + /** + * Scans for JDO methods of generic augmentation. + */ + private void scanForGenericJDOMethods() + { + // performance shortcut + if (jdoLikeMethods.isEmpty()) { + hasGenericJDOMethods = false; + env.message( + getI18N("enhancer.class_has_generic_jdo_methods", + String.valueOf(hasGenericJDOMethods))); + return; + } + + // sets of found/missing 'jdo*' members + final Set found = new HashSet(30); + final Set missing = new HashSet(30); + + scanJDOMethod(JDO_PC_jdoReplaceStateManager_Name, + JDO_PC_jdoReplaceStateManager_Sig, + JDO_PC_jdoReplaceStateManager_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoReplaceFlags_Name, + JDO_PC_jdoReplaceFlags_Sig, + JDO_PC_jdoReplaceFlags_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoGetPersistenceManager_Name, + JDO_PC_jdoGetPersistenceManager_Sig, + JDO_PC_jdoGetPersistenceManager_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoGetObjectId_Name, + JDO_PC_jdoGetObjectId_Sig, + JDO_PC_jdoGetObjectId_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoGetTransactionalObjectId_Name, + JDO_PC_jdoGetTransactionalObjectId_Sig, + JDO_PC_jdoGetTransactionalObjectId_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoIsPersistent_Name, + JDO_PC_jdoIsPersistent_Sig, + JDO_PC_jdoIsPersistent_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoIsTransactional_Name, + JDO_PC_jdoIsTransactional_Sig, + JDO_PC_jdoIsTransactional_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoIsNew_Name, + JDO_PC_jdoIsNew_Sig, + JDO_PC_jdoIsNew_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoIsDeleted_Name, + JDO_PC_jdoIsDeleted_Sig, + JDO_PC_jdoIsDeleted_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoIsDirty_Name, + JDO_PC_jdoIsDirty_Sig, + JDO_PC_jdoIsDirty_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoMakeDirty_Name, + JDO_PC_jdoMakeDirty_Sig, + JDO_PC_jdoMakeDirty_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoPreSerialize_Name, + JDO_PC_jdoPreSerialize_Sig, + JDO_PC_jdoPreSerialize_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoReplaceFields_Name, + JDO_PC_jdoReplaceFields_Sig, + JDO_PC_jdoReplaceFields_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoProvideFields_Name, + JDO_PC_jdoProvideFields_Sig, + JDO_PC_jdoProvideFields_Mods, + found, missing); + + if (found.isEmpty() ^ missing.isEmpty()) { + hasGenericJDOMethods = missing.isEmpty(); + env.message( + getI18N("enhancer.class_has_generic_jdo_methods", + String.valueOf(hasGenericJDOMethods))); + return; + } + + reportInconsistentJDOMembers(found, missing); + } + + /** + * Scans for JDO fields of specific augmentation. + */ + private void scanForSpecificJDOFields() + { + // performance shortcut + if (jdoLikeFields.isEmpty()) { + hasSpecificJDOFields = false; + env.message( + getI18N("enhancer.class_has_specific_jdo_fields", + String.valueOf(hasSpecificJDOFields))); + return; + } + + // sets of found/missing 'jdo*' members + final Set found = new HashSet(10); + final Set missing = new HashSet(10); + + scanJDOField(JDO_PC_jdoInheritedFieldCount_Name, + JDO_PC_jdoInheritedFieldCount_Sig, + JDO_PC_jdoInheritedFieldCount_Mods, + found, missing); + scanJDOField(JDO_PC_jdoFieldNames_Name, + JDO_PC_jdoFieldNames_Sig, + JDO_PC_jdoFieldNames_Mods, + found, missing); + scanJDOField(JDO_PC_jdoFieldTypes_Name, + JDO_PC_jdoFieldTypes_Sig, + JDO_PC_jdoFieldTypes_Mods, + found, missing); + scanJDOField(JDO_PC_jdoFieldFlags_Name, + JDO_PC_jdoFieldFlags_Sig, + JDO_PC_jdoFieldFlags_Mods, + found, missing); + scanJDOField(JDO_PC_jdoPersistenceCapableSuperclass_Name, + JDO_PC_jdoPersistenceCapableSuperclass_Sig, + JDO_PC_jdoPersistenceCapableSuperclass_Mods, + found, missing); + + if (found.isEmpty() ^ missing.isEmpty()) { + hasSpecificJDOFields = missing.isEmpty(); + env.message( + getI18N("enhancer.class_has_specific_jdo_fields", + String.valueOf(hasSpecificJDOFields))); + return; + } + + reportInconsistentJDOMembers(found, missing); + } + + /** + * Scans for JDO methods of specific augmentation. + */ + private void scanForSpecificJDOMethods() + { + // performance shortcut + if (jdoLikeMethods.isEmpty()) { + hasSpecificJDOMethods = false; + env.message( + getI18N("enhancer.class_has_specific_jdo_methods", + String.valueOf(hasSpecificJDOMethods))); + return; + } + + // sets of found/missing 'jdo*' members + final Set found = new HashSet(30); + final Set missing = new HashSet(30); + + scanJDOMethod(JDO_PC_jdoGetManagedFieldCount_Name, + JDO_PC_jdoGetManagedFieldCount_Sig, + JDO_PC_jdoGetManagedFieldCount_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoNewInstance_Name, + JDO_PC_jdoNewInstance_Sig, + JDO_PC_jdoNewInstance_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoNewInstance_Name, + JDO_PC_jdoNewInstance_Sig, + JDO_PC_jdoNewInstance_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoNewObjectIdInstance_Name, + JDO_PC_jdoNewObjectIdInstance_Sig, + JDO_PC_jdoNewObjectIdInstance_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoNewObjectIdInstance_Name, + JDO_PC_jdoNewObjectIdInstance_Sig, + JDO_PC_jdoNewObjectIdInstance_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoCopyKeyFieldsToObjectId_Name, + JDO_PC_jdoCopyKeyFieldsToObjectId_Sig, + JDO_PC_jdoCopyKeyFieldsToObjectId_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoCopyKeyFieldsToObjectId_OIFS_Name, + JDO_PC_jdoCopyKeyFieldsToObjectId_OIFS_Sig, + JDO_PC_jdoCopyKeyFieldsToObjectId_OIFS_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoCopyKeyFieldsFromObjectId_OIFC_Name, + JDO_PC_jdoCopyKeyFieldsFromObjectId_OIFC_Sig, + JDO_PC_jdoCopyKeyFieldsFromObjectId_OIFC_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoReplaceField_Name, + JDO_PC_jdoReplaceField_Sig, + JDO_PC_jdoReplaceField_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoProvideField_Name, + JDO_PC_jdoProvideField_Sig, + JDO_PC_jdoProvideField_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoCopyFields_Name, + JDO_PC_jdoCopyFields_Sig, + JDO_PC_jdoCopyFields_Mods, + found, missing); + scanJDOMethod(JDO_PC_jdoCopyField_Name, + JDONameHelper.getJDO_PC_jdoCopyField_Sig(className), + JDO_PC_jdoCopyField_Mods, + found, missing); + + if (found.isEmpty() ^ missing.isEmpty()) { + hasSpecificJDOMethods = missing.isEmpty(); + env.message( + getI18N("enhancer.class_has_specific_jdo_methods", + String.valueOf(hasSpecificJDOMethods))); + return; + } + + reportInconsistentJDOMembers(found, missing); + } + + /** + * Scans for JDO methods of generic augmentation. + */ + private void scanForCallbackJDOMethods() + { + // performance shortcut + if (jdoLikeMethods.isEmpty()) { + hasCallbackJDOMethods = false; + env.message( + getI18N("enhancer.class_has_callback_jdo_methods", + String.valueOf(hasCallbackJDOMethods))); + return; + } + + // sets of found/missing 'jdo*' members + final Set found = new HashSet(30); + final Set missing = new HashSet(30); + final boolean annotatable = true; + + scanJDOMethod(JDO_IC_jdoPostLoad_Name, + JDO_IC_jdoPostLoad_Sig, + JDO_IC_jdoPostLoad_Mods, + found, missing, !annotatable); + + scanJDOMethod(JDO_IC_jdoPreStore_Name, + JDO_IC_jdoPreStore_Sig, + JDO_IC_jdoPreStore_Mods, + found, missing, annotatable); + + scanJDOMethod(JDO_IC_jdoPreClear_Name, + JDO_IC_jdoPreClear_Sig, + JDO_IC_jdoPreClear_Mods, + found, missing, !annotatable); + + scanJDOMethod(JDO_IC_jdoPreDelete_Name, + JDO_IC_jdoPreDelete_Sig, + JDO_IC_jdoPreDelete_Mods, + found, missing, annotatable); + + // no requirement to check for 'missing' methods + if (!found.isEmpty()) { + hasCallbackJDOMethods = true; + env.message( + getI18N("enhancer.class_has_callback_jdo_methods", + String.valueOf(hasCallbackJDOMethods))); + } + } + + /** + * Verifies a JDO field signature. + */ + private void scanJDOField(String fieldName, + String expectedSig, + int expectedMods, + Set found, + Set missing) + { + final ClassField field = (ClassField)jdoLikeFields.get(fieldName); + if (field == null) { + missing.add(fieldName); + return; + } + found.add(fieldName); + + final String foundSig = field.signature().asString(); + final int foundMods = field.access(); + if (!expectedSig.equals(foundSig) || expectedMods != foundMods) { + env.error( + getI18N("enhancer.class_has_illegally_declared_jdo_member", + new Object[]{ userClassName, + fieldName, + expectedSig, + foundSig, + new Integer(expectedMods), + new Integer(foundMods) })); + } + } + + /** + * Verifies a JDO method signature. + */ + private void scanJDOMethod(String methodName, + String expectedSig, + int expectedMods, + Set found, + Set missing) + { + scanJDOMethod(methodName, expectedSig, expectedMods, + found, missing, true); + } + + /** + * Verifies a JDO method signature. + */ + private void scanJDOMethod(String methodName, + String expectedSig, + int expectedMods, + Set found, + Set missing, + boolean annotatable) + { + final String key = methodKey(methodName, expectedSig); + final ClassMethod method = (ClassMethod)jdoLikeMethods.get(key); + if (method == null) { + missing.add(key); + return; + } + found.add(key); + + final String foundSig = method.signature().asString(); + final int foundMods = method.access(); + if (!expectedSig.equals(foundSig) || expectedMods != foundMods) { + env.error( + getI18N("enhancer.class_has_illegally_declared_jdo_member", + new Object[]{ userClassName, + methodName, + expectedSig, + foundSig, + new Integer(expectedMods), + new Integer(foundMods) })); + } + + // remove jdo method from annotation candidates + if (!annotatable) { + Object m = annotatableMethods.remove(key); + affirm(m != null); + } + } + + /** + * Reports an error for some found/missing JDO fields or methods. + */ + private void reportInconsistentJDOMembers(Set found, + Set missing) + { + final Iterator fi = found.iterator(); + final StringBuffer f = new StringBuffer((String)fi.next()); + while (fi.hasNext()) { + f.append(", " + fi.next()); + } + + final Iterator mi = found.iterator(); + final StringBuffer m = new StringBuffer((String)mi.next()); + while (mi.hasNext()) { + m.append(", " + mi.next()); + } + + env.error( + getI18N("enhancer.class_has_inconsistently_declared_jdo_members", + userClassName, f.toString(), m.toString())); + } + + // ---------------------------------------------------------------------- + + static private String methodKey(String name, + String sig) + { + affirm(name != null); + affirm(sig != null && sig.charAt(0) == '(' && sig.indexOf(')') > 0); + final String parms = sig.substring(0, sig.indexOf(')') + 1); + return (name + parms); + } +}