Search in sources :

Example 11 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project HL4A by HL4A.

the class NodeTransformer method transform.

public final void transform(ScriptNode tree, boolean inStrictMode, CompilerEnvirons env) {
    boolean useStrictMode = inStrictMode;
    // many existing scripts.
    if ((env.getLanguageVersion() >= Context.VERSION_ES6) && tree.isInStrictMode()) {
        useStrictMode = true;
    }
    transformCompilationUnit(tree, useStrictMode);
    for (int i = 0; i != tree.getFunctionCount(); ++i) {
        FunctionNode fn = tree.getFunctionNode(i);
        transform(fn, useStrictMode, env);
    }
}
Also used : FunctionNode(org.mozilla.javascript.ast.FunctionNode)

Example 12 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project HL4A by HL4A.

the class CodeGenerator method visitExpression.

private void visitExpression(Node node, int contextFlags) {
    int type = node.getType();
    Node child = node.getFirstChild();
    int savedStackDepth = stackDepth;
    switch(type) {
        case Token.FUNCTION:
            {
                int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP);
                FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex);
                // See comments in visitStatement for Token.FUNCTION case
                if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION && fn.getFunctionType() != FunctionNode.ARROW_FUNCTION) {
                    throw Kit.codeBug();
                }
                addIndexOp(Icode_CLOSURE_EXPR, fnIndex);
                stackChange(1);
            }
            break;
        case Token.LOCAL_LOAD:
            {
                int localIndex = getLocalBlockRef(node);
                addIndexOp(Token.LOCAL_LOAD, localIndex);
                stackChange(1);
            }
            break;
        case Token.COMMA:
            {
                Node lastChild = node.getLastChild();
                while (child != lastChild) {
                    visitExpression(child, 0);
                    addIcode(Icode_POP);
                    stackChange(-1);
                    child = child.getNext();
                }
                // Preserve tail context flag if any
                visitExpression(child, contextFlags & ECF_TAIL);
            }
            break;
        case Token.USE_STACK:
            // Indicates that stack was modified externally,
            // like placed catch object
            stackChange(1);
            break;
        case Token.REF_CALL:
        case Token.CALL:
        case Token.NEW:
            {
                if (type == Token.NEW) {
                    visitExpression(child, 0);
                } else {
                    generateCallFunAndThis(child);
                }
                int argCount = 0;
                while ((child = child.getNext()) != null) {
                    visitExpression(child, 0);
                    ++argCount;
                }
                int callType = node.getIntProp(Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL);
                if (type != Token.REF_CALL && callType != Node.NON_SPECIALCALL) {
                    // embed line number and source filename
                    addIndexOp(Icode_CALLSPECIAL, argCount);
                    addUint8(callType);
                    addUint8(type == Token.NEW ? 1 : 0);
                    addUint16(lineNumber & 0xFFFF);
                } else {
                    // optimization will confuse the debugger)
                    if (type == Token.CALL && (contextFlags & ECF_TAIL) != 0 && !compilerEnv.isGenerateDebugInfo() && !itsInTryFlag) {
                        type = Icode_TAIL_CALL;
                    }
                    addIndexOp(type, argCount);
                }
                // adjust stack
                if (type == Token.NEW) {
                    // new: f, args -> result
                    stackChange(-argCount);
                } else {
                    // call: f, thisObj, args -> result
                    // ref_call: f, thisObj, args -> ref
                    stackChange(-1 - argCount);
                }
                if (argCount > itsData.itsMaxCalleeArgs) {
                    itsData.itsMaxCalleeArgs = argCount;
                }
            }
            break;
        case Token.AND:
        case Token.OR:
            {
                visitExpression(child, 0);
                addIcode(Icode_DUP);
                stackChange(1);
                int afterSecondJumpStart = iCodeTop;
                int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
                addGotoOp(jump);
                stackChange(-1);
                addIcode(Icode_POP);
                stackChange(-1);
                child = child.getNext();
                // Preserve tail context flag if any
                visitExpression(child, contextFlags & ECF_TAIL);
                resolveForwardGoto(afterSecondJumpStart);
            }
            break;
        case Token.HOOK:
            {
                Node ifThen = child.getNext();
                Node ifElse = ifThen.getNext();
                visitExpression(child, 0);
                int elseJumpStart = iCodeTop;
                addGotoOp(Token.IFNE);
                stackChange(-1);
                // Preserve tail context flag if any
                visitExpression(ifThen, contextFlags & ECF_TAIL);
                int afterElseJumpStart = iCodeTop;
                addGotoOp(Token.GOTO);
                resolveForwardGoto(elseJumpStart);
                stackDepth = savedStackDepth;
                // Preserve tail context flag if any
                visitExpression(ifElse, contextFlags & ECF_TAIL);
                resolveForwardGoto(afterElseJumpStart);
            }
            break;
        case Token.GETPROP:
        case Token.GETPROPNOWARN:
            visitExpression(child, 0);
            child = child.getNext();
            addStringOp(type, child.getString());
            break;
        case Token.DELPROP:
            boolean isName = child.getType() == Token.BINDNAME;
            visitExpression(child, 0);
            child = child.getNext();
            visitExpression(child, 0);
            if (isName) {
                // special handling for delete name
                addIcode(Icode_DELNAME);
            } else {
                addToken(Token.DELPROP);
            }
            stackChange(-1);
            break;
        case Token.GETELEM:
        case Token.BITAND:
        case Token.BITOR:
        case Token.BITXOR:
        case Token.LSH:
        case Token.RSH:
        case Token.URSH:
        case Token.ADD:
        case Token.SUB:
        case Token.MOD:
        case Token.DIV:
        case Token.MUL:
        case Token.EQ:
        case Token.NE:
        case Token.SHEQ:
        case Token.SHNE:
        case Token.IN:
        case Token.INSTANCEOF:
        case Token.LE:
        case Token.LT:
        case Token.GE:
        case Token.GT:
            visitExpression(child, 0);
            child = child.getNext();
            visitExpression(child, 0);
            addToken(type);
            stackChange(-1);
            break;
        case Token.POS:
        case Token.NEG:
        case Token.NOT:
        case Token.BITNOT:
        case Token.TYPEOF:
        case Token.VOID:
            visitExpression(child, 0);
            if (type == Token.VOID) {
                addIcode(Icode_POP);
                addIcode(Icode_UNDEF);
            } else {
                addToken(type);
            }
            break;
        case Token.GET_REF:
        case Token.DEL_REF:
            visitExpression(child, 0);
            addToken(type);
            break;
        case Token.SETPROP:
        case Token.SETPROP_OP:
            {
                visitExpression(child, 0);
                child = child.getNext();
                String property = child.getString();
                child = child.getNext();
                if (type == Token.SETPROP_OP) {
                    addIcode(Icode_DUP);
                    stackChange(1);
                    addStringOp(Token.GETPROP, property);
                    // Compensate for the following USE_STACK
                    stackChange(-1);
                }
                visitExpression(child, 0);
                addStringOp(Token.SETPROP, property);
                stackChange(-1);
            }
            break;
        case Token.SETELEM:
        case Token.SETELEM_OP:
            visitExpression(child, 0);
            child = child.getNext();
            visitExpression(child, 0);
            child = child.getNext();
            if (type == Token.SETELEM_OP) {
                addIcode(Icode_DUP2);
                stackChange(2);
                addToken(Token.GETELEM);
                stackChange(-1);
                // Compensate for the following USE_STACK
                stackChange(-1);
            }
            visitExpression(child, 0);
            addToken(Token.SETELEM);
            stackChange(-2);
            break;
        case Token.SET_REF:
        case Token.SET_REF_OP:
            visitExpression(child, 0);
            child = child.getNext();
            if (type == Token.SET_REF_OP) {
                addIcode(Icode_DUP);
                stackChange(1);
                addToken(Token.GET_REF);
                // Compensate for the following USE_STACK
                stackChange(-1);
            }
            visitExpression(child, 0);
            addToken(Token.SET_REF);
            stackChange(-1);
            break;
        case Token.STRICT_SETNAME:
        case Token.SETNAME:
            {
                String name = child.getString();
                visitExpression(child, 0);
                child = child.getNext();
                visitExpression(child, 0);
                addStringOp(type, name);
                stackChange(-1);
            }
            break;
        case Token.SETCONST:
            {
                String name = child.getString();
                visitExpression(child, 0);
                child = child.getNext();
                visitExpression(child, 0);
                addStringOp(Icode_SETCONST, name);
                stackChange(-1);
            }
            break;
        case Token.TYPEOFNAME:
            {
                int index = -1;
                // since the vars all exist there instead of in jregs
                if (itsInFunctionFlag && !itsData.itsNeedsActivation)
                    index = scriptOrFn.getIndexForNameNode(node);
                if (index == -1) {
                    addStringOp(Icode_TYPEOFNAME, node.getString());
                    stackChange(1);
                } else {
                    addVarOp(Token.GETVAR, index);
                    stackChange(1);
                    addToken(Token.TYPEOF);
                }
            }
            break;
        case Token.BINDNAME:
        case Token.NAME:
        case Token.STRING:
            addStringOp(type, node.getString());
            stackChange(1);
            break;
        case Token.INC:
        case Token.DEC:
            visitIncDec(node, child);
            break;
        case Token.NUMBER:
            {
                double num = node.getDouble();
                int inum = (int) num;
                if (inum == num) {
                    if (inum == 0) {
                        addIcode(Icode_ZERO);
                        // Check for negative zero
                        if (1.0 / num < 0.0) {
                            addToken(Token.NEG);
                        }
                    } else if (inum == 1) {
                        addIcode(Icode_ONE);
                    } else if ((short) inum == inum) {
                        addIcode(Icode_SHORTNUMBER);
                        // write short as uin16 bit pattern
                        addUint16(inum & 0xFFFF);
                    } else {
                        addIcode(Icode_INTNUMBER);
                        addInt(inum);
                    }
                } else {
                    int index = getDoubleIndex(num);
                    addIndexOp(Token.NUMBER, index);
                }
                stackChange(1);
            }
            break;
        case Token.GETVAR:
            {
                if (itsData.itsNeedsActivation)
                    Kit.codeBug();
                int index = scriptOrFn.getIndexForNameNode(node);
                addVarOp(Token.GETVAR, index);
                stackChange(1);
            }
            break;
        case Token.SETVAR:
            {
                if (itsData.itsNeedsActivation)
                    Kit.codeBug();
                int index = scriptOrFn.getIndexForNameNode(child);
                child = child.getNext();
                visitExpression(child, 0);
                addVarOp(Token.SETVAR, index);
            }
            break;
        case Token.SETCONSTVAR:
            {
                if (itsData.itsNeedsActivation)
                    Kit.codeBug();
                int index = scriptOrFn.getIndexForNameNode(child);
                child = child.getNext();
                visitExpression(child, 0);
                addVarOp(Token.SETCONSTVAR, index);
            }
            break;
        case Token.NULL:
        case Token.THIS:
        case Token.THISFN:
        case Token.FALSE:
        case Token.TRUE:
            addToken(type);
            stackChange(1);
            break;
        case Token.ENUM_NEXT:
        case Token.ENUM_ID:
            addIndexOp(type, getLocalBlockRef(node));
            stackChange(1);
            break;
        case Token.REGEXP:
            {
                int index = node.getExistingIntProp(Node.REGEXP_PROP);
                addIndexOp(Token.REGEXP, index);
                stackChange(1);
            }
            break;
        case Token.ARRAYLIT:
        case Token.OBJECTLIT:
            visitLiteral(node, child);
            break;
        case Token.ARRAYCOMP:
            visitArrayComprehension(node, child, child.getNext());
            break;
        case Token.REF_SPECIAL:
            visitExpression(child, 0);
            addStringOp(type, (String) node.getProp(Node.NAME_PROP));
            break;
        case Token.REF_MEMBER:
        case Token.REF_NS_MEMBER:
        case Token.REF_NAME:
        case Token.REF_NS_NAME:
            {
                int memberTypeFlags = node.getIntProp(Node.MEMBER_TYPE_PROP, 0);
                // generate possible target, possible namespace and member
                int childCount = 0;
                do {
                    visitExpression(child, 0);
                    ++childCount;
                    child = child.getNext();
                } while (child != null);
                addIndexOp(type, memberTypeFlags);
                stackChange(1 - childCount);
            }
            break;
        case Token.DOTQUERY:
            {
                int queryPC;
                updateLineNumber(node);
                visitExpression(child, 0);
                addIcode(Icode_ENTERDQ);
                stackChange(-1);
                queryPC = iCodeTop;
                visitExpression(child.getNext(), 0);
                addBackwardGoto(Icode_LEAVEDQ, queryPC);
            }
            break;
        case Token.DEFAULTNAMESPACE:
        case Token.ESCXMLATTR:
        case Token.ESCXMLTEXT:
            visitExpression(child, 0);
            addToken(type);
            break;
        case Token.YIELD:
            if (child != null) {
                visitExpression(child, 0);
            } else {
                addIcode(Icode_UNDEF);
                stackChange(1);
            }
            addToken(Token.YIELD);
            addUint16(node.getLineno() & 0xFFFF);
            break;
        case Token.WITHEXPR:
            {
                Node enterWith = node.getFirstChild();
                Node with = enterWith.getNext();
                visitExpression(enterWith.getFirstChild(), 0);
                addToken(Token.ENTERWITH);
                stackChange(-1);
                visitExpression(with.getFirstChild(), 0);
                addToken(Token.LEAVEWITH);
                break;
            }
        default:
            throw badTree(node);
    }
    if (savedStackDepth + 1 != stackDepth) {
        Kit.codeBug();
    }
}
Also used : ScriptNode(org.mozilla.javascript.ast.ScriptNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode)

Example 13 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

the class BodyCodegen method initOptFunctions_r.

private static void initOptFunctions_r(ScriptNode scriptOrFn) {
    for (int i = 0, N = scriptOrFn.getFunctionCount(); i != N; ++i) {
        FunctionNode fn = scriptOrFn.getFunctionNode(i);
        new OptFunctionNode(fn);
        initOptFunctions_r(fn);
    }
}
Also used : FunctionNode(org.mozilla.javascript.ast.FunctionNode)

Example 14 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

the class BodyCodegen method generateNativeFunctionOverrides.

private void generateNativeFunctionOverrides(ClassFileWriter cfw, String encodedSource) {
    // Override NativeFunction.getLanguageVersion() with
    // public int getLanguageVersion() { return <version-constant>; }
    cfw.startMethod("getLanguageVersion", "()I", ClassFileWriter.ACC_PUBLIC);
    cfw.addPush(compilerEnv.getLanguageVersion());
    cfw.add(ByteCode.IRETURN);
    // 1: this and no argument or locals
    cfw.stopMethod((short) 1);
    // The rest of NativeFunction overrides require specific code for each
    // script/function id
    final int Do_getFunctionName = 0;
    final int Do_getParamCount = 1;
    final int Do_getParamAndVarCount = 2;
    final int Do_getParamOrVarName = 3;
    final int Do_getEncodedSource = 4;
    final int Do_getParamOrVarConst = 5;
    final int SWITCH_COUNT = 6;
    for (int methodIndex = 0; methodIndex != SWITCH_COUNT; ++methodIndex) {
        if (methodIndex == Do_getEncodedSource && encodedSource == null) {
            continue;
        }
        // Generate:
        //   prologue;
        //   switch over function id to implement function-specific action
        //   epilogue
        short methodLocals;
        switch(methodIndex) {
            case Do_getFunctionName:
                // Only this
                methodLocals = 1;
                cfw.startMethod("getFunctionName", "()Ljava/lang/String;", ClassFileWriter.ACC_PUBLIC);
                break;
            case Do_getParamCount:
                // Only this
                methodLocals = 1;
                cfw.startMethod("getParamCount", "()I", ClassFileWriter.ACC_PUBLIC);
                break;
            case Do_getParamAndVarCount:
                // Only this
                methodLocals = 1;
                cfw.startMethod("getParamAndVarCount", "()I", ClassFileWriter.ACC_PUBLIC);
                break;
            case Do_getParamOrVarName:
                // this + paramOrVarIndex
                methodLocals = 1 + 1;
                cfw.startMethod("getParamOrVarName", "(I)Ljava/lang/String;", ClassFileWriter.ACC_PUBLIC);
                break;
            case Do_getParamOrVarConst:
                // this + paramOrVarName
                methodLocals = 1 + 1 + 1;
                cfw.startMethod("getParamOrVarConst", "(I)Z", ClassFileWriter.ACC_PUBLIC);
                break;
            case Do_getEncodedSource:
                // Only this
                methodLocals = 1;
                cfw.startMethod("getEncodedSource", "()Ljava/lang/String;", ClassFileWriter.ACC_PUBLIC);
                cfw.addPush(encodedSource);
                break;
            default:
                throw Kit.codeBug();
        }
        int count = scriptOrFnNodes.length;
        int switchStart = 0;
        int switchStackTop = 0;
        if (count > 1) {
            // Generate switch but only if there is more then one
            // script/function
            cfw.addLoadThis();
            cfw.add(ByteCode.GETFIELD, cfw.getClassName(), ID_FIELD_NAME, "I");
            // do switch from 1 .. count - 1 mapping 0 to the default case
            switchStart = cfw.addTableSwitch(1, count - 1);
        }
        for (int i = 0; i != count; ++i) {
            ScriptNode n = scriptOrFnNodes[i];
            if (i == 0) {
                if (count > 1) {
                    cfw.markTableSwitchDefault(switchStart);
                    switchStackTop = cfw.getStackTop();
                }
            } else {
                cfw.markTableSwitchCase(switchStart, i - 1, switchStackTop);
            }
            // Impelemnet method-specific switch code
            switch(methodIndex) {
                case Do_getFunctionName:
                    // Push function name
                    if (n.getType() == Token.SCRIPT) {
                        cfw.addPush("");
                    } else {
                        String name = ((FunctionNode) n).getName();
                        cfw.addPush(name);
                    }
                    cfw.add(ByteCode.ARETURN);
                    break;
                case Do_getParamCount:
                    // Push number of defined parameters
                    cfw.addPush(n.getParamCount());
                    cfw.add(ByteCode.IRETURN);
                    break;
                case Do_getParamAndVarCount:
                    // Push number of defined parameters and declared variables
                    cfw.addPush(n.getParamAndVarCount());
                    cfw.add(ByteCode.IRETURN);
                    break;
                case Do_getParamOrVarName:
                    // Push name of parameter using another switch
                    // over paramAndVarCount
                    int paramAndVarCount = n.getParamAndVarCount();
                    if (paramAndVarCount == 0) {
                        // The runtime should never call the method in this
                        // case but to make bytecode verifier happy return null
                        // as throwing execption takes more code
                        cfw.add(ByteCode.ACONST_NULL);
                        cfw.add(ByteCode.ARETURN);
                    } else if (paramAndVarCount == 1) {
                        // As above do not check for valid index but always
                        // return the name of the first param
                        cfw.addPush(n.getParamOrVarName(0));
                        cfw.add(ByteCode.ARETURN);
                    } else {
                        // Do switch over getParamOrVarName
                        // param or var index
                        cfw.addILoad(1);
                        // do switch from 1 .. paramAndVarCount - 1 mapping 0
                        // to the default case
                        int paramSwitchStart = cfw.addTableSwitch(1, paramAndVarCount - 1);
                        for (int j = 0; j != paramAndVarCount; ++j) {
                            if (cfw.getStackTop() != 0)
                                Kit.codeBug();
                            String s = n.getParamOrVarName(j);
                            if (j == 0) {
                                cfw.markTableSwitchDefault(paramSwitchStart);
                            } else {
                                cfw.markTableSwitchCase(paramSwitchStart, j - 1, 0);
                            }
                            cfw.addPush(s);
                            cfw.add(ByteCode.ARETURN);
                        }
                    }
                    break;
                case Do_getParamOrVarConst:
                    // Push name of parameter using another switch
                    // over paramAndVarCount
                    paramAndVarCount = n.getParamAndVarCount();
                    boolean[] constness = n.getParamAndVarConst();
                    if (paramAndVarCount == 0) {
                        // The runtime should never call the method in this
                        // case but to make bytecode verifier happy return null
                        // as throwing execption takes more code
                        cfw.add(ByteCode.ICONST_0);
                        cfw.add(ByteCode.IRETURN);
                    } else if (paramAndVarCount == 1) {
                        // As above do not check for valid index but always
                        // return the name of the first param
                        cfw.addPush(constness[0]);
                        cfw.add(ByteCode.IRETURN);
                    } else {
                        // Do switch over getParamOrVarName
                        // param or var index
                        cfw.addILoad(1);
                        // do switch from 1 .. paramAndVarCount - 1 mapping 0
                        // to the default case
                        int paramSwitchStart = cfw.addTableSwitch(1, paramAndVarCount - 1);
                        for (int j = 0; j != paramAndVarCount; ++j) {
                            if (cfw.getStackTop() != 0)
                                Kit.codeBug();
                            if (j == 0) {
                                cfw.markTableSwitchDefault(paramSwitchStart);
                            } else {
                                cfw.markTableSwitchCase(paramSwitchStart, j - 1, 0);
                            }
                            cfw.addPush(constness[j]);
                            cfw.add(ByteCode.IRETURN);
                        }
                    }
                    break;
                case Do_getEncodedSource:
                    // Push number encoded source start and end
                    // to prepare for encodedSource.substring(start, end)
                    cfw.addPush(n.getEncodedSourceStart());
                    cfw.addPush(n.getEncodedSourceEnd());
                    cfw.addInvoke(ByteCode.INVOKEVIRTUAL, "java/lang/String", "substring", "(II)Ljava/lang/String;");
                    cfw.add(ByteCode.ARETURN);
                    break;
                default:
                    throw Kit.codeBug();
            }
        }
        cfw.stopMethod(methodLocals);
    }
}
Also used : FunctionNode(org.mozilla.javascript.ast.FunctionNode) ScriptNode(org.mozilla.javascript.ast.ScriptNode)

Example 15 with FunctionNode

use of org.mozilla.javascript.ast.FunctionNode in project hackpad by dropbox.

the class BodyCodegen method generateEpilogue.

private void generateEpilogue() {
    if (compilerEnv.isGenerateObserverCount())
        addInstructionCount();
    if (isGenerator) {
        // generate locals initialization
        Map<Node, int[]> liveLocals = ((FunctionNode) scriptOrFn).getLiveLocals();
        if (liveLocals != null) {
            List<Node> nodes = ((FunctionNode) scriptOrFn).getResumptionPoints();
            for (int i = 0; i < nodes.size(); i++) {
                Node node = nodes.get(i);
                int[] live = liveLocals.get(node);
                if (live != null) {
                    cfw.markTableSwitchCase(generatorSwitch, getNextGeneratorState(node));
                    generateGetGeneratorLocalsState();
                    for (int j = 0; j < live.length; j++) {
                        cfw.add(ByteCode.DUP);
                        cfw.addLoadConstant(j);
                        cfw.add(ByteCode.AALOAD);
                        cfw.addAStore(live[j]);
                    }
                    cfw.add(ByteCode.POP);
                    cfw.add(ByteCode.GOTO, getTargetLabel(node));
                }
            }
        }
        // generate dispatch tables for finally
        if (finallys != null) {
            for (Node n : finallys.keySet()) {
                if (n.getType() == Token.FINALLY) {
                    FinallyReturnPoint ret = finallys.get(n);
                    // the finally will jump here
                    cfw.markLabel(ret.tableLabel, (short) 1);
                    // start generating a dispatch table
                    int startSwitch = cfw.addTableSwitch(0, ret.jsrPoints.size() - 1);
                    int c = 0;
                    cfw.markTableSwitchDefault(startSwitch);
                    for (int i = 0; i < ret.jsrPoints.size(); i++) {
                        // generate gotos back to the JSR location
                        cfw.markTableSwitchCase(startSwitch, c);
                        cfw.add(ByteCode.GOTO, ret.jsrPoints.get(i).intValue());
                        c++;
                    }
                }
            }
        }
    }
    if (epilogueLabel != -1) {
        cfw.markLabel(epilogueLabel);
    }
    if (hasVarsInRegs) {
        cfw.add(ByteCode.ARETURN);
        return;
    } else if (isGenerator) {
        if (((FunctionNode) scriptOrFn).getResumptionPoints() != null) {
            cfw.markTableSwitchDefault(generatorSwitch);
        }
        // change state for re-entry
        generateSetGeneratorResumptionPoint(GENERATOR_TERMINATE);
        // throw StopIteration
        cfw.addALoad(variableObjectLocal);
        addOptRuntimeInvoke("throwStopIteration", "(Ljava/lang/Object;)V");
        Codegen.pushUndefined(cfw);
        cfw.add(ByteCode.ARETURN);
    } else if (fnCurrent == null) {
        cfw.addALoad(popvLocal);
        cfw.add(ByteCode.ARETURN);
    } else {
        generateActivationExit();
        cfw.add(ByteCode.ARETURN);
        // Generate catch block to catch all and rethrow to call exit code
        // under exception propagation as well.
        int finallyHandler = cfw.acquireLabel();
        cfw.markHandler(finallyHandler);
        short exceptionObject = getNewWordLocal();
        cfw.addAStore(exceptionObject);
        // Duplicate generateActivationExit() in the catch block since it
        // takes less space then full-featured ByteCode.JSR/ByteCode.RET
        generateActivationExit();
        cfw.addALoad(exceptionObject);
        releaseWordLocal(exceptionObject);
        // rethrow
        cfw.add(ByteCode.ATHROW);
        // mark the handler
        cfw.addExceptionHandler(enterAreaStartLabel, epilogueLabel, finallyHandler, // catch any
        null);
    }
}
Also used : ScriptNode(org.mozilla.javascript.ast.ScriptNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode) FunctionNode(org.mozilla.javascript.ast.FunctionNode)

Aggregations

FunctionNode (org.mozilla.javascript.ast.FunctionNode)32 ScriptNode (org.mozilla.javascript.ast.ScriptNode)20 AstNode (org.mozilla.javascript.ast.AstNode)8 Name (org.mozilla.javascript.ast.Name)7 LetNode (org.mozilla.javascript.ast.LetNode)6 Jump (org.mozilla.javascript.ast.Jump)4 Scope (org.mozilla.javascript.ast.Scope)4 XmlString (org.mozilla.javascript.ast.XmlString)3 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 Iterator (java.util.Iterator)2 Map (java.util.Map)2 AstRoot (org.mozilla.javascript.ast.AstRoot)2 ErrorNode (org.mozilla.javascript.ast.ErrorNode)2 Block (org.mozilla.javascript.ast.Block)1 Comment (org.mozilla.javascript.ast.Comment)1 EmptyExpression (org.mozilla.javascript.ast.EmptyExpression)1 ExpressionStatement (org.mozilla.javascript.ast.ExpressionStatement)1 ObjectProperty (org.mozilla.javascript.ast.ObjectProperty)1 ParenthesizedExpression (org.mozilla.javascript.ast.ParenthesizedExpression)1