OptJSScriptCode.java

package org.mozilla.javascript.optimizer;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.GeneratedClassLoader;
import org.mozilla.javascript.JSCode;
import org.mozilla.javascript.JSScript;
import org.mozilla.javascript.Scriptable;

/**
 * Subclass of {@link OptJSCode} which narrows the type paramter to {@link JSScript}. This allows
 * compiled code to be type safe and avoid casting when accessing the executable object.
 */
public abstract class OptJSScriptCode extends OptJSCode<JSScript> {

    protected OptJSScriptCode() {}

    @Override
    public abstract Object execute(
            Context cx,
            JSScript executableObject,
            Object newTarget,
            Scriptable scope,
            Object thisObj,
            Object[] args);

    @Override
    public abstract Object resume(
            Context cx,
            JSScript executableObject,
            Object state,
            Scriptable scope,
            int operation,
            Object value);

    public static class Builder extends OptJSCode.Builder<JSScript> {
        public Builder(OptJSCode.BuilderEnv env) {
            super(env);
        }

        @Override
        public JSCode<JSScript> build() {
            if (built != null) {
                return built;
            }
            try {
                var subClassName = getClassName();
                var subClassBytes = getClassBytes();

                var loader = (GeneratedClassLoader) env.compiledClass.getClassLoader();
                Class<?> subClass = loader.defineClass(subClassName, subClassBytes);
                loader.linkClass(subClass);

                var instance = (OptJSScriptCode) subClass.getConstructor().newInstance();
                built = instance;
                return instance;
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        String getClassName() {
            return env.className + "ojsc" + Integer.toString(index);
        }

        @Override
        byte[] getClassBytes() {
            return Codegen.generateOptJSCode(
                    env.className, methodName, methodType, resumeName, resumeType, false, index);
        }
    }
}