docs: protected void invokeMethodHandler(ClassMethod method, MethodInformation methodInfo, boolean addReturnInstruction, BytecodeMethodResolver bytecodeMethodResolver, boolean addProceed, ClassMethod staticConstructor) {
          // now we need to build the bytecode. The order we do this in is as
          // follows:
          // load methodHandler
          // dup the methodhandler
          // invoke isDisabledHandler on the method handler to figure out of this is
          // a self invocation.
  
          // load this
          // load the method object
          // load the proceed method that invokes the superclass version of the
          // current method
          // create a new array the same size as the number of parameters
          // push our parameter values into the array
          // invokeinterface the invoke method
          // add checkcast to cast the result to the return type, or unbox if
          // primitive
          // add an appropriate return instruction
          final CodeAttribute b = method.getCodeAttribute();
          b.aload(0);
          getMethodHandlerField(method.getClassFile(), b);
  
          if (addProceed) {
              b.dup();
  
              // get the Stack
              b.invokestatic(InterceptionDecorationContext.class.getName(), "getStack", "()" + DescriptorUtils.makeDescriptor(Stack.class));
  
              // this is a self invocation optimisation
              // test to see if this is a self invocation, and if so invokespecial the
              // superclass method directly
              // Do not optimize in case of private and default methods
              if (!Reflections.isDefault(methodInfo.getMethod()) && !Modifier.isPrivate(method.getAccessFlags())) {
                  b.dupX1(); // Handler, Stack -> Stack, Handler, Stack
                  b.invokevirtual(COMBINED_INTERCEPTOR_AND_DECORATOR_STACK_METHOD_HANDLER_CLASS_NAME, "isDisabledHandler",
                          "(" + DescriptorUtils.makeDescriptor(Stack.class) + ")" + BytecodeUtils.BOOLEAN_CLASS_DESCRIPTOR);
                  b.iconst(0);
                  BranchEnd invokeSuperDirectly = b.ifIcmpeq();
                  // now build the bytecode that invokes the super class method
                  b.pop2(); // pop Stack and Handler
                  b.aload(0);
                  // create the method invocation
                  b.loadMethodParameters();
                  b.invokespecial(methodInfo.getDeclaringClass(), methodInfo.getName(), methodInfo.getDescriptor());
                  b.returnInstruction();
                  b.branchEnd(invokeSuperDirectly);
              }
          } else {
              b.aconstNull();
          }
  
          b.aload(0);
          bytecodeMethodResolver.getDeclaredMethod(method, methodInfo.getDeclaringClass(), methodInfo.getName(), methodInfo.getParameterTypes(), staticConstructor);
  
          if (addProceed) {
              if (Modifier.isPrivate(method.getAccessFlags())) {
                  // If the original method is private we can't use WeldSubclass.method$$super() as proceed
                  bytecodeMethodResolver.getDeclaredMethod(method, methodInfo.getDeclaringClass(), methodInfo.getName(), methodInfo.getParameterTypes(),
                          staticConstructor);
              } else {
                  bytecodeMethodResolver.getDeclaredMethod(method, method.getClassFile().getName(), methodInfo.getName() + SUPER_DELEGATE_SUFFIX,
                          methodInfo.getParameterTypes(), staticConstructor);
              }
          } else {
              b.aconstNull();
          }
  
          b.iconst(methodInfo.getParameterTypes().length);
          b.anewarray(Object.class.getName());
  
          int localVariableCount = 1;
  
          for (int i = 0; i < methodInfo.getParameterTypes().length; ++i) {
              String typeString = methodInfo.getParameterTypes()[i];
              b.dup(); // duplicate the array reference
              b.iconst(i);
              // load the parameter value
              BytecodeUtils.addLoadInstruction(b, typeString, localVariableCount);
              // box the parameter if necessary
              Boxing.boxIfNessesary(b, typeString);
              // and store it in the array
              b.aastore();
              if (isWide(typeString)) {
                  localVariableCount = localVariableCount + 2;
              } else {
                  localVariableCount++;
              }
          }
          // now we have all our arguments on the stack
          // lets invoke the method
          b.invokeinterface(StackAwareMethodHandler.class.getName(), INVOKE_METHOD_NAME, LJAVA_LANG_OBJECT, INVOKE_METHOD_PARAMETERS);
          if (addReturnInstruction) {
              // now we need to return the appropriate type
              if (methodInfo.getReturnType().equals(BytecodeUtils.VOID_CLASS_DESCRIPTOR)) {
                  b.returnInstruction();
              } else if (isPrimitive(methodInfo.getReturnType())) {
                  Boxing.unbox(b,method.getReturnType());
                  b.returnInstruction();
              } else {
                  b.checkcast(BytecodeUtils.getName(methodInfo.getReturnType()));
                  b.returnInstruction();
              }
          }
      }