private void emitMethods(final ClassEmitter ce, Map<Method, MethodInfo> methodMap, final Map<Method, Method> covariantMethods) {
    CallbackGenerator[] generators = CallbackInfo.getGenerators(callbackTypes);
    Map<MethodInfo, MethodInfo> covariantInfoMap = new HashMap<>();
    for (Method method : methodMap.keySet()) {
      final Method delegate = covariantMethods.get(method);
      if (delegate != null) {
        covariantInfoMap.put(methodMap.get(method), ReflectUtils.getMethodInfo(delegate, delegate.getModifiers()));
      }
    }
    BridgeMethodGenerator bridgeMethodGenerator = new BridgeMethodGenerator(covariantInfoMap);

    Map<CallbackGenerator,List<MethodInfo>> groups = new HashMap<>();
    final Map<MethodInfo,Integer> indexes = new HashMap<>();
    final Map<MethodInfo,Integer> originalModifiers = new HashMap<>();
    @SuppressWarnings("unchecked")
    final Map<MethodInfo,Integer> positions = CollectionUtils.getIndexMap(new ArrayList<>(methodMap.values()));

    for (Method actualMethod : methodMap.keySet()) {
      MethodInfo method = methodMap.get(actualMethod);
      int index = filter.accept(actualMethod);
      if (index >= callbackTypes.length) {
        throw new IllegalArgumentException("Callback filter returned an index that is too large: " + index);
      }
      originalModifiers.put(method, (actualMethod != null) ? actualMethod.getModifiers() : method.getModifiers());
      indexes.put(method, index);
      final CallbackGenerator generator = covariantMethods.containsKey(actualMethod)? bridgeMethodGenerator : generators[index];
      List<MethodInfo> group = groups.get(generator);
      if (group == null) {
        groups.put(generator, group = new ArrayList<>(methodMap.size()));
      }
      group.add(method);
    }

    CodeEmitter se = ce.getStaticHook();
    se.new_instance(THREAD_LOCAL);
    se.dup();
    se.invoke_constructor(THREAD_LOCAL, CSTRUCT_NULL);
    se.putfield(THREAD_CALLBACKS_FIELD);

    CallbackGenerator.Context context = new CallbackGenerator.Context() {
      @Override
      public ClassLoader getClassLoader() {
  	return AdvancedEnhancer.this.getClassLoader();
      }
      @Override
      public int getOriginalModifiers(MethodInfo method) {
        return originalModifiers.get(method);
      }
      @Override
      public int getIndex(MethodInfo method) {
        return indexes.get(method);
      }
      @Override
      public void emitCallback(CodeEmitter e, int index) {
        emitCurrentCallback(e, index);
      }
      @Override
      public Signature getImplSignature(MethodInfo method) {
        return rename(method.getSignature(), positions.get(method));
      }

      @Override
      public void emitLoadArgsAndInvoke(CodeEmitter emitter, MethodInfo info) {
        emitter.super_invoke(info.getSignature());
      }

      @Override
      public CodeEmitter beginMethod(ClassEmitter ce, MethodInfo method) {
        CodeEmitter e = EmitUtils.begin_method(ce, method);
        if (!interceptDuringConstruction &&
            !TypeUtils.isAbstract(method.getModifiers())) {
          $Label constructed = e.make_label();
          e.load_this();
          e.getfield(CONSTRUCTED_FIELD);
          e.if_jump(CodeEmitter.NE, constructed);
          e.load_this();
          e.load_args();
          e.super_invoke();
          e.return_value();
          e.mark(constructed);
        }
        return e;
      }
    };
    Set<CallbackGenerator> seenGen = new HashSet<>();
    for (int i = 0; i < callbackTypes.length + 1; i++) {
      CallbackGenerator gen = i == callbackTypes.length? bridgeMethodGenerator : generators[i];
      if (!seenGen.contains(gen)) {
        seenGen.add(gen);
        final List<MethodInfo> fmethods = groups.get(gen);
        if (fmethods != null) {
          try {
            gen.generate(ce, context, fmethods);
            gen.generateStatic(se, context, fmethods);
          } catch (RuntimeException x) {
            throw x;
          } catch (Exception x) {
            throw new CodeGenerationException(x);
          }
        }
      }
    }
    se.return_value();
    se.end_method();
  }
private void emitMethods(final ClassEmitter ce, Map<Method, MethodInfo> methodMap, final Map<Method, Method> covariantMethods)