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) { 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 & unchecked((int)(0xFFFF))); } else { // Only use the tail call optimization if we're not in a try // or we're not generating debug info (since the // 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: { bool 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; // use typeofname if an activation frame exists // 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 & unchecked((int)(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() & unchecked((int)(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(); } }
private void UpdateLineNumber(Node node) { itsLineNumber = node.GetLineno(); if (itsLineNumber == -1) { return; } cfw.AddLineNumberEntry((short)itsLineNumber); }
private void UpdateLineNumber(Node node) { int lineno = node.GetLineno(); if (lineno != lineNumber && lineno >= 0) { if (itsData.firstLinePC < 0) { itsData.firstLinePC = lineno; } lineNumber = lineno; AddIcode(Icode_LINE); AddUint16(lineno & unchecked((int)(0xFFFF))); } }