📄 codegen.java
字号:
cfw.startMethod("getParamOrVarName", "(I)Ljava/lang/String;", ClassFileWriter.ACC_PUBLIC); break; case Do_getEncodedSource: metodLocals = 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_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(metodLocals); } } 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, (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE)); cfw.addALoad(0); // proxy cfw.addALoad(1); // context cfw.addPush(reString); if (reFlags == null) { cfw.add(ByteCode.ACONST_NULL); } else { cfw.addPush(reFlags); } cfw.addInvoke(ByteCode.INVOKEINTERFACE, "org/mozilla/javascript/RegExpProxy", "compileRegExp", "(Lorg/mozilla/javascript/Context;" +"Ljava/lang/String;Ljava/lang/String;" +")Ljava/lang/Object;"); cfw.add(ByteCode.PUTSTATIC, mainClassName, reFieldName, reFieldType); } } cfw.addPush(1); cfw.add(ByteCode.PUTSTATIC, mainClassName, "_reInitDone", "Z"); cfw.add(ByteCode.RETURN); cfw.stopMethod((short)2); } private void emitConstantDudeInitializers(ClassFileWriter cfw) { int N = itsConstantListSize; if (N == 0) return; cfw.startMethod("<clinit>", "()V", (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_FINAL)); double[] array = itsConstantList; for (int i = 0; i != N; ++i) { double num = array[i]; String constantName = "_k" + i; String constantType = getStaticConstantWrapperType(num); cfw.addField(constantName, constantType, (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE)); int inum = (int)num; if (inum == num) { cfw.add(ByteCode.NEW, "java/lang/Integer"); cfw.add(ByteCode.DUP); cfw.addPush(inum); cfw.addInvoke(ByteCode.INVOKESPECIAL, "java/lang/Integer", "<init>", "(I)V"); } else { cfw.addPush(num); addDoubleWrap(cfw); } cfw.add(ByteCode.PUTSTATIC, mainClassName, constantName, constantType); } cfw.add(ByteCode.RETURN); cfw.stopMethod((short)0); } void pushRegExpArray(ClassFileWriter cfw, ScriptOrFnNode n, int contextArg, int scopeArg) { int regexpCount = n.getRegexpCount(); if (regexpCount == 0) throw badTree(); cfw.addPush(regexpCount); cfw.add(ByteCode.ANEWARRAY, "java/lang/Object"); cfw.addALoad(contextArg); cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/ScriptRuntime", "checkRegExpProxy", "(Lorg/mozilla/javascript/Context;" +")Lorg/mozilla/javascript/RegExpProxy;"); // Stack: proxy, array cfw.add(ByteCode.DUP); cfw.addALoad(contextArg); cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName, REGEXP_INIT_METHOD_NAME, REGEXP_INIT_METHOD_SIGNATURE); for (int i = 0; i != regexpCount; ++i) { // Stack: proxy, array cfw.add(ByteCode.DUP2); cfw.addALoad(contextArg); cfw.addALoad(scopeArg); cfw.add(ByteCode.GETSTATIC, mainClassName, getCompiledRegexpName(n, i), "Ljava/lang/Object;"); // Stack: compiledRegExp, scope, cx, proxy, array, proxy, array cfw.addInvoke(ByteCode.INVOKEINTERFACE, "org/mozilla/javascript/RegExpProxy", "wrapRegExp", "(Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +"Ljava/lang/Object;" +")Lorg/mozilla/javascript/Scriptable;"); // Stack: wrappedRegExp, array, proxy, array cfw.addPush(i); cfw.add(ByteCode.SWAP); cfw.add(ByteCode.AASTORE); // Stack: proxy, array } // remove proxy cfw.add(ByteCode.POP); } void pushNumberAsObject(ClassFileWriter cfw, double num) { if (num == 0.0) { if (1 / num > 0) { // +0.0 cfw.add(ByteCode.GETSTATIC, "org/mozilla/javascript/optimizer/OptRuntime", "zeroObj", "Ljava/lang/Double;"); } else { cfw.addPush(num); addDoubleWrap(cfw); } } else if (num == 1.0) { cfw.add(ByteCode.GETSTATIC, "org/mozilla/javascript/optimizer/OptRuntime", "oneObj", "Ljava/lang/Double;"); return; } else if (num == -1.0) { cfw.add(ByteCode.GETSTATIC, "org/mozilla/javascript/optimizer/OptRuntime", "minusOneObj", "Ljava/lang/Double;"); } else if (num != num) { cfw.add(ByteCode.GETSTATIC, "org/mozilla/javascript/ScriptRuntime", "NaNobj", "Ljava/lang/Double;"); } else if (itsConstantListSize >= 2000) { // There appears to be a limit in the JVM on either the number // of static fields in a class or the size of the class // initializer. Either way, we can't have any more than 2000 // statically init'd constants. cfw.addPush(num); addDoubleWrap(cfw); } else { int N = itsConstantListSize; int index = 0; if (N == 0) { itsConstantList = new double[64]; } else { double[] array = itsConstantList; while (index != N && array[index] != num) { ++index; } if (N == array.length) { array = new double[N * 2]; System.arraycopy(itsConstantList, 0, array, 0, N); itsConstantList = array; } } if (index == N) { itsConstantList[N] = num; itsConstantListSize = N + 1; } String constantName = "_k" + index; String constantType = getStaticConstantWrapperType(num); cfw.add(ByteCode.GETSTATIC, mainClassName, constantName, constantType); } } private static void addDoubleWrap(ClassFileWriter cfw) { cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/optimizer/OptRuntime", "wrapDouble", "(D)Ljava/lang/Double;"); } private static String getStaticConstantWrapperType(double num) { String constantType; int inum = (int)num; if (inum == num) { return "Ljava/lang/Integer;"; } else { return "Ljava/lang/Double;"; } } static void pushUndefined(ClassFileWriter cfw) { cfw.add(ByteCode.GETSTATIC, "org/mozilla/javascript/Undefined", "instance", "Ljava/lang/Object;"); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -