private void addFieldImplDataMethods()

in openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCDataGenerator.java [365:558]


    private void addFieldImplDataMethods(ClassNodeTracker cnt, ClassMetaData meta) {
        ClassNode classNode = cnt.getClassNode();
        int count = countImplDataFields(meta);
        FieldNode impl = null;

        // public void loadImplData(OpenJPAStateManager sm, int i)
        {
            MethodNode meth = new MethodNode(Opcodes.ACC_PRIVATE,
                                             "loadImplData",
                                             Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(OpenJPAStateManager.class), Type.INT_TYPE),
                                             null, null);
            classNode.methods.add(meth);
            InsnList instructions = meth.instructions;

            if (count == 0) {
                instructions.add(new InsnNode(Opcodes.RETURN));
            }
            else {
                // Object[] fieldImpl
                impl = new FieldNode(Opcodes.ACC_PRIVATE, "fieldImpl", Type.getDescriptor(Object[].class), null, null);
                classNode.fields.add(impl);

                // if (fieldImpl != null)
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, impl.name, impl.desc));

                LabelNode lblEndIf = new LabelNode();
                instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIf));
                instructions.add(new InsnNode(Opcodes.RETURN));
                instructions.add(lblEndIf);

                // Object obj = null;
                int objVarPos = AsmHelper.getLocalVarPos(meth);
                instructions.add(new InsnNode(Opcodes.ACONST_NULL));
                instructions.add(new VarInsnNode(Opcodes.ASTORE, objVarPos));

                LabelNode lblEnd = new LabelNode();
                instructions.add(new VarInsnNode(Opcodes.ILOAD, 2));
                // switch(i)
                LookupSwitchInsnNode lSwitch = new LookupSwitchInsnNode(lblEnd, null, null);
                FieldMetaData[] fields = meta.getFields();
                int cacheable = 0;
                for (int i = 0; i < fields.length; i++) {
                    if (!usesImplData(fields[i])) {
                        continue;
                    }

                    // case x: obj = fieldImpl[y]; break;
                    LabelNode lblCase = new LabelNode();
                    instructions.add(lblCase);
                    lSwitch.keys.add(i);
                    lSwitch.labels.add(lblCase);
                    instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, impl.name, impl.desc));
                    instructions.add(AsmHelper.getLoadConstantInsn(cacheable++));
                    instructions.add(new InsnNode(Opcodes.AALOAD));
                    instructions.add(new VarInsnNode(Opcodes.ASTORE, objVarPos));
                    instructions.add(new JumpInsnNode(Opcodes.GOTO, lblEnd));
                }
                // 'default:' is empty

                instructions.add(lblEnd);
                instructions.add(new VarInsnNode(Opcodes.ALOAD, objVarPos));

                // if (obj != null) return;
                lblEndIf = new LabelNode();
                instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIf));
                instructions.add(new InsnNode(Opcodes.RETURN));

                // end if
                instructions.add(lblEndIf);

                // sm.setImplData(index, impl);
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st parameter OpenJPAStateManager
                instructions.add(new VarInsnNode(Opcodes.ILOAD, 2)); // 2nd parameter int
                instructions.add(new VarInsnNode(Opcodes.ALOAD, objVarPos)); // the previously stored fieldImpl
                instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
                                                    Type.getInternalName(OpenJPAStateManager.class),
                                                    "setImplData",
                                                    Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, AsmHelper.TYPE_OBJECT)));
                instructions.add(new InsnNode(Opcodes.RETURN));
            }
        }

        // void storeImplData(OpenJPAStateManager sm, int index, boolean loaded)
        {
            MethodNode meth = new MethodNode(Opcodes.ACC_PRIVATE,
                                             "storeImplData",
                                             Type.getMethodDescriptor(Type.VOID_TYPE,
                                                                      Type.getType(OpenJPAStateManager.class), Type.INT_TYPE, Type.BOOLEAN_TYPE),
                                             null, null);
            classNode.methods.add(meth);
            InsnList instructions = meth.instructions;

            if (count == 0) {
                instructions.add(new InsnNode(Opcodes.RETURN));
            }
            else {
                // int arrIdx = -1;
                // switch(index)
                int arrIdxVarPos = AsmHelper.getLocalVarPos(meth);
                instructions.add(AsmHelper.getLoadConstantInsn(-1));
                instructions.add(new VarInsnNode(Opcodes.ISTORE, arrIdxVarPos));
                instructions.add(new VarInsnNode(Opcodes.ILOAD, 2)); // 2nd param int

                LabelNode lblEnd = new LabelNode();
                // switch(i)
                LookupSwitchInsnNode lSwitch = new LookupSwitchInsnNode(lblEnd, null, null);

                FieldMetaData[] fields = meta.getFields();
                int cacheable = 0;
                for (int i = 0; i < fields.length; i++) {
                    if (!usesImplData(fields[i])) {
                        continue;
                    }

                    // case x: arrIdx = y; break;
                    LabelNode lblCase = new LabelNode();
                    instructions.add(lblCase);
                    lSwitch.keys.add(i);
                    lSwitch.labels.add(lblCase);
                    instructions.add(AsmHelper.getLoadConstantInsn(cacheable++));
                    instructions.add(new VarInsnNode(Opcodes.ISTORE, arrIdxVarPos));
                    instructions.add(new JumpInsnNode(Opcodes.GOTO, lblEnd));
                }
                // 'default:' is empty

                instructions.add(lblEnd);

                // if (arrIdx != -1)
                instructions.add(AsmHelper.getLoadConstantInsn(-1));
                LabelNode lblEndIf = new LabelNode();
                instructions.add(new JumpInsnNode(Opcodes.IF_ICMPNE, lblEndIf));
                instructions.add(new InsnNode(Opcodes.RETURN));

                // end if
                instructions.add(lblEndIf);

                // if (loaded)
                instructions.add(new VarInsnNode(Opcodes.ILOAD, 3)); // 3rd param, boolean
                lblEndIf = new LabelNode();
                instructions.add(new JumpInsnNode(Opcodes.IFEQ, lblEndIf));

                // Object obj = sm.getImplData(index)
                int objVarPos = arrIdxVarPos+1;
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 1)); // 1st param, OpenJPAStateManager
                instructions.add(new VarInsnNode(Opcodes.ILOAD, 2)); // 2st param, int
                instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
                                                    Type.getInternalName(OpenJPAStateManager.class),
                                                    "getImplData",
                                                    Type.getMethodDescriptor(AsmHelper.TYPE_OBJECT, Type.INT_TYPE)));
                instructions.add(new VarInsnNode(Opcodes.ASTORE, objVarPos));

                // if (fieldImpl == null)
                //     fieldImpl = new Object[fields];

                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, impl.name, impl.desc));

                LabelNode lblEndIfNN = new LabelNode();
                instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIfNN));
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
                instructions.add(AsmHelper.getLoadConstantInsn(count));
                instructions.add(new TypeInsnNode(Opcodes.ANEWARRAY, Type.getInternalName(Object.class)));
                instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, impl.name, impl.desc));
                instructions.add(lblEndIfNN);

                // fieldImpl[arrIdx] = obj;
                // return;
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, impl.name, impl.desc));
                instructions.add(new VarInsnNode(Opcodes.ILOAD, arrIdxVarPos));
                instructions.add(new VarInsnNode(Opcodes.ALOAD, objVarPos));
                instructions.add(new InsnNode(Opcodes.AASTORE));
                instructions.add(new InsnNode(Opcodes.RETURN));

                instructions.add(lblEndIf);

                // if (fieldImpl != null)
                //         fieldImpl[index] = null;
                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, impl.name, impl.desc));
                lblEndIfNN = new LabelNode();
                instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblEndIfNN));
                instructions.add(new InsnNode(Opcodes.RETURN));

                instructions.add(lblEndIfNN);
                instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this
                instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, impl.name, impl.desc));
                instructions.add(new VarInsnNode(Opcodes.ILOAD, arrIdxVarPos));
                instructions.add(new InsnNode(Opcodes.ACONST_NULL));
                instructions.add(new InsnNode(Opcodes.AASTORE));
                instructions.add(new InsnNode(Opcodes.RETURN));
            }
        }
    }