private void TransformCompilationUnit(ScriptNode tree) { loops = new ObjArray(); loopEnds = new ObjArray(); // to save against upchecks if no finally blocks are used. hasFinally = false; // Flatten all only if we are not using scope objects for block scope bool createScopeObjects = tree.GetType() != Token.FUNCTION || ((FunctionNode)tree).RequiresActivation(); tree.FlattenSymbolTable(!createScopeObjects); //uncomment to print tree before transformation bool inStrictMode = tree is AstRoot && ((AstRoot)tree).IsInStrictMode(); TransformCompilationUnit_r(tree, tree, tree, createScopeObjects, inStrictMode); }
private void DetectDirectCall(Node node, ScriptNode tree) { if (tree.GetType() == Token.FUNCTION) { Node left = node.GetFirstChild(); // count the arguments int argCount = 0; Node arg = left.GetNext(); while (arg != null) { arg = arg.GetNext(); argCount++; } if (argCount == 0) { OptFunctionNode.Get(tree).itsContainsCalls0 = true; } if (possibleDirectCalls != null) { string targetName = null; if (left.GetType() == Token.NAME) { targetName = left.GetString(); } else { if (left.GetType() == Token.GETPROP) { targetName = left.GetFirstChild().GetNext().GetString(); } else { if (left.GetType() == Token.GETPROPNOWARN) { throw Kit.CodeBug(); } } } if (targetName != null) { OptFunctionNode ofn; ofn = possibleDirectCalls.Get(targetName); if (ofn != null && argCount == ofn.fnode.GetParamCount() && !ofn.fnode.RequiresActivation()) { // Refuse to directCall any function with more // than 32 parameters - prevent code explosion // for wacky test cases if (argCount <= 32) { node.PutProp(Node.DIRECTCALL_PROP, ofn); if (!ofn.IsTargetOfDirectCall()) { int index = directCallTargets.Size(); directCallTargets.Add(ofn); ofn.SetDirectTargetIndex(index); } } } } } } }
internal static bool IsGenerator(ScriptNode node) { return (node.GetType() == Token.FUNCTION) && ((FunctionNode)node).IsGenerator(); }
private void Transform(ScriptNode tree) { InitOptFunctions_r(tree); int optLevel = compilerEnv.GetOptimizationLevel(); IDictionary<string, OptFunctionNode> possibleDirectCalls = null; if (optLevel > 0) { if (tree.GetType() == Token.SCRIPT) { int functionCount = tree.GetFunctionCount(); for (int i = 0; i != functionCount; ++i) { OptFunctionNode ofn = OptFunctionNode.Get(tree, i); if (ofn.fnode.GetFunctionType() == FunctionNode.FUNCTION_STATEMENT) { string name = ofn.fnode.GetName(); if (name.Length != 0) { if (possibleDirectCalls == null) { possibleDirectCalls = new Dictionary<string, OptFunctionNode>(); } possibleDirectCalls.Put(name, ofn); } } } } } if (possibleDirectCalls != null) { directCallTargets = new ObjArray(); } OptTransformer ot = new OptTransformer(possibleDirectCalls, directCallTargets); ot.Transform(tree); if (optLevel > 0) { (new Rhino.Optimizer.Optimizer()).Optimize(tree); } }
internal virtual string GetBodyMethodSignature(ScriptNode n) { StringBuilder sb = new StringBuilder(); sb.Append('('); sb.Append(mainClassSignature); sb.Append("Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "Lorg/mozilla/javascript/Scriptable;"); if (n.GetType() == Token.FUNCTION) { OptFunctionNode ofn = OptFunctionNode.Get(n); if (ofn.IsTargetOfDirectCall()) { int pCount = ofn.fnode.GetParamCount(); for (int i = 0; i != pCount; i++) { sb.Append("Ljava/lang/Object;D"); } } } sb.Append("[Ljava/lang/Object;)Ljava/lang/Object;"); return sb.ToString(); }
private void TransformCompilationUnit_r(ScriptNode tree, Node parent, Scope scope, bool createScopeObjects, bool inStrictMode) { Node node = null; for (; ; ) { Node previous = null; if (node == null) { node = parent.GetFirstChild(); } else { previous = node; node = node.GetNext(); } if (node == null) { break; } int type = node.GetType(); if (createScopeObjects && (type == Token.BLOCK || type == Token.LOOP || type == Token.ARRAYCOMP) && (node is Scope)) { Scope newScope = (Scope)node; if (newScope.GetSymbolTable() != null) { // transform to let statement so we get a with statement // created to contain scoped let variables Node let = new Node(type == Token.ARRAYCOMP ? Token.LETEXPR : Token.LET); Node innerLet = new Node(Token.LET); let.AddChildToBack(innerLet); foreach (string name in newScope.GetSymbolTable().Keys) { innerLet.AddChildToBack(Node.NewString(Token.NAME, name)); } newScope.SetSymbolTable(null); // so we don't transform again Node oldNode = node; node = ReplaceCurrent(parent, previous, node, let); type = node.GetType(); let.AddChildToBack(oldNode); } } switch (type) { case Token.LABEL: case Token.SWITCH: case Token.LOOP: { loops.Push(node); loopEnds.Push(((Jump)node).target); break; } case Token.WITH: { loops.Push(node); Node leave = node.GetNext(); if (leave.GetType() != Token.LEAVEWITH) { Kit.CodeBug(); } loopEnds.Push(leave); break; } case Token.TRY: { Jump jump = (Jump)node; Node finallytarget = jump.GetFinally(); if (finallytarget != null) { hasFinally = true; loops.Push(node); loopEnds.Push(finallytarget); } break; } case Token.TARGET: case Token.LEAVEWITH: { if (!loopEnds.IsEmpty() && loopEnds.Peek() == node) { loopEnds.Pop(); loops.Pop(); } break; } case Token.YIELD: { ((FunctionNode)tree).AddResumptionPoint(node); break; } case Token.RETURN: { bool isGenerator = tree.GetType() == Token.FUNCTION && ((FunctionNode)tree).IsGenerator(); if (isGenerator) { node.PutIntProp(Node.GENERATOR_END_PROP, 1); } if (!hasFinally) { break; } // skip the whole mess. Node unwindBlock = null; for (int i = loops.Size() - 1; i >= 0; i--) { Node n = (Node)loops.Get(i); int elemtype = n.GetType(); if (elemtype == Token.TRY || elemtype == Token.WITH) { Node unwind; if (elemtype == Token.TRY) { Jump jsrnode = new Jump(Token.JSR); Node jsrtarget = ((Jump)n).GetFinally(); jsrnode.target = jsrtarget; unwind = jsrnode; } else { unwind = new Node(Token.LEAVEWITH); } if (unwindBlock == null) { unwindBlock = new Node(Token.BLOCK, node.GetLineno()); } unwindBlock.AddChildToBack(unwind); } } if (unwindBlock != null) { Node returnNode = node; Node returnExpr = returnNode.GetFirstChild(); node = ReplaceCurrent(parent, previous, node, unwindBlock); if (returnExpr == null || isGenerator) { unwindBlock.AddChildToBack(returnNode); } else { Node store = new Node(Token.EXPR_RESULT, returnExpr); unwindBlock.AddChildToFront(store); returnNode = new Node(Token.RETURN_RESULT); unwindBlock.AddChildToBack(returnNode); // transform return expression TransformCompilationUnit_r(tree, store, scope, createScopeObjects, inStrictMode); } // skip transformCompilationUnit_r to avoid infinite loop goto siblingLoop_continue; } break; } case Token.BREAK: case Token.CONTINUE: { Jump jump = (Jump)node; Jump jumpStatement = jump.GetJumpStatement(); if (jumpStatement == null) { Kit.CodeBug(); } for (int i = loops.Size(); ; ) { if (i == 0) { // Parser/IRFactory ensure that break/continue // always has a jump statement associated with it // which should be found throw Kit.CodeBug(); } --i; Node n = (Node)loops.Get(i); if (n == jumpStatement) { break; } int elemtype = n.GetType(); if (elemtype == Token.WITH) { Node leave = new Node(Token.LEAVEWITH); previous = AddBeforeCurrent(parent, previous, node, leave); } else { if (elemtype == Token.TRY) { Jump tryNode = (Jump)n; Jump jsrFinally = new Jump(Token.JSR); jsrFinally.target = tryNode.GetFinally(); previous = AddBeforeCurrent(parent, previous, node, jsrFinally); } } } if (type == Token.BREAK) { jump.target = jumpStatement.target; } else { jump.target = jumpStatement.GetContinue(); } jump.SetType(Token.GOTO); break; } case Token.CALL: { VisitCall(node, tree); break; } case Token.NEW: { VisitNew(node, tree); break; } case Token.LETEXPR: case Token.LET: { Node child = node.GetFirstChild(); if (child.GetType() == Token.LET) { // We have a let statement or expression rather than a // let declaration bool createWith = tree.GetType() != Token.FUNCTION || ((FunctionNode)tree).RequiresActivation(); node = VisitLet(createWith, parent, previous, node); break; } goto case Token.CONST; } case Token.CONST: case Token.VAR: { // fall through to process let declaration... Node result = new Node(Token.BLOCK); for (Node cursor = node.GetFirstChild(); cursor != null; ) { // Move cursor to next before createAssignment gets chance // to change n.next Node n = cursor; cursor = cursor.GetNext(); if (n.GetType() == Token.NAME) { if (!n.HasChildren()) { continue; } Node init = n.GetFirstChild(); n.RemoveChild(init); n.SetType(Token.BINDNAME); n = new Node(type == Token.CONST ? Token.SETCONST : Token.SETNAME, n, init); } else { // May be a destructuring assignment already transformed // to a LETEXPR if (n.GetType() != Token.LETEXPR) { throw Kit.CodeBug(); } } Node pop = new Node(Token.EXPR_VOID, n, node.GetLineno()); result.AddChildToBack(pop); } node = ReplaceCurrent(parent, previous, node, result); break; } case Token.TYPEOFNAME: { Scope defining = scope.GetDefiningScope(node.GetString()); if (defining != null) { node.SetScope(defining); } break; } case Token.TYPEOF: case Token.IFNE: { Node child = node.GetFirstChild(); if (type == Token.IFNE) { while (child.GetType() == Token.NOT) { child = child.GetFirstChild(); } if (child.GetType() == Token.EQ || child.GetType() == Token.NE) { Node first = child.GetFirstChild(); Node last = child.GetLastChild(); if (first.GetType() == Token.NAME && first.GetString().Equals("undefined")) { child = last; } else { if (last.GetType() == Token.NAME && last.GetString().Equals("undefined")) { child = first; } } } } if (child.GetType() == Token.GETPROP) { child.SetType(Token.GETPROPNOWARN); } break; } case Token.SETNAME: { if (inStrictMode) { node.SetType(Token.STRICT_SETNAME); } goto case Token.NAME; } case Token.NAME: case Token.SETCONST: case Token.DELPROP: { // Turn name to var for faster access if possible if (createScopeObjects) { break; } Node nameSource; if (type == Token.NAME) { nameSource = node; } else { nameSource = node.GetFirstChild(); if (nameSource.GetType() != Token.BINDNAME) { if (type == Token.DELPROP) { break; } throw Kit.CodeBug(); } } if (nameSource.GetScope() != null) { break; } // already have a scope set string name = nameSource.GetString(); Scope defining = scope.GetDefiningScope(name); if (defining != null) { nameSource.SetScope(defining); if (type == Token.NAME) { node.SetType(Token.GETVAR); } else { if (type == Token.SETNAME || type == Token.STRICT_SETNAME) { node.SetType(Token.SETVAR); nameSource.SetType(Token.STRING); } else { if (type == Token.SETCONST) { node.SetType(Token.SETCONSTVAR); nameSource.SetType(Token.STRING); } else { if (type == Token.DELPROP) { // Local variables are by definition permanent Node n = new Node(Token.FALSE); node = ReplaceCurrent(parent, previous, node, n); } else { throw Kit.CodeBug(); } } } } } break; } } TransformCompilationUnit_r(tree, node, node is Scope ? (Scope)node : scope, createScopeObjects, inStrictMode); siblingLoop_continue: ; } siblingLoop_break: ; }