private void createWriteReplace() {
   MethodIdentifier identifier = MethodIdentifier.getIdentifier(Object.class, "writeReplace");
   ClassMethod method =
       classFile.addMethod(AccessFlag.PROTECTED, "writeReplace", "Ljava/lang/Object;");
   method.addCheckedExceptions(ObjectStreamException.class);
   overrideMethod(method, identifier, new WriteReplaceBodyCreator());
 }
 @Override
 public void overrideMethod(ClassMethod method, Method superclassMethod) {
   CodeAttribute ca = method.getCodeAttribute();
   if (method.getName().equals("_getProxyInvocationDispatcher")) {
     ca.aload(0);
     ca.getfield(getClassName(), INVOCATION_DISPATCHER_FIELD, InvocationDispatcher.class);
     ca.returnInstruction();
   } else if (method.getName().equals("_setProxyInvocationDispatcher")) {
     ca.aload(0);
     ca.aload(1);
     ca.putfield(getClassName(), INVOCATION_DISPATCHER_FIELD, InvocationDispatcher.class);
     ca.returnInstruction();
   } else {
     throw new RuntimeException("Unkown method on interface " + ProxyInstance.class);
   }
 }
 /**
  * Writes the bytecode to load an instance of Method for the given method onto the stack
  *
  * <p>If loadMethod has not already been called for the given method then a static field to hold
  * the method is added to the class, and code is added to the static constructor to initialize the
  * field to the correct Method.
  *
  * @param methodToLoad the method to load
  * @param method the subclass method to populate
  */
 protected void loadMethodIdentifier(Method methodToLoad, ClassMethod method) {
   if (!methodIdentifiers.containsKey(methodToLoad)) {
     int identifierNo = identifierCount++;
     String fieldName = METHOD_FIELD_PREFIX + identifierNo;
     classFile.addField(AccessFlag.PRIVATE | AccessFlag.STATIC, fieldName, Method.class);
     methodIdentifiers.put(methodToLoad, identifierNo);
   }
   final Integer fieldNo = methodIdentifiers.get(methodToLoad);
   method
       .getCodeAttribute()
       .getstatic(getClassName(), METHOD_FIELD_PREFIX + fieldNo, METHOD_FIELD_DESCRIPTOR);
 }
 @Override
 public void overrideConstructor(ClassMethod method, Constructor<?> constructor) {
   CodeAttribute ca = method.getCodeAttribute();
   ca.aload(0);
   ca.iconst(0);
   ca.putfield(getClassName(), CONSTRUCTED_GUARD, "Z");
   ca.aload(0);
   ca.loadMethodParameters();
   ca.invokespecial(constructor);
   ca.aload(0);
   ca.iconst(1);
   ca.putfield(getClassName(), CONSTRUCTED_GUARD, "Z");
   ca.returnInstruction();
 }
 @Override
 public void overrideMethod(ClassMethod method, Method superclassMethod) {
   // superClassMethod will be null
   CodeAttribute ca = method.getCodeAttribute();
   ca.newInstruction(serializableProxyClass.getName());
   ca.dup();
   ca.invokespecial(serializableProxyClass.getName(), "<init>", "()V");
   ca.dup();
   ca.aload(0);
   ca.invokeinterface(
       SerializableProxy.class.getName(),
       "setProxyInstance",
       "(Lorg/jboss/proxy/ProxyInstance;)V");
   ca.returnInstruction();
 }
  private void setupCachedProxyFields() {
    cachedMethods.addAll(methodIdentifiers.keySet());

    // set the methods to be accessible
    AccessController.doPrivileged(
        new PrivilegedAction<Object>() {
          @Override
          public Object run() {
            for (Method method : cachedMethods) {
              method.setAccessible(true);
            }
            return null;
          }
        });

    // store the Method objects in a thread local, so that
    // the proxies <clinit> method can access them
    // this removes the need for reflection in the proxy <clinit> method
    final Method[] methods = new Method[identifierCount];
    for (Map.Entry<Method, Integer> entry : methodIdentifiers.entrySet()) {
      methods[entry.getValue()] = entry.getKey();
    }
    MethodStore.METHODS.put(new ClassIdentifier(classFile.getName(), getClassLoader()), methods);

    // add the bytecode to load the cached fields in the static constructor
    CodeAttribute ca = staticConstructor.getCodeAttribute();
    ca.getstatic(MethodStore.class.getName(), "METHODS", "Ljava/util/Map;");
    ca.newInstruction(ClassIdentifier.class);
    ca.dup();
    ca.ldc(classFile.getName());
    ca.loadClass(classFile.getName());
    ca.invokevirtual("java.lang.Class", "getClassLoader", "()Ljava/lang/ClassLoader;");
    ca.invokespecial(
        ClassIdentifier.class.getName(), "<init>", "(Ljava/lang/String;Ljava/lang/ClassLoader;)V");
    ca.invokeinterface(Map.class.getName(), "remove", "(Ljava/lang/Object;)Ljava/lang/Object;");
    ca.checkcast("[Ljava/lang/reflect/Method;");
    for (int i = 0; i < identifierCount; ++i) {
      ca.dup();
      ca.ldc(i);
      ca.aaload();
      ca.putstatic(getClassName(), METHOD_FIELD_PREFIX + i, METHOD_FIELD_DESCRIPTOR);
    }
  }
 // we simply want to load the corresponding identifier
 // and then forward it to the dispatcher
 @Override
 public void overrideMethod(ClassMethod method, Method superclassMethod) {
   CodeAttribute ca = method.getCodeAttribute();
   // first we need to check the constructed field
   ca.aload(0);
   ca.getfield(getClassName(), CONSTRUCTED_GUARD, "Z");
   // if the object has not been constructed yet invoke the superclass version of the method
   BranchEnd end = ca.ifne();
   ca.aload(0);
   ca.loadMethodParameters();
   ca.invokespecial(getSuperClassName(), method.getName(), method.getDescriptor());
   ca.returnInstruction();
   // normal invocation path begins here
   ca.branchEnd(end);
   ca.aload(0);
   ca.getfield(getClassName(), INVOCATION_DISPATCHER_FIELD, InvocationDispatcher.class);
   // now we have the dispatcher on the stack, we need to build an invocation
   ca.newInstruction(Invocation.class.getName());
   ca.dup();
   // the constructor we are using is Invocation(final Class<?> declaringClass, final
   // MethodIdentifier
   // methodIdentifier, final Object... args)
   ca.loadClass(getClassName());
   loadMethodIdentifier(superclassMethod, method);
   // now we need to stick the parameters into an array, boxing if nessesary
   String[] params = method.getParameters();
   ca.iconst(params.length);
   ca.anewarray("java/lang/Object");
   int loadPosition = 1;
   for (int i = 0; i < params.length; ++i) {
     ca.dup();
     ca.iconst(i);
     String type = params[i];
     if (type.length() == 1) { // primitive
       char typeChar = type.charAt(0);
       switch (typeChar) {
         case 'I':
           ca.iload(loadPosition);
           Boxing.boxInt(ca);
           break;
         case 'S':
           ca.iload(loadPosition);
           Boxing.boxShort(ca);
           break;
         case 'B':
           ca.iload(loadPosition);
           Boxing.boxByte(ca);
           break;
         case 'Z':
           ca.iload(loadPosition);
           Boxing.boxBoolean(ca);
           break;
         case 'C':
           ca.iload(loadPosition);
           Boxing.boxChar(ca);
           break;
         case 'D':
           ca.dload(loadPosition);
           Boxing.boxDouble(ca);
           loadPosition++;
           break;
         case 'J':
           ca.lload(loadPosition);
           Boxing.boxLong(ca);
           loadPosition++;
           break;
         case 'F':
           ca.fload(loadPosition);
           Boxing.boxFloat(ca);
           break;
         default:
           throw new RuntimeException("Unkown primitive type descriptor: " + typeChar);
       }
     } else {
       ca.aload(loadPosition);
     }
     ca.aastore();
     loadPosition++;
   }
   ca.invokespecial(
       Invocation.class.getName(),
       "<init>",
       "(Ljava/lang/Class;Lorg/jboss/invocation/MethodIdentifier;[Ljava/lang/Object;)V");
   // now we have the invocation on top of the stack, with the dispatcher below it
   ca.invokeinterface(
       InvocationDispatcher.class.getName(),
       "dispatch",
       "(Lorg/jboss/invocation/Invocation;)Lorg/jboss/invocation/InvocationReply;");
   ca.invokevirtual(InvocationReply.class.getName(), "getReply", "()Ljava/lang/Object;");
   if (superclassMethod.getReturnType() != void.class) {
     if (superclassMethod.getReturnType().isPrimitive()) {
       Boxing.unbox(ca, method.getReturnType());
     } else {
       ca.checkcast(superclassMethod.getReturnType().getName());
     }
   }
   ca.returnInstruction();
 }
 /** This method must be called by subclasses after they have finished generating the class. */
 protected void finalizeStaticConstructor() {
   setupCachedProxyFields();
   staticConstructor.getCodeAttribute().returnInstruction();
 }