public void Transform(ScriptNode tree) { TransformCompilationUnit(tree); for (int i = 0; i != tree.GetFunctionCount(); ++i) { FunctionNode fn = tree.GetFunctionNode(i); Transform(fn); } }
// It is assumed that (NumberType | AnyType) == AnyType internal virtual void Optimize(ScriptNode scriptOrFn) { // run on one function at a time for now int functionCount = scriptOrFn.GetFunctionCount(); for (int i = 0; i != functionCount; ++i) { OptFunctionNode f = OptFunctionNode.Get(scriptOrFn, i); OptimizeFunction(f); } }
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); }
public virtual object Compile(CompilerEnvirons compilerEnv, ScriptNode tree, string encodedSource, bool returnFunction) { int serial; lock (globalLock) { serial = ++globalSerialClassCounter; } string baseName = "c"; if (tree.GetSourceName().Length > 0) { baseName = tree.GetSourceName().ReplaceAll("\\W", "_"); if (!char.IsJavaIdentifierStart(baseName[0])) { baseName = "_" + baseName; } } string mainClassName = "org.mozilla.javascript.gen." + baseName + "_" + serial; byte[] mainClassBytes = CompileToClassFile(compilerEnv, mainClassName, tree, encodedSource, returnFunction); return new object[] { mainClassName, mainClassBytes }; }
// fixupTable[i] = (label_index << 32) | fixup_site // ECF_ or Expression Context Flags constants: for now only TAIL public virtual InterpreterData Compile(CompilerEnvirons compilerEnv, ScriptNode tree, string encodedSource, bool returnFunction) { this.compilerEnv = compilerEnv; new NodeTransformer().Transform(tree); if (returnFunction) { scriptOrFn = tree.GetFunctionNode(0); } else { scriptOrFn = tree; } itsData = new InterpreterData(compilerEnv.GetLanguageVersion(), scriptOrFn.GetSourceName(), encodedSource, ((AstRoot)tree).IsInStrictMode()); itsData.topLevel = true; if (returnFunction) { GenerateFunctionICode(); } else { GenerateICodeFromTree(scriptOrFn); } return itsData; }
private static void CollectScriptNodes_r(ScriptNode n, ObjArray x) { x.Add(n); int nestedCount = n.GetFunctionCount(); for (int i = 0; i != nestedCount; ++i) { CollectScriptNodes_r(n.GetFunctionNode(i), x); } }
private void InitScriptNodesData(ScriptNode scriptOrFn) { ObjArray x = new ObjArray(); CollectScriptNodes_r(scriptOrFn, x); int count = x.Size(); scriptOrFnNodes = new ScriptNode[count]; x.ToArray(scriptOrFnNodes); scriptOrFnIndexes = new ObjToIntMap(count); for (int i = 0; i != count; ++i) { scriptOrFnIndexes.Put(scriptOrFnNodes[i], i); } }
private static void InitOptFunctions_r(ScriptNode scriptOrFn) { for (int i = 0, N = scriptOrFn.GetFunctionCount(); i != N; ++i) { FunctionNode fn = scriptOrFn.GetFunctionNode(i); new OptFunctionNode(fn); InitOptFunctions_r(fn); } }
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); } }
private Exception ReportClassFileFormatException(ScriptNode scriptOrFn, string message) { string msg = scriptOrFn is FunctionNode ? ScriptRuntime.GetMessage2("msg.while.compiling.fn", ((FunctionNode)scriptOrFn).GetFunctionName(), message) : ScriptRuntime.GetMessage1("msg.while.compiling.script", message); return Context.ReportRuntimeError(msg, scriptOrFn.GetSourceName(), scriptOrFn.GetLineno(), null, 0); }
public static Rhino.Optimizer.OptFunctionNode Get(ScriptNode scriptOrFn) { return (Rhino.Optimizer.OptFunctionNode)scriptOrFn.GetCompilerData(); }
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: ; }
public object Compile(CompilerEnvirons compilerEnv, ScriptNode tree, string encodedSource, bool returnFunction) { CodeGenerator cgen = new CodeGenerator(); itsData = cgen.Compile(compilerEnv, tree, encodedSource, returnFunction); return itsData; }
/// <summary>Sets top current script or function scope</summary> public virtual void SetTop(ScriptNode top) { this.top = top; }
internal virtual string GetBodyMethodName(ScriptNode n) { return "_c_" + CleanName(n) + "_" + GetIndex(n); }
internal virtual string GetDirectCtorName(ScriptNode n) { return "_n" + GetIndex(n); }
internal virtual int GetIndex(ScriptNode n) { return scriptOrFnIndexes.GetExisting(n); }
private Node TransformScript(ScriptNode node) { decompiler.AddToken(Token.SCRIPT); if (currentScope != null) { Kit.CodeBug(); } currentScope = node; Node body = new Node(Token.BLOCK); foreach (Node kid in node) { body.AddChildToBack(Transform((AstNode)kid)); } node.RemoveChildren(); Node children = body.GetFirstChild(); if (children != null) { node.AddChildrenToBack(children); } return node; }
internal static bool IsGenerator(ScriptNode node) { return (node.GetType() == Token.FUNCTION) && ((FunctionNode)node).IsGenerator(); }
protected internal override void VisitCall(Node node, ScriptNode tree) { DetectDirectCall(node, tree); base.VisitCall(node, tree); }
/// <summary>Gets a Java-compatible "informative" name for the the ScriptOrFnNode</summary> internal virtual string CleanName(ScriptNode n) { string result = string.Empty; if (n is FunctionNode) { Name name = ((FunctionNode)n).GetFunctionName(); if (name == null) { result = "anonymous"; } else { result = name.GetIdentifier(); } } else { result = "script"; } return result; }
protected internal virtual void VisitCall(Node node, ScriptNode tree) { }
/// <summary>Sets parent scope</summary> public virtual void SetParentScope(Rhino.Ast.Scope parentScope) { this.parentScope = parentScope; this.top = parentScope == null ? (ScriptNode)this : parentScope.top; }
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(); }
internal virtual string GetCompiledRegexpName(ScriptNode n, int regexpIndex) { return "_re" + GetIndex(n) + "_" + regexpIndex; }
public virtual byte[] CompileToClassFile(CompilerEnvirons compilerEnv, string mainClassName, ScriptNode scriptOrFn, string encodedSource, bool returnFunction) { this.compilerEnv = compilerEnv; Transform(scriptOrFn); if (returnFunction) { scriptOrFn = scriptOrFn.GetFunctionNode(0); } InitScriptNodesData(scriptOrFn); this.mainClassName = mainClassName; this.mainClassSignature = ClassFileWriter.ClassNameToSignature(mainClassName); try { return GenerateCode(encodedSource); } catch (ClassFileWriter.ClassFileFormatException e) { throw ReportClassFileFormatException(scriptOrFn, e.Message); } }
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); } } } } } } }
public static Rhino.Optimizer.OptFunctionNode Get(ScriptNode scriptOrFn, int i) { FunctionNode fnode = scriptOrFn.GetFunctionNode(i); return (Rhino.Optimizer.OptFunctionNode)fnode.GetCompilerData(); }