private void generatePrologue()

in rhino/src/main/java/org/mozilla/javascript/optimizer/BodyCodegen.java [225:554]


    private void generatePrologue() {
        if (inDirectCallFunction) {
            int directParameterCount = scriptOrFn.getParamCount();
            // 0 is reserved for function Object 'this'
            // 1 is reserved for context
            // 2 is reserved for parentScope
            // 3 is reserved for script 'this'
            if (firstFreeLocal != 4) Kit.codeBug();
            for (int i = 0; i != directParameterCount; ++i) {
                varRegisters[i] = firstFreeLocal;
                // 3 is 1 for Object parm and 2 for double parm
                firstFreeLocal += 3;
            }
            if (!fnCurrent.getParameterNumberContext()) {
                // make sure that all parameters are objects
                itsForcedObjectParameters = true;
                for (int i = 0; i != directParameterCount; ++i) {
                    int reg = varRegisters[i];
                    cfw.addALoad(reg);
                    cfw.add(ByteCode.GETSTATIC, "java/lang/Void", "TYPE", "Ljava/lang/Class;");
                    int isObjectLabel = cfw.acquireLabel();
                    cfw.add(ByteCode.IF_ACMPNE, isObjectLabel);
                    cfw.addDLoad(reg + 1);
                    addDoubleWrap();
                    cfw.addAStore(reg);
                    cfw.markLabel(isObjectLabel);
                }
            }
        }

        if (fnCurrent != null) {
            // Use the enclosing scope of the function as our variable object.
            cfw.addALoad(funObjLocal);
            cfw.addInvoke(
                    ByteCode.INVOKEINTERFACE,
                    "org/mozilla/javascript/Scriptable",
                    "getParentScope",
                    "()Lorg/mozilla/javascript/Scriptable;");
            cfw.addAStore(variableObjectLocal);
        }

        // reserve 'args[]'
        argsLocal = firstFreeLocal++;
        localsMax = firstFreeLocal;

        // Generate Generator specific prelude
        if (isGenerator) {

            // reserve 'args[]'
            operationLocal = firstFreeLocal++;
            localsMax = firstFreeLocal;

            // Local 3 is a reference to a GeneratorState object. The rest
            // of codegen expects local 3 to be a reference to the thisObj.
            // So move the value in local 3 to generatorStateLocal, and load
            // the saved thisObj from the GeneratorState object.
            cfw.addALoad(thisObjLocal);
            generatorStateLocal = firstFreeLocal++;
            localsMax = firstFreeLocal;
            cfw.add(ByteCode.CHECKCAST, OptRuntime.GeneratorState.CLASS_NAME);
            cfw.add(ByteCode.DUP);
            cfw.addAStore(generatorStateLocal);
            cfw.add(
                    ByteCode.GETFIELD,
                    OptRuntime.GeneratorState.CLASS_NAME,
                    OptRuntime.GeneratorState.thisObj_NAME,
                    OptRuntime.GeneratorState.thisObj_TYPE);
            cfw.addAStore(thisObjLocal);

            if (epilogueLabel == -1) {
                epilogueLabel = cfw.acquireLabel();
            }

            List<Node> targets = ((FunctionNode) scriptOrFn).getResumptionPoints();
            if (targets != null) {
                // get resumption point
                generateGetGeneratorResumptionPoint();

                // generate dispatch table
                generatorSwitch = cfw.addTableSwitch(0, targets.size() + GENERATOR_START);
                generateCheckForThrowOrClose(-1, false, GENERATOR_START);
            }
        }

        // Compile RegExp and template literals if this is a script. For functions
        // this is performed during instantiation in functionInit
        if (fnCurrent == null) {
            if (scriptOrFn.getRegexpCount() != 0) {
                cfw.addALoad(contextLocal);
                cfw.addInvoke(
                        ByteCode.INVOKESTATIC,
                        codegen.mainClassName,
                        Codegen.REGEXP_INIT_METHOD_NAME,
                        Codegen.REGEXP_INIT_METHOD_SIGNATURE);
            }
            if (scriptOrFn.getTemplateLiteralCount() != 0) {
                cfw.addInvoke(
                        ByteCode.INVOKESTATIC,
                        codegen.mainClassName,
                        Codegen.TEMPLATE_LITERAL_INIT_METHOD_NAME,
                        Codegen.TEMPLATE_LITERAL_INIT_METHOD_SIGNATURE);
            }
        }

        if (compilerEnv.isGenerateObserverCount()) saveCurrentCodeOffset();

        // skip creating activation object or loading args for the body of a generator. The
        // activation record required by a generator has already been created
        // in generateGenerator().
        if (isGenerator) return;

        if (hasVarsInRegs) {
            // No need to create activation. Pad arguments if need be.
            int parmCount = scriptOrFn.getParamCount();
            if (parmCount > 0 && !inDirectCallFunction) {
                // Set up args array
                if (scriptOrFn.hasRestParameter()) {
                    cfw.addALoad(contextLocal);
                    cfw.addALoad(variableObjectLocal);
                    cfw.addALoad(argsLocal);
                    cfw.addPush(parmCount);
                    addScriptRuntimeInvoke(
                            "padAndRestArguments",
                            "("
                                    + "Lorg/mozilla/javascript/Context;"
                                    + "Lorg/mozilla/javascript/Scriptable;"
                                    + "[Ljava/lang/Object;"
                                    + "I"
                                    + ")[Ljava/lang/Object;");
                    cfw.addAStore(argsLocal);
                } else {
                    // check length of arguments, pad if need be
                    cfw.addALoad(argsLocal);
                    cfw.add(ByteCode.ARRAYLENGTH);
                    cfw.addPush(parmCount);
                    int label = cfw.acquireLabel();
                    cfw.add(ByteCode.IF_ICMPGE, label);
                    cfw.addALoad(argsLocal);
                    cfw.addPush(parmCount);
                    addScriptRuntimeInvoke(
                            "padArguments", "([Ljava/lang/Object;I)[Ljava/lang/Object;");
                    cfw.addAStore(argsLocal);
                    cfw.markLabel(label);
                }
            }

            int paramCount = fnCurrent.fnode.getParamCount();
            int varCount = fnCurrent.fnode.getParamAndVarCount();
            boolean[] constDeclarations = fnCurrent.fnode.getParamAndVarConst();

            // REMIND - only need to initialize the vars that don't get a value
            // before the next call and are used in the function
            int firstUndefVar = -1;
            for (int i = 0; i != varCount; ++i) {
                int reg = -1;
                if (i < paramCount) {
                    if (!inDirectCallFunction) {
                        reg = getNewWordLocal();
                        cfw.addALoad(argsLocal);
                        cfw.addPush(i);
                        cfw.add(ByteCode.AALOAD);
                        cfw.addAStore(reg);
                    }
                } else if (fnCurrent.isNumberVar(i)) {
                    reg = getNewWordPairLocal(constDeclarations[i]);
                    cfw.addPush(0.0);
                    cfw.addDStore(reg);
                } else {
                    reg = getNewWordLocal(constDeclarations[i]);
                    if (firstUndefVar == -1) {
                        Codegen.pushUndefined(cfw);
                        firstUndefVar = reg;
                    } else {
                        cfw.addALoad(firstUndefVar);
                    }
                    cfw.addAStore(reg);
                }
                if (reg >= 0) {
                    if (constDeclarations[i]) {
                        cfw.addPush(0);
                        cfw.addIStore(reg + (fnCurrent.isNumberVar(i) ? 2 : 1));
                    }
                    varRegisters[i] = reg;
                }

                // Add debug table entry if we're generating debug info
                if (compilerEnv.isGenerateDebugInfo()) {
                    String name = fnCurrent.fnode.getParamOrVarName(i);
                    String type = fnCurrent.isNumberVar(i) ? "D" : "Ljava/lang/Object;";
                    int startPC = cfw.getCurrentCodeOffset();
                    if (reg < 0) {
                        reg = varRegisters[i];
                    }
                    cfw.addVariableDescriptor(name, type, startPC, reg);
                }
            }

            // Skip creating activation object.
            return;
        }

        String debugVariableName;
        boolean isArrow = false;
        if (scriptOrFn instanceof FunctionNode) {
            isArrow = ((FunctionNode) scriptOrFn).getFunctionType() == FunctionNode.ARROW_FUNCTION;
        }
        if (fnCurrent != null) {
            debugVariableName = "activation";
            cfw.addALoad(funObjLocal);
            cfw.addALoad(contextLocal);
            cfw.addALoad(variableObjectLocal);
            cfw.addALoad(argsLocal);
            cfw.addPush(scriptOrFn.isInStrictMode());
            cfw.addPush(scriptOrFn.hasRestParameter());
            cfw.addPush(
                    !(scriptOrFn instanceof FunctionNode)
                            || ((FunctionNode) scriptOrFn).requiresArgumentObject());

            if (!isArrow) {
                // Just pass the home object of the function
                cfw.addLoadThis();
                cfw.addInvoke(
                        ByteCode.INVOKEVIRTUAL,
                        "org/mozilla/javascript/BaseFunction",
                        "getHomeObject",
                        "()Lorg/mozilla/javascript/Scriptable;");
            } else {
                // Propagate the home object from the activation scope (i.e. the NativeCall)
                int putNull = cfw.acquireLabel();
                int after = cfw.acquireLabel();

                cfw.addALoad(variableObjectLocal);
                cfw.add(ByteCode.INSTANCEOF, "org/mozilla/javascript/NativeCall");
                cfw.add(ByteCode.IFEQ, putNull);

                cfw.addALoad(variableObjectLocal);
                cfw.add(ByteCode.CHECKCAST, "org/mozilla/javascript/NativeCall");
                cfw.addInvoke(
                        ByteCode.INVOKEVIRTUAL,
                        "org/mozilla/javascript/NativeCall",
                        "getHomeObject",
                        "()Lorg/mozilla/javascript/Scriptable;");
                cfw.add(ByteCode.GOTO, after);

                cfw.markLabel(putNull);
                cfw.add(ByteCode.ACONST_NULL);

                cfw.markLabel(after);
            }

            String methodName =
                    isArrow ? "createArrowFunctionActivation" : "createFunctionActivation";
            addScriptRuntimeInvoke(
                    methodName,
                    "(Lorg/mozilla/javascript/NativeFunction;"
                            + "Lorg/mozilla/javascript/Context;"
                            + "Lorg/mozilla/javascript/Scriptable;"
                            + "[Ljava/lang/Object;"
                            + "Z"
                            + "Z"
                            + "Z"
                            + "Lorg/mozilla/javascript/Scriptable;"
                            + ")Lorg/mozilla/javascript/Scriptable;");
            cfw.addAStore(variableObjectLocal);
            cfw.addALoad(contextLocal);
            cfw.addALoad(variableObjectLocal);
            addScriptRuntimeInvoke(
                    "enterActivationFunction",
                    "(Lorg/mozilla/javascript/Context;"
                            + "Lorg/mozilla/javascript/Scriptable;"
                            + ")V");
        } else {
            debugVariableName = "global";
            cfw.addALoad(funObjLocal);
            cfw.addALoad(thisObjLocal);
            cfw.addALoad(contextLocal);
            cfw.addALoad(variableObjectLocal);
            cfw.addPush(0); // false to indicate it is not eval script
            addScriptRuntimeInvoke(
                    "initScript",
                    "(Lorg/mozilla/javascript/NativeFunction;"
                            + "Lorg/mozilla/javascript/Scriptable;"
                            + "Lorg/mozilla/javascript/Context;"
                            + "Lorg/mozilla/javascript/Scriptable;"
                            + "Z"
                            + ")V");
        }

        enterAreaStartLabel = cfw.acquireLabel();
        epilogueLabel = cfw.acquireLabel();
        cfw.markLabel(enterAreaStartLabel);

        generateNestedFunctionInits();

        // default is to generate debug info
        if (compilerEnv.isGenerateDebugInfo()) {
            cfw.addVariableDescriptor(
                    debugVariableName,
                    "Lorg/mozilla/javascript/Scriptable;",
                    cfw.getCurrentCodeOffset(),
                    variableObjectLocal);
        }

        if (fnCurrent == null) {
            // OPT: use dataflow to prove that this assignment is dead
            popvLocal = getNewWordLocal();
            Codegen.pushUndefined(cfw);
            cfw.addAStore(popvLocal);

            int linenum = scriptOrFn.getEndLineno();
            if (linenum != -1) cfw.addLineNumberEntry((short) linenum);

        } else {
            if (fnCurrent.itsContainsCalls0) {
                itsZeroArgArray = getNewWordLocal();
                cfw.add(
                        ByteCode.GETSTATIC,
                        "org/mozilla/javascript/ScriptRuntime",
                        "emptyArgs",
                        "[Ljava/lang/Object;");
                cfw.addAStore(itsZeroArgArray);
            }
            if (fnCurrent.itsContainsCalls1) {
                itsOneArgArray = getNewWordLocal();
                cfw.addPush(1);
                cfw.add(ByteCode.ANEWARRAY, "java/lang/Object");
                cfw.addAStore(itsOneArgArray);
            }
        }
    }