ObjectReaderCreatorASM.java

package com.alibaba.fastjson2.reader;

import com.alibaba.fastjson2.*;
import com.alibaba.fastjson2.codec.BeanInfo;
import com.alibaba.fastjson2.codec.FieldInfo;
import com.alibaba.fastjson2.function.*;
import com.alibaba.fastjson2.internal.asm.*;
import com.alibaba.fastjson2.schema.JSONSchema;
import com.alibaba.fastjson2.util.*;
import com.alibaba.fastjson2.writer.ObjectWriterProvider;

import java.io.Serializable;
import java.lang.reflect.*;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.*;

import static com.alibaba.fastjson2.internal.CodeGenUtils.fieldReader;
import static com.alibaba.fastjson2.internal.asm.ASMUtils.*;
import static com.alibaba.fastjson2.reader.ObjectReader.HASH_TYPE;
import static com.alibaba.fastjson2.reader.ObjectReaderCreatorASM.MethodWriterContext.*;
import static com.alibaba.fastjson2.util.JDKUtils.*;

public class ObjectReaderCreatorASM
        extends ObjectReaderCreator {
    // GraalVM not support
    // Android not support
    public static final ObjectReaderCreatorASM INSTANCE = new ObjectReaderCreatorASM(DynamicClassLoader.getInstance());

    protected static final AtomicLong seed = new AtomicLong();

    protected final DynamicClassLoader classLoader;

    static final String METHOD_DESC_GET_ITEM_OBJECT_READER = "(" + DESC_JSON_READER + ")" + DESC_OBJECT_READER;
    static final String METHOD_DESC_GET_OBJECT_READER_1 = "(" + DESC_JSON_READER + ")" + DESC_OBJECT_READER;
    static final String METHOD_DESC_INIT = "(Ljava/lang/Class;" + DESC_SUPPLIER + DESC_FIELD_READER_ARRAY + ")V";
    static final String METHOD_DESC_ADAPTER_INIT = "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;J" + DESC_JSONSCHEMA + DESC_SUPPLIER + "Ljava/util/function/Function;" + DESC_FIELD_READER_ARRAY + ")V";
    static final String METHOD_DESC_READ_OBJECT = "(" + DESC_JSON_READER + "Ljava/lang/reflect/Type;Ljava/lang/Object;J)Ljava/lang/Object;";
    static final String METHOD_DESC_GET_FIELD_READER = "(J)" + DESC_FIELD_READER;
    static final String METHOD_DESC_READ_FIELD_VALUE = "(" + DESC_JSON_READER + "Ljava/lang/Object;)V";
    static final String READ_FIELD_READER_UL = "(J" + DESC_JSON_READER + "JLjava/lang/Object;)V";
    static final String METHOD_DESC_ADD_RESOLVE_TASK = "(" + DESC_JSON_READER + "Ljava/lang/Object;Ljava/lang/String;)V";
    static final String METHOD_DESC_CHECK_ARRAY_AUTO_TYPE = "(" + DESC_JSON_READER + ")" + DESC_OBJECT_READER;
    static final String METHOD_DESC_PROCESS_EXTRA = "(" + DESC_JSON_READER + "Ljava/lang/Object;J)V";

    static final String METHOD_DESC_JSON_READER_CHECK_ARRAY_AUTO_TYPE = "(" + DESC_JSON_READER + "J)" + DESC_OBJECT_READER;
    static final String METHOD_DESC_READ_ARRAY_MAPPING_JSONB_OBJECT0 = "(" + DESC_JSON_READER + "Ljava/lang/Object;I)V";

    static final int THIS = 0;

    static final String packageName;
    static final Map<Class, FieldReaderInfo> infos = new HashMap<>();

    static {
        Package pkg = ObjectReaderCreatorASM.class.getPackage();
        packageName = pkg != null ? pkg.getName() : "";

        infos.put(boolean.class, new FieldReaderInfo(ASMUtils.type(ObjBoolConsumer.class), "(Ljava/lang/Object;Z)V", "(Z)V", Opcodes.ILOAD, "readFieldBoolValue", "()Z", Opcodes.ISTORE));
        infos.put(char.class, new FieldReaderInfo(ASMUtils.type(ObjCharConsumer.class), "(Ljava/lang/Object;C)V", "(C)V", Opcodes.ILOAD, "readInt32Value", "()C", Opcodes.ISTORE));
        infos.put(byte.class, new FieldReaderInfo(ASMUtils.type(ObjByteConsumer.class), "(Ljava/lang/Object;B)V", "(B)V", Opcodes.ILOAD, "readInt32Value", "()B", Opcodes.ISTORE));
        infos.put(short.class, new FieldReaderInfo(ASMUtils.type(ObjShortConsumer.class), "(Ljava/lang/Object;S)V", "(S)V", Opcodes.ILOAD, "readInt32Value", "()S", Opcodes.ISTORE));
        infos.put(int.class, new FieldReaderInfo(ASMUtils.type(ObjIntConsumer.class), "(Ljava/lang/Object;I)V", "(I)V", Opcodes.ILOAD, "readInt32Value", "()I", Opcodes.ISTORE));
        infos.put(long.class, new FieldReaderInfo(ASMUtils.type(ObjLongConsumer.class), "(Ljava/lang/Object;J)V", "(J)V", Opcodes.LLOAD, "readInt64Value", "()V", Opcodes.LSTORE));
        infos.put(float.class, new FieldReaderInfo(ASMUtils.type(ObjFloatConsumer.class), "(Ljava/lang/Object;F)V", "(F)V", Opcodes.FLOAD, "readFieldFloatValue", "()F", Opcodes.FSTORE));
        infos.put(double.class, new FieldReaderInfo(ASMUtils.type(ObjDoubleConsumer.class), "(Ljava/lang/Object;D)V", "(D)V", Opcodes.DLOAD, "readFloatDoubleValue", "()D", Opcodes.DSTORE));

        infos.put(String.class, new FieldReaderInfo(ASMUtils.type(BiConsumer.class), "(Ljava/lang/Object;Ljava/lang/Object;)V", "(Ljava/lang/String;)V", Opcodes.ALOAD, "readString", "()Ljava/lang/String;", Opcodes.ASTORE));
        infos.put(Integer.class, new FieldReaderInfo(ASMUtils.type(BiConsumer.class), "(Ljava/lang/Object;Ljava/lang/Integer;)V", "(Ljava/lang/Integer;)V", Opcodes.ALOAD, "readInt32", "()Ljava/lang/Integer;", Opcodes.ASTORE));
    }

    static final String[] fieldItemObjectReader = new String[1024];

    static String fieldObjectReader(int i) {
        switch (i) {
            case 0:
                return "objectReader0";
            case 1:
                return "objectReader1";
            case 2:
                return "objectReader2";
            case 3:
                return "objectReader3";
            case 4:
                return "objectReader4";
            case 5:
                return "objectReader5";
            case 6:
                return "objectReader6";
            case 7:
                return "objectReader7";
            case 8:
                return "objectReader8";
            case 9:
                return "objectReader9";
            case 10:
                return "objectReader10";
            case 11:
                return "objectReader11";
            case 12:
                return "objectReader12";
            case 13:
                return "objectReader13";
            case 14:
                return "objectReader14";
            case 15:
                return "objectReader15";
            default:
                String base = "objectReader";
                int size = IOUtils.stringSize(i);
                char[] chars = new char[base.length() + size];
                base.getChars(0, base.length(), chars, 0);
                IOUtils.getChars(i, chars.length, chars);
                return new String(chars);
        }
    }

    static String fieldItemObjectReader(int i) {
        String fieldName = fieldItemObjectReader[i];

        if (fieldName != null) {
            return fieldName;
        }

        String base = "itemReader";
        int size = IOUtils.stringSize(i);
        char[] chars = new char[base.length() + size];
        base.getChars(0, base.length(), chars, 0);
        IOUtils.getChars(i, chars.length, chars);
        fieldItemObjectReader[i] = fieldName = new String(chars);
        return fieldName;
    }

    private static class FieldReaderInfo {
        final String interfaceDesc;
        final String acceptDesc;
        final String setterDesc;
        final int loadCode;
        final String readMethodName;
        final String readMethodDesc;
        final int storeCode;

        FieldReaderInfo(
                String interfaceDesc,
                String acceptDesc,
                String setterDesc,
                int loadCode,
                String readMethodName,
                String readMethodDesc,
                int storeCode) {
            this.interfaceDesc = interfaceDesc;
            this.acceptDesc = acceptDesc;
            this.setterDesc = setterDesc;
            this.loadCode = loadCode;
            this.readMethodName = readMethodName;
            this.readMethodDesc = readMethodDesc;
            this.storeCode = storeCode;
        }
    }

    public ObjectReaderCreatorASM(ClassLoader classLoader) {
        this.classLoader = classLoader instanceof DynamicClassLoader
                ? (DynamicClassLoader) classLoader
                : new DynamicClassLoader(classLoader);
    }

    @Override
    public <T> ObjectReader<T> createObjectReader(
            Class<T> objectClass,
            Type objectType,
            boolean fieldBased,
            ObjectReaderProvider provider
    ) {
        boolean externalClass = objectClass != null && classLoader.isExternalClass(objectClass);
        int objectClassModifiers = objectClass.getModifiers();

        if (Modifier.isAbstract(objectClassModifiers) || Modifier.isInterface(objectClassModifiers)) {
            return super.createObjectReader(objectClass, objectType, fieldBased, provider);
        }

        BeanInfo beanInfo = new BeanInfo(provider);
        provider.getBeanInfo(beanInfo, objectClass);
        if (externalClass || !Modifier.isPublic(objectClassModifiers)) {
            beanInfo.readerFeatures |= FieldInfo.JIT;
        }

        if (beanInfo.deserializer != null && ObjectReader.class.isAssignableFrom(beanInfo.deserializer)) {
            try {
                Constructor constructor = beanInfo.deserializer.getDeclaredConstructor();
                constructor.setAccessible(true);
                return (ObjectReader<T>) constructor.newInstance();
            } catch (InstantiationException | IllegalAccessException | NoSuchMethodException |
                     InvocationTargetException e) {
                throw new JSONException("create deserializer error", e);
            }
        }

        if (fieldBased && (objectClass.isInterface() || BeanUtils.isRecord(objectClass))) {
            fieldBased = false;
        }

        if (Enum.class.isAssignableFrom(objectClass) && (beanInfo.createMethod == null || beanInfo.createMethod.getParameterCount() == 1)) {
            return createEnumReader(objectClass, beanInfo.createMethod, provider);
        }

        if (beanInfo.creatorConstructor != null || beanInfo.createMethod != null) {
            return createObjectReaderWithCreator(objectClass, objectType, provider, beanInfo);
        }

        if (beanInfo.builder != null) {
            return createObjectReaderWithBuilder(objectClass, objectType, provider, beanInfo);
        }

        if (Throwable.class.isAssignableFrom(objectClass) || BeanUtils.isExtendedMap(objectClass)) {
            return super.createObjectReader(objectClass, objectType, fieldBased, provider);
        }

        if (objectClass == Class.class) {
            return ObjectReaderImplClass.INSTANCE;
        }

        FieldReader[] fieldReaderArray = createFieldReaders(objectClass, objectType, beanInfo, fieldBased, provider);
        boolean match = fieldReaderArray.length <= 96;

        if (!fieldBased) {
            if (JVM_VERSION >= 9 && objectClass == StackTraceElement.class) {
                try {
                    Constructor<StackTraceElement> constructor = StackTraceElement.class.getConstructor(String.class, String.class, String.class, String.class, String.class, String.class, int.class);
                    return createObjectReaderNoneDefaultConstructor(constructor, "", "classLoaderName", "moduleName", "moduleVersion", "declaringClass", "methodName", "fileName", "lineNumber");
                } catch (NoSuchMethodException | SecurityException ignored) {
                }
            }

            for (FieldReader fieldReader : fieldReaderArray) {
                if (fieldReader.isReadOnly()
                        || fieldReader.isUnwrapped()
                ) {
                    match = false;
                    break;
                }

                if ((fieldReader.features & FieldInfo.READ_USING_MASK) != 0) {
                    match = false;
                    break;
                }
            }
        }

        if (beanInfo.autoTypeBeforeHandler != null) {
            match = false;
        }

        if (match) {
            for (FieldReader fieldReader : fieldReaderArray) {
                if (fieldReader.defaultValue != null || fieldReader.schema != null) {
                    match = false;
                    break;
                }

                Class fieldClass = fieldReader.fieldClass;
                if (fieldClass != null && !Modifier.isPublic(fieldClass.getModifiers())) {
                    match = false;
                    break;
                }

                if (fieldReader instanceof FieldReaderMapField
                        && ((FieldReaderMapField<?>) fieldReader).arrayToMapKey != null) {
                    match = false;
                    break;
                }

                if (fieldReader instanceof FieldReaderMapMethod
                        && ((FieldReaderMapMethod<?>) fieldReader).arrayToMapKey != null) {
                    match = false;
                    break;
                }
            }
        }

        if (match
                && (beanInfo.rootName != null
                || (beanInfo.schema != null && !beanInfo.schema.isEmpty()))) {
            match = false;
        }

        if (!match) {
            return super.createObjectReader(objectClass, objectType, fieldBased, provider);
        }

        Constructor defaultConstructor = null;
        if (!Modifier.isInterface(objectClassModifiers) && !Modifier.isAbstract(objectClassModifiers)) {
            Constructor constructor = BeanUtils.getDefaultConstructor(objectClass, true);
            if (constructor != null) {
                defaultConstructor = constructor;
                try {
                    constructor.setAccessible(true);
                } catch (SecurityException ignored) {
                    // ignored
                }
            }
        }

        if (beanInfo.seeAlso != null && beanInfo.seeAlso.length != 0) {
            return createObjectReaderSeeAlso(
                    objectClass,
                    beanInfo.typeKey,
                    beanInfo.seeAlso,
                    beanInfo.seeAlsoNames,
                    beanInfo.seeAlsoDefault,
                    fieldReaderArray
            );
        }

        if (!fieldBased) {
            if (defaultConstructor == null) {
                return super.createObjectReader(objectClass, objectType, false, provider);
            }
        }

        return jitObjectReader(
                objectClass,
                objectType,
                fieldBased,
                externalClass,
                objectClassModifiers,
                beanInfo,
                null,
                fieldReaderArray,
                defaultConstructor
        );
    }

    @Override
    protected <T> ObjectReaderNoneDefaultConstructor createNoneDefaultConstructorObjectReader(
            Class objectClass,
            BeanInfo beanInfo,
            Function<Map<Long, Object>, T> constructorFunction,
            List<Constructor> alternateConstructors,
            String[] parameterNames,
            FieldReader[] paramFieldReaders,
            FieldReader[] fieldReaderArray
    ) {
        ObjectReaderNoneDefaultConstructor objectReaderAdapter = new ObjectReaderNoneDefaultConstructor(
                objectClass,
                beanInfo.typeKey,
                beanInfo.typeName,
                beanInfo.readerFeatures,
                constructorFunction,
                alternateConstructors,
                parameterNames,
                paramFieldReaders,
                fieldReaderArray,
                beanInfo.seeAlso,
                beanInfo.seeAlsoNames
        );

        boolean match = true;

        if (beanInfo.autoTypeBeforeHandler != null
                || fieldReaderArray.length != 0
                || (!(constructorFunction instanceof ConstructorFunction) && (!(constructorFunction instanceof FactoryFunction)))
                || (alternateConstructors != null && !alternateConstructors.isEmpty())
                || classLoader.isExternalClass(objectClass)
                || (beanInfo.readerFeatures & JSONReader.Feature.SupportAutoType.mask) != 0
                || (objectReaderAdapter.noneDefaultConstructor != null && objectReaderAdapter.noneDefaultConstructor.getParameterCount() != paramFieldReaders.length)
                || (constructorFunction instanceof FactoryFunction && ((FactoryFunction<T>) constructorFunction).paramNames.length != paramFieldReaders.length)
                || paramFieldReaders.length > 64
        ) {
            match = false;
        }

        if (match) {
            for (FieldReader fieldReader : paramFieldReaders) {
                if (fieldReader.getInitReader() != null) {
                    match = false;
                    break;
                }

                if (fieldReader.defaultValue != null || fieldReader.schema != null) {
                    match = false;
                    break;
                }

                Class fieldClass = fieldReader.fieldClass;
                if (fieldClass != null && (!Modifier.isPublic(fieldClass.getModifiers()) || classLoader.isExternalClass(fieldClass))) {
                    match = false;
                    break;
                }

                if (fieldReader instanceof FieldReaderMapField
                        && ((FieldReaderMapField<?>) fieldReader).arrayToMapKey != null) {
                    match = false;
                    break;
                }

                if (fieldReader instanceof FieldReaderMapMethod
                        && ((FieldReaderMapMethod<?>) fieldReader).arrayToMapKey != null) {
                    match = false;
                    break;
                }
            }
        }

        if (!match) {
            return objectReaderAdapter;
        }

        boolean externalClass = objectClass != null && classLoader.isExternalClass(objectClass);
        ClassWriter cw = new ClassWriter(
                (e) -> objectClass.getName().equals(e) ? objectClass : null
        );

        beanInfo.readerFeatures |= FieldInfo.DISABLE_REFERENCE_DETECT;
        ObjectReadContext context = new ObjectReadContext(beanInfo, objectClass, cw, externalClass, paramFieldReaders, null);
        context.objectReaderAdapter = objectReaderAdapter;

        genFields(paramFieldReaders, cw, TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR);

        cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, context.classNameType, TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR, new String[]{});

        {
            String MD_INIT = "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;JLjava/util/function/Function;Ljava/util/List;[Ljava/lang/String;[Lcom/alibaba/fastjson2/reader/FieldReader;[Lcom/alibaba/fastjson2/reader/FieldReader;[Ljava/lang/Class;[Ljava/lang/String;)V";

            MethodWriter mw = cw.visitMethod(
                    Opcodes.ACC_PUBLIC,
                    "<init>",
                    MD_INIT,
                    fieldReaderArray.length <= 12 ? 32 : 128);
            mw.aload(THIS);
            mw.aload(1); // CLASS
            mw.aload(2); // TYPE_KEY
            mw.aload(3); // TYPE_NAME
            mw.lload(4); // FEATURES
            mw.aload(6); // CREATOR
            mw.aload(7); // alternateConstructors
            mw.aload(8); // paramNames
            mw.aload(9); // paramFieldReaders
            mw.aload(10); // setterFieldReaders
            mw.aload(11); // seeAlso
            mw.aload(12); // seeAlsoNames
            mw.invokespecial(TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR, "<init>", MD_INIT);

            int FIELD_READER_ARRAY = 9;
            genInitFields(paramFieldReaders, context.classNameType, true, FIELD_READER_ARRAY, mw, TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR);

            mw.return_();
            mw.visitMaxs(3, 3);
        }

        genMethodReadObject(context, beanInfo.readerFeatures);

        if (!context.disableJSONB()) {
            genMethodReadJSONBObject(context, beanInfo.readerFeatures);
        }

        byte[] code = cw.toByteArray();
        try {
            Class<?> readerClass = classLoader.defineClassPublic(context.classNameFull, code, 0, code.length);

            Constructor<?> constructor = readerClass.getConstructors()[0];
            return (ObjectReaderNoneDefaultConstructor) constructor
                    .newInstance(
                            objectClass,
                            beanInfo.typeKey,
                            beanInfo.typeName,
                            beanInfo.readerFeatures,
                            constructorFunction,
                            alternateConstructors,
                            parameterNames,
                            paramFieldReaders,
                            fieldReaderArray,
                            null,
                            null
                    );
        } catch (Throwable e) {
            throw new JSONException(
                    "create objectReader error"
                            + (objectClass == null ? "" : ", objectType " + objectClass.getTypeName()), e);
        }
    }

    @Override
    public <T> ObjectReader<T> createObjectReader(
            Class<T> objectClass,
            String typeKey,
            String rootName,
            long features,
            JSONSchema schema,
            Supplier<T> defaultCreator,
            Function buildFunction,
            FieldReader... fieldReaders
    ) {
        if (objectClass == null && defaultCreator != null && buildFunction == null) {
            boolean allFunction = true;
            for (int i = 0; i < fieldReaders.length; i++) {
                FieldReader fieldReader = fieldReaders[i];
                if (fieldReader.getFunction() == null) {
                    allFunction = false;
                    break;
                }
            }

            if (allFunction) {
                BeanInfo beanInfo = new BeanInfo(JSONFactory.getDefaultObjectReaderProvider());
                return jitObjectReader(
                        objectClass,
                        objectClass,
                        false,
                        false,
                        0,
                        beanInfo,
                        defaultCreator,
                        fieldReaders,
                        null
                );
            }
        }

        return super.createObjectReader(
                objectClass,
                typeKey,
                rootName,
                features,
                schema,
                defaultCreator,
                buildFunction,
                fieldReaders
        );
    }

    private <T> ObjectReaderBean jitObjectReader(
            Class<T> objectClass,
            Type objectType,
            boolean fieldBased,
            boolean externalClass,
            int objectClassModifiers,
            BeanInfo beanInfo,
            Supplier<T> defaultCreator,
            FieldReader[] fieldReaderArray,
            Constructor defaultConstructor
    ) {
        ClassWriter cw = new ClassWriter(
                (e) -> objectClass.getName().equals(e) ? objectClass : null
        );

        ObjectReadContext context = new ObjectReadContext(beanInfo, objectClass, cw, externalClass, fieldReaderArray, defaultConstructor);

        final boolean generatedFields = fieldReaderArray.length <= 96;

        String objectReaderSuper;
        switch (fieldReaderArray.length) {
            case 1:
                objectReaderSuper = TYPE_OBJECT_READER_1;
                break;
            case 2:
                objectReaderSuper = TYPE_OBJECT_READER_2;
                break;
            case 3:
                objectReaderSuper = TYPE_OBJECT_READER_3;
                break;
            case 4:
                objectReaderSuper = TYPE_OBJECT_READER_4;
                break;
            case 5:
                objectReaderSuper = TYPE_OBJECT_READER_5;
                break;
            case 6:
                objectReaderSuper = TYPE_OBJECT_READER_6;
                break;
            case 7:
                objectReaderSuper = TYPE_OBJECT_READER_7;
                break;
            case 8:
                objectReaderSuper = TYPE_OBJECT_READER_8;
                break;
            case 9:
                objectReaderSuper = TYPE_OBJECT_READER_9;
                break;
            case 10:
                objectReaderSuper = TYPE_OBJECT_READER_10;
                break;
            case 11:
                objectReaderSuper = TYPE_OBJECT_READER_11;
                break;
            case 12:
                objectReaderSuper = TYPE_OBJECT_READER_12;
                break;
            default:
                objectReaderSuper = TYPE_OBJECT_READER_ADAPTER;
                break;
        }

        if (generatedFields) {
            genFields(fieldReaderArray, cw, objectReaderSuper);
        }

        cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, context.classNameType, objectReaderSuper, new String[]{});

        {
            final int CLASS = 1, SUPPLIER = 2, FIELD_READER_ARRAY = 3;

            MethodWriter mw = cw.visitMethod(
                    Opcodes.ACC_PUBLIC,
                    "<init>",
                    METHOD_DESC_INIT,
                    fieldReaderArray.length <= 12 ? 32 : 128);
            mw.aload(THIS);
            mw.aload(CLASS);
            if (beanInfo.typeKey != null) {
                mw.visitLdcInsn(beanInfo.typeKey);
            } else {
                mw.aconst_null();
            }
            mw.aconst_null();
            mw.visitLdcInsn(beanInfo.readerFeatures);
            mw.aconst_null();
            mw.aload(SUPPLIER);
            mw.aconst_null();
            mw.aload(FIELD_READER_ARRAY);
            mw.invokespecial(objectReaderSuper, "<init>", METHOD_DESC_ADAPTER_INIT);

            genInitFields(fieldReaderArray, context.classNameType, generatedFields, FIELD_READER_ARRAY, mw, objectReaderSuper);

            mw.return_();
            mw.visitMaxs(3, 3);
        }

        {
            String methodName = fieldBased && defaultConstructor == null ? "createInstance0" : "createInstance";

            if ((externalClass && defaultConstructor != null)
                    || fieldBased && (defaultConstructor == null || !Modifier.isPublic(defaultConstructor.getModifiers()) || !Modifier.isPublic(objectClass.getModifiers()))) {
                MethodWriter mw = cw.visitMethod(
                        Opcodes.ACC_PUBLIC,
                        methodName,
                        "(J)Ljava/lang/Object;",
                        32
                );
                mw.getstatic(TYPE_UNSAFE_UTILS, "UNSAFE", "Lsun/misc/Unsafe;");
                mw.aload(0);
                mw.getfield(TYPE_OBJECT_READER_ADAPTER, "objectClass", "Ljava/lang/Class;");
                mw.invokevirtual("sun/misc/Unsafe", "allocateInstance", "(Ljava/lang/Class;)Ljava/lang/Object;");
                mw.areturn();
                mw.visitMaxs(3, 3);
            } else if (defaultConstructor != null && Modifier.isPublic(defaultConstructor.getModifiers()) && Modifier.isPublic(objectClass.getModifiers())) {
                MethodWriter mw = cw.visitMethod(
                        Opcodes.ACC_PUBLIC,
                        methodName,
                        "(J)Ljava/lang/Object;",
                        32
                );
                newObject(mw, context.objectType, defaultConstructor);
                mw.areturn();
                mw.visitMaxs(3, 3);
            }
        }

        Supplier<T> supplier;
        if (defaultConstructor != null) {
            boolean publicObject = Modifier.isPublic(objectClassModifiers) && !classLoader.isExternalClass(objectClass);
            boolean jit = !publicObject || !Modifier.isPublic(defaultConstructor.getModifiers());
            supplier = createSupplier(defaultConstructor, jit);
        } else {
            supplier = defaultCreator;
        }

        if (generatedFields) {
            long readerFeatures = beanInfo.readerFeatures;
            if (fieldBased) {
                readerFeatures |= JSONReader.Feature.FieldBased.mask;
            }

            boolean disableArrayMapping = context.disableSupportArrayMapping();
            boolean disableJSONB = context.disableJSONB();

            context.objectReaderAdapter = new ObjectReaderAdapter(objectClass, beanInfo.typeKey, beanInfo.typeName, readerFeatures, null, supplier, null, fieldReaderArray);

            if (!disableJSONB) {
                genMethodReadJSONBObject(context, readerFeatures);
                if (!disableArrayMapping) {
                    genMethodReadJSONBObjectArrayMapping(context, readerFeatures);
                }
            }

            genMethodReadObject(context, readerFeatures);

            if (objectReaderSuper == TYPE_OBJECT_READER_ADAPTER
                    || objectReaderSuper == TYPE_OBJECT_READER_1
                    || objectReaderSuper == TYPE_OBJECT_READER_2
                    || objectReaderSuper == TYPE_OBJECT_READER_3
                    || objectReaderSuper == TYPE_OBJECT_READER_4
                    || objectReaderSuper == TYPE_OBJECT_READER_5
                    || objectReaderSuper == TYPE_OBJECT_READER_6
                    || objectReaderSuper == TYPE_OBJECT_READER_7
                    || objectReaderSuper == TYPE_OBJECT_READER_8
                    || objectReaderSuper == TYPE_OBJECT_READER_9
                    || objectReaderSuper == TYPE_OBJECT_READER_10
                    || objectReaderSuper == TYPE_OBJECT_READER_11
                    || objectReaderSuper == TYPE_OBJECT_READER_12
            ) {
                genMethodGetFieldReader(context);
                genMethodGetFieldReaderLCase(context);
            }
        }

        byte[] code = cw.toByteArray();
        try {
            Class<?> readerClass = classLoader.defineClassPublic(context.classNameFull, code, 0, code.length);

            Constructor<?> constructor = readerClass.getConstructors()[0];
            return (ObjectReaderBean) constructor
                    .newInstance(objectClass, supplier, fieldReaderArray);
        } catch (Throwable e) {
            throw new JSONException(
                    "create objectReader error"
                            + (objectType == null ? "" : ", objectType " + objectType.getTypeName()),
                    e
            );
        }
    }

    private static void newObject(MethodWriter mw, String TYPE_OBJECT, Constructor defaultConstructor) {
        mw.new_(TYPE_OBJECT);
        mw.dup();
        if (defaultConstructor.getParameterCount() == 0) {
            mw.invokespecial(TYPE_OBJECT, "<init>", "()V");
        } else {
            Class paramType = defaultConstructor.getParameterTypes()[0];
            mw.aconst_null();
            mw.invokespecial(TYPE_OBJECT, "<init>", "(" + ASMUtils.desc(paramType) + ")V");
        }
    }

    private void genMethodGetFieldReader(ObjectReadContext context) {
        ObjectReaderAdapter objectReaderAdapter = context.objectReaderAdapter;
        FieldReader[] fieldReaderArray = context.fieldReaders;
        MethodWriter mw = context.cw.visitMethod(
                Opcodes.ACC_PUBLIC,
                "getFieldReader",
                "(J)" + DESC_FIELD_READER,
                512
        );

        final int HASH_CODE_64 = 1;
        final int HASH_CODE_32 = 3;

        Label rtnlt = new Label();
        if (fieldReaderArray.length > 6) {
            Map<Integer, List<Long>> map = new TreeMap();

            for (int i = 0; i < objectReaderAdapter.hashCodes.length; i++) {
                long hashCode64 = objectReaderAdapter.hashCodes[i];
                int hashCode32 = (int) (hashCode64 ^ (hashCode64 >>> 32));
                List<Long> hashCode64List = map.computeIfAbsent(hashCode32, k -> new ArrayList<>());
                hashCode64List.add(hashCode64);
            }
            int[] hashCode32Keys = new int[map.size()];
            {
                int off = 0;
                for (Integer key : map.keySet()) {
                    hashCode32Keys[off++] = key;
                }
            }
            Arrays.sort(hashCode32Keys);

            // // int hashCode32 = (int)(hashCode64 ^ (hashCode64 >>> 32));
            mw.lload(HASH_CODE_64);
            mw.lload(HASH_CODE_64);
            mw.bipush(32);
            mw.lushr();
            mw.lxor();
            mw.l2i();
            mw.istore(HASH_CODE_32);

            Label dflt = new Label();
            Label[] labels = new Label[hashCode32Keys.length];
            for (int i = 0; i < labels.length; i++) {
                labels[i] = new Label();
            }

            mw.iload(HASH_CODE_32);
            mw.visitLookupSwitchInsn(dflt, hashCode32Keys, labels);

            for (int i = 0; i < labels.length; i++) {
                mw.visitLabel(labels[i]);

                int hashCode32 = hashCode32Keys[i];
                List<Long> hashCode64Array = map.get(hashCode32);
                for (int j = 0, size = hashCode64Array.size(); j < size; j++) {
                    long hashCode64 = hashCode64Array.get(j);

                    Label next = size > 1 ? new Label() : dflt;
                    mw.lload(HASH_CODE_64);
                    mw.visitLdcInsn(hashCode64);
                    mw.lcmp();
                    mw.ifne(next);

                    int m = Arrays.binarySearch(objectReaderAdapter.hashCodes, hashCode64);
                    int index = objectReaderAdapter.mapping[m];
                    mw.aload(THIS);
                    mw.getfield(context.classNameType, fieldReader(index), DESC_FIELD_READER);
                    mw.goto_(rtnlt);

                    if (next != dflt) {
                        mw.visitLabel(next);
                    }
                }

                mw.goto_(dflt);
            }

            mw.visitLabel(dflt);
        } else {
            for (int i = 0; i < fieldReaderArray.length; ++i) {
                Label next_ = new Label(), get_ = new Label();
                String fieldName = fieldReaderArray[i].fieldName;
                long hashCode64 = fieldReaderArray[i].fieldNameHash;

                mw.lload(HASH_CODE_64);
                mw.visitLdcInsn(hashCode64);
                mw.lcmp();
                mw.ifne(next_);

                mw.visitLabel(get_);
                mw.aload(THIS);
                mw.getfield(context.classNameType, fieldReader(i), DESC_FIELD_READER);
                mw.goto_(rtnlt);

                mw.visitLabel(next_);
            }
        }
        mw.aconst_null();
        mw.areturn();

        mw.visitLabel(rtnlt);
        mw.areturn();

        mw.visitMaxs(5, 5);
    }

    private void genMethodGetFieldReaderLCase(ObjectReadContext context) {
        ObjectReaderAdapter objectReaderAdapter = context.objectReaderAdapter;
        FieldReader[] fieldReaderArray = context.fieldReaders;
        MethodWriter mw = context.cw.visitMethod(
                Opcodes.ACC_PUBLIC,
                "getFieldReaderLCase",
                "(J)" + DESC_FIELD_READER,
                512
        );

        final int HASH_CODE_64 = 1;
        final int HASH_CODE_32 = 3;

        Label rtnlt = new Label();
        if (fieldReaderArray.length > 6) {
            Map<Integer, List<Long>> map = new TreeMap();

            for (int i = 0; i < objectReaderAdapter.hashCodesLCase.length; i++) {
                long hashCode64 = objectReaderAdapter.hashCodesLCase[i];
                int hashCode32 = (int) (hashCode64 ^ (hashCode64 >>> 32));
                List<Long> hashCode64List = map.computeIfAbsent(hashCode32, k -> new ArrayList<>());
                hashCode64List.add(hashCode64);
            }
            int[] hashCode32Keys = new int[map.size()];
            {
                int off = 0;
                for (Integer key : map.keySet()) {
                    hashCode32Keys[off++] = key;
                }
            }
            Arrays.sort(hashCode32Keys);

            // // int hashCode32 = (int)(hashCode64 ^ (hashCode64 >>> 32));
            mw.lload(HASH_CODE_64);
            mw.lload(HASH_CODE_64);
            mw.bipush(32);
            mw.lushr();
            mw.lxor();
            mw.l2i();
            mw.istore(HASH_CODE_32);

            Label dflt = new Label();
            Label[] labels = new Label[hashCode32Keys.length];
            for (int i = 0; i < labels.length; i++) {
                labels[i] = new Label();
            }

            mw.iload(HASH_CODE_32);
            mw.visitLookupSwitchInsn(dflt, hashCode32Keys, labels);

            for (int i = 0; i < labels.length; i++) {
                mw.visitLabel(labels[i]);

                int hashCode32 = hashCode32Keys[i];
                List<Long> hashCode64Array = map.get(hashCode32);
                for (long hashCode64 : hashCode64Array) {
                    mw.lload(HASH_CODE_64);
                    mw.visitLdcInsn(hashCode64);
                    mw.lcmp();
                    mw.ifne(dflt);

                    int m = Arrays.binarySearch(objectReaderAdapter.hashCodesLCase, hashCode64);
                    int index = objectReaderAdapter.mappingLCase[m];
                    mw.aload(THIS);
                    mw.getfield(context.classNameType, fieldReader(index), DESC_FIELD_READER);
                    mw.goto_(rtnlt);
                }

                mw.goto_(dflt);
            }

            mw.visitLabel(dflt);
        } else {
            for (int i = 0; i < fieldReaderArray.length; ++i) {
                Label next_ = new Label(), get_ = new Label();
                String fieldName = fieldReaderArray[i].fieldName;
                long hashCode64 = fieldReaderArray[i].fieldNameHashLCase;

                mw.lload(HASH_CODE_64);
                mw.visitLdcInsn(hashCode64);
                mw.lcmp();
                mw.ifne(next_);

                mw.visitLabel(get_);
                mw.aload(THIS);
                mw.getfield(context.classNameType, fieldReader(i), DESC_FIELD_READER);
                mw.goto_(rtnlt);

                mw.visitLabel(next_);
            }
        }
        mw.aconst_null();
        mw.areturn();

        mw.visitLabel(rtnlt);
        mw.areturn();

        mw.visitMaxs(5, 5);
    }

    private void genInitFields(
            FieldReader[] fieldReaderArray,
            String classNameType,
            boolean generatedFields,
            int FIELD_READER_ARRAY,
            MethodWriter mw,
            String objectReaderSuper
    ) {
        if ((objectReaderSuper != TYPE_OBJECT_READER_ADAPTER && objectReaderSuper != TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR) || !generatedFields) {
            return;
        }

        for (int i = 0; i < fieldReaderArray.length; i++) {
            mw.aload(THIS);
            mw.aload(FIELD_READER_ARRAY);
            mw.iconst_n(i);
            mw.aaload();
            mw.putfield(classNameType, fieldReader(i), DESC_FIELD_READER);
        }
    }

    private void genFields(FieldReader[] fieldReaderArray, ClassWriter cw, String objectReaderSuper) {
        if (objectReaderSuper == TYPE_OBJECT_READER_ADAPTER || objectReaderSuper == TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR) {
            for (int i = 0; i < fieldReaderArray.length; i++) {
                FieldWriter fv = cw.visitField(Opcodes.ACC_PUBLIC, fieldReader(i), DESC_FIELD_READER);
            }

            for (int i = 0; i < fieldReaderArray.length; i++) {
                FieldWriter fv = cw.visitField(Opcodes.ACC_PUBLIC, fieldObjectReader(i), DESC_OBJECT_READER);
            }
        }

        for (int i = 0; i < fieldReaderArray.length; i++) {
            Class fieldClass = fieldReaderArray[i].fieldClass;
            if (List.class.isAssignableFrom(fieldClass)) {
                cw.visitField(Opcodes.ACC_PUBLIC, fieldItemObjectReader(i), DESC_OBJECT_READER);
            }
        }
    }

    /**
     *  <blockquote><pre>
     *      class Bean {
     *          private String field1;
     *          private int field2;
     *      }
     *
     *      public void readJSONBObject(JSONReader jsonReader, Type fieldType, Object fieldName, long features) {
     *          features = jsonReader.features(features);
     *          if (nextIfNull()) {
     *              return null;
     *          }
     *
     *          jsonReader.errorOnNoneSerializable(this.objectClass);
     *
     *          if (jsonReader.isArray() && jsonReader.isSupportBeanArray()) {
     *              return readArrayMappingObject(jsonReader, fieldType, fieldName, features);
     *          }
     *
     *          Bean object = new Bean();
     *
     *          jsonReader.nextIfObjectStart();
     *
     *          for (;;) {
     *              if (jsonReader.nextIfObjectEnd()) {
     *                  break;
     *              }
     *              switch(jsonReader.getRawInt()) {
     *                  case field1NameHash32:
     *                      if(jsonReader.nextIfName4Match2()) {
     *                          object.field1 = jsonReader.readString();
     *                          break;
     *                      }
     *                      goto hashCode64Start;
     *                  case field2NameHash32:
     *                      if(jsonReader.nextIfName4Match2()) {
     *                          object.field2 = jsonReader.readInt();
     *                          break;
     *                      }
     *                      goto hashCode64Start;
     *                  default:
     *                      goto hashCode64Start;
     *              }
     *
     *              hashCode64Start:
     *              long hashCode64 = readFieldNameHashCode();
     *
     *              if (this.typeKeyHashCode == hashCode64) {
     *                  object = this.autoType(jsonReader);
     *              }
     *
     *              switch(jsonReader.getFieldOrdinal(hashCode64)) {
     *                  case 0:
     *                      object.field1 = jsonReader.readString();
     *              }
     *          }
     *
     *
     *      }
     *  </pre></blockquote>
     */
    private <T> void genMethodReadJSONBObject(ObjectReadContext context, long readerFeatures) {
        String classNameType = context.classNameType;
        FieldReader[] fieldReaderArray = context.fieldReaders;
        Class objectClass = context.objectClass;
        boolean fieldBased = (readerFeatures & JSONReader.Feature.FieldBased.mask) != 0;
        ObjectReaderAdapter objectReaderAdapter = context.objectReaderAdapter;

        MethodWriter mw = context.cw.visitMethod(Opcodes.ACC_PUBLIC,
                "readJSONBObject",
                METHOD_DESC_READ_OBJECT,
                2048
        );

        boolean disableArrayMapping = context.disableSupportArrayMapping();
        boolean disableAutoType = context.disableAutoType();

        MethodWriterContext mwc = new MethodWriterContext(mw, 6, true);
        mw.aload(JSON_READER);
        mw.lload(FEATURES);
        mw.invokevirtual(TYPE_JSON_READER, "features", "(J)J");
        mw.lstore(FEATURES);

        final int OBJECT = mwc.var("object");
        final int I = mwc.var("I");
        final int HASH_CODE64 = mwc.var2("hashCode64");
        final int HASH_CODE_32 = mwc.var("hashCode32");
        final int FIELD_READER = mwc.var("fieldReader");

        if (!disableAutoType) {
            genCheckAutoType(classNameType, mwc);
        }

        {
            /*
             * if (jsonReader.nextIfNull()) {
             *      return null;
             * }
             */
            Label notNull_ = new Label();
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "nextIfNull", "()Z");
            mw.ifeq(notNull_);
            mw.aconst_null();
            mw.areturn();
            mw.visitLabel(notNull_);
        }

        if (objectClass != null && !Serializable.class.isAssignableFrom(objectClass)) {
            mw.aload(JSON_READER);
            mw.aload(THIS);
            mw.getfield(classNameType, "objectClass", "Ljava/lang/Class;");
            mw.invokevirtual(TYPE_JSON_READER, "errorOnNoneSerializable", "(Ljava/lang/Class;)V");
        }

        if (!disableArrayMapping) {
            Label L0 = new Label();

            // if (jsonReader.isArray() && jsonReader.isSupportBeanArray()) {
            {
                Label startArray_ = new Label(), endArray_ = new Label();
                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "isArray", "()Z");
                mw.ifeq(L0);

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "isSupportBeanArray", "()Z");
                mw.ifeq(endArray_);

                mw.aload(THIS);
                mw.aload(JSON_READER);
                mw.aload(FIELD_TYPE);
                mw.aload(FIELD_NAME);
                mw.lload(FEATURES);
                mw.invokevirtual(classNameType, "readArrayMappingObject", METHOD_DESC_READ_OBJECT);
                mw.areturn();

                mw.visitLabel(endArray_);
            }

            mw.visitLabel(L0);
        }

        if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
            {
                /*
                 * if (jsonReader.hasAutoTypeBeforeHandler()
                 *      || (features & (JSONReader.Feature.SupportSmartMatch.mask | JSONReader.Feature.SupportAutoType.mask)) != 0
                 * ) {
                 *     return super.readObject(jsonReader, fieldType, fieldName, features);
                 * }
                 */
                Label L3 = new Label(), L4 = new Label();
                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "hasAutoTypeBeforeHandler", "()Z");
                mw.ifne(L3);

                mw.lload(FEATURES);
                mw.visitLdcInsn(JSONReader.Feature.SupportSmartMatch.mask | JSONReader.Feature.SupportAutoType.mask);
                mw.land();
                mw.lconst_0();
                mw.lcmp();
                mw.ifeq(L4);

                mw.visitLabel(L3);
                mw.aload(THIS);
                mw.aload(JSON_READER);
                mw.aload(FIELD_TYPE);
                mw.aload(FIELD_NAME);
                mw.lload(FEATURES);
                mw.invokespecial(TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR, "readJSONBObject", METHOD_DESC_READ_OBJECT);
                mw.areturn();

                mw.visitLabel(L4);
            }

            genInitForNonDefaultConstructor(fieldReaderArray, mwc);
        } else {
            genCreateObject(mw, context, classNameType);
            mw.astore(OBJECT);
        }

        mw.aload(JSON_READER);
        mw.invokevirtual(TYPE_JSON_READER, "nextIfObjectStart", "()Z");
        mw.pop();

        // for (int i = 0; i < entry_cnt; ++i) {
        Label L_FOR_START = new Label(), L_FOR_END = new Label(), L_FOR_INC = new Label();
        if (!disableAutoType) {
            mw.iconst_0();
            mw.istore(I);
        }

        mw.visitLabel(L_FOR_START);

        Label hashCode64Start = new Label();

        mw.aload(JSON_READER);
        mw.invokevirtual(TYPE_JSON_READER, "nextIfObjectEnd", "()Z");
        mw.ifne(L_FOR_END);

        boolean switchGen = false;
        if (context.fieldNameLengthMin >= 2 && context.fieldNameLengthMax <= 43) {
            genRead243(
                    context,
                    fieldBased,
                    mwc,
                    OBJECT,
                    L_FOR_INC,
                    hashCode64Start
            );
            switchGen = true;
        }

        mw.visitLabel(hashCode64Start);

        mw.aload(JSON_READER);
        mw.invokevirtual(TYPE_JSON_READER, "readFieldNameHashCode", "()J");
        mw.dup2();
        mw.lstore(HASH_CODE64);
        mw.lconst_0();
        mw.lcmp();
        mw.ifeq(L_FOR_INC);

        if (!disableAutoType && !(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
            /*
             * if (hashCode64 == this.typeKeyHashCode() && hashCode64 != 0) {
             *      object = this.autoType(jsonReader);
             * }
             */
            Label endAutoType_ = new Label();
            mw.lload(HASH_CODE64);
            mw.aload(THIS);
            mw.getfield(classNameType, "typeKeyHashCode", "J");
            mw.lcmp();
            mw.ifne(endAutoType_);

            mw.lload(HASH_CODE64);
            mw.lconst_0();
            mw.lcmp();
            mw.ifeq(endAutoType_);

            // protected T autoType(JSONReader jsonReader, int entryCnt) {
            mw.aload(THIS);
            mw.aload(JSON_READER);
            mw.invokevirtual(classNameType, "autoType", "(" + DESC_JSON_READER + ")Ljava/lang/Object;");
            mw.astore(OBJECT);
            mw.goto_(L_FOR_END);

            mw.visitLabel(endAutoType_);
        }

        if (switchGen) {
            if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
                genReadHashCode64ValueForNonDefaultConstructor(context, mwc, HASH_CODE64, fieldBased, OBJECT, L_FOR_INC);
            } else {
                /*
                 * this.readFieldValue(hashCode64, jsonReader, features, object);
                 */
                mw.aload(THIS);
                mw.lload(HASH_CODE64);
                mw.aload(JSON_READER);
                mw.lload(FEATURES);
                mw.aload(OBJECT);
                mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "readFieldValue", READ_FIELD_READER_UL);
            }
            mw.goto_(L_FOR_INC); // continue
            // continue
        } else if (fieldReaderArray.length > 6) {
            // use switch
            Map<Integer, List<Long>> map = new TreeMap();

            for (int i = 0; i < objectReaderAdapter.hashCodes.length; i++) {
                long hashCode64 = objectReaderAdapter.hashCodes[i];
                int hashCode32 = (int) (hashCode64 ^ (hashCode64 >>> 32));
                List<Long> hashCode64List = map.computeIfAbsent(hashCode32, k -> new ArrayList<>());
                hashCode64List.add(hashCode64);
            }
            int[] hashCode32Keys = new int[map.size()];
            {
                int off = 0;
                for (Integer key : map.keySet()) {
                    hashCode32Keys[off++] = key;
                }
            }
            Arrays.sort(hashCode32Keys);

            // int hashCode32 = (int)(hashCode64 ^ (hashCode64 >>> 32));
            mw.lload(HASH_CODE64);
            mw.lload(HASH_CODE64);
            mw.bipush(32);
            mw.lushr();
            mw.lxor();
            mw.l2i();
            mw.istore(HASH_CODE_32);

            Label dflt = new Label();
            Label[] labels = new Label[hashCode32Keys.length];
            for (int i = 0; i < labels.length; i++) {
                labels[i] = new Label();
            }

            mw.iload(HASH_CODE_32);
            mw.visitLookupSwitchInsn(dflt, hashCode32Keys, labels);

            for (int i = 0; i < labels.length; i++) {
                mw.visitLabel(labels[i]);

                int hashCode32 = hashCode32Keys[i];
                List<Long> hashCode64Array = map.get(hashCode32);
                for (int j = 0, size = hashCode64Array.size(); j < size; j++) {
                    long hashCode64 = hashCode64Array.get(j);

                    Label next = size > 1 ? new Label() : dflt;

                    mw.lload(HASH_CODE64);
                    mw.visitLdcInsn(hashCode64);
                    mw.lcmp();
                    mw.ifne(next);

                    int m = Arrays.binarySearch(objectReaderAdapter.hashCodes, hashCode64);
                    int index = objectReaderAdapter.mapping[m];

                    FieldReader fieldReader = fieldReaderArray[index];

                    genReadFieldValue(
                            context,
                            fieldReader,
                            fieldBased,
                            mwc,
                            OBJECT,
                            index,
                            true // JSONB
                    );
                    mw.goto_(L_FOR_INC);

                    if (next != dflt) {
                        mw.visitLabel(next);
                    }
                }

                mw.goto_(L_FOR_INC);
            }

            // switch_default
            mw.visitLabel(dflt);

            boolean disableSmartMatch = context.disableSmartMatch();
            if (!disableSmartMatch && !(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
                Label fieldReaderNull_ = new Label();

                if ((readerFeatures & JSONReader.Feature.SupportSmartMatch.mask) == 0) {
                    mw.aload(JSON_READER);
                    mw.lload(FEATURES);
                    mw.invokevirtual(TYPE_JSON_READER, "isSupportSmartMatch", "(J)Z");
                    mw.ifeq(fieldReaderNull_);
                }

                mw.aload(THIS);
                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "getNameHashCodeLCase", "()J");
                mw.invokeinterface(TYPE_OBJECT_READER, "getFieldReaderLCase", METHOD_DESC_GET_FIELD_READER);
                mw.dup();
                mw.astore(FIELD_READER);
                mw.ifnull(fieldReaderNull_);

                mw.aload(FIELD_READER);
                mw.aload(JSON_READER);
                mw.aload(OBJECT);
                mw.invokevirtual(TYPE_FIELD_READE, "readFieldValueJSONB", METHOD_DESC_READ_FIELD_VALUE);
                mw.goto_(L_FOR_INC); // continue

                mw.visitLabel(fieldReaderNull_);
            }
        } else {
            for (int i = 0; i < fieldReaderArray.length; ++i) {
                Label next_ = new Label();

                // if (hashCode64 == <nameHashCode>) {
                FieldReader fieldReader = fieldReaderArray[i];

                long hashCode64 = Fnv.hashCode64(fieldReader.fieldName);
                mw.lload(HASH_CODE64);
                mw.visitLdcInsn(hashCode64);
                mw.lcmp();
                mw.ifne(next_);

                genReadFieldValue(
                        context,
                        fieldReader,
                        fieldBased,
                        mwc,
                        OBJECT,
                        i,
                        false // arrayMapping
                );

                mw.goto_(L_FOR_INC); // continue

                mw.visitLabel(next_);
            }

            Label processExtra_ = new Label();

            if ((readerFeatures & JSONReader.Feature.SupportSmartMatch.mask) == 0) {
                mw.aload(JSON_READER);
                mw.lload(FEATURES);
                mw.invokevirtual(TYPE_JSON_READER, "isSupportSmartMatch", "(J)Z");
                mw.ifeq(processExtra_);
            }

            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "getNameHashCodeLCase", "()J");
            mw.lstore(HASH_CODE64);

            for (int i = 0; i < fieldReaderArray.length; ++i) {
                Label next_ = new Label();

                // if (hashCode64 == <nameHashCode>) {
                FieldReader fieldReader = fieldReaderArray[i];

                long hashCode64 = Fnv.hashCode64(fieldReader.fieldName);
                mw.lload(HASH_CODE64);
                mw.visitLdcInsn(hashCode64);
                mw.lcmp();
                mw.ifne(next_);

                genReadFieldValue(
                        context,
                        fieldReader,
                        fieldBased,
                        mwc,
                        OBJECT,
                        i,
                        false // arrayMapping
                );

                mw.goto_(L_FOR_INC); // continue

                mw.visitLabel(next_);
            }
            mw.visitLabel(processExtra_);
        }

        if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "skipValue", "()V");
        } else {
            mw.aload(THIS);
            mw.aload(JSON_READER);
            mw.aload(OBJECT);
            mw.lload(FEATURES);
            mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "processExtra", METHOD_DESC_PROCESS_EXTRA);
        }
        mw.goto_(L_FOR_INC); // continue

        mw.visitLabel(L_FOR_INC);
        if (!disableAutoType) {
            mw.visitIincInsn(I, 1);
        }
        mw.goto_(L_FOR_START);

        mw.visitLabel(L_FOR_END);

        if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
            createObjectForNonConstructor(context, mwc);
        } else {
            mw.aload(OBJECT);
        }
        mw.areturn();

        mw.visitMaxs(5, 10);
    }

    private void genReadHashCode64ValueForNonDefaultConstructor(
            ObjectReadContext context,
            MethodWriterContext mwc,
            int HASH_CODE64,
            boolean fieldBased,
            int OBJECT,
            Label L_FOR_INC
    ) {
        /*
         *  swith(this.getFieldOrdinal(hashCode64)) {
         *      case 0:
         *          fieldValue0 = ...;
         *          break;
         *      case 1:
         *          fieldValue0 = ...;
         *          break;
         *      default:
         *          skipValue();
         *          break;
         *  }
         *  goto
         */
        FieldReader[] fieldReaderArray = context.fieldReaders;
        MethodWriter mw = mwc.mw;
        mw.aload(THIS);
        mw.lload(HASH_CODE64);
        mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "getFieldOrdinal", "(J)I");

        Label dflt = new Label();
        Label[] labels = new Label[fieldReaderArray.length];
        int[] switchKeys = new int[fieldReaderArray.length];
        for (int i = 0; i < fieldReaderArray.length; i++) {
            labels[i] = new Label();
            switchKeys[i] = i;
        }

        mw.visitLookupSwitchInsn(dflt, switchKeys, labels);

        for (int i = 0; i < fieldReaderArray.length; i++) {
            mw.visitLabel(labels[i]);
            FieldReader fieldReader = fieldReaderArray[i];
            genReadFieldValue(
                    context,
                    fieldReader,
                    fieldBased,
                    mwc,
                    OBJECT,
                    i,
                    false
            );
            mw.goto_(L_FOR_INC);
        }

        // jsonReader.skipValue();
        mw.visitLabel(dflt);
        mw.aload(JSON_READER);
        mw.invokevirtual(TYPE_JSON_READER, "skipValue", "()V");
    }

    private <T> void genMethodReadJSONBObjectArrayMapping(ObjectReadContext context, long readerFeatures) {
        FieldReader[] fieldReaderArray = context.fieldReaders;
        String classNameType = context.classNameType;
        boolean fieldBased = (readerFeatures & JSONReader.Feature.FieldBased.mask) != 0;

        MethodWriter mw = context.cw.visitMethod(Opcodes.ACC_PUBLIC,
                "readArrayMappingJSONBObject",
                METHOD_DESC_READ_OBJECT,
                512
        );

        MethodWriterContext mwc = new MethodWriterContext(mw, 6, true);
        mw.aload(JSON_READER);
        mw.lload(FEATURES);
        mw.invokevirtual(TYPE_JSON_READER, "features", "(J)J");
        mw.lstore(FEATURES);

        final int OBJECT = mwc.var("object");
        final int ENTRY_CNT = mwc.var("entryCnt");

        if (!context.disableAutoType()) {
            genCheckAutoType(classNameType, mwc);
        }

        {
            Label notNull_ = new Label();
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "nextIfNull", "()Z");
            mw.ifeq(notNull_);
            mw.aconst_null();
            mw.areturn();
            mw.visitLabel(notNull_);
        }

        genCreateObject(mw, context, classNameType);
        mw.astore(OBJECT);

        Label fieldEnd_ = new Label(), entryCountMatch_ = new Label();

        mw.aload(JSON_READER);
        mw.invokevirtual(TYPE_JSON_READER, "startArray", "()I");
        mw.dup();
        mw.istore(ENTRY_CNT);
        mw.visitLdcInsn(fieldReaderArray.length);
        mw.if_icmpne(entryCountMatch_);

        for (int i = 0; i < fieldReaderArray.length; ++i) {
            FieldReader fieldReader = fieldReaderArray[i];
            genReadFieldValue(
                    context,
                    fieldReader,
                    fieldBased,
                    mwc,
                    OBJECT,
                    i,
                    true // arrayMapping
            );
        }
        mw.goto_(fieldEnd_);

        mw.visitLabel(entryCountMatch_);
        mw.aload(THIS);
        mw.aload(JSON_READER);
        mw.aload(OBJECT);
        mw.iload(ENTRY_CNT);
        mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "readArrayMappingJSONBObject0", METHOD_DESC_READ_ARRAY_MAPPING_JSONB_OBJECT0);
        mw.visitLabel(fieldEnd_);

        mw.aload(OBJECT);
        mw.areturn();

        mw.visitMaxs(5, 10);
    }

    private void genCheckAutoType(String classNameType, MethodWriterContext mwc) {
        MethodWriter mw = mwc.mw;
        int AUTO_TYPE_OBJECT_READER = mwc.var("autoTypeObjectReader");
        Label checkArrayAutoTypeNull_ = new Label();

        mw.aload(THIS);
        mw.aload(JSON_READER);
        mw.lload(FEATURES);
        mw.invokevirtual(classNameType, "checkAutoType", METHOD_DESC_JSON_READER_CHECK_ARRAY_AUTO_TYPE);

        mw.dup();
        mw.astore(AUTO_TYPE_OBJECT_READER);
        mw.ifnull(checkArrayAutoTypeNull_);

        mw.aload(AUTO_TYPE_OBJECT_READER);
        mw.aload(JSON_READER);
        mw.aload(FIELD_TYPE);
        mw.aload(FIELD_NAME);
        mw.lload(FEATURES);
        mw.invokeinterface(TYPE_OBJECT_READER, "readJSONBObject", METHOD_DESC_READ_OBJECT);
        mw.areturn();

        mw.visitLabel(checkArrayAutoTypeNull_);
    }

    private <T> void genMethodReadObject(ObjectReadContext context, long readerFeatures) {
        FieldReader[] fieldReaderArray = context.fieldReaders;
        String classNameType = context.classNameType;
        boolean fieldBased = (readerFeatures & JSONReader.Feature.FieldBased.mask) != 0;

        MethodWriter mw = context.cw.visitMethod(
                Opcodes.ACC_PUBLIC,
                "readObject",
                METHOD_DESC_READ_OBJECT,
                2048
        );

        MethodWriterContext mwc = new MethodWriterContext(mw, 6, false);

        final int OBJECT = mwc.var("object");
        final int I = mwc.var("I");
        final int HASH_CODE64 = mwc.var2("hashCode64");
        final int HASH_CODE_32 = mwc.var("hashCode32");
        final int FIELD_READER = mwc.var("fieldReader");

        boolean disableArrayMapping = context.disableSupportArrayMapping();
        boolean disableAutoType = context.disableAutoType();
        boolean disableJSONB = context.disableJSONB();
        boolean disableSmartMatch = context.disableSmartMatch();

        if (!disableJSONB) {
            /*
             * if (jsonReader.json) {
             *     return readJSONBObject(jsonReader, fieldType, fieldName, features);
             * }
             */
            Label L0 = new Label();
            mw.aload(JSON_READER);
            mw.getfield(TYPE_JSON_READER, "jsonb", "Z");
            mw.ifeq(L0);

            mw.aload(THIS);
            mw.aload(JSON_READER);
            mw.aload(FIELD_TYPE);
            mw.aload(FIELD_NAME);
            mw.lload(FEATURES);
            mw.invokevirtual(classNameType, "readJSONBObject", METHOD_DESC_READ_OBJECT);
            mw.areturn();

            mw.visitLabel(L0);
        }

        /*
         * long features = jsonReader.features(features);
         */
        mw.aload(JSON_READER);
        mw.lload(FEATURES);
        mw.invokevirtual(TYPE_JSON_READER, "features", "(J)J");
        mw.lstore(FEATURES);

        if (!disableSmartMatch || !disableArrayMapping) {
            /*
             * if (jsonReader.isArray()) {
             *     if ((features & JSONReader.Feature.SupportArrayToBean.mask) != 0) {
             *         return readArrayMappingObject(jsonReader, fieldType, fieldName, features);
             *     }
             *     return processObjectInputSingleItemArray(jsonReader, fieldType, fieldName, features);
             * }
             */
            Label L1 = new Label();
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "isArray", "()Z");
            mw.ifeq(L1);

            if (!disableArrayMapping) {
                Label singleItemArray_ = new Label();

                if ((readerFeatures & JSONReader.Feature.SupportArrayToBean.mask) == 0) {
                    mw.aload(JSON_READER);
                    mw.lload(FEATURES);
                    mw.invokevirtual(TYPE_JSON_READER, "isSupportBeanArray", "(J)Z");
                    mw.ifeq(singleItemArray_);
                }

                mw.aload(THIS);
                mw.aload(JSON_READER);
                mw.aload(FIELD_TYPE);
                mw.aload(FIELD_NAME);
                mw.lload(FEATURES);
                mw.invokevirtual(classNameType, "readArrayMappingObject", METHOD_DESC_READ_OBJECT);
                mw.areturn();

                mw.visitLabel(singleItemArray_);
            }

            mw.aload(THIS);
            mw.aload(JSON_READER);
            mw.aload(FIELD_TYPE);
            mw.aload(FIELD_NAME);
            mw.lload(FEATURES);
            mw.invokevirtual(classNameType, "processObjectInputSingleItemArray", METHOD_DESC_READ_OBJECT);
            mw.areturn();

            mw.visitLabel(L1);
        }

        Label end_ = new Label();

        {
            /*
             * if (jsonReader.nextIfObjectStart()) {
             *    if (jsonReader.nextIfNull()) {
             *         return null;
             *    }
             * }
             */
            Label L2 = new Label();

            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "nextIfObjectStart", "()Z");
            mw.ifne(L2);

            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "nextIfNullOrEmptyString", "()Z");
            mw.ifeq(L2);

            mw.aconst_null();
            mw.areturn();

            mw.visitLabel(L2);
        }

        if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
            {
                /*
                 * if (jsonReader.hasAutoTypeBeforeHandler()
                 *      || (features & (JSONReader.Feature.SupportSmartMatch.mask | JSONReader.Feature.SupportAutoType.mask)) != 0
                 * ) {
                 *     return super.readObject(jsonReader, fieldType, fieldName, features);
                 * }
                 */
                Label L3 = new Label(), L4 = new Label();
                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "hasAutoTypeBeforeHandler", "()Z");
                mw.ifne(L3);

                mw.lload(FEATURES);
                mw.visitLdcInsn(JSONReader.Feature.SupportSmartMatch.mask | JSONReader.Feature.SupportAutoType.mask);
                mw.land();
                mw.lconst_0();
                mw.lcmp();
                mw.ifeq(L4);

                mw.visitLabel(L3);
                mw.aload(THIS);
                mw.aload(JSON_READER);
                mw.aload(FIELD_TYPE);
                mw.aload(FIELD_NAME);
                mw.lload(FEATURES);
                mw.invokespecial(TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR, "readObject", METHOD_DESC_READ_OBJECT);
                mw.areturn();

                mw.visitLabel(L4);
            }

            genInitForNonDefaultConstructor(fieldReaderArray, mwc);
        } else {
            genCreateObject(mw, context, classNameType);
            mw.astore(OBJECT);
        }

        /*
         * for (int i = 0; i < entry_cnt; ++i) {
         *    long hashCode64 = jsonReader.readFieldNameHashCode();
         * }
         */
        Label L_FOR_START = new Label(), L_FOR_END = new Label(), L_FOR_INC = new Label();

        if (!disableAutoType) {
            mw.iconst_0();
            mw.istore(I);
        }
        mw.visitLabel(L_FOR_START);

        Label hashCode64Start = new Label();

        mw.aload(JSON_READER);
        mw.invokevirtual(TYPE_JSON_READER, "nextIfObjectEnd", "()Z");
        mw.ifne(L_FOR_END);

        boolean switchGen = false;
        if (context.fieldNameLengthMin >= 5 && context.fieldNameLengthMax <= 7) {
            genRead57(
                    context,
                    fieldBased,
                    mwc,
                    OBJECT,
                    L_FOR_INC,
                    hashCode64Start
            );
            switchGen = true;
        } else if (context.fieldNameLengthMin >= 2 && context.fieldNameLengthMax <= 43) {
            genRead243(
                    context,
                    fieldBased,
                    mwc,
                    OBJECT,
                    L_FOR_INC,
                    hashCode64Start
            );
            switchGen = true;
        }

        mw.visitLabel(hashCode64Start);

        {
            /*
             * long hashCode64 = jsonReader.readFieldNameHashCode();
             * if (hashCode64 == -1) {
             *     break;
             * }
             */
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readFieldNameHashCode", "()J");
            mw.dup2();
            mw.lstore(HASH_CODE64);

            mw.visitLdcInsn(-1L);
            mw.lcmp();
            mw.ifeq(L_FOR_END);
        }

        if (!disableAutoType && !(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
            Label noneAutoType_ = new Label();

            // if (i != 0 && hash == HASH_TYPE && jsonReader.isSupportAutoType())
            mw.iload(I);
            mw.ifne(noneAutoType_);

            mw.lload(HASH_CODE64);
            mw.visitLdcInsn(HASH_TYPE);
            mw.lcmp();
            mw.ifne(noneAutoType_);

            if ((readerFeatures & JSONReader.Feature.SupportAutoType.mask) == 0) {
                mw.aload(JSON_READER);
                mw.lload(FEATURES);
                mw.invokevirtual(TYPE_JSON_READER, "isSupportAutoTypeOrHandler", "(J)Z");
                mw.ifeq(noneAutoType_);
            }

            mw.aload(THIS);
            mw.aload(JSON_READER);
            mw.aload(THIS);
            mw.getfield(classNameType, "objectClass", "Ljava/lang/Class;");
            mw.lload(FEATURES);
            mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "autoType", "(" + ASMUtils.desc(JSONReader.class) + "Ljava/lang/Class;J)Ljava/lang/Object;");
            mw.areturn();

            mw.visitLabel(noneAutoType_);
        }

        // continue
        if (switchGen) {
            if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
                genReadHashCode64ValueForNonDefaultConstructor(context, mwc, HASH_CODE64, fieldBased, OBJECT, L_FOR_INC);
            } else {
                /*
                 * this.readFieldValue(hashCode64, jsonReader, features, object);
                 */
                mw.aload(THIS);
                mw.lload(HASH_CODE64);
                mw.aload(JSON_READER);
                mw.lload(FEATURES);
                mw.aload(OBJECT);
                mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "readFieldValue", READ_FIELD_READER_UL);
            }
            mw.goto_(L_FOR_INC); // continue
        } else if (fieldReaderArray.length > 6) {
            // use switch
            Map<Integer, List<Long>> map = new TreeMap();

            for (int i = 0; i < context.objectReaderAdapter.hashCodes.length; i++) {
                long hashCode64 = context.objectReaderAdapter.hashCodes[i];
                int hashCode32 = (int) (hashCode64 ^ (hashCode64 >>> 32));
                List<Long> hashCode64List = map.computeIfAbsent(hashCode32, k -> new ArrayList<>());
                hashCode64List.add(hashCode64);
            }
            int[] hashCode32Keys = new int[map.size()];
            {
                int off = 0;
                for (Integer key : map.keySet()) {
                    hashCode32Keys[off++] = key;
                }
            }
            Arrays.sort(hashCode32Keys);

            // int hashCode32 = (int)(hashCode64 ^ (hashCode64 >>> 32));
            mw.lload(HASH_CODE64);
            mw.lload(HASH_CODE64);
            mw.bipush(32);
            mw.lushr();
            mw.lxor();
            mw.l2i();
            mw.istore(HASH_CODE_32);

            Label dflt = new Label();
            Label[] labels = new Label[hashCode32Keys.length];
            for (int i = 0; i < labels.length; i++) {
                labels[i] = new Label();
            }

            mw.iload(HASH_CODE_32);
            mw.visitLookupSwitchInsn(dflt, hashCode32Keys, labels);

            for (int i = 0; i < labels.length; i++) {
                mw.visitLabel(labels[i]);

                int hashCode32 = hashCode32Keys[i];
                List<Long> hashCode64Array = map.get(hashCode32);
                for (int j = 0, size = hashCode64Array.size(); j < size; j++) {
                    long hashCode64 = hashCode64Array.get(j);

                    Label next = size > 1 ? new Label() : dflt;
                    mw.lload(HASH_CODE64);
                    mw.visitLdcInsn(hashCode64);
                    mw.lcmp();
                    mw.ifne(next);

                    int m = Arrays.binarySearch(context.objectReaderAdapter.hashCodes, hashCode64);
                    int index = context.objectReaderAdapter.mapping[m];

                    FieldReader fieldReader = fieldReaderArray[index];

                    genReadFieldValue(
                            context,
                            fieldReader,
                            fieldBased,
                            mwc,
                            OBJECT,
                            index,
                            false // arrayMapping
                    );
                    mw.goto_(L_FOR_INC);

                    if (next != dflt) {
                        mw.visitLabel(next);
                    }
                }

                mw.goto_(L_FOR_INC);
            }

            mw.visitLabel(dflt);

            if (!disableSmartMatch && !(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
                Label fieldReaderNull_ = new Label();
                if ((readerFeatures & JSONReader.Feature.SupportSmartMatch.mask) == 0) {
                    mw.lload(FEATURES);
                    mw.visitLdcInsn(JSONReader.Feature.SupportSmartMatch.mask);
                    mw.land();
                    mw.lconst_0();
                    mw.lcmp();
                    mw.ifeq(fieldReaderNull_);
                }

                mw.aload(THIS);
                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "getNameHashCodeLCase", "()J");
                mw.invokeinterface(TYPE_OBJECT_READER, "getFieldReaderLCase", METHOD_DESC_GET_FIELD_READER);
                mw.dup();
                mw.astore(FIELD_READER);
                mw.ifnull(fieldReaderNull_);

                mw.aload(FIELD_READER);
                mw.aload(JSON_READER);
                mw.aload(OBJECT);
                mw.invokevirtual(TYPE_FIELD_READE, "readFieldValue", METHOD_DESC_READ_FIELD_VALUE);
                mw.goto_(L_FOR_INC); // continue

                mw.visitLabel(fieldReaderNull_);
            }
        } else {
            for (int i = 0; i < fieldReaderArray.length; ++i) {
                Label next_ = new Label(), get_ = new Label();

                // if (hashCode64 == <nameHashCode>) {
                FieldReader fieldReader = fieldReaderArray[i];

                String fieldName = fieldReader.fieldName;
                long hashCode64 = fieldReader.fieldNameHash;

                mw.lload(HASH_CODE64);
                mw.visitLdcInsn(hashCode64);
                mw.lcmp();
                mw.ifne(next_);

                mw.visitLabel(get_);
                genReadFieldValue(
                        context,
                        fieldReader,
                        fieldBased,
                        mwc,
                        OBJECT,
                        i,
                        false // arrayMapping
                );

                mw.goto_(L_FOR_INC); // continue

                mw.visitLabel(next_);
            }

            Label processExtra_ = new Label();

            if (!disableSmartMatch) {
                if ((readerFeatures & JSONReader.Feature.SupportSmartMatch.mask) == 0) {
                    mw.lload(FEATURES);
                    mw.visitLdcInsn(JSONReader.Feature.SupportSmartMatch.mask);
                    mw.land();
                    mw.lconst_0();
                    mw.lcmp();
                    mw.ifeq(processExtra_);
                }

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "getNameHashCodeLCase", "()J");
                mw.lstore(HASH_CODE64);

                for (int i = 0; i < fieldReaderArray.length; ++i) {
                    Label next_ = new Label(), get_ = new Label();

                    // if (hashCode64 == <nameHashCode>) {
                    FieldReader fieldReader = fieldReaderArray[i];

                    String fieldName = fieldReader.fieldName;
                    long hashCode64 = fieldReader.fieldNameHash;
                    long hashCode64LCase = fieldReader.fieldNameHashLCase;

                    mw.lload(HASH_CODE64);
                    mw.visitLdcInsn(hashCode64);
                    mw.lcmp();
                    mw.ifeq(get_);

                    if (hashCode64LCase != hashCode64) {
                        mw.lload(HASH_CODE64);
                        mw.visitLdcInsn(hashCode64LCase);
                        mw.lcmp();
                        mw.ifne(next_);
                    } else {
                        mw.goto_(next_);
                    }

                    mw.visitLabel(get_);
                    genReadFieldValue(
                            context,
                            fieldReader,
                            fieldBased,
                            mwc,
                            OBJECT,
                            i,
                            false // arrayMapping
                    );

                    mw.goto_(L_FOR_INC); // continue

                    mw.visitLabel(next_);
                }
            }

            mw.visitLabel(processExtra_);
        }
        if (!switchGen) {
            if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "skipValue", "()V");
            } else {
                mw.aload(THIS);
                mw.aload(JSON_READER);
                mw.aload(OBJECT);
                mw.lload(FEATURES);
                mw.invokevirtual(TYPE_OBJECT_READER_ADAPTER, "processExtra", METHOD_DESC_PROCESS_EXTRA);
            }
            mw.goto_(L_FOR_INC); // continue
        }

        mw.visitLabel(L_FOR_INC);
        if (!disableAutoType) {
            mw.visitIincInsn(I, 1);
        }
        mw.goto_(L_FOR_START);

        mw.visitLabel(L_FOR_END);

        mw.visitLabel(end_);

        if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
            createObjectForNonConstructor(context, mwc);
        } else {
            mw.aload(OBJECT);
        }
        mw.areturn();

        mw.visitMaxs(5, 10);
    }

    private void createObjectForNonConstructor(ObjectReadContext context, MethodWriterContext mwc) {
        FieldReader[] fieldReaderArray = context.fieldReaders;
        MethodWriter mw = mwc.mw;
        ObjectReaderNoneDefaultConstructor objectReaderNoneDefaultConstructor = (ObjectReaderNoneDefaultConstructor) context.objectReaderAdapter;
        boolean constructDirect = true;
        if (classLoader.isExternalClass(context.objectClass)
                || context.objectClass.getTypeParameters().length != 0
                || (objectReaderNoneDefaultConstructor.constructor != null && !Modifier.isPublic(objectReaderNoneDefaultConstructor.constructor.getModifiers()))
                || (context.objectClass != null && !Modifier.isPublic(context.objectClass.getModifiers()))
                || objectReaderNoneDefaultConstructor.factoryFunction != null
                || objectReaderNoneDefaultConstructor.noneDefaultConstructor != null && !Modifier.isPublic(objectReaderNoneDefaultConstructor.noneDefaultConstructor.getModifiers())
        ) {
            constructDirect = false;
        }

        if (constructDirect) {
            mw.new_(context.objectType);
            mw.dup();
            StringBuilder buf = new StringBuilder().append("(");
            for (FieldReader fieldReader : fieldReaderArray) {
                mw.loadLocal(fieldReader.fieldClass, mwc.var(fieldReader));
                buf.append(ASMUtils.desc(fieldReader.fieldClass));
            }
            buf.append(")V");
            mw.invokespecial(context.objectType, "<init>", buf.toString());
        } else {
            mw.aload(THIS);
            mw.iconst_n(fieldReaderArray.length);
            mw.anewArray("java/lang/Object");
            for (int i = 0; i < fieldReaderArray.length; i++) {
                FieldReader fieldReader = fieldReaderArray[i];
                mw.dup();
                mw.iconst_n(i);
                mw.loadLocal(fieldReader.fieldClass, mwc.var(fieldReader));
                if (fieldReader.fieldClass == int.class) {
                    mw.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
                } else if (fieldReader.fieldClass == long.class) {
                    mw.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
                } else if (fieldReader.fieldClass == float.class) {
                    mw.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
                } else if (fieldReader.fieldClass == double.class) {
                    mw.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
                } else if (fieldReader.fieldClass == boolean.class) {
                    mw.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
                } else if (fieldReader.fieldClass == short.class) {
                    mw.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
                } else if (fieldReader.fieldClass == byte.class) {
                    mw.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
                } else if (fieldReader.fieldClass == char.class) {
                    mw.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
                }
                mw.aastore();
            }
            mw.invokevirtual(TYPE_OBJECT_READER_NONE_DEFAULT_CONSTRUCTOR, "createInstance", "([Ljava/lang/Object;)Ljava/lang/Object;");
        }
    }

    private static void genInitForNonDefaultConstructor(FieldReader[] fieldReaderArray, MethodWriterContext mwc) {
        MethodWriter mw = mwc.mw;
        for (FieldReader fieldReader : fieldReaderArray) {
            Class fieldClass = fieldReader.fieldClass;
            int var = mwc.var(fieldReader);
            if (fieldClass == byte.class || fieldClass == short.class || fieldClass == int.class || fieldClass == boolean.class || fieldClass == char.class) {
                mw.iconst_0();
                mw.istore(var);
            } else if (fieldClass == long.class) {
                mw.lconst_0();
                mw.lstore(var);
            } else if (fieldClass == float.class) {
                mw.iconst_0();
                mw.i2f();
                mw.fstore(var);
            } else if (fieldClass == double.class) {
                mw.iconst_0();
                mw.i2d();
                mw.dstore(var);
            } else {
                mw.aconst_null();
                mw.astore(var);
            }
        }
    }

    private void genRead243(
            ObjectReadContext context,
            boolean fieldBased,
            MethodWriterContext mwc,
            int OBJECT,
            Label L_FOR_INC,
            Label hashCode64Start
    ) {
        String classNameType = context.classNameType;
        FieldReader[] fieldReaderArray = context.fieldReaders;
        boolean jsonb = mwc.jsonb;
        MethodWriter mw = mwc.mw;
        IdentityHashMap<FieldReader, Integer> readerIndexMap = new IdentityHashMap<>();
        Map<Integer, List<FieldReader>> name0Map = new TreeMap<>();
        for (int i = 0; i < fieldReaderArray.length; ++i) {
            FieldReader fieldReader = fieldReaderArray[i];
            readerIndexMap.put(fieldReader, i);

            byte[] name0Bytes = new byte[4];
            if (jsonb) {
                byte[] fieldNameJSONB = JSONB.toBytes(fieldReader.fieldName);
                System.arraycopy(fieldNameJSONB, 0, name0Bytes, 0, Math.min(4, fieldNameJSONB.length));
            } else {
                byte[] fieldName = fieldReader.fieldName.getBytes(StandardCharsets.UTF_8);
                name0Bytes[0] = '"';
                if (fieldName.length == 2) {
                    System.arraycopy(fieldName, 0, name0Bytes, 1, 2);
                    name0Bytes[3] = '"';
                } else {
                    System.arraycopy(fieldName, 0, name0Bytes, 1, 3);
                }
            }

            int name0 = UNSAFE.getInt(name0Bytes, ARRAY_BYTE_BASE_OFFSET);

            List<FieldReader> fieldReaders = name0Map.get(name0);
            if (fieldReaders == null) {
                fieldReaders = new ArrayList<>();
                name0Map.put(name0, fieldReaders);
            }
            fieldReaders.add(fieldReader);
        }

        Label dflt = new Label();
        int[] switchKeys = new int[name0Map.size()];
        Label[] labels = new Label[name0Map.size()];
        {
            Iterator it = name0Map.keySet().iterator();
            for (int i = 0; i < labels.length; i++) {
                labels[i] = new Label();
                switchKeys[i] = (Integer) it.next();
            }
        }

        mw.aload(JSON_READER);
        mw.invokevirtual(TYPE_JSON_READER, "getRawInt", "()I");
        mw.visitLookupSwitchInsn(dflt, switchKeys, labels);

        for (int i = 0; i < labels.length; i++) {
            mw.visitLabel(labels[i]);

            int name0 = switchKeys[i];
            List<FieldReader> fieldReaders = name0Map.get(name0);
            for (int j = 0; j < fieldReaders.size(); j++) {
                Label nextJ = null;
                if (j + 1 != fieldReaders.size()) {
                    nextJ = new Label();
                }

                FieldReader fieldReader = fieldReaders.get(j);
                int fieldReaderIndex = readerIndexMap.get(fieldReader);
                byte[] fieldName = fieldReader.fieldName.getBytes(StandardCharsets.UTF_8);
                int fieldNameLength = fieldName.length;
                switch (fieldNameLength) {
                    case 2:
                        mw.aload(JSON_READER);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match2", "()Z");
                        break;
                    case 3:
                        mw.aload(JSON_READER);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match3", "()Z");
                        break;
                    case 4: {
                        mw.aload(JSON_READER);
                        mw.iconst_n(fieldName[3]);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match4", "(B)Z");
                        break;
                    }
                    case 5: {
                        byte[] bytes4 = new byte[4];
                        bytes4[0] = fieldName[3];
                        bytes4[1] = fieldName[4];
                        bytes4[2] = '"';
                        bytes4[3] = ':';
                        int name1 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name1 &= 0xFFFF;
                        }
                        mw.aload(JSON_READER);
                        mw.iconst_n(name1);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match5", "(I)Z");
                        break;
                    }
                    case 6: {
                        byte[] bytes4 = new byte[4];
                        bytes4[0] = fieldName[3];
                        bytes4[1] = fieldName[4];
                        bytes4[2] = fieldName[5];
                        bytes4[3] = '"';
                        int name1 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name1 &= 0xFFFFFF;
                        }
                        mw.aload(JSON_READER);
                        mw.iconst_n(name1);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match6", "(I)Z");
                        break;
                    }
                    case 7: {
                        int name1 = UNSAFE.getInt(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        mw.aload(JSON_READER);
                        mw.iconst_n(name1);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match7", "(I)Z");
                        break;
                    }
                    case 8: {
                        int name1 = UNSAFE.getInt(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        mw.aload(JSON_READER);
                        mw.iconst_n(name1);
                        mw.iconst_n(fieldName[7]);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match8", "(IB)Z");
                        break;
                    }
                    case 9: {
                        byte[] bytes8 = new byte[8];
                        System.arraycopy(fieldName, 3, bytes8, 0, 6);
                        bytes8[6] = '"';
                        bytes8[7] = ':';
                        long name1 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name1 &= 0xFFFFFFFFFFFFL;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match9", "(J)Z");
                        break;
                    }
                    case 10: {
                        byte[] bytes8 = new byte[8];
                        System.arraycopy(fieldName, 3, bytes8, 0, 7);
                        bytes8[7] = '"';
                        long name1 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name1 &= 0xFFFFFFFFFFFFFFL;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match10", "(J)Z");
                        break;
                    }
                    case 11: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match11", "(J)Z");
                        break;
                    }
                    case 12: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.iconst_n(fieldName[11]);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match12", "(JB)Z");
                        break;
                    }
                    case 13: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        byte[] bytes4 = new byte[4];
                        bytes4[0] = fieldName[11];
                        bytes4[1] = fieldName[12];
                        bytes4[2] = '"';
                        bytes4[3] = ':';
                        int name2 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name2 &= 0xFFFF;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.iconst_n(name2);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match13", "(JI)Z");
                        break;
                    }
                    case 14: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        byte[] bytes4 = new byte[4];
                        bytes4[0] = fieldName[11];
                        bytes4[1] = fieldName[12];
                        bytes4[2] = fieldName[13];
                        bytes4[3] = '"';
                        int name2 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name2 &= 0xFFFFFF;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.iconst_n(name2);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match14", "(JI)Z");
                        break;
                    }
                    case 15: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        int name2 = UNSAFE.getInt(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.iconst_n(name2);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match15", "(JI)Z");
                        break;
                    }
                    case 16: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        int name2 = UNSAFE.getInt(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.iconst_n(name2);
                        mw.visitLdcInsn(fieldName[15]);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match16", "(JIB)Z");
                        break;
                    }
                    case 17: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);

                        byte[] bytes8 = new byte[8];
                        System.arraycopy(fieldName, 11, bytes8, 0, 6);
                        bytes8[6] = '"';
                        bytes8[7] = ':';
                        long name2 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name2 &= 0xFFFFFFFFFFFFL;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match17", "(JJ)Z");
                        break;
                    }
                    case 18: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);

                        byte[] bytes8 = new byte[8];
                        System.arraycopy(fieldName, 11, bytes8, 0, 7);
                        bytes8[7] = '"';
                        long name2 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name2 &= 0xFFFFFFFFFFFFFFL;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match18", "(JJ)Z");
                        break;
                    }
                    case 19: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match19", "(JJ)Z");
                        break;
                    }
                    case 20: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.iconst_n(fieldName[19]);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match20", "(JJB)Z");
                        break;
                    }
                    case 21: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        byte[] bytes4 = new byte[4];
                        bytes4[0] = fieldName[19];
                        bytes4[1] = fieldName[20];
                        bytes4[2] = '"';
                        bytes4[3] = ':';
                        int name3 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name3 &= 0xFFFF;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.iconst_n(name3);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match21", "(JJI)Z");
                        break;
                    }
                    case 22: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        byte[] bytes4 = new byte[4];
                        bytes4[0] = fieldName[19];
                        bytes4[1] = fieldName[20];
                        bytes4[2] = fieldName[21];
                        bytes4[3] = '"';
                        int name3 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name3 &= 0xFFFFFF;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.iconst_n(name3);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match22", "(JJI)Z");
                        break;
                    }
                    case 23: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        int name3 = UNSAFE.getInt(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.iconst_n(name3);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match23", "(JJI)Z");
                        break;
                    }
                    case 24: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        int name3 = UNSAFE.getInt(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.iconst_n(name3);
                        mw.visitLdcInsn(fieldName[23]);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match24", "(JJIB)Z");
                        break;
                    }
                    case 25: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);

                        byte[] bytes8 = new byte[8];
                        System.arraycopy(fieldName, 19, bytes8, 0, 6);
                        bytes8[6] = '"';
                        bytes8[7] = ':';
                        long name3 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name3 &= 0xFFFFFFFFFFFFL;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match25", "(JJJ)Z");
                        break;
                    }
                    case 26: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);

                        byte[] bytes8 = new byte[8];
                        System.arraycopy(fieldName, 19, bytes8, 0, 7);
                        bytes8[7] = '"';
                        long name3 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name3 &= 0xFFFFFFFFFFFFFFL;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match26", "(JJJ)Z");
                        break;
                    }
                    case 27: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match27", "(JJJ)Z");
                        break;
                    }
                    case 28: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(fieldName[27]);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match28", "(JJJB)Z");
                        break;
                    }
                    case 29: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        byte[] bytes4 = new byte[4];
                        bytes4[0] = fieldName[27];
                        bytes4[1] = fieldName[28];
                        bytes4[2] = '"';
                        bytes4[3] = ':';
                        int name4 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name4 &= 0xFFFF;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.iconst_n(name4);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match29", "(JJJI)Z");
                        break;
                    }
                    case 30: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        byte[] bytes4 = new byte[4];
                        bytes4[0] = fieldName[27];
                        bytes4[1] = fieldName[28];
                        bytes4[2] = fieldName[29];
                        bytes4[3] = '"';
                        int name4 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name4 &= 0xFFFFFF;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.iconst_n(name4);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match30", "(JJJI)Z");
                        break;
                    }
                    case 31: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        int name4 = UNSAFE.getInt(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.iconst_n(name4);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match31", "(JJJI)Z");
                        break;
                    }
                    case 32: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        int name4 = UNSAFE.getInt(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.iconst_n(fieldName[31]);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match32", "(JJJIB)Z");
                        break;
                    }
                    case 33: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        byte[] bytes8 = new byte[8];
                        System.arraycopy(fieldName, 27, bytes8, 0, 6);
                        bytes8[6] = '"';
                        bytes8[7] = ':';
                        long name4 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name4 &= 0xFFFFFFFFFFFFL;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match33", "(JJJJ)Z");
                        break;
                    }
                    case 34: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        byte[] bytes8 = new byte[8];
                        System.arraycopy(fieldName, 27, bytes8, 0, 7);
                        bytes8[7] = '"';
                        long name4 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name4 &= 0xFFFFFFFFFFFFFFL;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match34", "(JJJJ)Z");
                        break;
                    }
                    case 35: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        long name4 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);

                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match35", "(JJJJ)Z");
                        break;
                    }
                    case 36: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        long name4 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);

                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.iconst_n(fieldName[35]);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match36", "(JJJJB)Z");
                        break;
                    }
                    case 37: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        long name4 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);
                        byte[] bytes4 = new byte[4];
                        bytes4[0] = fieldName[35];
                        bytes4[1] = fieldName[36];
                        bytes4[2] = '"';
                        bytes4[3] = ':';
                        int name5 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name5 &= 0xFFFF;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.iconst_n(name5);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match37", "(JJJJI)Z");
                        break;
                    }
                    case 38: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        long name4 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);
                        byte[] bytes4 = new byte[4];
                        bytes4[0] = fieldName[35];
                        bytes4[1] = fieldName[36];
                        bytes4[2] = fieldName[37];
                        bytes4[3] = '"';
                        int name5 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name5 &= 0xFFFFFF;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.iconst_n(name5);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match38", "(JJJJI)Z");
                        break;
                    }
                    case 39: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        long name4 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);
                        int name5 = UNSAFE.getInt(fieldName, ARRAY_BYTE_BASE_OFFSET + 35);

                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.iconst_n(name5);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match39", "(JJJJI)Z");
                        break;
                    }
                    case 40: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        long name4 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);
                        int name5 = UNSAFE.getInt(fieldName, ARRAY_BYTE_BASE_OFFSET + 35);

                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.iconst_n(name5);
                        mw.iconst_n(fieldName[39]);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match40", "(JJJJIB)Z");
                        break;
                    }
                    case 41: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        long name4 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);

                        byte[] bytes8 = new byte[8];
                        System.arraycopy(fieldName, 35, bytes8, 0, 6);
                        bytes8[6] = '"';
                        bytes8[7] = ':';
                        long name5 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name5 &= 0xFFFFFFFFFFFFL;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.visitLdcInsn(name5);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match41", "(JJJJJ)Z");
                        break;
                    }
                    case 42: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        long name4 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);

                        byte[] bytes8 = new byte[8];
                        System.arraycopy(fieldName, 35, bytes8, 0, 7);
                        bytes8[7] = '"';
                        long name5 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                        if (jsonb) {
                            name5 &= 0xFFFFFFFFFFFFFFL;
                        }
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.visitLdcInsn(name5);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match42", "(JJJJJ)Z");
                        break;
                    }
                    case 43: {
                        long name1 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 3);
                        long name2 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 11);
                        long name3 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 19);
                        long name4 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 27);
                        long name5 = UNSAFE.getLong(fieldName, ARRAY_BYTE_BASE_OFFSET + 35);
                        mw.aload(JSON_READER);
                        mw.visitLdcInsn(name1);
                        mw.visitLdcInsn(name2);
                        mw.visitLdcInsn(name3);
                        mw.visitLdcInsn(name4);
                        mw.visitLdcInsn(name5);
                        mw.invokevirtual(TYPE_JSON_READER, "nextIfName4Match43", "(JJJJJ)Z");
                        break;
                    }
                    default:
                        throw new IllegalStateException("fieldNameLength " + fieldNameLength);
                }

                mw.ifeq(nextJ != null ? nextJ : hashCode64Start);
                genReadFieldValue(
                        context,
                        fieldReader,
                        fieldBased,
                        mwc,
                        OBJECT,
                        fieldReaderIndex,
                        false // arrayMapping
                );

                mw.goto_(L_FOR_INC);

                if (nextJ != null) {
                    mw.visitLabel(nextJ);
                }
            }

            mw.goto_(dflt);
        }

        mw.visitLabel(dflt);
    }

    private void genRead57(
            ObjectReadContext context,
            boolean fieldBased,
            MethodWriterContext mwc,
            int OBJECT,
            Label L_FOR_INC,
            Label hashCode64Start
    ) {
        FieldReader[] fieldReaderArray = context.fieldReaders;
        /*
         * long rawLong = jsonReader.getRawLong();
         * if (rawLong == 0) {
         *     goto hashCode64Start;
         * }
         */
        int RAW_LONG = mwc.var2("RAW_LONG");
        MethodWriter mw = mwc.mw;

        mw.aload(JSON_READER);
        mw.invokevirtual(TYPE_JSON_READER, "getRawLong", "()J");
        mw.dup2();
        mw.lstore(RAW_LONG);
        mw.lconst_0();
        mw.lcmp();
        mw.ifeq(hashCode64Start);

        for (int i = 0; i < fieldReaderArray.length; ++i) {
            Label next_ = new Label();
            FieldReader fieldReader = fieldReaderArray[i];
            byte[] fieldName = fieldReader.fieldName.getBytes(StandardCharsets.UTF_8);
            int fieldNameLength = fieldName.length;
            byte[] bytes8 = new byte[8];
            String nextMethodName;
            switch (fieldNameLength) {
                case 5:
                    bytes8[0] = '"';
                    System.arraycopy(fieldName, 0, bytes8, 1, 5);
                    bytes8[6] = '"';
                    bytes8[7] = ':';
                    nextMethodName = "nextIfName8Match0";
                    break;
                case 6:
                    bytes8[0] = '"';
                    System.arraycopy(fieldName, 0, bytes8, 1, 6);
                    bytes8[7] = '"';
                    nextMethodName = "nextIfName8Match1";
                    break;
                case 7:
                    bytes8[0] = '"';
                    System.arraycopy(fieldName, 0, bytes8, 1, 7);
                    nextMethodName = "nextIfName8Match2";
                    break;
                default:
                    throw new IllegalStateException("length " + fieldNameLength);
            }
            long rawLong = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
            mw.lload(RAW_LONG);
            mw.visitLdcInsn(rawLong);
            mw.lcmp();
            mw.ifne(next_);

            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, nextMethodName, "()Z");
            mw.ifeq(hashCode64Start);

            genReadFieldValue(
                    context,
                    fieldReader,
                    fieldBased,
                    mwc,
                    OBJECT,
                    i,
                    false // arrayMapping
            );

            mw.goto_(L_FOR_INC); // continue

            mw.visitLabel(next_);
        }
    }

    private <T> void genCreateObject(
            MethodWriter mw,
            ObjectReadContext context,
            String classNameType
    ) {
        Constructor defaultConstructor = context.defaultConstructor;
        Supplier creator = context.objectReaderAdapter.creator;
        Class objectClass = context.objectClass;

        int objectModifiers = objectClass == null ? Modifier.PUBLIC : objectClass.getModifiers();
        boolean publicObject = Modifier.isPublic(objectModifiers) && (objectClass == null || !classLoader.isExternalClass(objectClass));

        if (defaultConstructor == null || !publicObject || !Modifier.isPublic(defaultConstructor.getModifiers())) {
            if (creator != null) {
                mw.aload(THIS);
                mw.getfield(classNameType, "creator", "Ljava/util/function/Supplier;");
                mw.invokeinterface("java/util/function/Supplier", "get", "()Ljava/lang/Object;");
            } else {
                mw.aload(THIS);
                mw.aload(JSON_READER);
                mw.lload(FEATURES);
                mw.invokevirtual(TYPE_JSON_READER, "features", "(J)J");
                mw.invokevirtual(classNameType, "createInstance", "(J)Ljava/lang/Object;");
            }
            if (publicObject) {
                mw.checkcast(context.objectType);
            }
        } else {
            newObject(mw, context.objectType, context.defaultConstructor);
        }

        if (context.hasStringField) {
            /*
             * if ((features & JSONReader.Feature.InitStringFieldAsEmpty.mask) != 0) {
             *    this.initStringFieldAsEmpty(object);
             * }
             */
            Label L0 = new Label();
            mw.lload(FEATURES);
            mw.visitLdcInsn(JSONReader.Feature.InitStringFieldAsEmpty.mask);
            mw.land();
            mw.lconst_0();
            mw.lcmp();
            mw.ifeq(L0);

            mw.dup();
            mw.aload(THIS);
            mw.swap();
            mw.invokevirtual(classNameType, "initStringFieldAsEmpty", "(Ljava/lang/Object;)V");
            mw.visitLabel(L0);
        }
    }

    private <T> void genReadFieldValue(
            ObjectReadContext context,
            FieldReader fieldReader,
            boolean fieldBased,
            MethodWriterContext mwc,
            int OBJECT,
            int fieldReaderIndex,
            boolean arrayMapping
    ) {
        String classNameType = context.classNameType;
        boolean jsonb = mwc.jsonb;
        Class objectClass = context.objectClass;
        Class fieldClass = fieldReader.fieldClass;
        Type fieldType = fieldReader.fieldType;
        long fieldFeatures = fieldReader.features;
        String format = fieldReader.format;
        Type itemType = fieldReader.itemType;

        MethodWriter mw = mwc.mw;

        if ((fieldFeatures & JSONReader.Feature.NullOnError.mask) != 0) {
            mw.aload(THIS);
            mw.getfield(classNameType, fieldReader(fieldReaderIndex), DESC_FIELD_READER);
            mw.aload(JSON_READER);
            mw.aload(OBJECT);
            mw.invokevirtual(TYPE_FIELD_READE, "readFieldValue", METHOD_DESC_READ_FIELD_VALUE);
            return;
        }

        Field field = fieldReader.field;
        Method method = fieldReader.method;

        Label endSet_ = new Label();

        String TYPE_FIELD_CLASS = ASMUtils.type(fieldClass);
        String DESC_FIELD_CLASS = ASMUtils.desc(fieldClass);

        if (!(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
            mw.aload(OBJECT);
        }
        int fieldModifier = 0;
        if ((fieldBased || method == null) && field != null) {
            fieldModifier = field.getModifiers();
        }

        if (fieldBased
                && Modifier.isPublic(objectClass.getModifiers())
                && Modifier.isPublic(fieldModifier)
                && !Modifier.isFinal(fieldModifier)
                && !classLoader.isExternalClass(objectClass)
        ) {
            mw.checkcast(context.objectType);
        }

        if (fieldClass == boolean.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readBoolValue", "()Z");
        } else if (fieldClass == byte.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt32Value", "()I");
        } else if (fieldClass == short.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt32Value", "()I");
        } else if (fieldClass == int.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt32Value", "()I");
        } else if (fieldClass == long.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt64Value", "()J");
        } else if (fieldClass == float.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readFloatValue", "()F");
        } else if (fieldClass == double.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readDoubleValue", "()D");
        } else if (fieldClass == char.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readCharValue", "()C");
        } else if (fieldClass == String.class) {
            mw.aload(JSON_READER);
            Label null_ = new Label();

            mw.invokevirtual(TYPE_JSON_READER, "readString", "()Ljava/lang/String;");
            mw.dup();
            mw.ifnull(null_);

            if ("trim".equals(format)) {
                mw.invokevirtual("java/lang/String", "trim", "()Ljava/lang/String;");
            } else if ("upper".equals(format)) {
                mw.invokevirtual("java/lang/String", "toUpperCase", "()Ljava/lang/String;");
            }
            mw.visitLabel(null_);
        } else if (fieldClass == Boolean.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readBool", "()Ljava/lang/Boolean;");
        } else if (fieldClass == Byte.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt8", "()Ljava/lang/Byte;");
        } else if (fieldClass == Short.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt16", "()Ljava/lang/Short;");
        } else if (fieldClass == Integer.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt32", "()Ljava/lang/Integer;");
        } else if (fieldClass == Long.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt64", "()Ljava/lang/Long;");
        } else if (fieldClass == Float.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readFloat", "()Ljava/lang/Float;");
        } else if (fieldClass == Double.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readDouble", "()Ljava/lang/Double;");
        } else if (fieldClass == BigDecimal.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readBigDecimal", "()Ljava/math/BigDecimal;");
        } else if (fieldClass == BigInteger.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readBigInteger", "()Ljava/math/BigInteger;");
        } else if (fieldClass == Number.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readNumber", "()Ljava/lang/Number;");
        } else if (fieldClass == UUID.class) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readUUID", "()Ljava/util/UUID;");
        } else if (fieldClass == LocalDate.class && fieldReader.format == null) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readLocalDate", "()Ljava/time/LocalDate;");
        } else if (fieldClass == OffsetDateTime.class && fieldReader.format == null) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readOffsetDateTime", "()Ljava/time/OffsetDateTime;");
        } else if (fieldClass == Date.class && fieldReader.format == null) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readDate", "()Ljava/util/Date;");
        } else if (fieldClass == Calendar.class && fieldReader.format == null) {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readCalendar", "()Ljava/util/Calendar;");
        } else {
            Label endObject_ = new Label();

            boolean disableReferenceDetect = context.disableReferenceDetect();
            Integer REFERENCE = null;
            if (!disableReferenceDetect) {
                REFERENCE = mwc.var("REFERENCE");
            }

            if ((!disableReferenceDetect) && (!ObjectWriterProvider.isPrimitiveOrEnum(fieldClass))) {
                Label endReference_ = new Label(), addResolveTask_ = new Label();

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "isReference", "()Z");
                mw.ifeq(endReference_);

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "readReference", "()Ljava/lang/String;");
                if (context.objectClass == null || fieldClass.isAssignableFrom(context.objectClass)) {
                    mw.dup();
                    mw.astore(REFERENCE);
                    mw.visitLdcInsn("..");
                    mw.invokevirtual("java/lang/String", "equals", "(Ljava/lang/Object;)Z");
                    mw.ifeq(addResolveTask_);

                    if (objectClass != null && fieldClass.isAssignableFrom(objectClass)) {
                        mw.aload(OBJECT);
//                    mw.visitTypeInsn(CHECKCAST, TYPE_FIELD_CLASS); // cast
                        mw.goto_(endObject_);
                    }

                    mw.visitLabel(addResolveTask_);
                } else {
                    mw.astore(REFERENCE);
                }

                mw.aload(THIS);
                mw.getfield(classNameType, fieldReader(fieldReaderIndex), DESC_FIELD_READER);
                mw.aload(JSON_READER);
                mw.aload(OBJECT);
                mw.aload(REFERENCE);
                mw.invokevirtual(TYPE_FIELD_READE, "addResolveTask", METHOD_DESC_ADD_RESOLVE_TASK);
                mw.pop();
                mw.goto_(endSet_);

                mw.visitLabel(endReference_);
            }

            if (!fieldReader.fieldClassSerializable) {
                Label endIgnoreCheck_ = new Label();

                /*
                 * if ((features & Feature.IgnoreNoneSerializable.mask) != 0) {
                 *     jsonReader.skipValue();
                 *     goto endSet_;
                 * }
                 */
                mw.lload(FEATURES);
                mw.visitLdcInsn(JSONReader.Feature.IgnoreNoneSerializable.mask);
                mw.land();
                mw.lconst_0();
                mw.lcmp();
                mw.ifeq(endIgnoreCheck_);

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "skipValue", "()V");
                if (!(context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor)) {
                    mw.pop();
                }
                mw.goto_(endSet_);

                mw.visitLabel(endIgnoreCheck_);
            }

            boolean list = List.class.isAssignableFrom(fieldClass)
                    && fieldReader.getInitReader() == null
                    && !fieldClass.getName().startsWith("com.google.common.collect.Immutable");

            if (list) {
                Class itemClass = TypeUtils.getMapping(itemType);
                if (itemClass != null
                        && (Collection.class.isAssignableFrom(itemClass) || !Modifier.isPublic(itemClass.getModifiers()))
                ) {
                    list = false;
                }
            }

            if (list && !fieldClass.isInterface() && !BeanUtils.hasPublicDefaultConstructor(fieldClass)) {
                list = false;
            }

            if (list) {
                genReadFieldValueList(
                        fieldReader,
                        classNameType,
                        mwc,
                        OBJECT,
                        fieldReaderIndex,
                        arrayMapping,
                        objectClass,
                        fieldClass,
                        fieldType,
                        fieldFeatures,
                        itemType,
                        TYPE_FIELD_CLASS,
                        context,
                        fieldBased
                );
            } else {
                final String FIELD_OBJECT_READER = fieldObjectReader(fieldReaderIndex);

                Label valueNotNull_ = new Label();

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "nextIfNull", "()Z");
                mw.ifeq(valueNotNull_);

                if (fieldClass == Optional.class) {
                    mw.invokestatic("java/util/Optional", "empty", "()Ljava/util/Optional;");
                } else if (fieldClass == OptionalInt.class) {
                    mw.invokestatic("java/util/OptionalInt", "empty", "()Ljava/util/OptionalInt;");
                } else if (fieldClass == OptionalLong.class) {
                    mw.invokestatic("java/util/OptionalLong", "empty", "()Ljava/util/OptionalLong;");
                } else if (fieldClass == OptionalDouble.class) {
                    mw.invokestatic("java/util/OptionalDouble", "empty", "()Ljava/util/OptionalDouble;");
                } else {
                    mw.aconst_null();
                }
                mw.goto_(endObject_);

                mw.visitLabel(valueNotNull_);

                if (fieldClass == String[].class) {
                    mw.aload(JSON_READER);
                    mw.invokevirtual(TYPE_JSON_READER, "readStringArray", "()[Ljava/lang/String;");
                } else if (fieldClass == int[].class) {
                    mw.aload(JSON_READER);
                    mw.invokevirtual(TYPE_JSON_READER, "readInt32ValueArray", "()[I");
                } else if (fieldClass == long[].class) {
                    mw.aload(JSON_READER);
                    mw.invokevirtual(TYPE_JSON_READER, "readInt64ValueArray", "()[J");
                } else {
                    if (Enum.class.isAssignableFrom(fieldClass) & !jsonb) {
                        genReadEnumValueRaw(
                                fieldReader,
                                classNameType,
                                mwc,
                                fieldReaderIndex,
                                fieldType,
                                fieldClass,
                                fieldFeatures,
                                FIELD_OBJECT_READER
                        );
                    } else {
                        genReadObject(
                                fieldReader,
                                classNameType,
                                mwc,
                                fieldReaderIndex,
                                fieldType,
                                fieldFeatures,
                                FIELD_OBJECT_READER
                        );
                    }

                    if (method != null
                            || ((objectClass == null || Modifier.isPublic(objectClass.getModifiers()))
                            && Modifier.isPublic(fieldModifier)
                            && !Modifier.isFinal(fieldModifier)
                            && !classLoader.isExternalClass(objectClass))
                    ) {
                        mw.checkcast(TYPE_FIELD_CLASS); // cast
                    }

                    if (fieldReader.noneStaticMemberClass) {
                        try {
                            Field this0 = fieldClass.getDeclaredField("this$0");
                            long fieldOffset = UNSAFE.objectFieldOffset(this0);

                            Label notNull_ = new Label();
                            mw.dup();
                            mw.ifnull(notNull_);
                            mw.dup();
                            mw.getstatic(TYPE_UNSAFE_UTILS, "UNSAFE", "Lsun/misc/Unsafe;");
                            mw.swap();
                            mw.visitLdcInsn(fieldOffset);
                            mw.aload(OBJECT);
                            mw.invokevirtual("sun/misc/Unsafe", "putObject", "(Ljava/lang/Object;JLjava/lang/Object;)V");
                            mw.visitLabel(notNull_);
                        } catch (NoSuchFieldException e) {
                            // ignored
                        }
                    }
                }
            }

            mw.visitLabel(endObject_);
        }

        if (field != null) {
            String fieldClassName = fieldClass.getName();
            boolean setDirect = (objectClass.getModifiers() & Modifier.PUBLIC) != 0
                    && (fieldModifier & Modifier.PUBLIC) != 0
                    && (fieldModifier & Modifier.FINAL) == 0
                    && (ObjectWriterProvider.isPrimitiveOrEnum(fieldClass) || fieldClassName.startsWith("java.") || fieldClass.getClassLoader() == ObjectReaderProvider.FASTJSON2_CLASS_LOADER)
                    && !classLoader.isExternalClass(objectClass)
                    && field.getDeclaringClass() == objectClass;
            if (setDirect) {
                mw.putfield(context.objectType, field.getName(), DESC_FIELD_CLASS);
            } else {
                int FIELD_VALUE = mwc.var(fieldClass);

                String methodName, methodDes;
                int LOAD;
                if (fieldClass == int.class) {
                    methodName = "putInt";
                    methodDes = "(Ljava/lang/Object;JI)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == long.class) {
                    methodName = "putLong";
                    methodDes = "(Ljava/lang/Object;JJ)V";
                    mw.lstore(FIELD_VALUE);
                    LOAD = Opcodes.LLOAD;
                } else if (fieldClass == float.class) {
                    methodName = "putFloat";
                    methodDes = "(Ljava/lang/Object;JF)V";
                    mw.fstore(FIELD_VALUE);
                    LOAD = Opcodes.FLOAD;
                } else if (fieldClass == double.class) {
                    methodName = "putDouble";
                    methodDes = "(Ljava/lang/Object;JD)V";
                    mw.dstore(FIELD_VALUE);
                    LOAD = Opcodes.DLOAD;
                } else if (fieldClass == char.class) {
                    methodName = "putChar";
                    methodDes = "(Ljava/lang/Object;JC)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == byte.class) {
                    methodName = "putByte";
                    methodDes = "(Ljava/lang/Object;JB)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == short.class) {
                    methodName = "putShort";
                    methodDes = "(Ljava/lang/Object;JS)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == boolean.class) {
                    methodName = "putBoolean";
                    methodDes = "(Ljava/lang/Object;JZ)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else {
                    methodName = "putObject";
                    methodDes = "(Ljava/lang/Object;JLjava/lang/Object;)V";
                    mw.astore(FIELD_VALUE);
                    LOAD = Opcodes.ALOAD;
                }

                mw.getstatic(TYPE_UNSAFE_UTILS, "UNSAFE", "Lsun/misc/Unsafe;");
                mw.swap();

                mw.visitLdcInsn(
                        UNSAFE.objectFieldOffset(field));
                mw.visitVarInsn(LOAD, FIELD_VALUE);
                mw.invokevirtual("sun/misc/Unsafe", methodName, methodDes);
            }
        } else if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
            if (!fieldClass.isPrimitive()) {
                mw.checkcast(ASMUtils.type(fieldClass));
            }
            mw.storeLocal(fieldClass, mwc.var(fieldReader));
        } else {
            boolean invokeFieldReaderAccept = context.externalClass || method == null || !context.publicClass;

            if (invokeFieldReaderAccept) {
                int FIELD_VALUE = mwc.var(fieldClass);

                String acceptMethodDesc;
                int LOAD;
                if (fieldClass == boolean.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;Z)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == byte.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;B)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == short.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;S)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == int.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;I)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == long.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;J)V";
                    mw.lstore(FIELD_VALUE);
                    LOAD = Opcodes.LLOAD;
                } else if (fieldClass == char.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;C)V";
                    mw.istore(FIELD_VALUE);
                    LOAD = Opcodes.ILOAD;
                } else if (fieldClass == float.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;F)V";
                    mw.fstore(FIELD_VALUE);
                    LOAD = Opcodes.FLOAD;
                } else if (fieldClass == double.class) {
                    acceptMethodDesc = "(Ljava/lang/Object;D)V";
                    mw.dstore(FIELD_VALUE);
                    LOAD = Opcodes.DLOAD;
                } else {
                    acceptMethodDesc = "(Ljava/lang/Object;Ljava/lang/Object;)V";
                    mw.astore(FIELD_VALUE);
                    LOAD = Opcodes.ALOAD;
                }

                mw.aload(THIS);
                mw.getfield(classNameType, fieldReader(fieldReaderIndex), DESC_FIELD_READER);
                BiConsumer function = fieldReader.getFunction();
                if (function instanceof FieldBiConsumer) {
                    FieldBiConsumer fieldBiConsumer = (FieldBiConsumer) function;
                    mw.invokevirtual(TYPE_FIELD_READE, "getFunction", "()Ljava/util/function/BiConsumer;");
                    mw.checkcast(type(FieldBiConsumer.class));
                    mw.getfield(type(FieldBiConsumer.class), "consumer", desc(FieldConsumer.class));
                    mw.swap();
                    mw.visitLdcInsn(fieldBiConsumer.fieldIndex);
                    mw.visitVarInsn(LOAD, FIELD_VALUE);
                    mw.invokeinterface(type(FieldConsumer.class), "accept", "(Ljava/lang/Object;ILjava/lang/Object;)V");
                } else {
                    mw.swap();
                    mw.visitVarInsn(LOAD, FIELD_VALUE);
                    mw.invokevirtual(TYPE_FIELD_READE, "accept", acceptMethodDesc);
                }
            } else {
                Class<?> returnType = method.getReturnType();
                String methodName = method.getName();

                String methodDesc = null;
                if (returnType == Void.TYPE) {
                    if (fieldClass == boolean.class) {
                        methodDesc = "(Z)V";
                    } else if (fieldClass == byte.class) {
                        methodDesc = "(B)V";
                    } else if (fieldClass == short.class) {
                        methodDesc = "(S)V";
                    } else if (fieldClass == int.class) {
                        methodDesc = "(I)V";
                    } else if (fieldClass == long.class) {
                        methodDesc = "(J)V";
                    } else if (fieldClass == char.class) {
                        methodDesc = "(C)V";
                    } else if (fieldClass == float.class) {
                        methodDesc = "(F)V";
                    } else if (fieldClass == double.class) {
                        methodDesc = "(D)V";
                    } else if (fieldClass == Boolean.class) {
                        methodDesc = "(Ljava/lang/Boolean;)V";
                    } else if (fieldClass == Integer.class) {
                        methodDesc = "(Ljava/lang/Integer;)V";
                    } else if (fieldClass == Long.class) {
                        methodDesc = "(Ljava/lang/Long;)V";
                    } else if (fieldClass == Float.class) {
                        methodDesc = "(Ljava/lang/Float;)V";
                    } else if (fieldClass == Double.class) {
                        methodDesc = "(Ljava/lang/Double;)V";
                    } else if (fieldClass == BigDecimal.class) {
                        methodDesc = "(Ljava/math/BigDecimal;)V";
                    } else if (fieldClass == String.class) {
                        methodDesc = "(Ljava/lang/String;)V";
                    } else if (fieldClass == UUID.class) {
                        methodDesc = "(Ljava/util/UUID;)V";
                    } else if (fieldClass == List.class) {
                        methodDesc = "(Ljava/util/List;)V";
                    } else if (fieldClass == Map.class) {
                        methodDesc = "(Ljava/util/Map;)V";
                    }
                }

                if (methodDesc == null) {
                    methodDesc = "(" + DESC_FIELD_CLASS + ")" + ASMUtils.desc(returnType);
                }
                mw.invokevirtual(context.objectType, methodName, methodDesc);
                if (returnType != void.class) {
                    mw.pop();
                }
            }
            // TODO BUILD METHOD
        }

        mw.visitLabel(endSet_);
    }

    private void genReadObject(
            FieldReader fieldReader,
            String classNameType,
            MethodWriterContext mwc,
            int i,
            Type fieldType,
            long fieldFeatures,
            String FIELD_OBJECT_READER
    ) {
        // object.<setMethod>(this.objectReader_<i>.readObject(jsonReader))
        Label notNull_ = new Label();
        MethodWriter mw = mwc.mw;
        boolean jsonb = mwc.jsonb;

        mw.aload(THIS);
        mw.getfield(classNameType, FIELD_OBJECT_READER, DESC_OBJECT_READER);
        mw.ifnonnull(notNull_);

        mw.aload(THIS);
        mw.aload(THIS);
        mw.getfield(classNameType, fieldReader(i), DESC_FIELD_READER);
        mw.aload(JSON_READER);
        mw.invokevirtual(TYPE_FIELD_READE, "getObjectReader", METHOD_DESC_GET_OBJECT_READER_1);
        mw.putfield(classNameType, FIELD_OBJECT_READER, DESC_OBJECT_READER);

        mw.visitLabel(notNull_);
        mw.aload(THIS);
        mw.getfield(classNameType, FIELD_OBJECT_READER, DESC_OBJECT_READER);

        mw.aload(JSON_READER);
        gwGetFieldType(classNameType, mw, i, fieldType);
        mw.visitLdcInsn(fieldReader.fieldName);
        mw.visitLdcInsn(fieldFeatures);
        mw.invokeinterface(
                TYPE_OBJECT_READER,
                jsonb ? "readJSONBObject" : "readObject",
                METHOD_DESC_READ_OBJECT);
    }

    private void genReadEnumValueRaw(
            FieldReader fieldReader,
            String classNameType,
            MethodWriterContext mwc,
            int fieldIndex,
            Type fieldType,
            Class fieldClass,
            long fieldFeatures,
            String FIELD_OBJECT_READER
    ) {
        MethodWriter mw = mwc.mw;
        boolean jsonb = mwc.jsonb;
        Object[] enums = fieldClass.getEnumConstants();

        Map<Integer, List<Enum>> name0Map = new TreeMap<>();
        int nameLengthMin = 0, nameLengthMax = 0;
        if (enums != null) {
            for (int i = 0; i < enums.length; i++) {
                Enum e = (Enum) enums[i];
                byte[] enumName = e.name().getBytes(StandardCharsets.UTF_8);
                int nameLength = enumName.length;
                if (i == 0) {
                    nameLengthMin = nameLength;
                    nameLengthMax = nameLength;
                } else {
                    nameLengthMin = Math.min(nameLength, nameLengthMin);
                    nameLengthMax = Math.max(nameLength, nameLengthMax);
                }

                byte[] name0Bytes = new byte[4];
                name0Bytes[0] = '"';
                if (enumName.length == 2) {
                    System.arraycopy(enumName, 0, name0Bytes, 1, 2);
                    name0Bytes[3] = '"';
                } else if (enumName.length >= 3) {
                    System.arraycopy(enumName, 0, name0Bytes, 1, 3);
                }
                int name0 = UNSAFE.getInt(name0Bytes, ARRAY_BYTE_BASE_OFFSET);

                List<Enum> enumList = name0Map.get(name0);
                if (enumList == null) {
                    enumList = new ArrayList<>();
                    name0Map.put(name0, enumList);
                }
                enumList.add(e);
            }
        }

        Label dflt = new Label(), enumEnd = new Label();

        Label notNull_ = new Label();

        mw.aload(THIS);
        mw.getfield(classNameType, FIELD_OBJECT_READER, DESC_OBJECT_READER);
        mw.ifnonnull(notNull_);

        mw.aload(THIS);
        mw.aload(THIS);
        mw.getfield(classNameType, fieldReader(fieldIndex), DESC_FIELD_READER);
        mw.aload(JSON_READER);
        mw.invokevirtual(TYPE_FIELD_READE, "getObjectReader", METHOD_DESC_GET_OBJECT_READER_1);
        mw.putfield(classNameType, FIELD_OBJECT_READER, DESC_OBJECT_READER);

        mw.visitLabel(notNull_);
        mw.aload(THIS);
        mw.getfield(classNameType, FIELD_OBJECT_READER, DESC_OBJECT_READER);
        mw.instanceOf(type(ObjectReaderImplEnum.class));
        mw.ifeq(dflt);

        if (nameLengthMin >= 2 && nameLengthMax <= 11) {
            int[] switchKeys = new int[name0Map.size()];
            Label[] labels = new Label[name0Map.size()];
            {
                Iterator it = name0Map.keySet().iterator();
                for (int j = 0; j < labels.length; j++) {
                    labels[j] = new Label();
                    switchKeys[j] = (Integer) it.next();
                }
            }

            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "getRawInt", "()I");
            mw.visitLookupSwitchInsn(dflt, switchKeys, labels);

            for (int i = 0; i < labels.length; i++) {
                mw.visitLabel(labels[i]);

                int name0 = switchKeys[i];
                List<Enum> enumList = name0Map.get(name0);
                for (int j = 0; j < enumList.size(); j++) {
                    Label nextJ = null;
                    if (j > 0) {
                        nextJ = new Label();
                    }

                    Enum e = enumList.get(j);
                    byte[] enumName = e.name().getBytes(StandardCharsets.UTF_8);
                    int fieldNameLength = enumName.length;
                    switch (fieldNameLength) {
                        case 2:
                            mw.aload(JSON_READER);
                            mw.invokevirtual(TYPE_JSON_READER, "nextIfValue4Match2", "()Z");
                            break;
                        case 3:
                            mw.aload(JSON_READER);
                            mw.invokevirtual(TYPE_JSON_READER, "nextIfValue4Match3", "()Z");
                            break;
                        case 4: {
                            mw.aload(JSON_READER);
                            mw.visitLdcInsn(enumName[3]);
                            mw.invokevirtual(TYPE_JSON_READER, "nextIfValue4Match4", "(B)Z");
                            break;
                        }
                        case 5: {
                            mw.aload(JSON_READER);
                            mw.visitLdcInsn(enumName[3]);
                            mw.visitLdcInsn(enumName[4]);
                            mw.invokevirtual(TYPE_JSON_READER, "nextIfValue4Match5", "(BB)Z");
                            break;
                        }
                        case 6: {
                            byte[] bytes4 = new byte[4];
                            bytes4[0] = enumName[3];
                            bytes4[1] = enumName[4];
                            bytes4[2] = enumName[5];
                            bytes4[3] = '"';
                            int name1 = UNSAFE.getInt(bytes4, ARRAY_BYTE_BASE_OFFSET);
                            mw.aload(JSON_READER);
                            mw.visitLdcInsn(name1);
                            mw.invokevirtual(TYPE_JSON_READER, "nextIfValue4Match6", "(I)Z");
                            break;
                        }
                        case 7: {
                            int name1 = UNSAFE.getInt(enumName, ARRAY_BYTE_BASE_OFFSET + 3);
                            mw.aload(JSON_READER);
                            mw.visitLdcInsn(name1);
                            mw.invokevirtual(TYPE_JSON_READER, "nextIfValue4Match7", "(I)Z");
                            break;
                        }
                        case 8: {
                            int name1 = UNSAFE.getInt(enumName, ARRAY_BYTE_BASE_OFFSET + 3);
                            mw.aload(JSON_READER);
                            mw.visitLdcInsn(name1);
                            mw.visitLdcInsn(enumName[7]);
                            mw.invokevirtual(TYPE_JSON_READER, "nextIfValue4Match8", "(IB)Z");
                            break;
                        }
                        case 9: {
                            int name1 = UNSAFE.getInt(enumName, ARRAY_BYTE_BASE_OFFSET + 3);
                            mw.aload(JSON_READER);
                            mw.visitLdcInsn(name1);
                            mw.visitLdcInsn(enumName[7]);
                            mw.visitLdcInsn(enumName[8]);
                            mw.invokevirtual(TYPE_JSON_READER, "nextIfValue4Match9", "(IBB)Z");
                            break;
                        }
                        case 10: {
                            byte[] bytes8 = new byte[8];
                            System.arraycopy(enumName, 3, bytes8, 0, 7);
                            bytes8[7] = '"';
                            long name1 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                            mw.aload(JSON_READER);
                            mw.visitLdcInsn(name1);
                            mw.invokevirtual(TYPE_JSON_READER, "nextIfValue4Match10", "(J)Z");
                            break;
                        }
                        case 11: {
                            byte[] bytes8 = new byte[8];
                            System.arraycopy(enumName, 3, bytes8, 0, 8);
                            long name1 = UNSAFE.getLong(bytes8, ARRAY_BYTE_BASE_OFFSET);
                            mw.aload(JSON_READER);
                            mw.visitLdcInsn(name1);
                            mw.invokevirtual(TYPE_JSON_READER, "nextIfValue4Match11", "(J)Z");
                            break;
                        }
                        default:
                            throw new IllegalStateException("fieldNameLength " + fieldNameLength);
                    }

                    mw.ifeq(nextJ != null ? nextJ : dflt);

                    mw.aload(THIS);
                    mw.getfield(classNameType, FIELD_OBJECT_READER, DESC_OBJECT_READER);
                    mw.checkcast(type(ObjectReaderImplEnum.class));
                    mw.visitLdcInsn(e.ordinal());
                    mw.invokevirtual(type(ObjectReaderImplEnum.class), "getEnumByOrdinal", "(I)Ljava/lang/Enum;");
                    mw.goto_(enumEnd);

                    if (nextJ != null) {
                        mw.visitLabel(nextJ);
                    }
                }

                mw.goto_(dflt);
            }
        }

        mw.visitLabel(dflt);

        mw.aload(THIS);
        mw.getfield(classNameType, FIELD_OBJECT_READER, DESC_OBJECT_READER);
        mw.aload(JSON_READER);
        gwGetFieldType(classNameType, mw, fieldIndex, fieldType);
        mw.visitLdcInsn(fieldReader.fieldName);
        mw.visitLdcInsn(fieldFeatures);
        mw.invokeinterface(
                TYPE_OBJECT_READER,
                jsonb ? "readJSONBObject" : "readObject",
                METHOD_DESC_READ_OBJECT);

        mw.visitLabel(enumEnd);
    }

    private void genReadFieldValueList(
            FieldReader fieldReader,
            String classNameType,
            MethodWriterContext mwc,
            int OBJECT,
            int i,
            boolean arrayMapping,
            Class objectClass,
            Class fieldClass,
            Type fieldType,
            long fieldFeatures,
            Type itemType,
            String TYPE_FIELD_CLASS,
            ObjectReadContext context,
            boolean fieldBased
    ) {
        boolean jsonb = mwc.jsonb;
        if (itemType == null) {
            itemType = Object.class;
        }

        Class itemClass = TypeUtils.getMapping(itemType);
        String ITEM_OBJECT_READER = fieldItemObjectReader(i);
        MethodWriter mw = mwc.mw;

        int LIST;
        if (context.objectReaderAdapter instanceof ObjectReaderNoneDefaultConstructor) {
            LIST = mwc.var(fieldReader);
        } else {
            LIST = mwc.var(fieldClass);
        }
        Integer AUTO_TYPE_OBJECT_READER = mwc.var(ObjectReader.class);

        String LIST_TYPE = fieldClass.isInterface() ? "java/util/ArrayList" : TYPE_FIELD_CLASS;

        Label loadList_ = new Label(), listNotNull_ = new Label(), listInitEnd_ = new Label();

        boolean initCapacity = JVM_VERSION == 8 && "java/util/ArrayList".equals(LIST_TYPE);
        int ITEM_CNT = mwc.var("ITEM_CNT");

        if (jsonb) {
            if (!context.disableAutoType()) {
                Label checkAutoTypeNull_ = new Label();

                mw.aload(THIS);
                mw.getfield(classNameType, fieldReader(i), DESC_FIELD_READER);
                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_FIELD_READE, "checkObjectAutoType", METHOD_DESC_CHECK_ARRAY_AUTO_TYPE);
                mw.dup();
                mw.astore(AUTO_TYPE_OBJECT_READER);
                mw.ifnull(checkAutoTypeNull_);

                mw.aload(AUTO_TYPE_OBJECT_READER);
                mw.aload(JSON_READER);
                gwGetFieldType(classNameType, mw, i, fieldType);
                mw.visitLdcInsn(fieldReader.fieldName);
                mw.visitLdcInsn(fieldFeatures);
                mw.invokeinterface(TYPE_OBJECT_READER, "readJSONBObject", METHOD_DESC_READ_OBJECT);
                mw.checkcast(TYPE_FIELD_CLASS);
                mw.astore(LIST);
                mw.goto_(loadList_);

                mw.visitLabel(checkAutoTypeNull_);
            }

            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "startArray", "()I");
            mw.dup();
            mw.istore(ITEM_CNT);
            mw.visitLdcInsn(-1);
            mw.if_icmpne(listNotNull_);

            mw.aconst_null();
            mw.astore(LIST);
            mw.goto_(loadList_);

            mw.visitLabel(listNotNull_);

            if (fieldReader.method == null && fieldReader.field != null) {
                long fieldOffset = UNSAFE.objectFieldOffset(fieldReader.field);
                mw.getstatic(TYPE_UNSAFE_UTILS, "UNSAFE", "Lsun/misc/Unsafe;");
                mw.aload(OBJECT);
                mw.visitLdcInsn(fieldOffset);
                mw.invokevirtual("sun/misc/Unsafe", "getObject", "(Ljava/lang/Object;J)Ljava/lang/Object;");
                mw.dup();
                mw.checkcast(TYPE_FIELD_CLASS);
                mw.astore(LIST);
                Label listNull_ = new Label();
                mw.ifnull(listNull_);

                mw.aload(LIST);
                mw.invokevirtual("java/lang/Object", "getClass", "()Ljava/lang/Class;");
                mw.getstatic("java/util/Collections", "EMPTY_LIST", "Ljava/util/List;");
                mw.invokevirtual("java/lang/Object", "getClass", "()Ljava/lang/Class;");
                mw.if_acmpne(listInitEnd_);
                mw.visitLabel(listNull_);
            }

            mw.new_(LIST_TYPE);
            mw.dup();
            if (initCapacity) {
                mw.iload(ITEM_CNT);
                mw.invokespecial(LIST_TYPE, "<init>", "(I)V");
            } else {
                mw.invokespecial(LIST_TYPE, "<init>", "()V");
            }
            mw.astore(LIST);
            mw.visitLabel(listInitEnd_);
        } else {
            Label match_ = new Label(), skipValue_ = new Label(), loadNull_ = new Label();

            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "nextIfNull", "()Z");
            mw.ifne(loadNull_);

            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "nextIfArrayStart", "()Z");
            mw.ifne(match_);

            if (itemClass == String.class) {
                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "isString", "()Z");
                mw.ifeq(skipValue_);

                mw.new_(LIST_TYPE);
                mw.dup();
                if (initCapacity) {
                    mw.visitLdcInsn(10);
                    mw.invokespecial(LIST_TYPE, "<init>", "(I)V");
                } else {
                    mw.invokespecial(LIST_TYPE, "<init>", "()V");
                }
                mw.astore(LIST);

                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "nextIfNullOrEmptyString", "()Z");
                mw.ifne(loadList_);

                mw.aload(LIST);
                mw.aload(JSON_READER);
                if (itemClass == String.class) {
                    mw.invokevirtual(TYPE_JSON_READER, "readString", "()Ljava/lang/String;");
                }
                mw.invokeinterface("java/util/List", "add", "(Ljava/lang/Object;)Z");
                mw.pop();

                mw.goto_(loadList_);
            } else if (itemType instanceof Class) {
                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "nextIfNullOrEmptyString", "()Z");
                mw.ifne(loadNull_);

                // nextIfNullOrEmptyString
                mw.new_(LIST_TYPE);
                mw.dup();
                if (initCapacity) {
                    mw.visitLdcInsn(10);
                    mw.invokespecial(LIST_TYPE, "<init>", "(I)V");
                } else {
                    mw.invokespecial(LIST_TYPE, "<init>", "()V");
                }
                mw.astore(LIST);

                mw.aload(JSON_READER);
                mw.aload(LIST);
                mw.visitLdcInsn((Class) itemType);
                mw.invokevirtual(TYPE_JSON_READER, "readArray", "(Ljava/util/List;Ljava/lang/reflect/Type;)V");

                mw.goto_(loadList_);
            }

            mw.visitLabel(skipValue_);
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "skipValue", "()V");

            mw.visitLabel(loadNull_);
            mw.aconst_null();
            mw.astore(LIST);
            mw.goto_(loadList_);

            mw.visitLabel(match_);
            mw.new_(LIST_TYPE);
            mw.dup();
            if (initCapacity) {
                mw.visitLdcInsn(10);
                mw.invokespecial(LIST_TYPE, "<init>", "(I)V");
            } else {
                mw.invokespecial(LIST_TYPE, "<init>", "()V");
            }
            mw.astore(LIST);
        }

        int J = mwc.var("J");
        Label for_start_j_ = new Label(), for_end_j_ = new Label(), for_inc_j_ = new Label();
        mw.iconst_0();
        mw.istore(J);

        mw.visitLabel(for_start_j_);

        if (jsonb) {
            // j < item_cnt
            mw.iload(J);
            mw.iload(ITEM_CNT);
            mw.if_icmpge(for_end_j_);
        } else {
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "nextIfArrayEnd", "()Z");
            mw.ifne(for_end_j_);
        }

        if (itemType == String.class) {
            mw.aload(LIST);
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readString", "()Ljava/lang/String;");
        } else if (itemType == Integer.class) {
            mw.aload(LIST);
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt32", "()Ljava/lang/Integer;");
        } else if (itemType == Long.class) {
            mw.aload(LIST);
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_JSON_READER, "readInt64", "()Ljava/lang/Long;");
        } else {
            Label notNull_ = new Label();

            mw.aload(THIS);
            mw.getfield(classNameType, ITEM_OBJECT_READER, DESC_OBJECT_READER);
            mw.ifnonnull(notNull_);

            mw.aload(THIS);
            mw.aload(THIS);
            mw.getfield(classNameType, fieldReader(i), DESC_FIELD_READER);
            mw.aload(JSON_READER);
            mw.invokevirtual(TYPE_FIELD_READE, "getItemObjectReader", METHOD_DESC_GET_ITEM_OBJECT_READER);

            mw.putfield(classNameType, ITEM_OBJECT_READER, DESC_OBJECT_READER);

            mw.visitLabel(notNull_);

            if (!context.disableReferenceDetect()) {
                mw.aload(JSON_READER);
                mw.aload(LIST);
                mw.iload(J);
                mw.invokevirtual(TYPE_JSON_READER, "readReference", "(Ljava/util/List;I)Z");
                mw.ifne(for_inc_j_);
            }
            mw.aload(LIST);

            Label readObject_ = new Label(), readObjectEnd_ = new Label();
            if (arrayMapping) {
                mw.aload(JSON_READER);
                mw.invokevirtual(TYPE_JSON_READER, "isArray", "()Z");
                mw.ifeq(readObject_);

                mw.aload(THIS);
                mw.getfield(classNameType, ITEM_OBJECT_READER, DESC_OBJECT_READER);

                mw.aload(JSON_READER);
                gwGetFieldType(classNameType, mw, i, fieldType);
                mw.visitLdcInsn(fieldReader.fieldName);
                mw.lload(FEATURES);
                mw.invokeinterface(
                        TYPE_OBJECT_READER,
                        jsonb ? "readArrayMappingJSONBObject" : "readArrayMappingObject",
                        METHOD_DESC_READ_OBJECT);

                mw.goto_(readObjectEnd_);

                mw.visitLabel(readObject_);
            }

            mw.aload(THIS);
            mw.getfield(classNameType, ITEM_OBJECT_READER, DESC_OBJECT_READER);

            mw.aload(JSON_READER);
            gwGetFieldType(classNameType, mw, i, fieldType);
            mw.visitLdcInsn(fieldReader.fieldName);
            mw.lload(FEATURES);
            mw.invokeinterface(
                    TYPE_OBJECT_READER,
                    jsonb ? "readJSONBObject" : "readObject",
                    METHOD_DESC_READ_OBJECT);

            if (arrayMapping) {
                mw.visitLabel(readObjectEnd_);
            }
        }
        mw.invokeinterface("java/util/List", "add", "(Ljava/lang/Object;)Z");
        mw.pop();

        mw.visitLabel(for_inc_j_);
        mw.visitIincInsn(J, 1);
        mw.goto_(for_start_j_);

        mw.visitLabel(for_end_j_);

        mw.visitLabel(loadList_);
        mw.aload(LIST);
    }

    private void gwGetFieldType(String classNameType, MethodWriter mw, int i, Type fieldType) {
        if (fieldType instanceof Class) {
            Class fieldClass = (Class) fieldType;
            String fieldClassName = fieldClass.getName();
            boolean publicClass = Modifier.isPublic(fieldClass.getModifiers());
            boolean internalClass = fieldClassName.startsWith("java.")
                    || fieldClass == JSONArray.class
                    || fieldClass == JSONObject.class;
            if (publicClass && internalClass) {
                mw.visitLdcInsn((Class) fieldType);
                return;
            }
        }

        mw.aload(THIS);
        mw.getfield(classNameType, fieldReader(i), DESC_FIELD_READER);
        mw.getfield(TYPE_FIELD_READE, "fieldType", "Ljava/lang/reflect/Type;");
    }

    static class ObjectReadContext {
        final BeanInfo beanInfo;
        final Class objectClass;
        final ClassWriter cw;
        final boolean publicClass;
        final boolean externalClass;
        final FieldReader[] fieldReaders;
        final boolean hasStringField;
        final int fieldNameLengthMin;
        final int fieldNameLengthMax;
        final String classNameType;
        final String classNameFull;
        final Constructor defaultConstructor;
        ObjectReaderAdapter objectReaderAdapter;
        final String objectType;

        public ObjectReadContext(
                BeanInfo beanInfo,
                Class objectClass,
                ClassWriter cw,
                boolean externalClass,
                FieldReader[] fieldReaders,
                Constructor defaultConstructor
        ) {
            this.beanInfo = beanInfo;
            this.objectClass = objectClass;
            this.cw = cw;
            this.publicClass = objectClass == null || Modifier.isPublic(objectClass.getModifiers());
            this.externalClass = externalClass;
            this.fieldReaders = fieldReaders;
            this.defaultConstructor = defaultConstructor;
            this.objectType = objectClass == null ? ASMUtils.TYPE_OBJECT : ASMUtils.type(objectClass);

            int fieldNameLengthMin = 0, fieldNameLengthMax = 0;
            boolean hasStringField = false;
            for (int i = 0; i < fieldReaders.length; i++) {
                FieldReader fieldReader = fieldReaders[i];
                if (fieldReader.fieldClass == String.class) {
                    hasStringField = true;
                }

                byte[] nameUTF8 = fieldReader.fieldName.getBytes(StandardCharsets.UTF_8);
                int fieldNameLength = nameUTF8.length;
                for (byte ch : nameUTF8) {
                    if (ch <= 0) {
                        fieldNameLength = -1;
                        break;
                    }
                }

                if (i == 0) {
                    fieldNameLengthMin = fieldNameLength;
                    fieldNameLengthMax = fieldNameLength;
                } else {
                    fieldNameLengthMin = Math.min(fieldNameLength, fieldNameLengthMin);
                    fieldNameLengthMax = Math.max(fieldNameLength, fieldNameLengthMax);
                }
            }
            this.hasStringField = hasStringField;
            this.fieldNameLengthMin = fieldNameLengthMin;
            this.fieldNameLengthMax = fieldNameLengthMax;

            String className = "ORG_" + seed.incrementAndGet() + "_" + fieldReaders.length + (objectClass == null ? "" : "_" + objectClass.getSimpleName());

            Package pkg = ObjectReaderCreatorASM.class.getPackage();
            if (pkg != null) {
                classNameFull = packageName + '.' + className;
                classNameType = classNameFull.replace('.', '/');
            } else {
                classNameType = className;
                classNameFull = className;
            }
        }

        public boolean disableSupportArrayMapping() {
            return (beanInfo.readerFeatures & FieldInfo.DISABLE_ARRAY_MAPPING) != 0;
        }

        public boolean disableReferenceDetect() {
            return (beanInfo.readerFeatures & FieldInfo.DISABLE_REFERENCE_DETECT) != 0;
        }

        public boolean disableAutoType() {
            return (beanInfo.readerFeatures & FieldInfo.DISABLE_AUTO_TYPE) != 0;
        }

        public boolean disableJSONB() {
            return (beanInfo.readerFeatures & FieldInfo.DISABLE_JSONB) != 0;
        }

        public boolean disableSmartMatch() {
            return (beanInfo.readerFeatures & FieldInfo.DISABLE_SMART_MATCH) != 0;
        }
    }

    public Function<Consumer, ByteArrayValueConsumer> createByteArrayValueConsumerCreator(
            Class objectClass,
            FieldReader[] fieldReaderArray
    ) {
        return createValueConsumer0(objectClass, fieldReaderArray, true);
    }

    public Function<Consumer, CharArrayValueConsumer> createCharArrayValueConsumerCreator(
            Class objectClass,
            FieldReader[] fieldReaderArray
    ) {
        return createValueConsumer0(objectClass, fieldReaderArray, false);
    }

    private Function createValueConsumer0(
            Class objectClass,
            FieldReader[] fieldReaderArray,
            boolean bytes
    ) {
        Constructor defaultConstructor = BeanUtils.getDefaultConstructor(objectClass, false);
        if (defaultConstructor == null || !Modifier.isPublic(objectClass.getModifiers())) {
            return null;
        }

        ClassWriter cw = new ClassWriter(
                (e) -> objectClass.getName().equals(e) ? objectClass : null
        );

        String className = (bytes ? "VBACG_" : "VCACG_")
                + seed.incrementAndGet()
                + "_" + fieldReaderArray.length
                + "_" + objectClass.getSimpleName();
        String classNameType;
        String classNameFull;

        Package pkg = ObjectReaderCreatorASM.class.getPackage();
        if (pkg != null) {
            classNameFull = packageName + '.' + className;
            classNameType = classNameFull.replace('.', '/');
        } else {
            classNameType = className;
            classNameFull = className;
        }

        String TYPE_OBJECT = ASMUtils.type(objectClass);
        String DESC_OBJECT = ASMUtils.desc(objectClass);

        cw.visitField(Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, "consumer", "Ljava/util/function/Consumer;");
        cw.visitField(Opcodes.ACC_PUBLIC, "object", DESC_OBJECT);

        cw.visit(
                Opcodes.V1_8,
                Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
                classNameType,
                "java/lang/Object",
                new String[]{
                        bytes ? TYPE_BYTE_ARRAY_VALUE_CONSUMER : TYPE_CHAR_ARRAY_VALUE_CONSUMER
                }
        );

        {
            final int CONSUMER = 1;

            MethodWriter mw = cw.visitMethod(
                    Opcodes.ACC_PUBLIC,
                    "<init>",
                    "(Ljava/util/function/Consumer;)V",
                    32
            );
            mw.aload(THIS);
            mw.invokespecial("java/lang/Object", "<init>", "()V");

            mw.aload(THIS);
            mw.aload(CONSUMER);
            mw.putfield(classNameType, "consumer", "Ljava/util/function/Consumer;");

            mw.return_();
            mw.visitMaxs(3, 3);
        }

        {
            MethodWriter mw = cw.visitMethod(
                    Opcodes.ACC_PUBLIC,
                    "beforeRow",
                    "(I)V",
                    32
            );

            mw.aload(THIS);
            newObject(mw, TYPE_OBJECT, defaultConstructor);
            mw.putfield(classNameType, "object", DESC_OBJECT);

            mw.return_();
            mw.visitMaxs(3, 3);
        }

        {
            MethodWriter mw = cw.visitMethod(
                    Opcodes.ACC_PUBLIC,
                    "afterRow",
                    "(I)V",
                    32
            );

            mw.aload(THIS);
            mw.getfield(classNameType, "consumer", "Ljava/util/function/Consumer;");
            mw.aload(THIS);
            mw.getfield(classNameType, "object", DESC_OBJECT);
            mw.invokeinterface("java/util/function/Consumer", "accept", "(Ljava/lang/Object;)V");

            mw.aload(THIS);
            mw.aconst_null();
            mw.putfield(classNameType, "object", DESC_OBJECT);

            mw.return_();
            mw.visitMaxs(3, 3);
        }

        {
            final int ROW = 1, COLUMN = 2, BYTES = 3, OFF = 4, LEN = 5, CHARSET = 6;

            String methodDesc;
            if (bytes) {
                methodDesc = "(II[BIILjava/nio/charset/Charset;)V";
            } else {
                methodDesc = "(II[CII)V";
            }

            MethodWriter mw = cw.visitMethod(
                    Opcodes.ACC_PUBLIC,
                    "accept",
                    methodDesc,
                    32
            );

            Label switch_ = new Label(), L0_ = new Label(), L1_ = new Label();

            mw.iload(LEN);
            mw.ifne(L0_);
            mw.return_();

            mw.visitLabel(L0_);
            mw.iload(COLUMN);
            mw.ifge(L1_);
            mw.return_();

            mw.visitLabel(L1_);
            mw.iload(COLUMN);
            mw.visitLdcInsn(fieldReaderArray.length);
            mw.if_icmple(switch_);
            mw.return_();

            mw.visitLabel(switch_);

            Label dflt = new Label();
            Label[] labels = new Label[fieldReaderArray.length];
            int[] columns = new int[fieldReaderArray.length];
            for (int i = 0; i < columns.length; i++) {
                columns[i] = i;
                labels[i] = new Label();
            }

            mw.iload(COLUMN);
            mw.visitLookupSwitchInsn(dflt, columns, labels);

            for (int i = 0; i < labels.length; i++) {
                mw.visitLabel(labels[i]);
                FieldReader fieldReader = fieldReaderArray[i];
                Field field = fieldReader.field;
                Class fieldClass = fieldReader.fieldClass;
                Type fieldType = fieldReader.fieldType;

                mw.aload(THIS);
                mw.getfield(classNameType, "object", DESC_OBJECT);

                String DESC_FIELD_CLASS, DESC_METHOD;
                if (fieldType == Integer.class
                        || fieldType == int.class
                        || fieldType == Short.class
                        || fieldType == short.class
                        || fieldType == Byte.class
                        || fieldType == byte.class
                ) {
                    mw.aload(BYTES);
                    mw.iload(OFF);
                    mw.iload(LEN);
                    mw.invokestatic(TYPE_TYPE_UTILS, "parseInt", bytes ? "([BII)I" : "([CII)I");

                    if (fieldType == short.class) {
                        DESC_FIELD_CLASS = "S";
                        DESC_METHOD = "(S)V";
                    } else if (fieldType == Short.class) {
                        mw.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
                        DESC_FIELD_CLASS = "Ljava/lang/Short;";
                        DESC_METHOD = "(Ljava/lang/Short;)V";
                    } else if (fieldType == byte.class) {
                        DESC_FIELD_CLASS = "B";
                        DESC_METHOD = "(B)V";
                    } else if (fieldType == Byte.class) {
                        mw.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
                        DESC_FIELD_CLASS = "Ljava/lang/Byte;";
                        DESC_METHOD = "(Ljava/lang/Byte;)V";
                    } else if (fieldType == int.class) {
                        DESC_FIELD_CLASS = "I";
                        DESC_METHOD = "(I)V";
                    } else {
                        mw.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
                        DESC_FIELD_CLASS = "Ljava/lang/Integer;";
                        DESC_METHOD = "(Ljava/lang/Integer;)V";
                    }
                } else if (fieldType == Long.class || fieldType == long.class) {
                    mw.aload(BYTES);
                    mw.iload(OFF);
                    mw.iload(LEN);
                    mw.invokestatic(TYPE_TYPE_UTILS, "parseLong", bytes ? "([BII)J" : "([CII)J");
                    if (fieldType == long.class) {
                        DESC_FIELD_CLASS = "J";
                        DESC_METHOD = "(J)V";
                    } else {
                        mw.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
                        DESC_FIELD_CLASS = "Ljava/lang/Long;";
                        DESC_METHOD = "(Ljava/lang/Long;)V";
                    }
                } else if (fieldType == Float.class || fieldType == float.class) {
                    mw.aload(BYTES);
                    mw.iload(OFF);
                    mw.iload(LEN);
                    mw.invokestatic(TYPE_TYPE_UTILS, "parseFloat", bytes ? "([BII)F" : "([CII)F");

                    if (fieldType == float.class) {
                        DESC_FIELD_CLASS = "F";
                        DESC_METHOD = "(F)V";
                    } else {
                        mw.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
                        DESC_FIELD_CLASS = "Ljava/lang/Float;";
                        DESC_METHOD = "(Ljava/lang/Float;)V";
                    }
                } else if (fieldType == Double.class || fieldType == double.class) {
                    mw.aload(BYTES);
                    mw.iload(OFF);
                    mw.iload(LEN);
                    mw.invokestatic(TYPE_TYPE_UTILS, "parseDouble", bytes ? "([BII)D" : "([CII)D");

                    if (fieldType == double.class) {
                        DESC_FIELD_CLASS = "D";
                        DESC_METHOD = "(D)V";
                    } else {
                        mw.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
                        DESC_FIELD_CLASS = "Ljava/lang/Double;";
                        DESC_METHOD = "(Ljava/lang/Double;)V";
                    }
                } else if (fieldType == Boolean.class || fieldType == boolean.class) {
                    mw.aload(BYTES);
                    mw.iload(OFF);
                    mw.iload(LEN);
                    mw.invokestatic(TYPE_TYPE_UTILS, "parseBoolean", bytes ? "([BII)Ljava/lang/Boolean;" : "([CII)Ljava/lang/Boolean;");

                    if (fieldType == boolean.class) {
                        mw.invokevirtual("java/lang/Boolean", "booleanValue", "()Z");
                        DESC_FIELD_CLASS = "Z";
                        DESC_METHOD = "(Z)V";
                    } else {
                        DESC_FIELD_CLASS = "Ljava/lang/Boolean;";
                        DESC_METHOD = "(Ljava/lang/Boolean;)V";
                    }
                } else if (fieldType == Date.class) {
                    mw.new_("java/util/Date");

                    // long millis = DateUtils.parseMillis(bytes, off, len, charset);
                    mw.dup();
                    mw.aload(BYTES);
                    mw.iload(OFF);
                    mw.iload(LEN);
                    if (bytes) {
                        mw.aload(CHARSET);
                        mw.invokestatic(TYPE_DATE_UTILS, "parseMillis", "([BIILjava/nio/charset/Charset;)J");
                    } else {
                        mw.invokestatic(TYPE_DATE_UTILS, "parseMillis", "([CII)J");
                    }
                    mw.invokespecial("java/util/Date", "<init>", "(J)V");

                    DESC_FIELD_CLASS = "Ljava/util/Date;";
                    DESC_METHOD = "(Ljava/util/Date;)V";
                } else if (fieldType == BigDecimal.class) {
                    mw.aload(BYTES);
                    mw.iload(OFF);
                    mw.iload(LEN);
                    mw.invokestatic(TYPE_TYPE_UTILS, "parseBigDecimal", bytes ? "([BII)Ljava/math/BigDecimal;" : "([CII)Ljava/math/BigDecimal;");

                    DESC_FIELD_CLASS = "Ljava/math/BigDecimal;";
                    DESC_METHOD = "(Ljava/math/BigDecimal;)V";
                } else {
                    mw.new_("java/lang/String");
                    mw.dup();
                    mw.aload(BYTES);
                    mw.iload(OFF);
                    mw.iload(LEN);
                    if (bytes) {
                        mw.aload(CHARSET);
                        mw.invokespecial("java/lang/String", "<init>", "([BIILjava/nio/charset/Charset;)V");
                    } else {
                        mw.invokespecial("java/lang/String", "<init>", "([CII)V");
                    }

                    if (fieldType == String.class) {
                        DESC_FIELD_CLASS = "Ljava/lang/String;";
                        DESC_METHOD = "(Ljava/lang/String;)V";
                    } else {
                        DESC_FIELD_CLASS = ASMUtils.desc(fieldClass);
                        if (fieldClass == char.class) {
                            DESC_METHOD = "(C)V";
                        } else {
                            DESC_METHOD = "(" + DESC_FIELD_CLASS + ")V";
                        }

                        mw.visitLdcInsn(fieldClass);
                        mw.invokestatic(TYPE_TYPE_UTILS, "cast", "(Ljava/lang/Object;Ljava/lang/Class;)Ljava/lang/Object;");
                        mw.checkcast(ASMUtils.type(fieldClass));
                    }
                }

                if (fieldReader.method != null) {
                    if (fieldReader.method.getReturnType() != void.class) {
                        return null;
                    }

                    mw.invokevirtual(TYPE_OBJECT, fieldReader.method.getName(), DESC_METHOD);
                } else if (field != null) {
                    mw.putfield(TYPE_OBJECT, field.getName(), DESC_FIELD_CLASS);
                } else {
                    return null;
                }
                mw.goto_(dflt);
            }

            mw.visitLabel(dflt);

            mw.return_();
            mw.visitMaxs(3, 3);
        }

        byte[] code = cw.toByteArray();

        try {
            Class<?> consumerClass = classLoader.defineClassPublic(classNameFull, code, 0, code.length);
            Constructor<?> constructor = consumerClass.getConstructor(Consumer.class);
            return (c) -> {
                try {
                    return constructor.newInstance(c);
                } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
                    throw new JSONException("create ByteArrayValueConsumer error", e);
                }
            };
        } catch (Throwable e) {
            e.printStackTrace();
        }
        return null;
    }

    static class MethodWriterContext {
        final MethodWriter mw;
        final Map<Object, Integer> variants = new LinkedHashMap<>();
        final boolean jsonb;
        int maxVariant;
        static final int JSON_READER = 1;
        static final int FIELD_TYPE = 2;
        static final int FIELD_NAME = 3;
        static final int FEATURES = 4;

        public MethodWriterContext(MethodWriter mw, int maxVariant, boolean jsonb) {
            this.mw = mw;
            this.maxVariant = maxVariant;
            this.jsonb = jsonb;
        }

        int var(Object key) {
            Integer var = variants.get(key);
            if (var == null) {
                var = maxVariant;
                variants.put(key, var);
                if (key == long.class || key == double.class) {
                    maxVariant += 2;
                } else {
                    maxVariant += 1;
                }
            }
            return var;
        }

        int var(FieldReader fieldReader) {
            return var("_param_" + fieldReader.fieldName, fieldReader.fieldClass);
        }

        int var(String name, Class type) {
            Integer var = variants.get(name);
            if (var == null) {
                var = maxVariant;
                variants.put(name, var);
                if (type == long.class || type == double.class) {
                    maxVariant += 2;
                } else {
                    maxVariant += 1;
                }
            }
            return var;
        }

        int var2(Object key) {
            Integer var = variants.get(key);
            if (var == null) {
                var = maxVariant;
                variants.put(key, var);
                maxVariant += 2;
            }
            return var;
        }
    }
}