📄 codegen.java
字号:
if (isGenerator) { // generate the user visible method which when invoked will // return a generator object generateGenerator(); } } // This creates a the user-facing function that returns a NativeGenerator // object. private void generateGenerator() { cfw.startMethod(codegen.getBodyMethodName(scriptOrFn), codegen.getBodyMethodSignature(scriptOrFn), (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE)); initBodyGeneration(); argsLocal = firstFreeLocal++; localsMax = firstFreeLocal; // get top level scope 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); } // generators are forced to have an activation record 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); // create a function object cfw.add(ByteCode.NEW, codegen.mainClassName); // Call function constructor cfw.add(ByteCode.DUP); cfw.addALoad(variableObjectLocal); cfw.addALoad(contextLocal); // load 'cx' cfw.addPush(scriptOrFnIndex); cfw.addInvoke(ByteCode.INVOKESPECIAL, codegen.mainClassName, "<init>", Codegen.FUNCTION_CONSTRUCTOR_SIGNATURE); // Init mainScript field cfw.add(ByteCode.DUP); if (isTopLevel) Kit.codeBug(); // Only functions can be generators cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.GETFIELD, codegen.mainClassName, Codegen.DIRECT_CALL_PARENT_FIELD, codegen.mainClassSignature); cfw.add(ByteCode.PUTFIELD, codegen.mainClassName, Codegen.DIRECT_CALL_PARENT_FIELD, codegen.mainClassSignature); generateNestedFunctionInits(); // create the NativeGenerator object that we return cfw.addALoad(variableObjectLocal); cfw.addALoad(thisObjLocal); cfw.addLoadConstant(maxLocals); cfw.addLoadConstant(maxStack); addOptRuntimeInvoke("createNativeGenerator", "(Lorg/mozilla/javascript/NativeFunction;" +"Lorg/mozilla/javascript/Scriptable;" +"Lorg/mozilla/javascript/Scriptable;II" +")Lorg/mozilla/javascript/Scriptable;"); cfw.add(ByteCode.ARETURN); cfw.stopMethod((short)(localsMax + 1)); } private void generateNestedFunctionInits() { int functionCount = scriptOrFn.getFunctionCount(); for (int i = 0; i != functionCount; i++) { OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn, i); if (ofn.fnode.getFunctionType() == FunctionNode.FUNCTION_STATEMENT) { visitFunction(ofn, FunctionNode.FUNCTION_STATEMENT); } } } 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 int[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; generatorStateLocal = -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; // Generate Generator specific prelude if (isGenerator) { // reserve 'args[]' operationLocal = firstFreeLocal++; localsMax = firstFreeLocal; // Local 3 is a reference to a GeneratorState object. The rest // of codegen expects local 3 to be a reference to the thisObj. // So move the value in local 3 to generatorStateLocal, and load // the saved thisObj from the GeneratorState object. cfw.addALoad(thisObjLocal); generatorStateLocal = firstFreeLocal++; localsMax = firstFreeLocal; cfw.add(ByteCode.CHECKCAST, OptRuntime.GeneratorState.CLASS_NAME); cfw.add(ByteCode.DUP); cfw.addAStore(generatorStateLocal); cfw.add(ByteCode.GETFIELD, OptRuntime.GeneratorState.CLASS_NAME, OptRuntime.GeneratorState.thisObj_NAME, OptRuntime.GeneratorState.thisObj_TYPE); cfw.addAStore(thisObjLocal); if (epilogueLabel == -1) { epilogueLabel = cfw.acquireLabel(); } ArrayList targets = ((FunctionNode)scriptOrFn).getResumptionPoints(); if (targets != null) { // get resumption point generateGetGeneratorResumptionPoint(); // generate dispatch table generatorSwitch = cfw.addTableSwitch(0, targets.size() + GENERATOR_START); generateCheckForThrowOrClose(-1, false, GENERATOR_START); } } 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 (compilerEnv.isGenerateObserverCount()) saveCurrentCodeOffset(); 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(); boolean [] constDeclarations = fnCurrent.fnode.getParamAndVarConst(); // 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(constDeclarations[i]); cfw.addPush(0.0); cfw.addDStore(reg); } else { reg = getNewWordLocal(constDeclarations[i]); if (firstUndefVar == -1) { Codegen.pushUndefined(cfw); firstUndefVar = reg; } else { cfw.addALoad(firstUndefVar); } cfw.addAStore(reg); } if (reg >= 0) { if (constDeclarations[i]) { cfw.addPush(0); cfw.addIStore(reg + (fnCurrent.isNumberVar(i) ? 2 : 1)); } varRegisters[i] = reg; } // Add debug table entry 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; } // skip creating activation object for the body of a generator. The // activation record required by a generator has already been created // in generateGenerator(). if (isGenerator) 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/Scrip
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -