Esempio n. 1
0
        void VisitStatement (Node node)
        {
            int type = node.Type;
            Node child = node.FirstChild;
            switch (type) {


                case Token.FUNCTION: {
                        int fnIndex = node.getExistingIntProp (Node.FUNCTION_PROP);
                        int fnType = scriptOrFn.getFunctionNode (fnIndex).FunctionType;
                        // Only function expressions or function expression
                        // statements needs closure code creating new function
                        // object on stack as function statements are initialized
                        // at script/function start
                        // In addition function expression can not present here
                        // at statement level, they must only present as expressions.
                        if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) {
                            addIndexOp (Icode_CLOSURE_STMT, fnIndex);
                        }
                        else {
                            if (fnType != FunctionNode.FUNCTION_STATEMENT) {
                                throw Context.CodeBug ();
                            }
                        }
                    }
                    break;


                case Token.SCRIPT:
                case Token.LABEL:
                case Token.LOOP:
                case Token.BLOCK:
                case Token.EMPTY:
                case Token.WITH:
                    updateLineNumber (node);
                    while (child != null) {
                        VisitStatement (child);
                        child = child.Next;
                    }
                    break;


                case Token.ENTERWITH:
                    VisitExpression (child, 0);
                    addToken (Token.ENTERWITH);
                    stackChange (-1);
                    break;


                case Token.LEAVEWITH:
                    addToken (Token.LEAVEWITH);
                    break;


                case Token.LOCAL_BLOCK: {
                        int local = allocLocal ();
                        node.putIntProp (Node.LOCAL_PROP, local);
                        updateLineNumber (node);
                        while (child != null) {
                            VisitStatement (child);
                            child = child.Next;
                        }
                        addIndexOp (Icode_LOCAL_CLEAR, local);
                        releaseLocal (local);
                    }
                    break;

                case Token.DEBUGGER:
                    updateLineNumber (node);
                    addIcode (Icode_DEBUGGER);
                    break;

                case Token.SWITCH:
                    updateLineNumber (node); {
                        // See comments in IRFactory.createSwitch() for description
                        // of SWITCH node
                        Node switchNode = (Node.Jump)node;
                        VisitExpression (child, 0);
                        for (Node.Jump caseNode = (Node.Jump)child.Next; caseNode != null; caseNode = (Node.Jump)caseNode.Next) {
                            if (caseNode.Type != Token.CASE)
                                throw badTree (caseNode);
                            Node test = caseNode.FirstChild;
                            addIcode (Icode_DUP);
                            stackChange (1);
                            VisitExpression (test, 0);
                            addToken (Token.SHEQ);
                            stackChange (-1);
                            // If true, Icode_IFEQ_POP will jump and remove case
                            // value from stack
                            addGoto (caseNode.target, Icode_IFEQ_POP);
                            stackChange (-1);
                        }
                        addIcode (Icode_POP);
                        stackChange (-1);
                    }
                    break;


                case Token.TARGET:
                    markTargetLabel (node);
                    break;


                case Token.IFEQ:
                case Token.IFNE: {
                        Node target = ((Node.Jump)node).target;
                        VisitExpression (child, 0);
                        addGoto (target, type);
                        stackChange (-1);
                    }
                    break;


                case Token.GOTO: {
                        Node target = ((Node.Jump)node).target;
                        addGoto (target, type);
                    }
                    break;


                case Token.JSR: {
                        Node target = ((Node.Jump)node).target;
                        addGoto (target, Icode_GOSUB);
                    }
                    break;


                case Token.FINALLY: {
                        // Account for incomming GOTOSUB address
                        stackChange (1);
                        int finallyRegister = getLocalBlockRef (node);
                        addIndexOp (Icode_STARTSUB, finallyRegister);
                        stackChange (-1);
                        while (child != null) {
                            VisitStatement (child);
                            child = child.Next;
                        }
                        addIndexOp (Icode_RETSUB, finallyRegister);
                    }
                    break;


                case Token.EXPR_VOID:
                case Token.EXPR_RESULT:
                    updateLineNumber (node);
                    VisitExpression (child, 0);
                    addIcode ((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT);
                    stackChange (-1);
                    break;


                case Token.TRY: {
                        Node.Jump tryNode = (Node.Jump)node;
                        int exceptionObjectLocal = getLocalBlockRef (tryNode);
                        int scopeLocal = allocLocal ();

                        addIndexOp (Icode_SCOPE_SAVE, scopeLocal);

                        int tryStart = itsICodeTop;
                        while (child != null) {
                            VisitStatement (child);
                            child = child.Next;
                        }

                        Node catchTarget = tryNode.target;
                        if (catchTarget != null) {
                            int catchStartPC = itsLabelTable [getTargetLabel (catchTarget)];
                            addExceptionHandler (tryStart, catchStartPC, catchStartPC, false, exceptionObjectLocal, scopeLocal);
                        }
                        Node finallyTarget = tryNode.Finally;
                        if (finallyTarget != null) {
                            int finallyStartPC = itsLabelTable [getTargetLabel (finallyTarget)];
                            addExceptionHandler (tryStart, finallyStartPC, finallyStartPC, true, exceptionObjectLocal, scopeLocal);
                        }

                        addIndexOp (Icode_LOCAL_CLEAR, scopeLocal);
                        releaseLocal (scopeLocal);
                    }
                    break;


                case Token.CATCH_SCOPE: {
                        int localIndex = getLocalBlockRef (node);
                        int scopeIndex = node.getExistingIntProp (Node.CATCH_SCOPE_PROP);
                        string name = child.String;
                        child = child.Next;
                        VisitExpression (child, 0); // load expression object
                        addStringPrefix (name);
                        addIndexPrefix (localIndex);
                        addToken (Token.CATCH_SCOPE);
                        addUint8 (scopeIndex != 0 ? 1 : 0);
                        stackChange (-1);
                    }
                    break;


                case Token.THROW:
                    updateLineNumber (node);
                    VisitExpression (child, 0);
                    addToken (Token.THROW);
                    addUint16 (itsLineNumber & 0xFFFF);
                    stackChange (-1);
                    break;


                case Token.RETHROW:
                    updateLineNumber (node);
                    addIndexOp (Token.RETHROW, getLocalBlockRef (node));
                    break;


                case Token.RETURN:
                    updateLineNumber (node);
                    if (child != null) {
                        VisitExpression (child, ECF_TAIL);
                        addToken (Token.RETURN);
                        stackChange (-1);
                    }
                    else {
                        addIcode (Icode_RETUNDEF);
                    }
                    break;


                case Token.RETURN_RESULT:
                    updateLineNumber (node);
                    addToken (Token.RETURN_RESULT);
                    break;


                case Token.ENUM_INIT_KEYS:
                case Token.ENUM_INIT_VALUES:
                    VisitExpression (child, 0);
                    addIndexOp (type, getLocalBlockRef (node));
                    stackChange (-1);
                    break;


                default:
                    throw badTree (node);

            }

            if (itsStackDepth != 0) {
                throw Context.CodeBug ();
            }
        }
Esempio n. 2
0
        /// <summary> Try/Catch/Finally
        /// 
        /// The IRFactory tries to express as much as possible in the tree;
        /// the responsibilities remaining for Codegen are to add the Java
        /// handlers: (Either (but not both) of TARGET and FINALLY might not
        /// be defined)
        /// - a catch handler for javascript exceptions that unwraps the
        /// exception onto the stack and GOTOes to the catch target
        /// - a finally handler
        /// ... and a goto to GOTO around these handlers.
        /// </summary>
        internal Node CreateTryCatchFinally(Node tryBlock, Node catchBlocks, Node finallyBlock, int lineno)
        {
            bool hasFinally = (finallyBlock != null) && (finallyBlock.Type != Token.BLOCK || finallyBlock.hasChildren ());

            // short circuit
            if (tryBlock.Type == Token.BLOCK && !tryBlock.hasChildren () && !hasFinally) {
                return tryBlock;
            }

            bool hasCatch = catchBlocks.hasChildren ();

            // short circuit
            if (!hasFinally && !hasCatch) {
                // bc finally might be an empty block...
                return tryBlock;
            }

            Node handlerBlock = new Node (Token.LOCAL_BLOCK);
            Node.Jump pn = new Node.Jump (Token.TRY, tryBlock, lineno);
            pn.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);

            if (hasCatch) {
                // jump around catch code
                Node endCatch = Node.newTarget ();
                pn.addChildToBack (makeJump (Token.GOTO, endCatch));

                // make a TARGET for the catch that the tcf node knows about
                Node catchTarget = Node.newTarget ();
                pn.target = catchTarget;
                // mark it
                pn.addChildToBack (catchTarget);

                //
                //  Given
                //
                //   try {
                //       tryBlock;
                //   } catch (e if condition1) {
                //       something1;
                //   ...
                //
                //   } catch (e if conditionN) {
                //       somethingN;
                //   } catch (e) {
                //       somethingDefault;
                //   }
                //
                //  rewrite as
                //
                //   try {
                //       tryBlock;
                //       goto after_catch:
                //   } catch (x) {
                //       with (newCatchScope(e, x)) {
                //           if (condition1) {
                //               something1;
                //               goto after_catch;
                //           }
                //       }
                //   ...
                //       with (newCatchScope(e, x)) {
                //           if (conditionN) {
                //               somethingN;
                //               goto after_catch;
                //           }
                //       }
                //       with (newCatchScope(e, x)) {
                //           somethingDefault;
                //           goto after_catch;
                //       }
                //   }
                // after_catch:
                //
                // If there is no default catch, then the last with block
                // arround  "somethingDefault;" is replaced by "rethrow;"

                // It is assumed that catch handler generation will store
                // exeception object in handlerBlock register

                // Block with local for exception scope objects
                Node catchScopeBlock = new Node (Token.LOCAL_BLOCK);

                // expects catchblocks children to be (cond block) pairs.
                Node cb = catchBlocks.FirstChild;
                bool hasDefault = false;
                int scopeIndex = 0;
                while (cb != null) {
                    int catchLineNo = cb.Lineno;

                    Node name = cb.FirstChild;
                    Node cond = name.Next;
                    Node catchStatement = cond.Next;
                    cb.removeChild (name);
                    cb.removeChild (cond);
                    cb.removeChild (catchStatement);

                    // Add goto to the catch statement to jump out of catch
                    // but prefix it with LEAVEWITH since try..catch produces
                    // "with"code in order to limit the scope of the exception
                    // object.
                    catchStatement.addChildToBack (new Node (Token.LEAVEWITH));
                    catchStatement.addChildToBack (makeJump (Token.GOTO, endCatch));

                    // Create condition "if" when present
                    Node condStmt;
                    if (cond.Type == Token.EMPTY) {
                        condStmt = catchStatement;
                        hasDefault = true;
                    }
                    else {
                        condStmt = CreateIf (cond, catchStatement, null, catchLineNo);
                    }

                    // Generate code to Create the scope object and store
                    // it in catchScopeBlock register
                    Node catchScope = new Node (Token.CATCH_SCOPE, name, CreateUseLocal (handlerBlock));
                    catchScope.putProp (Node.LOCAL_BLOCK_PROP, catchScopeBlock);
                    catchScope.putIntProp (Node.CATCH_SCOPE_PROP, scopeIndex);
                    catchScopeBlock.addChildToBack (catchScope);

                    // Add with statement based on catch scope object
                    catchScopeBlock.addChildToBack (CreateWith (CreateUseLocal (catchScopeBlock), condStmt, catchLineNo));

                    // move to next cb
                    cb = cb.Next;
                    ++scopeIndex;
                }
                pn.addChildToBack (catchScopeBlock);
                if (!hasDefault) {
                    // Generate code to rethrow if no catch clause was executed
                    Node rethrow = new Node (Token.RETHROW);
                    rethrow.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);
                    pn.addChildToBack (rethrow);
                }

                pn.addChildToBack (endCatch);
            }

            if (hasFinally) {
                Node finallyTarget = Node.newTarget ();
                pn.Finally = finallyTarget;

                // add jsr finally to the try block
                pn.addChildToBack (makeJump (Token.JSR, finallyTarget));

                // jump around finally code
                Node finallyEnd = Node.newTarget ();
                pn.addChildToBack (makeJump (Token.GOTO, finallyEnd));

                pn.addChildToBack (finallyTarget);
                Node fBlock = new Node (Token.FINALLY, finallyBlock);
                fBlock.putProp (Node.LOCAL_BLOCK_PROP, handlerBlock);
                pn.addChildToBack (fBlock);

                pn.addChildToBack (finallyEnd);
            }
            handlerBlock.addChildToBack (pn);
            return handlerBlock;
        }
Esempio n. 3
0
        internal Node CreateIncDec(int nodeType, bool post, Node child)
        {
            child = makeReference (child);
            if (child == null) {
                string msg;
                if (nodeType == Token.DEC) {
                    msg = "msg.bad.decr";
                }
                else {
                    msg = "msg.bad.incr";
                }
                parser.ReportError (msg);
                return null;
            }

            int childType = child.Type;

            switch (childType) {

                case Token.NAME:
                case Token.GETPROP:
                case Token.GETELEM:
                case Token.GET_REF: {
                        Node n = new Node (nodeType, child);
                        int incrDecrMask = 0;
                        if (nodeType == Token.DEC) {
                            incrDecrMask |= Node.DECR_FLAG;
                        }
                        if (post) {
                            incrDecrMask |= Node.POST_FLAG;
                        }
                        n.putIntProp (Node.INCRDECR_PROP, incrDecrMask);
                        return n;
                    }
            }
            throw Context.CodeBug ();
        }
Esempio n. 4
0
 /// <summary> Regular expressions</summary>
 internal Node CreateRegExp(int regexpIndex)
 {
     Node n = new Node (Token.REGEXP);
     n.putIntProp (Node.REGEXP_PROP, regexpIndex);
     return n;
 }
Esempio n. 5
0
 internal Node CreateCallOrNew(int nodeType, Node child)
 {
     int type = Node.NON_SPECIALCALL;
     if (child.Type == Token.NAME) {
         string name = child.String;
         if (name.Equals ("eval")) {
             type = Node.SPECIALCALL_EVAL;
         }
         else if (name.Equals ("With")) {
             type = Node.SPECIALCALL_WITH;
         }
     }
     else if (child.Type == Token.GETPROP) {
         string name = child.LastChild.String;
         if (name.Equals ("eval")) {
             type = Node.SPECIALCALL_EVAL;
         }
     }
     Node node = new Node (nodeType, child);
     if (type != Node.NON_SPECIALCALL) {
         // Calls to these functions require activation objects.
         setRequiresActivation ();
         node.putIntProp (Node.SPECIALCALL_PROP, type);
     }
     return node;
 }