All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.llamalad7.mixinextras.sugar.impl.ShareInfo Maven / Gradle / Ivy

package com.llamalad7.mixinextras.sugar.impl;

import com.llamalad7.mixinextras.injector.StackExtension;
import com.llamalad7.mixinextras.sugar.impl.ref.LocalRefUtils;
import com.llamalad7.mixinextras.utils.TargetDecorations;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import org.spongepowered.asm.mixin.injection.struct.Target;
import org.spongepowered.asm.util.Annotations;

import java.util.*;

public class ShareInfo {
    private int lvtIndex;
    private final ShareType shareType;
    private final Collection initialization = new ArrayList<>();

    private ShareInfo(int lvtIndex, Type innerType) {
        this.lvtIndex = lvtIndex;
        this.shareType = new ShareType(innerType);
    }

    public int getLvtIndex() {
        return lvtIndex;
    }

    public void setLvtIndex(int lvtIndex) {
        this.lvtIndex = lvtIndex;
    }

    public ShareType getShareType() {
        return shareType;
    }

    public void addToLvt(Target target) {
        shareType.addToLvt(target, lvtIndex);
    }

    public InsnList initialize() {
        InsnList init = shareType.initialize(lvtIndex);
        initialization.addAll(Arrays.asList(init.toArray()));
        return init;
    }

    public AbstractInsnNode load() {
        return new VarInsnNode(Opcodes.ALOAD, lvtIndex);
    }

    public void stripInitializerFrom(MethodNode method) {
        initialization.forEach(method.instructions::remove);
    }

    public static ShareInfo getOrCreate(Target target, AnnotationNode shareAnnotation, Type paramType, IMixinInfo mixin, StackExtension stack) {
        if (!SugarApplicator.isSugar(shareAnnotation.desc) || !shareAnnotation.desc.endsWith("Share;")) {
            return null;
        }
        Type innerType = getInnerType(paramType);
        Map infos = TargetDecorations.getOrPut(target, "ShareSugar_Infos", HashMap::new);
        ShareId id = getId(shareAnnotation, mixin);
        ShareInfo shareInfo = infos.get(id);
        if (shareInfo == null) {
            shareInfo = new ShareInfo(target.allocateLocal(), innerType);
            infos.put(id, shareInfo);
            shareInfo.addToLvt(target);
            target.insns.insert(shareInfo.initialize());
            if (stack != null) {
                stack.ensureAtLeast(innerType.getSize() + 2); // duped ref and dummy value
            }
        } else {
            if (!innerType.equals(shareInfo.shareType.getInnerType())) {
                throw new SugarApplicationException(
                        String.format(
                                "Share id %s in %s was requested for different types %s and %s!",
                                id, target, innerType, shareInfo.shareType.getInnerType()
                        )
                );
            }
        }
        return shareInfo;
    }

    private static Type getInnerType(Type paramType) {
        Type innerType = LocalRefUtils.getTargetType(paramType, Type.getType(Object.class));
        if (innerType == paramType) {
            throw new SugarApplicationException("@Share parameter must be some variation of LocalRef.");
        }
        return innerType;
    }

    private static ShareId getId(AnnotationNode shareAnnotation, IMixinInfo mixin) {
        return new ShareId(
                Annotations.getValue(shareAnnotation, "namespace", mixin.getClassName()),
                Annotations.getValue(shareAnnotation)
        );
    }

    private static class ShareId {
        private final String namespace;
        private final String id;

        private ShareId(String namespace, String id) {
            this.namespace = namespace;
            this.id = id;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ShareId shareId = (ShareId) o;
            return Objects.equals(namespace, shareId.namespace) && Objects.equals(id, shareId.id);
        }

        @Override
        public int hashCode() {
            return Objects.hash(namespace, id);
        }

        @Override
        public String toString() {
            return namespace + ':' + id;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy