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

io.neow3j.compiler.InitsslotNeoMethod Maven / Gradle / Ivy

package io.neow3j.compiler;

import io.neow3j.script.OpCode;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;

import java.io.IOException;
import java.util.List;

import static io.neow3j.compiler.Compiler.isAssertionDisabledStaticField;
import static io.neow3j.compiler.Compiler.isEvent;

public class InitsslotNeoMethod extends NeoMethod {

    private static final String INITSSLOT_METHOD_NAME = "_initialize";
    private static final String DESIRED_ASSERTION_STATUS = "desiredAssertionStatus";

    /**
     * Constructs a new INITSSLOT method.
     *
     * @param asmMethod   the Java method this Neo method is converted from.
     * @param sourceClass the Java class from which this method originates.
     * @param compUnit    the compilation unit object of the ongoing compilation, required for its classloader.
     */
    public InitsslotNeoMethod(MethodNode asmMethod, ClassNode sourceClass, CompilationUnit compUnit) {
        super(asmMethod, sourceClass);
        setName(INITSSLOT_METHOD_NAME);
        setIsAbiMethod(true);
        byte[] operand = new byte[]{(byte) calcNumberOfContractVariables(sourceClass.fields, compUnit)};
        addInstruction(new NeoInstruction(OpCode.INITSSLOT, operand));
    }

    private int calcNumberOfContractVariables(List fields, CompilationUnit compUnit) {
        // Events are not counted as contract variables. They are only definitions and don't appear as actual
        // variables in the NeoVM script. We don't check for a maximum amount of contract variables here, that is
        // done in Compiler.collectContractVariables(ClassNode asmClass).
        return (int) fields.stream()
                .filter(f -> !isEvent(f.desc, compUnit))
                .count();
    }

    protected boolean containsOnlyAssertionRelatedInstructions() {
        AbstractInsnNode insn = getAsmMethod().instructions.getFirst().getNext().getNext();
        if (insn.getType() == AbstractInsnNode.LDC_INSN &&
                insn.getNext().getType() == AbstractInsnNode.METHOD_INSN) {
            MethodInsnNode methodInsn = (MethodInsnNode) insn.getNext();
            if (methodInsn.name.equals(DESIRED_ASSERTION_STATUS)) {
                insn = insn.getNext();
                while (!isAssertionDisabledStaticField(insn)) {
                    insn = insn.getNext();
                }
                return insn.getNext().getOpcode() == JVMOpcode.RETURN.getOpcode();
            }
        }
        return false;
    }

    @Override
    public void convert(CompilationUnit compUnit) throws IOException {
        AbstractInsnNode insn = getAsmMethod().instructions.get(0);
        while (insn != null) {
            if (insn.getOpcode() >= JVMOpcode.ISTORE.getOpcode() &&
                    insn.getOpcode() <= JVMOpcode.SASTORE.getOpcode()) {
                throw new CompilerException(this, "Local variables are not supported in the static constructor");
            }
            // Events must not be initialized, i.e., their constructor's must not be called.
            // Event variable are not actually variables in the NeoVM script code, just definitions.
            throwOnEventConstructorCall(insn, compUnit);
            insn = Compiler.handleInsn(insn, this, compUnit);
            insn = insn.getNext();
        }
        insertTryCatchBlocks();
    }

    private void throwOnEventConstructorCall(AbstractInsnNode insn, CompilationUnit compUnit) {
        if (insn instanceof TypeInsnNode) {
            TypeInsnNode typeInsn = (TypeInsnNode) insn;
            String desc = Type.getObjectType(typeInsn.desc).getDescriptor();
            if (isEvent(desc, compUnit)) {
                throw new CompilerException(this, "Events must not be initialized by calling their constructor.");
            }
        }
    }

    @Override
    public void initialize(CompilationUnit compUnit) {
        throw new UnsupportedOperationException("The INITSSLOT method cannotneed to be initialized with local " +
                "variable and parameter slots.");
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy