Exemple #1
0
		internal static void RunFlowAnalyzes(OptFunctionNode fn, Node[] statementNodes)
		{
			int paramCount = fn.fnode.GetParamCount();
			int varCount = fn.fnode.GetParamAndVarCount();
			int[] varTypes = new int[varCount];
			// If the variable is a parameter, it could have any type.
			for (int i = 0; i != paramCount; ++i)
			{
				varTypes[i] = Rhino.Optimizer.Optimizer.AnyType;
			}
			// If the variable is from a "var" statement, its typeEvent will be set
			// when we see the setVar node.
			for (int i_1 = paramCount; i_1 != varCount; ++i_1)
			{
				varTypes[i_1] = Rhino.Optimizer.Optimizer.NoType;
			}
			Block[] theBlocks = BuildBlocks(statementNodes);
			ReachingDefDataFlow(fn, statementNodes, theBlocks, varTypes);
			TypeFlow(fn, statementNodes, theBlocks, varTypes);
			for (int i_2 = paramCount; i_2 != varCount; i_2++)
			{
				if (varTypes[i_2] == Rhino.Optimizer.Optimizer.NumberType)
				{
					fn.SetIsNumberVar(i_2);
				}
			}
		}
Exemple #2
0
		private void OptimizeFunction(OptFunctionNode theFunction)
		{
			if (theFunction.fnode.RequiresActivation())
			{
				return;
			}
			inDirectCallFunction = theFunction.IsTargetOfDirectCall();
			this.theFunction = theFunction;
			ObjArray statementsArray = new ObjArray();
			BuildStatementList_r(theFunction.fnode, statementsArray);
			Node[] theStatementNodes = new Node[statementsArray.Size()];
			statementsArray.ToArray(theStatementNodes);
			Block.RunFlowAnalyzes(theFunction, theStatementNodes);
			if (!theFunction.fnode.RequiresActivation())
			{
				parameterUsedInNumberContext = false;
				foreach (Node theStatementNode in theStatementNodes)
				{
					RewriteForNumberVariables(theStatementNode, NumberType);
				}
				theFunction.SetParameterNumberContext(parameterUsedInNumberContext);
			}
		}
Exemple #3
0
		private void GenerateFunctionInit(ClassFileWriter cfw, OptFunctionNode ofn)
		{
			int CONTEXT_ARG = 1;
			int SCOPE_ARG = 2;
			cfw.StartMethod(GetFunctionInitMethodName(ofn), FUNCTION_INIT_SIGNATURE, (short)(ClassFileWriter.ACC_PRIVATE | ClassFileWriter.ACC_FINAL));
			// Call NativeFunction.initScriptFunction
			cfw.AddLoadThis();
			cfw.AddALoad(CONTEXT_ARG);
			cfw.AddALoad(SCOPE_ARG);
			cfw.AddInvoke(ByteCode.INVOKEVIRTUAL, "org/mozilla/javascript/NativeFunction", "initScriptFunction", "(Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + ")V");
			// precompile all regexp literals
			if (ofn.fnode.GetRegexpCount() != 0)
			{
				cfw.AddALoad(CONTEXT_ARG);
				cfw.AddInvoke(ByteCode.INVOKESTATIC, mainClassName, REGEXP_INIT_METHOD_NAME, REGEXP_INIT_METHOD_SIGNATURE);
			}
			cfw.Add(ByteCode.RETURN);
			// 3 = (scriptThis/functionRef) + scope + context
			cfw.StopMethod((short)3);
		}
Exemple #4
0
		private void VisitOptimizedCall(Node node, OptFunctionNode target, int type, Node child)
		{
			Node firstArgChild = child.GetNext();
			string className = codegen.mainClassName;
			short thisObjLocal = 0;
			if (type == Token.NEW)
			{
				GenerateExpression(child, node);
			}
			else
			{
				GenerateFunctionAndThisObj(child, node);
				thisObjLocal = GetNewWordLocal();
				cfw.AddAStore(thisObjLocal);
			}
			// stack: ... functionObj
			int beyond = cfw.AcquireLabel();
			int regularCall = cfw.AcquireLabel();
			cfw.Add(ByteCode.DUP);
			cfw.Add(ByteCode.INSTANCEOF, className);
			cfw.Add(ByteCode.IFEQ, regularCall);
			cfw.Add(ByteCode.CHECKCAST, className);
			cfw.Add(ByteCode.DUP);
			cfw.Add(ByteCode.GETFIELD, className, Codegen.ID_FIELD_NAME, "I");
			cfw.AddPush(codegen.GetIndex(target.fnode));
			cfw.Add(ByteCode.IF_ICMPNE, regularCall);
			// stack: ... directFunct
			cfw.AddALoad(contextLocal);
			cfw.AddALoad(variableObjectLocal);
			// stack: ... directFunc cx scope
			if (type == Token.NEW)
			{
				cfw.Add(ByteCode.ACONST_NULL);
			}
			else
			{
				cfw.AddALoad(thisObjLocal);
			}
			// stack: ... directFunc cx scope thisObj
			Node argChild = firstArgChild;
			while (argChild != null)
			{
				int dcp_register = NodeIsDirectCallParameter(argChild);
				if (dcp_register >= 0)
				{
					cfw.AddALoad(dcp_register);
					cfw.AddDLoad(dcp_register + 1);
				}
				else
				{
					if (argChild.GetIntProp(Node.ISNUMBER_PROP, -1) == Node.BOTH)
					{
						cfw.Add(ByteCode.GETSTATIC, "java/lang/Void", "TYPE", "Ljava/lang/Class;");
						GenerateExpression(argChild, node);
					}
					else
					{
						GenerateExpression(argChild, node);
						cfw.AddPush(0.0);
					}
				}
				argChild = argChild.GetNext();
			}
			cfw.Add(ByteCode.GETSTATIC, "org/mozilla/javascript/ScriptRuntime", "emptyArgs", "[Ljava/lang/Object;");
			cfw.AddInvoke(ByteCode.INVOKESTATIC, codegen.mainClassName, (type == Token.NEW) ? codegen.GetDirectCtorName(target.fnode) : codegen.GetBodyMethodName(target.fnode), codegen.GetBodyMethodSignature(target.fnode));
			cfw.Add(ByteCode.GOTO, beyond);
			cfw.MarkLabel(regularCall);
			// stack: ... functionObj
			cfw.AddALoad(contextLocal);
			cfw.AddALoad(variableObjectLocal);
			// stack: ... functionObj cx scope
			if (type != Token.NEW)
			{
				cfw.AddALoad(thisObjLocal);
				ReleaseWordLocal(thisObjLocal);
			}
			// stack: ... functionObj cx scope thisObj
			// XXX: this will generate code for the child array the second time,
			// so expression code generation better not to alter tree structure...
			GenerateCallArgArray(node, firstArgChild, true);
			if (type == Token.NEW)
			{
				AddScriptRuntimeInvoke("newObject", "(Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "[Ljava/lang/Object;" + ")Lorg/mozilla/javascript/Scriptable;");
			}
			else
			{
				cfw.AddInvoke(ByteCode.INVOKEINTERFACE, "org/mozilla/javascript/Callable", "call", "(Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "Lorg/mozilla/javascript/Scriptable;" + "[Ljava/lang/Object;" + ")Ljava/lang/Object;");
			}
			cfw.MarkLabel(beyond);
		}
Exemple #5
0
		private void VisitFunction(OptFunctionNode ofn, int functionType)
		{
			int fnIndex = codegen.GetIndex(ofn.fnode);
			cfw.Add(ByteCode.NEW, codegen.mainClassName);
			// Call function constructor
			cfw.Add(ByteCode.DUP);
			cfw.AddALoad(variableObjectLocal);
			cfw.AddALoad(contextLocal);
			// load 'cx'
			cfw.AddPush(fnIndex);
			cfw.AddInvoke(ByteCode.INVOKESPECIAL, codegen.mainClassName, "<init>", Codegen.FUNCTION_CONSTRUCTOR_SIGNATURE);
			if (functionType == FunctionNode.FUNCTION_EXPRESSION)
			{
				// Leave closure object on stack and do not pass it to
				// initFunction which suppose to connect statements to scope
				return;
			}
			cfw.AddPush(functionType);
			cfw.AddALoad(variableObjectLocal);
			cfw.AddALoad(contextLocal);
			// load 'cx'
			AddOptRuntimeInvoke("initFunction", "(Lorg/mozilla/javascript/NativeFunction;" + "I" + "Lorg/mozilla/javascript/Scriptable;" + "Lorg/mozilla/javascript/Context;" + ")V");
		}
Exemple #6
0
		private void EmitDirectConstructor(ClassFileWriter cfw, OptFunctionNode ofn)
		{
			cfw.StartMethod(GetDirectCtorName(ofn.fnode), GetBodyMethodSignature(ofn.fnode), (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
			int argCount = ofn.fnode.GetParamCount();
			int firstLocal = (4 + argCount * 3) + 1;
			cfw.AddALoad(0);
			// this
			cfw.AddALoad(1);
			// cx
			cfw.AddALoad(2);
			// scope
			cfw.AddInvoke(ByteCode.INVOKEVIRTUAL, "org/mozilla/javascript/BaseFunction", "createObject", "(Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + ")Lorg/mozilla/javascript/Scriptable;");
			cfw.AddAStore(firstLocal);
			cfw.AddALoad(0);
			cfw.AddALoad(1);
			cfw.AddALoad(2);
			cfw.AddALoad(firstLocal);
			for (int i = 0; i < argCount; i++)
			{
				cfw.AddALoad(4 + (i * 3));
				cfw.AddDLoad(5 + (i * 3));
			}
			cfw.AddALoad(4 + argCount * 3);
			cfw.AddInvoke(ByteCode.INVOKESTATIC, mainClassName, GetBodyMethodName(ofn.fnode), GetBodyMethodSignature(ofn.fnode));
			int exitLabel = cfw.AcquireLabel();
			cfw.Add(ByteCode.DUP);
			// make a copy of direct call result
			cfw.Add(ByteCode.INSTANCEOF, "org/mozilla/javascript/Scriptable");
			cfw.Add(ByteCode.IFEQ, exitLabel);
			// cast direct call result
			cfw.Add(ByteCode.CHECKCAST, "org/mozilla/javascript/Scriptable");
			cfw.Add(ByteCode.ARETURN);
			cfw.MarkLabel(exitLabel);
			cfw.AddALoad(firstLocal);
			cfw.Add(ByteCode.ARETURN);
			cfw.StopMethod((short)(firstLocal + 1));
		}
Exemple #7
0
		internal virtual string GetFunctionInitMethodName(OptFunctionNode ofn)
		{
			return "_i" + GetIndex(ofn.fnode);
		}
Exemple #8
0
		private void PrintLiveOnEntrySet(OptFunctionNode fn)
		{
		}
Exemple #9
0
		private static bool FindDefPoints(OptFunctionNode fn, Node n, int[] varTypes)
		{
			bool result = false;
			Node first = n.GetFirstChild();
			for (Node next = first; next != null; next = next.GetNext())
			{
				result |= FindDefPoints(fn, next, varTypes);
			}
			switch (n.GetType())
			{
				case Token.DEC:
				case Token.INC:
				{
					if (first.GetType() == Token.GETVAR)
					{
						// theVar is a Number now
						int i = fn.GetVarIndex(first);
						result |= AssignType(varTypes, i, Rhino.Optimizer.Optimizer.NumberType);
					}
					break;
				}

				case Token.SETVAR:
				{
					Node rValue = first.GetNext();
					int theType = FindExpressionType(fn, rValue, varTypes);
					int i = fn.GetVarIndex(n);
					result |= AssignType(varTypes, i, theType);
					break;
				}
			}
			return result;
		}
Exemple #10
0
		private bool DoTypeFlow(OptFunctionNode fn, Node[] statementNodes, int[] varTypes)
		{
			bool changed = false;
			for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++)
			{
				Node n = statementNodes[i];
				if (n != null)
				{
					changed |= FindDefPoints(fn, n, varTypes);
				}
			}
			return changed;
		}
Exemple #11
0
		private static int FindExpressionType(OptFunctionNode fn, Node n, int[] varTypes)
		{
			switch (n.GetType())
			{
				case Token.NUMBER:
				{
					return Rhino.Optimizer.Optimizer.NumberType;
				}

				case Token.CALL:
				case Token.NEW:
				case Token.REF_CALL:
				{
					return Rhino.Optimizer.Optimizer.AnyType;
				}

				case Token.GETELEM:
				case Token.GETPROP:
				case Token.NAME:
				case Token.THIS:
				{
					return Rhino.Optimizer.Optimizer.AnyType;
				}

				case Token.GETVAR:
				{
					return varTypes[fn.GetVarIndex(n)];
				}

				case Token.INC:
				case Token.DEC:
				case Token.MUL:
				case Token.DIV:
				case Token.MOD:
				case Token.BITOR:
				case Token.BITXOR:
				case Token.BITAND:
				case Token.BITNOT:
				case Token.LSH:
				case Token.RSH:
				case Token.URSH:
				case Token.SUB:
				case Token.POS:
				case Token.NEG:
				{
					return Rhino.Optimizer.Optimizer.NumberType;
				}

				case Token.VOID:
				{
					// NYI: undefined type
					return Rhino.Optimizer.Optimizer.AnyType;
				}

				case Token.FALSE:
				case Token.TRUE:
				case Token.EQ:
				case Token.NE:
				case Token.LT:
				case Token.LE:
				case Token.GT:
				case Token.GE:
				case Token.SHEQ:
				case Token.SHNE:
				case Token.NOT:
				case Token.INSTANCEOF:
				case Token.IN:
				case Token.DEL_REF:
				case Token.DELPROP:
				{
					// NYI: boolean type
					return Rhino.Optimizer.Optimizer.AnyType;
				}

				case Token.STRING:
				case Token.TYPEOF:
				case Token.TYPEOFNAME:
				{
					// NYI: string type
					return Rhino.Optimizer.Optimizer.AnyType;
				}

				case Token.NULL:
				case Token.REGEXP:
				case Token.ARRAYCOMP:
				case Token.ARRAYLIT:
				case Token.OBJECTLIT:
				{
					return Rhino.Optimizer.Optimizer.AnyType;
				}

				case Token.ADD:
				{
					// XXX: actually, we know it's not
					// number, but no type yet for that
					// if the lhs & rhs are known to be numbers, we can be sure that's
					// the result, otherwise it could be a string.
					Node child = n.GetFirstChild();
					int lType = FindExpressionType(fn, child, varTypes);
					int rType = FindExpressionType(fn, child.GetNext(), varTypes);
					return lType | rType;
				}

				case Token.HOOK:
				{
					// we're not distinguishing strings yet
					Node ifTrue = n.GetFirstChild().GetNext();
					Node ifFalse = ifTrue.GetNext();
					int ifTrueType = FindExpressionType(fn, ifTrue, varTypes);
					int ifFalseType = FindExpressionType(fn, ifFalse, varTypes);
					return ifTrueType | ifFalseType;
				}

				case Token.COMMA:
				case Token.SETVAR:
				case Token.SETNAME:
				case Token.SETPROP:
				case Token.SETELEM:
				{
					return FindExpressionType(fn, n.GetLastChild(), varTypes);
				}

				case Token.AND:
				case Token.OR:
				{
					Node child = n.GetFirstChild();
					int lType = FindExpressionType(fn, child, varTypes);
					int rType = FindExpressionType(fn, child.GetNext(), varTypes);
					return lType | rType;
				}
			}
			return Rhino.Optimizer.Optimizer.AnyType;
		}
Exemple #12
0
		private void InitLiveOnEntrySets(OptFunctionNode fn, Node[] statementNodes)
		{
			int listLength = fn.GetVarCount();
			itsUseBeforeDefSet = new BitArray(listLength);
			itsNotDefSet = new BitArray(listLength);
			itsLiveOnEntrySet = new BitArray(listLength);
			itsLiveOnExitSet = new BitArray(listLength);
			for (int i = itsStartNodeIndex; i <= itsEndNodeIndex; i++)
			{
				Node n = statementNodes[i];
				LookForVariableAccess(fn, n);
			}
			itsNotDefSet.Flip(0, listLength);
		}
Exemple #13
0
		private void LookForVariableAccess(OptFunctionNode fn, Node n)
		{
			switch (n.GetType())
			{
				case Token.TYPEOFNAME:
				{
					// TYPEOFNAME may be used with undefined names, which is why
					// this is handled separately from GETVAR above.
					int varIndex = fn.fnode.GetIndexForNameNode(n);
					if (varIndex > -1 && !itsNotDefSet.Get(varIndex))
					{
						itsUseBeforeDefSet.Set(varIndex);
					}
					break;
				}

				case Token.DEC:
				case Token.INC:
				{
					Node child = n.GetFirstChild();
					if (child.GetType() == Token.GETVAR)
					{
						int varIndex = fn.GetVarIndex(child);
						if (!itsNotDefSet.Get(varIndex))
						{
							itsUseBeforeDefSet.Set(varIndex);
						}
						itsNotDefSet.Set(varIndex);
					}
					else
					{
						LookForVariableAccess(fn, child);
					}
					break;
				}

				case Token.SETVAR:
				{
					Node lhs = n.GetFirstChild();
					Node rhs = lhs.GetNext();
					LookForVariableAccess(fn, rhs);
					itsNotDefSet.Set(fn.GetVarIndex(n));
					break;
				}

				case Token.GETVAR:
				{
					int varIndex = fn.GetVarIndex(n);
					if (!itsNotDefSet.Get(varIndex))
					{
						itsUseBeforeDefSet.Set(varIndex);
					}
					break;
				}

				default:
				{
					Node child_1 = n.GetFirstChild();
					while (child_1 != null)
					{
						LookForVariableAccess(fn, child_1);
						child_1 = child_1.GetNext();
					}
					break;
				}
			}
		}
Exemple #14
0
		private static void TypeFlow(OptFunctionNode fn, Node[] statementNodes, Block[] theBlocks, int[] varTypes)
		{
			bool[] visit = new bool[theBlocks.Length];
			bool[] doneOnce = new bool[theBlocks.Length];
			int vIndex = 0;
			bool needRescan = false;
			visit[vIndex] = true;
			while (true)
			{
				if (visit[vIndex] || !doneOnce[vIndex])
				{
					doneOnce[vIndex] = true;
					visit[vIndex] = false;
					if (theBlocks[vIndex].DoTypeFlow(fn, statementNodes, varTypes))
					{
						Block[] succ = theBlocks[vIndex].itsSuccessors;
						if (succ != null)
						{
							for (int i = 0; i < succ.Length; i++)
							{
								int index = succ[i].itsBlockID;
								visit[index] = true;
								needRescan |= (index < vIndex);
							}
						}
					}
				}
				if (vIndex == (theBlocks.Length - 1))
				{
					if (needRescan)
					{
						vIndex = 0;
						needRescan = false;
					}
					else
					{
						break;
					}
				}
				else
				{
					vIndex++;
				}
			}
		}
Exemple #15
0
		private static void ReachingDefDataFlow(OptFunctionNode fn, Node[] statementNodes, Block[] theBlocks, int[] varTypes)
		{
			for (int i = 0; i < theBlocks.Length; i++)
			{
				theBlocks[i].InitLiveOnEntrySets(fn, statementNodes);
			}
			bool[] visit = new bool[theBlocks.Length];
			bool[] doneOnce = new bool[theBlocks.Length];
			int vIndex = theBlocks.Length - 1;
			bool needRescan = false;
			visit[vIndex] = true;
			while (true)
			{
				if (visit[vIndex] || !doneOnce[vIndex])
				{
					doneOnce[vIndex] = true;
					visit[vIndex] = false;
					if (theBlocks[vIndex].DoReachedUseDataFlow())
					{
						Block[] pred = theBlocks[vIndex].itsPredecessors;
						if (pred != null)
						{
							for (int i_1 = 0; i_1 < pred.Length; i_1++)
							{
								int index = pred[i_1].itsBlockID;
								visit[index] = true;
								needRescan |= (index > vIndex);
							}
						}
					}
				}
				if (vIndex == 0)
				{
					if (needRescan)
					{
						vIndex = theBlocks.Length - 1;
						needRescan = false;
					}
					else
					{
						break;
					}
				}
				else
				{
					vIndex--;
				}
			}
			theBlocks[0].MarkAnyTypeVariables(varTypes);
		}