📄 interpreter.java
字号:
case Icode_INTNUMBER: return "INTNUMBER"; case Icode_LITERAL_NEW: return "LITERAL_NEW"; case Icode_LITERAL_SET: return "LITERAL_SET"; case Icode_SPARE_ARRAYLIT: return "SPARE_ARRAYLIT"; case Icode_REG_IND_C0: return "REG_IND_C0"; case Icode_REG_IND_C1: return "REG_IND_C1"; case Icode_REG_IND_C2: return "REG_IND_C2"; case Icode_REG_IND_C3: return "REG_IND_C3"; case Icode_REG_IND_C4: return "REG_IND_C4"; case Icode_REG_IND_C5: return "REG_IND_C5"; case Icode_REG_IND1: return "LOAD_IND1"; case Icode_REG_IND2: return "LOAD_IND2"; case Icode_REG_IND4: return "LOAD_IND4"; case Icode_REG_STR_C0: return "REG_STR_C0"; case Icode_REG_STR_C1: return "REG_STR_C1"; case Icode_REG_STR_C2: return "REG_STR_C2"; case Icode_REG_STR_C3: return "REG_STR_C3"; case Icode_REG_STR1: return "LOAD_STR1"; case Icode_REG_STR2: return "LOAD_STR2"; case Icode_REG_STR4: return "LOAD_STR4"; case Icode_GETVAR1: return "GETVAR1"; case Icode_SETVAR1: return "SETVAR1"; case Icode_UNDEF: return "UNDEF"; case Icode_ZERO: return "ZERO"; case Icode_ONE: return "ONE"; case Icode_ENTERDQ: return "ENTERDQ"; case Icode_LEAVEDQ: return "LEAVEDQ"; case Icode_TAIL_CALL: return "TAIL_CALL"; case Icode_LOCAL_CLEAR: return "LOCAL_CLEAR"; } // icode without name throw new IllegalStateException(String.valueOf(bytecode)); } private static boolean validIcode(int icode) { return MIN_ICODE <= icode && icode <= -1; } private static boolean validTokenCode(int token) { return Token.FIRST_BYTECODE_TOKEN <= token && token <= Token.LAST_BYTECODE_TOKEN; } private static boolean validBytecode(int bytecode) { return validIcode(bytecode) || validTokenCode(bytecode); } public Object compile(CompilerEnvirons compilerEnv, ScriptOrFnNode tree, String encodedSource, boolean returnFunction) { this.compilerEnv = compilerEnv; new NodeTransformer().transform(tree); if (Token.printTrees) { System.out.println(tree.toStringTree(tree)); } if (returnFunction) { tree = tree.getFunctionNode(0); } scriptOrFn = tree; itsData = new InterpreterData(compilerEnv.getLanguageVersion(), scriptOrFn.getSourceName(), encodedSource); itsData.topLevel = true; if (returnFunction) { generateFunctionICode(); } else { generateICodeFromTree(scriptOrFn); } return itsData; } public Script createScriptObject(Object bytecode, Object staticSecurityDomain) { InterpreterData idata = (InterpreterData)bytecode; return InterpretedFunction.createScript(itsData, staticSecurityDomain); } public Function createFunctionObject(Context cx, Scriptable scope, Object bytecode, Object staticSecurityDomain) { InterpreterData idata = (InterpreterData)bytecode; return InterpretedFunction.createFunction(cx, scope, itsData, staticSecurityDomain); } private void generateFunctionICode() { itsInFunctionFlag = true; FunctionNode theFunction = (FunctionNode)scriptOrFn; itsData.itsFunctionType = theFunction.getFunctionType(); itsData.itsNeedsActivation = theFunction.requiresActivation(); itsData.itsName = theFunction.getFunctionName(); if (!theFunction.getIgnoreDynamicScope()) { if (compilerEnv.isUseDynamicScope()) { itsData.useDynamicScope = true; } } generateICodeFromTree(theFunction.getLastChild()); } private void generateICodeFromTree(Node tree) { generateNestedFunctions(); generateRegExpLiterals(); visitStatement(tree); fixLabelGotos(); // add RETURN_RESULT only to scripts as function always ends with RETURN if (itsData.itsFunctionType == 0) { addToken(Token.RETURN_RESULT); } if (itsData.itsICode.length != itsICodeTop) { // Make itsData.itsICode length exactly itsICodeTop to save memory // and catch bugs with jumps beyound icode as early as possible byte[] tmp = new byte[itsICodeTop]; System.arraycopy(itsData.itsICode, 0, tmp, 0, itsICodeTop); itsData.itsICode = tmp; } if (itsStrings.size() == 0) { itsData.itsStringTable = null; } else { itsData.itsStringTable = new String[itsStrings.size()]; ObjToIntMap.Iterator iter = itsStrings.newIterator(); for (iter.start(); !iter.done(); iter.next()) { String str = (String)iter.getKey(); int index = iter.getValue(); if (itsData.itsStringTable[index] != null) Kit.codeBug(); itsData.itsStringTable[index] = str; } } if (itsDoubleTableTop == 0) { itsData.itsDoubleTable = null; } else if (itsData.itsDoubleTable.length != itsDoubleTableTop) { double[] tmp = new double[itsDoubleTableTop]; System.arraycopy(itsData.itsDoubleTable, 0, tmp, 0, itsDoubleTableTop); itsData.itsDoubleTable = tmp; } if (itsExceptionTableTop != 0 && itsData.itsExceptionTable.length != itsExceptionTableTop) { int[] tmp = new int[itsExceptionTableTop]; System.arraycopy(itsData.itsExceptionTable, 0, tmp, 0, itsExceptionTableTop); itsData.itsExceptionTable = tmp; } itsData.itsMaxVars = scriptOrFn.getParamAndVarCount(); // itsMaxFrameArray: interpret method needs this amount for its // stack and sDbl arrays itsData.itsMaxFrameArray = itsData.itsMaxVars + itsData.itsMaxLocals + itsData.itsMaxStack; itsData.argNames = scriptOrFn.getParamAndVarNames(); itsData.argCount = scriptOrFn.getParamCount(); itsData.encodedSourceStart = scriptOrFn.getEncodedSourceStart(); itsData.encodedSourceEnd = scriptOrFn.getEncodedSourceEnd(); if (itsLiteralIds.size() != 0) { itsData.literalIds = itsLiteralIds.toArray(); } if (Token.printICode) dumpICode(itsData); } private void generateNestedFunctions() { int functionCount = scriptOrFn.getFunctionCount(); if (functionCount == 0) return; InterpreterData[] array = new InterpreterData[functionCount]; for (int i = 0; i != functionCount; i++) { FunctionNode def = scriptOrFn.getFunctionNode(i); Interpreter jsi = new Interpreter(); jsi.compilerEnv = compilerEnv; jsi.scriptOrFn = def; jsi.itsData = new InterpreterData(itsData); jsi.generateFunctionICode(); array[i] = jsi.itsData; } itsData.itsNestedFunctions = array; } private void generateRegExpLiterals() { int N = scriptOrFn.getRegexpCount(); if (N == 0) return; Context cx = Context.getContext(); RegExpProxy rep = ScriptRuntime.checkRegExpProxy(cx); Object[] array = new Object[N]; for (int i = 0; i != N; i++) { String string = scriptOrFn.getRegexpString(i); String flags = scriptOrFn.getRegexpFlags(i); array[i] = rep.compileRegExp(cx, string, flags); } itsData.itsRegExpLiterals = array; } private void updateLineNumber(Node node) { int lineno = node.getLineno(); if (lineno != itsLineNumber && lineno >= 0) { if (itsData.firstLinePC < 0) { itsData.firstLinePC = lineno; } itsLineNumber = lineno; addIcode(Icode_LINE); addUint16(lineno & 0xFFFF); } } private RuntimeException badTree(Node node) { throw new RuntimeException(node.toString()); } private void visitStatement(Node node) { int type = node.getType(); Node child = node.getFirstChild(); switch (type) { case Token.FUNCTION: { int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); int fnType = scriptOrFn.getFunctionNode(fnIndex). getFunctionType(); // Only function expressions or function expression // statements needs closure code creating new function // object on stack as function statements are initialized // at script/function start // In addition function expression can not present here // at statement level, they must only present as expressions. if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { addIndexOp(Icode_CLOSURE_STMT, fnIndex); } else { if (fnType != FunctionNode.FUNCTION_STATEMENT) { throw Kit.codeBug(); } } } break; case Token.SCRIPT: case Token.LABEL: case Token.LOOP: case Token.BLOCK: case Token.EMPTY: case Token.WITH: updateLineNumber(node); while (child != null) { visitStatement(child); child = child.getNext(); } break; case Token.ENTERWITH: visitExpression(child, 0); addToken(Token.ENTERWITH); stackChange(-1); break; case Token.LEAVEWITH: addToken(Token.LEAVEWITH); break; case Token.LOCAL_BLOCK: { int local = allocLocal(); node.putIntProp(Node.LOCAL_PROP, local); updateLineNumber(node); while (child != null) { visitStatement(child); child = child.getNext(); } addIndexOp(Icode_LOCAL_CLEAR, local); releaseLocal(local); } break; case Token.SWITCH: updateLineNumber(node); // See comments in IRFactory.createSwitch() for description // of SWITCH node { Node switchNode = (Node.Jump)node; visitExpression(child, 0); for (Node.Jump caseNode = (Node.Jump)child.getNext(); caseNode != null; caseNode = (Node.Jump)caseNode.getNext()) { if (caseNode.getType() != Token.CASE) throw badTree(caseNode); Node test = caseNode.getFirstChild(); addIcode(Icode_DUP); stackChange(1); visitExpression(test, 0); addToken(Token.SHEQ); stackChange(-1); // If true, Icode_IFEQ_POP will jump and remove case // value from stack addGoto(caseNode.target, Icode_IFEQ_POP); stackChange(-1); } addIcode(Icode_POP); stackChange(-1); } break; case Token.TARGET: markTargetLabel(node); break; case Token.IFEQ : case Token.IFNE : { Node target = ((Node.Jump)node).target; visitExpression(child, 0); addGoto(target, type); stackChange(-1); } break; case Token.GOTO: { Node target = ((Node.Jump)node).target; addGoto(target, type); } break; case Token.JSR: { Node target = ((Node.Jump)node).target; addGoto(target, Icode_GOSUB); } break; case Token.FINALLY: { // Account for incomming GOTOSUB address stackChange(1); int finallyRegister = getLocalBlockRef(node); addIndexOp(Icode_STARTSUB, finallyRegister); stackChange(-1); while (child != null) { visitStatement(child); child = child.getNext(); } addIndexOp(Icode_RETSUB, finallyRegister); } break; case Token.EXPR_VOID: case Token.EXPR_RESULT: updateLineNumber(node); visitExpression(child, 0); addIcode((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT); stackChange(-1); break; case Token.TRY: {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -