OptJSCode.java

package org.mozilla.javascript.optimizer;

import org.mozilla.classfile.ByteCode;
import org.mozilla.classfile.ClassFileWriter;
import org.mozilla.javascript.JSCode;
import org.mozilla.javascript.ScriptOrFn;

/** Subclass of {@link JSCode} for compiled Java methods. */
public abstract class OptJSCode<T extends ScriptOrFn<T>> extends JSCode<T> {

    protected OptJSCode() {}

    /**
     * Builder environment used in the creation of {@link OptJSCode} objects. This hold information
     * on whether literals will need to be initialised, and a reference to the class containing the
     * method implementation once it has been built.
     */
    public static class BuilderEnv {
        boolean hasRegExpLiterals;
        boolean hasTemplateLiterals;
        Class<?> compiledClass;
        final String className;

        public BuilderEnv(String className) {
            this.className = className;
        }
    }

    /**
     * A builder for {@link OptJSCode}. Holds the builder environment, names and types of execute
     * and resume methods, an index within the set of descriptors owned by the class, and the built
     * version of the object (used to avoid generating duplicate classes at runtime).
     */
    public abstract static class Builder<T extends ScriptOrFn<T>> extends JSCode.Builder<T> {
        final BuilderEnv env;
        String methodName;
        String methodType;
        String resumeName;
        String resumeType;
        int index;
        OptJSCode<T> built;

        public Builder(BuilderEnv env) {
            this.env = env;
        }

        /** Return the name of the generated {@link OptJSCode} subclass. */
        abstract String getClassName();

        /** Return the bytes of the generated {@link OptJSCode} subclass. */
        abstract byte[] getClassBytes();

        /**
         * Generate bytecode to instantiate the generated {@link OptJSCode} subclass. This is used
         * by the class compiler.
         */
        void buildByteCode(ClassFileWriter cfw) {
            var className = getClassName();
            var signature = className.replaceAll("\\.", "/");
            cfw.add(ByteCode.NEW, signature);
            cfw.add(ByteCode.DUP);
            cfw.addInvoke(ByteCode.INVOKESPECIAL, className, "<init>", "()V");
        }
    }
}