void (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(); }