📄 codegen.java
字号:
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); } } // default is to generate debug info if (compilerEnv.isGenerateDebugInfo()) { cfw.addVariableDescriptor(debugVariableName, "Lorg/mozilla/javascript/Scriptable;", cfw.getCurrentCodeOffset(), variableObjectLocal); } if (fnCurrent == null) { // OPT: use dataflow to prove that this assignment is dead popvLocal = getNewWordLocal(); Codegen.pushUndefined(cfw); cfw.addAStore(popvLocal); int linenum = scriptOrFn.getEndLineno(); if (linenum != -1) cfw.addLineNumberEntry((short)linenum); } else { if (fnCurrent.itsContainsCalls0) { itsZeroArgArray = getNewWordLocal(); cfw.add(ByteCode.GETSTATIC, "org/mozilla/javascript/ScriptRuntime", "emptyArgs", "[Ljava/lang/Object;"); cfw.addAStore(itsZeroArgArray); } if (fnCurrent.itsContainsCalls1) { itsOneArgArray = getNewWordLocal(); cfw.addPush(1); cfw.add(ByteCode.ANEWARRAY, "java/lang/Object"); cfw.addAStore(itsOneArgArray); } } } private void generateEpilogue() { if (hasVarsInRegs) { if (epilogueLabel != -1) { cfw.markLabel(epilogueLabel); } cfw.add(ByteCode.ARETURN); return; } cfw.markLabel(epilogueLabel); if (fnCurrent == null) { cfw.addALoad(popvLocal); cfw.add(ByteCode.ARETURN); } else { generateActivationExit(); cfw.add(ByteCode.ARETURN); // Generate catch block to catch all and rethrow to call exit code // under exception propagation as well. int finallyHandler = cfw.acquireLabel(); cfw.markHandler(finallyHandler); short exceptionObject = getNewWordLocal(); cfw.addAStore(exceptionObject); // Duplicate generateActivationExit() in the catch block since it // takes less space then full-fetured ByteCode.JSR/ByteCode.RET generateActivationExit(); cfw.addALoad(exceptionObject); releaseWordLocal(exceptionObject); // rethrow cfw.add(ByteCode.ATHROW); // mark the handler cfw.addExceptionHandler(enterAreaStartLabel, epilogueLabel, finallyHandler, null); // catch any } } private void generateActivationExit() { if (fnCurrent == null || hasVarsInRegs) throw Kit.codeBug(); cfw.addALoad(contextLocal); addScriptRuntimeInvoke("exitActivationFunction", "(Lorg/mozilla/javascript/Context;)V"); } private void generateStatement(Node node, Node parent) { // System.out.println("gen code for " + node.toString()); updateLineNumber(node); int type = node.getType(); Node child = node.getFirstChild(); switch (type) { case Token.LOOP: case Token.LABEL: case Token.WITH: case Token.SCRIPT: case Token.BLOCK: case Token.EMPTY: // no-ops. while (child != null) { generateStatement(child, node); child = child.getNext(); } break; case Token.LOCAL_BLOCK: { int local = getNewWordLocal(); node.putIntProp(Node.LOCAL_PROP, local); while (child != null) { generateStatement(child, node); child = child.getNext(); } releaseWordLocal((short)local); node.removeProp(Node.LOCAL_PROP); break; } case Token.FUNCTION: { int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn, fnIndex); int t = ofn.fnode.getFunctionType(); if (t == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { visitFunction(ofn, t); } else { if (t != FunctionNode.FUNCTION_STATEMENT) { throw Codegen.badTree(); } } break; } case Token.TRY: visitTryCatchFinally((Node.Jump)node, child); break; case Token.CATCH_SCOPE: { int local = getLocalBlockRegister(node); int scopeIndex = node.getExistingIntProp(Node.CATCH_SCOPE_PROP); String name = child.getString(); // name of exception child = child.getNext(); generateExpression(child, node); // load expression object if (scopeIndex == 0) { cfw.add(ByteCode.ACONST_NULL); } else { // Load previous catch scope object cfw.addALoad(local); } cfw.addPush(name); cfw.addALoad(contextLocal); cfw.addALoad(variableObjectLocal); addScriptRuntimeInvoke( "newCatchScope", "(Ljava/lang/Throwable;" +"Lorg/mozilla/javascript/Scriptable;" +"Ljava/lang/String;" +"Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +")Lorg/mozilla/javascript/Scriptable;"); cfw.addAStore(local); } break; case Token.THROW: generateExpression(child, node); cfw.add(ByteCode.NEW, "org/mozilla/javascript/JavaScriptException"); cfw.add(ByteCode.DUP_X1); cfw.add(ByteCode.SWAP); cfw.addPush(scriptOrFn.getSourceName()); cfw.addPush(itsLineNumber); cfw.addInvoke( ByteCode.INVOKESPECIAL, "org/mozilla/javascript/JavaScriptException", "<init>", "(Ljava/lang/Object;Ljava/lang/String;I)V"); cfw.add(ByteCode.ATHROW); break; case Token.RETHROW: cfw.addALoad(getLocalBlockRegister(node)); cfw.add(ByteCode.ATHROW); break; case Token.RETURN_RESULT: case Token.RETURN: if (child != null) { generateExpression(child, node); } else if (type == Token.RETURN) { Codegen.pushUndefined(cfw); } else { if (popvLocal < 0) throw Codegen.badTree(); cfw.addALoad(popvLocal); } if (epilogueLabel == -1) { if (!hasVarsInRegs) throw Codegen.badTree(); epilogueLabel = cfw.acquireLabel(); } cfw.add(ByteCode.GOTO, epilogueLabel); break; case Token.SWITCH: visitSwitch((Node.Jump)node, child); break; case Token.ENTERWITH: generateExpression(child, node); cfw.addALoad(contextLocal); cfw.addALoad(variableObjectLocal); addScriptRuntimeInvoke( "enterWith", "(Ljava/lang/Object;" +"Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +")Lorg/mozilla/javascript/Scriptable;"); cfw.addAStore(variableObjectLocal); break; case Token.LEAVEWITH: cfw.addALoad(variableObjectLocal); addScriptRuntimeInvoke( "leaveWith", "(Lorg/mozilla/javascript/Scriptable;" +")Lorg/mozilla/javascript/Scriptable;"); cfw.addAStore(variableObjectLocal); break; case Token.ENUM_INIT_KEYS: case Token.ENUM_INIT_VALUES: generateExpression(child, node); cfw.addALoad(contextLocal); cfw.addPush(type == Token.ENUM_INIT_VALUES); addScriptRuntimeInvoke("enumInit", "(Ljava/lang/Object;" +"Lorg/mozilla/javascript/Context;" +"Z" +")Ljava/lang/Object;"); cfw.addAStore(getLocalBlockRegister(node)); break; case Token.EXPR_VOID: if (child.getType() == Token.SETVAR) { /* special case this so as to avoid unnecessary load's & pop's */ visitSetVar(child, child.getFirstChild(), false); } else { generateExpression(child, node); if (node.getIntProp(Node.ISNUMBER_PROP, -1) != -1) cfw.add(ByteCode.POP2); else cfw.add(ByteCode.POP); } break; case Token.EXPR_RESULT: generateExpression(child, node); if (popvLocal < 0) { popvLocal = getNewWordLocal(); } cfw.addAStore(popvLocal); break; case Token.TARGET: { int label = getTargetLabel(node); cfw.markLabel(label); } break; case Token.JSR: case Token.GOTO: case Token.IFEQ: case Token.IFNE: visitGOTO((Node.Jump)node, type, child); break; case Token.FINALLY: { //Save return address in a new local where int finallyRegister = getNewWordLocal(); cfw.addAStore(finallyRegister); while (child != null) { generateStatement(child, node); child = child.getNext(); } cfw.add(ByteCode.RET, finallyRegister); releaseWordLocal((short)finallyRegister); } break; default: throw Codegen.badTree(); } } private void generateExpression(Node node, Node parent) { int type = node.getType(); Node child = node.getFirstChild(); switch (type) { case Token.USE_STACK: break; case Token.FUNCTION: if (fnCurrent != null || parent.getType() != Token.SCRIPT) { int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); OptFunctionNode ofn = OptFunctionNode.get(scriptOrFn, fnIndex); int t = ofn.fnode.getFunctionType(); if (t != FunctionNode.FUNCTION_EXPRESSION) { throw Codegen.badTree(); } visitFunction(ofn, t); } break; case Token.NAME: { cfw.addALoad(contextLocal); cfw.addALoad(variableObjectLocal); cfw.addPush(node.getString()); addScriptRuntimeInvoke( "name", "(Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +"Ljava/lang/String;" +")Ljava/lang/Object;"); } break; case Token.CALL: case Token.NEW: { int specialType = node.getIntProp(Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -