📄 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 * Roger Lawrence * Andi Vajda * * 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;/** * This class generates code for a given IR tree. * * @author Norris Boyd * @author Roger Lawrence */public class Codegen extends Interpreter{ 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; mainClassSignature = ClassFileWriter.classNameToSignature(mainClassName); return generateCode(encodedSource); } 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, optLevel); } } 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) { ScriptOrFnNode script = scriptOrFnNodes[0]; cfw.addInterface("org/mozilla/javascript/Script"); generateScriptCtor(cfw, script); generateMain(cfw); generateExecute(cfw, script); } generateCallMethod(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.generateBodyCode(); if (n.getType() == Token.FUNCTION) { OptFunctionNode ofn = OptFunctionNode.get(n); generateFunctionInit(cfw, ofn); if (ofn.isTargetOfDirectCall()) { emitDirectConstructor(cfw, ofn); } } } if (directCallTargets != null) { int N = directCallTargets.size(); for (int j = 0; j != N; ++j) { cfw.addField(getDirectTargetFieldName(j), mainClassSignature, ClassFileWriter.ACC_PRIVATE); } } emitRegExpInit(cfw); emitConstantDudeInitializers(cfw); return cfw.toByteArray(); } private void emitDirectConstructor(ClassFileWriter cfw, OptFunctionNode ofn) {/* we generate .. Scriptable directConstruct(<directCallArgs>) { Scriptable newInstance = createObject(cx, scope); Object val = <body-name>(cx, scope, newInstance, <directCallArgs>); if (val instanceof Scriptable) { return (Scriptable) val; } return newInstance; }*/ 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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -