📄 codegen.java
字号:
/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Rhino code, released * May 6, 1999. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1997-2000 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Norris Boyd * Kemal Bayram * Igor Bukanov * Bob Jervis * Roger Lawrence * Andi Vajda * Hannes Wallnoefer * * Alternatively, the contents of this file may be used under the terms of * the GNU General Public License Version 2 or later (the "GPL"), in which * case the provisions of the GPL are applicable instead of those above. If * you wish to allow use of your version of this file only under the terms of * the GPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replacing * them with the notice and other provisions required by the GPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the GPL. * * ***** END LICENSE BLOCK ***** */package org.mozilla.javascript.optimizer;import org.mozilla.javascript.*;import org.mozilla.classfile.*;import java.util.*;import java.lang.reflect.Constructor;import java.util.Hashtable;/** * This class generates code for a given IR tree. * * @author Norris Boyd * @author Roger Lawrence */public class Codegen implements Evaluator{ public void captureStackInfo(RhinoException ex) { throw new UnsupportedOperationException(); } public String getSourcePositionFromStack(Context cx, int[] linep) { throw new UnsupportedOperationException(); } public String getPatchedStack(RhinoException ex, String nativeStackTrace) { throw new UnsupportedOperationException(); } public List getScriptStack(RhinoException ex) { throw new UnsupportedOperationException(); } public void setEvalScriptFlag(Script script) { throw new UnsupportedOperationException(); } public Object compile(CompilerEnvirons compilerEnv, ScriptOrFnNode tree, String encodedSource, boolean returnFunction) { int serial; synchronized (globalLock) { serial = ++globalSerialClassCounter; } String mainClassName = "org.mozilla.javascript.gen.c"+serial; byte[] mainClassBytes = compileToClassFile(compilerEnv, mainClassName, tree, encodedSource, returnFunction); return new Object[] { mainClassName, mainClassBytes }; } public Script createScriptObject(Object bytecode, Object staticSecurityDomain) { Class cl = defineClass(bytecode, staticSecurityDomain); Script script; try { script = (Script)cl.newInstance(); } catch (Exception ex) { throw new RuntimeException ("Unable to instantiate compiled class:"+ex.toString()); } return script; } public Function createFunctionObject(Context cx, Scriptable scope, Object bytecode, Object staticSecurityDomain) { Class cl = defineClass(bytecode, staticSecurityDomain); NativeFunction f; try { Constructor ctor = cl.getConstructors()[0]; Object[] initArgs = { scope, cx, new Integer(0) }; f = (NativeFunction)ctor.newInstance(initArgs); } catch (Exception ex) { throw new RuntimeException ("Unable to instantiate compiled class:"+ex.toString()); } return f; } private Class defineClass(Object bytecode, Object staticSecurityDomain) { Object[] nameBytesPair = (Object[])bytecode; String className = (String)nameBytesPair[0]; byte[] classBytes = (byte[])nameBytesPair[1]; // The generated classes in this case refer only to Rhino classes // which must be accessible through this class loader ClassLoader rhinoLoader = getClass().getClassLoader(); GeneratedClassLoader loader; loader = SecurityController.createLoader(rhinoLoader, staticSecurityDomain); Exception e; try { Class cl = loader.defineClass(className, classBytes); loader.linkClass(cl); return cl; } catch (SecurityException x) { e = x; } catch (IllegalArgumentException x) { e = x; } throw new RuntimeException("Malformed optimizer package " + e); } byte[] compileToClassFile(CompilerEnvirons compilerEnv, String mainClassName, ScriptOrFnNode scriptOrFn, String encodedSource, boolean returnFunction) { this.compilerEnv = compilerEnv; transform(scriptOrFn); if (Token.printTrees) { System.out.println(scriptOrFn.toStringTree(scriptOrFn)); } if (returnFunction) { scriptOrFn = scriptOrFn.getFunctionNode(0); } initScriptOrFnNodesData(scriptOrFn); this.mainClassName = mainClassName; this.mainClassSignature = ClassFileWriter.classNameToSignature(mainClassName); try { return generateCode(encodedSource); } catch (ClassFileWriter.ClassFileFormatException e) { throw reportClassFileFormatException(scriptOrFn, e.getMessage()); } } private RuntimeException reportClassFileFormatException( ScriptOrFnNode scriptOrFn, String message) { String msg = scriptOrFn instanceof 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); } private void transform(ScriptOrFnNode tree) { initOptFunctions_r(tree); int optLevel = compilerEnv.getOptimizationLevel(); Hashtable possibleDirectCalls = null; if (optLevel > 0) { /* * Collect all of the contained functions into a hashtable * so that the call optimizer can access the class name & parameter * count for any call it encounters */ 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.getFunctionName(); if (name.length() != 0) { if (possibleDirectCalls == null) { possibleDirectCalls = new Hashtable(); } possibleDirectCalls.put(name, ofn); } } } } } if (possibleDirectCalls != null) { directCallTargets = new ObjArray(); } OptTransformer ot = new OptTransformer(possibleDirectCalls, directCallTargets); ot.transform(tree); if (optLevel > 0) { (new Optimizer()).optimize(tree); } } private static void initOptFunctions_r(ScriptOrFnNode scriptOrFn) { for (int i = 0, N = scriptOrFn.getFunctionCount(); i != N; ++i) { FunctionNode fn = scriptOrFn.getFunctionNode(i); new OptFunctionNode(fn); initOptFunctions_r(fn); } } private void initScriptOrFnNodesData(ScriptOrFnNode scriptOrFn) { ObjArray x = new ObjArray(); collectScriptOrFnNodes_r(scriptOrFn, x); int count = x.size(); scriptOrFnNodes = new ScriptOrFnNode[count]; x.toArray(scriptOrFnNodes); scriptOrFnIndexes = new ObjToIntMap(count); for (int i = 0; i != count; ++i) { scriptOrFnIndexes.put(scriptOrFnNodes[i], i); } } private static void collectScriptOrFnNodes_r(ScriptOrFnNode n, ObjArray x) { x.add(n); int nestedCount = n.getFunctionCount(); for (int i = 0; i != nestedCount; ++i) { collectScriptOrFnNodes_r(n.getFunctionNode(i), x); } } private byte[] generateCode(String encodedSource) { boolean hasScript = (scriptOrFnNodes[0].getType() == Token.SCRIPT); boolean hasFunctions = (scriptOrFnNodes.length > 1 || !hasScript); String sourceFile = null; if (compilerEnv.isGenerateDebugInfo()) { sourceFile = scriptOrFnNodes[0].getSourceName(); } ClassFileWriter cfw = new ClassFileWriter(mainClassName, SUPER_CLASS_NAME, sourceFile); cfw.addField(ID_FIELD_NAME, "I", ClassFileWriter.ACC_PRIVATE); cfw.addField(DIRECT_CALL_PARENT_FIELD, mainClassSignature, ClassFileWriter.ACC_PRIVATE); cfw.addField(REGEXP_ARRAY_FIELD_NAME, REGEXP_ARRAY_FIELD_TYPE, ClassFileWriter.ACC_PRIVATE); if (hasFunctions) { generateFunctionConstructor(cfw); } if (hasScript) { cfw.addInterface("org/mozilla/javascript/Script"); generateScriptCtor(cfw); generateMain(cfw); generateExecute(cfw); } generateCallMethod(cfw); generateResumeGenerator(cfw); generateNativeFunctionOverrides(cfw, encodedSource); int count = scriptOrFnNodes.length; for (int i = 0; i != count; ++i) { ScriptOrFnNode n = scriptOrFnNodes[i]; BodyCodegen bodygen = new BodyCodegen(); bodygen.cfw = cfw; bodygen.codegen = this; bodygen.compilerEnv = compilerEnv; bodygen.scriptOrFn = n; bodygen.scriptOrFnIndex = i; try { bodygen.generateBodyCode(); } catch (ClassFileWriter.ClassFileFormatException e) { throw reportClassFileFormatException(n, e.getMessage()); } if (n.getType() == Token.FUNCTION) { OptFunctionNode ofn = OptFunctionNode.get(n); generateFunctionInit(cfw, ofn); if (ofn.isTargetOfDirectCall()) { emitDirectConstructor(cfw, ofn); } } } if (directCallTargets != null) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -