📄 codegen.java
字号:
final int SCOPE_ARG = 1; final int CONTEXT_ARG = 2; final int ID_ARG = 3; cfw.startMethod("<init>", FUNCTION_CONSTRUCTOR_SIGNATURE, ClassFileWriter.ACC_PUBLIC); cfw.addALoad(0); cfw.addInvoke(ByteCode.INVOKESPECIAL, SUPER_CLASS_NAME, "<init>", "()V"); cfw.addLoadThis(); cfw.addILoad(ID_ARG); cfw.add(ByteCode.PUTFIELD, cfw.getClassName(), ID_FIELD_NAME, "I"); cfw.addLoadThis(); cfw.addALoad(CONTEXT_ARG); cfw.addALoad(SCOPE_ARG); int start = (scriptOrFnNodes[0].getType() == Token.SCRIPT) ? 1 : 0; int end = scriptOrFnNodes.length; if (start == end) throw badTree(); boolean generateSwitch = (2 <= end - start); int switchStart = 0; int switchStackTop = 0; if (generateSwitch) { cfw.addILoad(ID_ARG); // do switch from (start + 1, end - 1) mapping start to // the default case switchStart = cfw.addTableSwitch(start + 1, end - 1); } for (int i = start; i != end; ++i) { if (generateSwitch) { if (i == start) { cfw.markTableSwitchDefault(switchStart); switchStackTop = cfw.getStackTop(); } else { cfw.markTableSwitchCase(switchStart, i - 1 - start, switchStackTop); } } OptFunctionNode ofn = OptFunctionNode.get(scriptOrFnNodes[i]); cfw.addInvoke(ByteCode.INVOKEVIRTUAL, mainClassName, getFunctionInitMethodName(ofn), FUNCTION_INIT_SIGNATURE); cfw.add(ByteCode.RETURN); } // 4 = this + scope + context + id cfw.stopMethod((short)4); } private void generateFunctionInit(ClassFileWriter cfw, OptFunctionNode ofn) { final int CONTEXT_ARG = 1; final int SCOPE_ARG = 2; cfw.startMethod(getFunctionInitMethodName(ofn), FUNCTION_INIT_SIGNATURE, (short)(ClassFileWriter.ACC_PRIVATE | ClassFileWriter.ACC_FINAL)); // Call NativeFunction.initScriptFunction cfw.addLoadThis(); cfw.addALoad(CONTEXT_ARG); cfw.addALoad(SCOPE_ARG); cfw.addInvoke(ByteCode.INVOKEVIRTUAL, "org/mozilla/javascript/NativeFunction", "initScriptFunction", "(Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +")V"); // precompile all regexp literals int regexpCount = ofn.fnode.getRegexpCount(); if (regexpCount != 0) { cfw.addLoadThis(); pushRegExpArray(cfw, ofn.fnode, CONTEXT_ARG, SCOPE_ARG); cfw.add(ByteCode.PUTFIELD, mainClassName, REGEXP_ARRAY_FIELD_NAME, REGEXP_ARRAY_FIELD_TYPE); } cfw.add(ByteCode.RETURN); // 3 = (scriptThis/functionRef) + scope + context cfw.stopMethod((short)3); } private void generateNativeFunctionOverrides(ClassFileWriter cfw, String encodedSource) { // Override NativeFunction.getLanguageVersion() with // public int getLanguageVersion() { return <version-constant>; } cfw.startMethod("getLanguageVersion", "()I", ClassFileWriter.ACC_PUBLIC); cfw.addPush(compilerEnv.getLanguageVersion()); cfw.add(ByteCode.IRETURN); // 1: this and no argument or locals cfw.stopMethod((short)1); // The rest of NativeFunction overrides require specific code for each // script/function id final int Do_getFunctionName = 0; final int Do_getParamCount = 1; final int Do_getParamAndVarCount = 2; final int Do_getParamOrVarName = 3; final int Do_getEncodedSource = 4; final int Do_getParamOrVarConst = 5; final int SWITCH_COUNT = 6; for (int methodIndex = 0; methodIndex != SWITCH_COUNT; ++methodIndex) { if (methodIndex == Do_getEncodedSource && encodedSource == null) { continue; } // Generate: // prologue; // switch over function id to implement function-specific action // epilogue short methodLocals; switch (methodIndex) { case Do_getFunctionName: methodLocals = 1; // Only this cfw.startMethod("getFunctionName", "()Ljava/lang/String;", ClassFileWriter.ACC_PUBLIC); break; case Do_getParamCount: methodLocals = 1; // Only this cfw.startMethod("getParamCount", "()I", ClassFileWriter.ACC_PUBLIC); break; case Do_getParamAndVarCount: methodLocals = 1; // Only this cfw.startMethod("getParamAndVarCount", "()I", ClassFileWriter.ACC_PUBLIC); break; case Do_getParamOrVarName: methodLocals = 1 + 1; // this + paramOrVarIndex cfw.startMethod("getParamOrVarName", "(I)Ljava/lang/String;", ClassFileWriter.ACC_PUBLIC); break; case Do_getParamOrVarConst: methodLocals = 1 + 1 + 1; // this + paramOrVarName cfw.startMethod("getParamOrVarConst", "(I)Z", ClassFileWriter.ACC_PUBLIC); break; case Do_getEncodedSource: methodLocals = 1; // Only this cfw.startMethod("getEncodedSource", "()Ljava/lang/String;", ClassFileWriter.ACC_PUBLIC); cfw.addPush(encodedSource); break; default: throw Kit.codeBug(); } int count = scriptOrFnNodes.length; int switchStart = 0; int switchStackTop = 0; if (count > 1) { // Generate switch but only if there is more then one // script/function cfw.addLoadThis(); cfw.add(ByteCode.GETFIELD, cfw.getClassName(), ID_FIELD_NAME, "I"); // do switch from 1 .. count - 1 mapping 0 to the default case switchStart = cfw.addTableSwitch(1, count - 1); } for (int i = 0; i != count; ++i) { ScriptOrFnNode n = scriptOrFnNodes[i]; if (i == 0) { if (count > 1) { cfw.markTableSwitchDefault(switchStart); switchStackTop = cfw.getStackTop(); } } else { cfw.markTableSwitchCase(switchStart, i - 1, switchStackTop); } // Impelemnet method-specific switch code switch (methodIndex) { case Do_getFunctionName: // Push function name if (n.getType() == Token.SCRIPT) { cfw.addPush(""); } else { String name = ((FunctionNode)n).getFunctionName(); cfw.addPush(name); } cfw.add(ByteCode.ARETURN); break; case Do_getParamCount: // Push number of defined parameters cfw.addPush(n.getParamCount()); cfw.add(ByteCode.IRETURN); break; case Do_getParamAndVarCount: // Push number of defined parameters and declared variables cfw.addPush(n.getParamAndVarCount()); cfw.add(ByteCode.IRETURN); break; case Do_getParamOrVarName: // Push name of parameter using another switch // over paramAndVarCount int paramAndVarCount = n.getParamAndVarCount(); if (paramAndVarCount == 0) { // The runtime should never call the method in this // case but to make bytecode verifier happy return null // as throwing execption takes more code cfw.add(ByteCode.ACONST_NULL); cfw.add(ByteCode.ARETURN); } else if (paramAndVarCount == 1) { // As above do not check for valid index but always // return the name of the first param cfw.addPush(n.getParamOrVarName(0)); cfw.add(ByteCode.ARETURN); } else { // Do switch over getParamOrVarName cfw.addILoad(1); // param or var index // do switch from 1 .. paramAndVarCount - 1 mapping 0 // to the default case int paramSwitchStart = cfw.addTableSwitch( 1, paramAndVarCount - 1); for (int j = 0; j != paramAndVarCount; ++j) { if (cfw.getStackTop() != 0) Kit.codeBug(); String s = n.getParamOrVarName(j); if (j == 0) { cfw.markTableSwitchDefault(paramSwitchStart); } else { cfw.markTableSwitchCase(paramSwitchStart, j - 1, 0); } cfw.addPush(s); cfw.add(ByteCode.ARETURN); } } break; case Do_getParamOrVarConst: // Push name of parameter using another switch // over paramAndVarCount paramAndVarCount = n.getParamAndVarCount(); boolean [] constness = n.getParamAndVarConst(); if (paramAndVarCount == 0) { // The runtime should never call the method in this // case but to make bytecode verifier happy return null // as throwing execption takes more code cfw.add(ByteCode.ICONST_0); cfw.add(ByteCode.IRETURN); } else if (paramAndVarCount == 1) { // As above do not check for valid index but always // return the name of the first param cfw.addPush(constness[0]); cfw.add(ByteCode.IRETURN); } else { // Do switch over getParamOrVarName cfw.addILoad(1); // param or var index // do switch from 1 .. paramAndVarCount - 1 mapping 0 // to the default case int paramSwitchStart = cfw.addTableSwitch( 1, paramAndVarCount - 1); for (int j = 0; j != paramAndVarCount; ++j) { if (cfw.getStackTop() != 0) Kit.codeBug(); if (j == 0) { cfw.markTableSwitchDefault(paramSwitchStart); } else { cfw.markTableSwitchCase(paramSwitchStart, j - 1, 0); } cfw.addPush(constness[j]); cfw.add(ByteCode.IRETURN); } } break; case Do_getEncodedSource: // Push number encoded source start and end // to prepare for encodedSource.substring(start, end) cfw.addPush(n.getEncodedSourceStart()); cfw.addPush(n.getEncodedSourceEnd()); cfw.addInvoke(ByteCode.INVOKEVIRTUAL, "java/lang/String", "substring", "(II)Ljava/lang/String;"); cfw.add(ByteCode.ARETURN); break; default: throw Kit.codeBug(); } } cfw.stopMethod(methodLocals); } } private void emitRegExpInit(ClassFileWriter cfw) { // precompile all regexp literals int totalRegCount = 0; for (int i = 0; i != scriptOrFnNodes.length; ++i) { totalRegCount += scriptOrFnNodes[i].getRegexpCount(); } if (totalRegCount == 0) { return; } cfw.startMethod(REGEXP_INIT_METHOD_NAME, REGEXP_INIT_METHOD_SIGNATURE, (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE | ClassFileWriter.ACC_SYNCHRONIZED)); cfw.addField("_reInitDone", "Z", (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE)); cfw.add(ByteCode.GETSTATIC, mainClassName, "_reInitDone", "Z"); int doInit = cfw.acquireLabel(); cfw.add(ByteCode.IFEQ, doInit); cfw.add(ByteCode.RETURN); cfw.markLabel(doInit); for (int i = 0; i != scriptOrFnNodes.length; ++i) { ScriptOrFnNode n = scriptOrFnNodes[i]; int regCount = n.getRegexpCount(); for (int j = 0; j != regCount; ++j) { String reFieldName = getCompiledRegexpName(n, j); String reFieldType = "Ljava/lang/Object;"; String reString = n.getRegexpString(j); String reFlags = n.getRegexpFlags(j); cfw.addField(reFieldName, reFieldType,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -