int getLocalBlockRef (Node node) { Node localBlock = (Node)node.getProp (Node.LOCAL_BLOCK_PROP); return localBlock.getExistingIntProp (Node.LOCAL_PROP); }
void VisitExpression (Node node, int contextFlags) { if (VisitExpressionOptimized (node, contextFlags)) return; int type = node.Type; Node child = node.FirstChild; int savedStackDepth = itsStackDepth; 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 switch (fn.FunctionType) { case FunctionNode.FUNCTION_EXPRESSION: addIndexOp (Icode_CLOSURE_EXPR, fnIndex); break; default: throw Context.CodeBug (); } 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.LastChild; while (child != lastChild) { VisitExpression (child, 0); addIcode (Icode_POP); stackChange (-1); child = child.Next; } // 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.Next) != null) { VisitExpression (child, 0); ++argCount; } int callType = node.getIntProp (Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL); if (callType != Node.NON_SPECIALCALL) { // embed line number and source filename addIndexOp (Icode_CALLSPECIAL, argCount); addUint8 (callType); addUint8 (type == Token.NEW ? 1 : 0); addUint16 (itsLineNumber & 0xFFFF); } else { if (type == Token.CALL) { if ((contextFlags & ECF_TAIL) != 0) { 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 = itsICodeTop; int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ; addGotoOp (jump); stackChange (-1); addIcode (Icode_POP); stackChange (-1); child = child.Next; // Preserve tail context flag if any VisitExpression (child, contextFlags & ECF_TAIL); resolveForwardGoto (afterSecondJumpStart); } break; case Token.HOOK: { Node ifThen = child.Next; Node ifElse = ifThen.Next; VisitExpression (child, 0); int elseJumpStart = itsICodeTop; addGotoOp (Token.IFNE); ; stackChange (-1); // Preserve tail context flag if any VisitExpression (ifThen, contextFlags & ECF_TAIL); int afterElseJumpStart = itsICodeTop; addGotoOp (Token.GOTO); resolveForwardGoto (elseJumpStart); itsStackDepth = savedStackDepth; // Preserve tail context flag if any VisitExpression (ifElse, contextFlags & ECF_TAIL); resolveForwardGoto (afterElseJumpStart); } break; case Token.GETPROP: VisitExpression (child, 0); child = child.Next; addStringOp (Token.GETPROP, child.String); break; case Token.ADD: case Token.GETELEM: case Token.DELPROP: case Token.BITAND: case Token.BITOR: case Token.BITXOR: case Token.LSH: case Token.RSH: case Token.URSH: 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); VisitExpression (child.Next, 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: case Token.SETPROP_GETTER: case Token.SETPROP_SETTER: { VisitExpression (child, 0); child = child.Next; string property = child.String; child = child.Next; 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 ((type == Token.SETPROP_OP) ? Token.SETPROP : type, property); stackChange (-1); } break; case Token.SETELEM: case Token.SETELEM_OP: VisitExpression (child, 0); child = child.Next; VisitExpression (child, 0); child = child.Next; 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.Next; 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.SETNAME: { string name = child.String; VisitExpression (child, 0); child = child.Next; VisitExpression (child, 0); addStringOp (Token.SETNAME, name); stackChange (-1); } break; case Token.TYPEOFNAME: { string name = node.String; 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.getParamOrVarIndex (name); if (index == -1) { addStringOp (Icode_TYPEOFNAME, name); 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.String); stackChange (1); break; case Token.INC: case Token.DEC: VisitIncDec (node, child); break; case Token.NUMBER: { double num = node.Double; 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) Context.CodeBug (); string name = node.String; int index = scriptOrFn.getParamOrVarIndex (name); addVarOp (Token.GETVAR, index); stackChange (1); } break; case Token.SETVAR: { if (itsData.itsNeedsActivation) Context.CodeBug (); string name = child.String; child = child.Next; VisitExpression (child, 0); int index = scriptOrFn.getParamOrVarIndex (name); addVarOp (Token.SETVAR, 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.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.Next; } 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 = itsICodeTop; VisitExpression (child.Next, 0); addBackwardGoto (Icode_LEAVEDQ, queryPC); } break; case Token.DEFAULTNAMESPACE: case Token.ESCXMLATTR: case Token.ESCXMLTEXT: VisitExpression (child, 0); addToken (type); break; default: throw badTree (node); } //if (savedStackDepth + 1 != itsStackDepth) { // EcmaScriptHelper.CodeBug(); //} }
void VisitLiteral (Node node, Node child) { int type = node.Type; int count; object [] propertyIds = null; if (type == Token.ARRAYLIT) { count = 0; for (Node n = child; n != null; n = n.Next) { ++count; } } else if (type == Token.OBJECTLIT) { propertyIds = (object [])node.getProp (Node.OBJECT_IDS_PROP); count = propertyIds.Length; } else { throw badTree (node); } addIndexOp (Icode_LITERAL_NEW, count); stackChange (1); while (child != null) { VisitExpression (child, 0); addIcode (Icode_LITERAL_SET); stackChange (-1); child = child.Next; } if (type == Token.ARRAYLIT) { int [] skipIndexes = (int [])node.getProp (Node.SKIP_INDEXES_PROP); if (skipIndexes == null) { addToken (Token.ARRAYLIT); } else { int index = itsLiteralIds.size (); itsLiteralIds.add (skipIndexes); addIndexOp (Icode_SPARE_ARRAYLIT, index); } } else { int index = itsLiteralIds.size (); itsLiteralIds.add (propertyIds); addIndexOp (Token.OBJECTLIT, index); } }