📄 codegen.java
字号:
int getIndex(ScriptOrFnNode n) { return scriptOrFnIndexes.getExisting(n); } static String getDirectTargetFieldName(int i) { return "_dt" + i; } String getDirectCtorName(ScriptOrFnNode n) { return "_n"+getIndex(n); } String getBodyMethodName(ScriptOrFnNode n) { return "_c"+getIndex(n); } String getBodyMethodSignature(ScriptOrFnNode n) { StringBuffer sb = new StringBuffer(); 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(); } String getFunctionInitMethodName(OptFunctionNode ofn) { return "_i"+getIndex(ofn.fnode); } String getCompiledRegexpName(ScriptOrFnNode n, int regexpIndex) { return "_re"+getIndex(n)+"_"+regexpIndex; } static RuntimeException badTree() { throw new RuntimeException("Bad tree in codegen"); } void setMainMethodClass(String className) { mainMethodClass = className; } static final String DEFAULT_MAIN_METHOD_CLASS = "org.mozilla.javascript.optimizer.OptRuntime"; private static final String SUPER_CLASS_NAME = "org.mozilla.javascript.NativeFunction"; static final String DIRECT_CALL_PARENT_FIELD = "_dcp"; private static final String ID_FIELD_NAME = "_id"; private static final String REGEXP_INIT_METHOD_NAME = "_reInit"; private static final String REGEXP_INIT_METHOD_SIGNATURE = "(Lorg/mozilla/javascript/RegExpProxy;" +"Lorg/mozilla/javascript/Context;" +")V"; static final String REGEXP_ARRAY_FIELD_NAME = "_re"; static final String REGEXP_ARRAY_FIELD_TYPE = "[Ljava/lang/Object;"; static final String FUNCTION_INIT_SIGNATURE = "(Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +")V"; static final String FUNCTION_CONSTRUCTOR_SIGNATURE = "(Lorg/mozilla/javascript/Scriptable;" +"Lorg/mozilla/javascript/Context;I)V"; private static final Object globalLock = new Object(); private static int globalSerialClassCounter; private CompilerEnvirons compilerEnv; private ObjArray directCallTargets; ScriptOrFnNode[] scriptOrFnNodes; private ObjToIntMap scriptOrFnIndexes; private String mainMethodClass = DEFAULT_MAIN_METHOD_CLASS; String mainClassName; String mainClassSignature; boolean itsUseDynamicScope; int languageVersion; private double[] itsConstantList; private int itsConstantListSize;}class BodyCodegen{ void generateBodyCode() { initBodyGeneration(); cfw.startMethod(codegen.getBodyMethodName(scriptOrFn), codegen.getBodyMethodSignature(scriptOrFn), (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE)); generatePrologue(); Node treeTop; if (fnCurrent != null) { treeTop = scriptOrFn.getLastChild(); } else { treeTop = scriptOrFn; } generateStatement(treeTop, null); generateEpilogue(); cfw.stopMethod((short)(localsMax + 1)); } private void initBodyGeneration() { isTopLevel = (scriptOrFn == codegen.scriptOrFnNodes[0]); varRegisters = null; if (scriptOrFn.getType() == Token.FUNCTION) { fnCurrent = OptFunctionNode.get(scriptOrFn); hasVarsInRegs = !fnCurrent.fnode.requiresActivation(); if (hasVarsInRegs) { int n = fnCurrent.fnode.getParamAndVarCount(); if (n != 0) { varRegisters = new short[n]; } } inDirectCallFunction = fnCurrent.isTargetOfDirectCall(); if (inDirectCallFunction && !hasVarsInRegs) Codegen.badTree(); } else { fnCurrent = null; hasVarsInRegs = false; inDirectCallFunction = false; } locals = new boolean[MAX_LOCALS]; funObjLocal = 0; contextLocal = 1; variableObjectLocal = 2; thisObjLocal = 3; localsMax = (short) 4; // number of parms + "this" firstFreeLocal = 4; popvLocal = -1; argsLocal = -1; itsZeroArgArray = -1; itsOneArgArray = -1; scriptRegexpLocal = -1; epilogueLabel = -1; enterAreaStartLabel = -1; } /** * Generate the prologue for a function or script. */ private void generatePrologue() { if (inDirectCallFunction) { int directParameterCount = scriptOrFn.getParamCount(); // 0 is reserved for function Object 'this' // 1 is reserved for context // 2 is reserved for parentScope // 3 is reserved for script 'this' if (firstFreeLocal != 4) Kit.codeBug(); for (int i = 0; i != directParameterCount; ++i) { varRegisters[i] = firstFreeLocal; // 3 is 1 for Object parm and 2 for double parm firstFreeLocal += 3; } if (!fnCurrent.getParameterNumberContext()) { // make sure that all parameters are objects itsForcedObjectParameters = true; for (int i = 0; i != directParameterCount; ++i) { short reg = varRegisters[i]; cfw.addALoad(reg); cfw.add(ByteCode.GETSTATIC, "java/lang/Void", "TYPE", "Ljava/lang/Class;"); int isObjectLabel = cfw.acquireLabel(); cfw.add(ByteCode.IF_ACMPNE, isObjectLabel); cfw.addDLoad(reg + 1); addDoubleWrap(); cfw.addAStore(reg); cfw.markLabel(isObjectLabel); } } } if (fnCurrent != null && !inDirectCallFunction && (!compilerEnv.isUseDynamicScope() || fnCurrent.fnode.getIgnoreDynamicScope())) { // Unless we're either in a direct call or using dynamic scope, // use the enclosing scope of the function as our variable object. cfw.addALoad(funObjLocal); cfw.addInvoke(ByteCode.INVOKEINTERFACE, "org/mozilla/javascript/Scriptable", "getParentScope", "()Lorg/mozilla/javascript/Scriptable;"); cfw.addAStore(variableObjectLocal); } // reserve 'args[]' argsLocal = firstFreeLocal++; localsMax = firstFreeLocal; if (fnCurrent == null) { // See comments in case Token.REGEXP if (scriptOrFn.getRegexpCount() != 0) { scriptRegexpLocal = getNewWordLocal(); codegen.pushRegExpArray(cfw, scriptOrFn, contextLocal, variableObjectLocal); cfw.addAStore(scriptRegexpLocal); } } if (hasVarsInRegs) { // No need to create activation. Pad arguments if need be. int parmCount = scriptOrFn.getParamCount(); if (parmCount > 0 && !inDirectCallFunction) { // Set up args array // check length of arguments, pad if need be cfw.addALoad(argsLocal); cfw.add(ByteCode.ARRAYLENGTH); cfw.addPush(parmCount); int label = cfw.acquireLabel(); cfw.add(ByteCode.IF_ICMPGE, label); cfw.addALoad(argsLocal); cfw.addPush(parmCount); addScriptRuntimeInvoke("padArguments", "([Ljava/lang/Object;I" +")[Ljava/lang/Object;"); cfw.addAStore(argsLocal); cfw.markLabel(label); } int paramCount = fnCurrent.fnode.getParamCount(); int varCount = fnCurrent.fnode.getParamAndVarCount(); // REMIND - only need to initialize the vars that don't get a value // before the next call and are used in the function short firstUndefVar = -1; for (int i = 0; i != varCount; ++i) { short reg = -1; if (i < paramCount) { if (!inDirectCallFunction) { reg = getNewWordLocal(); cfw.addALoad(argsLocal); cfw.addPush(i); cfw.add(ByteCode.AALOAD); cfw.addAStore(reg); } } else if (fnCurrent.isNumberVar(i)) { reg = getNewWordPairLocal(); cfw.addPush(0.0); cfw.addDStore(reg); } else { reg = getNewWordLocal(); if (firstUndefVar == -1) { Codegen.pushUndefined(cfw); firstUndefVar = reg; } else { cfw.addALoad(firstUndefVar); } cfw.addAStore(reg); } if (reg >= 0) { varRegisters[i] = reg; } // Add debug table enry if we're generating debug info if (compilerEnv.isGenerateDebugInfo()) { String name = fnCurrent.fnode.getParamOrVarName(i); String type = fnCurrent.isNumberVar(i) ? "D" : "Ljava/lang/Object;"; int startPC = cfw.getCurrentCodeOffset(); if (reg < 0) { reg = varRegisters[i]; } cfw.addVariableDescriptor(name, type, startPC, reg); } } // Skip creating activation object. return; } String debugVariableName; if (fnCurrent != null) { debugVariableName = "activation"; cfw.addALoad(funObjLocal); cfw.addALoad(variableObjectLocal); cfw.addALoad(argsLocal); addScriptRuntimeInvoke("createFunctionActivation", "(Lorg/mozilla/javascript/NativeFunction;" +"Lorg/mozilla/javascript/Scriptable;" +"[Ljava/lang/Object;" +")Lorg/mozilla/javascript/Scriptable;"); cfw.addAStore(variableObjectLocal); cfw.addALoad(contextLocal); cfw.addALoad(variableObjectLocal); addScriptRuntimeInvoke("enterActivationFunction", "(Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +")V"); } else { debugVariableName = "global"; cfw.addALoad(funObjLocal); cfw.addALoad(thisObjLocal); cfw.addALoad(contextLocal); cfw.addALoad(variableObjectLocal); cfw.addPush(0); // false to indicate it is not eval script addScriptRuntimeInvoke("initScript", "(Lorg/mozilla/javascript/NativeFunction;" +"Lorg/mozilla/javascript/Scriptable;" +"Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +"Z" +")V"); } enterAreaStartLabel = cfw.acquireLabel(); epilogueLabel = cfw.acquireLabel(); cfw.markLabel(enterAreaStartLabel); int functionCount = scriptOrFn.getFunctionCount();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -