Esempio n. 1
0
		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();
			}
		}
Esempio n. 2
0
		private void UpdateLineNumber(Node node)
		{
			itsLineNumber = node.GetLineno();
			if (itsLineNumber == -1)
			{
				return;
			}
			cfw.AddLineNumberEntry((short)itsLineNumber);
		}
Esempio n. 3
0
		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)));
			}
		}