Categories:
Audio (13)
Biotech (29)
Bytecode (36)
Database (77)
Framework (7)
Game (7)
General (507)
Graphics (53)
I/O (35)
IDE (2)
JAR Tools (101)
JavaBeans (21)
JDBC (121)
JDK (426)
JSP (20)
Logging (108)
Mail (58)
Messaging (8)
Network (84)
PDF (97)
Report (7)
Scripting (84)
Security (32)
Server (121)
Servlet (26)
SOAP (24)
Testing (54)
Web (15)
XML (309)
Collections:
Other Resources:
Rhino JavaScript Java Library Source Code
Rhino JavaScript Java Library is an open-source implementation of JavaScript written entirely in Java.
Rhino JavaScript Java Library Source Code files are provided in binary package (rhino-1.7.14.zip).
You can also browse the source code below:
✍: FYIcenter.com
⏎ org/mozilla/javascript/CodeGenerator.java
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.math.BigInteger; import java.util.List; import org.mozilla.javascript.ast.AstNode; import org.mozilla.javascript.ast.AstRoot; import org.mozilla.javascript.ast.Block; import org.mozilla.javascript.ast.FunctionNode; import org.mozilla.javascript.ast.Jump; import org.mozilla.javascript.ast.Scope; import org.mozilla.javascript.ast.ScriptNode; import org.mozilla.javascript.ast.TemplateCharacters; import org.mozilla.javascript.ast.VariableInitializer; /** Generates bytecode for the Interpreter. */ class CodeGenerator extends Icode { private static final int MIN_LABEL_TABLE_SIZE = 32; private static final int MIN_FIXUP_TABLE_SIZE = 40; private CompilerEnvirons compilerEnv; private boolean itsInFunctionFlag; private boolean itsInTryFlag; private InterpreterData itsData; private ScriptNode scriptOrFn; private int iCodeTop; private int stackDepth; private int lineNumber; private int doubleTableTop; private ObjToIntMap strings = new ObjToIntMap(20); private ObjToIntMap bigInts = new ObjToIntMap(20); private int localTop; private int[] labelTable; private int labelTableTop; // fixupTable[i] = (label_index << 32) | fixup_site private long[] fixupTable; private int fixupTableTop; private ObjArray literalIds = new ObjArray(); private int exceptionTableTop; // ECF_ or Expression Context Flags constants: for now only TAIL private static final int ECF_TAIL = 1 << 0; public InterpreterData compile( CompilerEnvirons compilerEnv, ScriptNode tree, String encodedSource, boolean returnFunction) { this.compilerEnv = compilerEnv; if (Token.printTrees) { System.out.println("before transform:"); System.out.println(tree.toStringTree(tree)); } new NodeTransformer().transform(tree, compilerEnv); if (Token.printTrees) { System.out.println("after transform:"); System.out.println(tree.toStringTree(tree)); } if (returnFunction) { scriptOrFn = tree.getFunctionNode(0); } else { scriptOrFn = tree; } itsData = new InterpreterData( compilerEnv.getLanguageVersion(), scriptOrFn.getSourceName(), encodedSource, scriptOrFn.isInStrictMode()); itsData.topLevel = true; if (returnFunction) { generateFunctionICode(); } else { generateICodeFromTree(scriptOrFn); } return itsData; } private void generateFunctionICode() { itsInFunctionFlag = true; FunctionNode theFunction = (FunctionNode) scriptOrFn; itsData.itsFunctionType = theFunction.getFunctionType(); itsData.itsNeedsActivation = theFunction.requiresActivation(); if (theFunction.getFunctionName() != null) { itsData.itsName = theFunction.getName(); } if (theFunction.isGenerator()) { addIcode(Icode_GENERATOR); addUint16(theFunction.getBaseLineno() & 0xFFFF); } if (theFunction.isInStrictMode()) { itsData.isStrict = true; } if (theFunction.isES6Generator()) { itsData.isES6Generator = true; } itsData.declaredAsVar = (theFunction.getParent() instanceof VariableInitializer); generateICodeFromTree(theFunction.getLastChild()); } private void generateICodeFromTree(Node tree) { generateNestedFunctions(); generateRegExpLiterals(); generateTemplateLiterals(); visitStatement(tree, 0); 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 != iCodeTop) { // Make itsData.itsICode length exactly iCodeTop to save memory // and catch bugs with jumps beyond icode as early as possible byte[] tmp = new byte[iCodeTop]; System.arraycopy(itsData.itsICode, 0, tmp, 0, iCodeTop); itsData.itsICode = tmp; } if (strings.size() == 0) { itsData.itsStringTable = null; } else { itsData.itsStringTable = new String[strings.size()]; ObjToIntMap.Iterator iter = strings.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 (doubleTableTop == 0) { itsData.itsDoubleTable = null; } else if (itsData.itsDoubleTable.length != doubleTableTop) { double[] tmp = new double[doubleTableTop]; System.arraycopy(itsData.itsDoubleTable, 0, tmp, 0, doubleTableTop); itsData.itsDoubleTable = tmp; } if (bigInts.size() == 0) { itsData.itsBigIntTable = null; } else { itsData.itsBigIntTable = new BigInteger[bigInts.size()]; ObjToIntMap.Iterator iter = bigInts.newIterator(); for (iter.start(); !iter.done(); iter.next()) { BigInteger bigInt = (BigInteger) iter.getKey(); int index = iter.getValue(); if (itsData.itsBigIntTable[index] != null) Kit.codeBug(); itsData.itsBigIntTable[index] = bigInt; } } if (exceptionTableTop != 0 && itsData.itsExceptionTable.length != exceptionTableTop) { int[] tmp = new int[exceptionTableTop]; System.arraycopy(itsData.itsExceptionTable, 0, tmp, 0, exceptionTableTop); 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.argIsConst = scriptOrFn.getParamAndVarConst(); itsData.argCount = scriptOrFn.getParamCount(); itsData.encodedSourceStart = scriptOrFn.getEncodedSourceStart(); itsData.encodedSourceEnd = scriptOrFn.getEncodedSourceEnd(); if (literalIds.size() != 0) { itsData.literalIds = literalIds.toArray(); } if (Token.printICode) Interpreter.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 fn = scriptOrFn.getFunctionNode(i); CodeGenerator gen = new CodeGenerator(); gen.compilerEnv = compilerEnv; gen.scriptOrFn = fn; gen.itsData = new InterpreterData(itsData); gen.generateFunctionICode(); array[i] = gen.itsData; final AstNode fnParent = fn.getParent(); if (!(fnParent instanceof AstRoot || fnParent instanceof Scope || fnParent instanceof Block)) { gen.itsData.declaredAsFunctionExpression = true; } } 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 generateTemplateLiterals() { int N = scriptOrFn.getTemplateLiteralCount(); if (N == 0) return; Object[] array = new Object[N]; for (int i = 0; i != N; i++) { List<TemplateCharacters> strings = scriptOrFn.getTemplateLiteralStrings(i); int j = 0; String[] values = new String[strings.size() * 2]; for (TemplateCharacters s : strings) { values[j++] = s.getValue(); values[j++] = s.getRawValue(); } array[i] = values; } itsData.itsTemplateLiterals = array; } private void updateLineNumber(Node node) { int lineno = node.getLineno(); if (lineno != lineNumber && lineno >= 0) { if (itsData.firstLinePC < 0) { itsData.firstLinePC = lineno; } lineNumber = lineno; addIcode(Icode_LINE); addUint16(lineno & 0xFFFF); } } private static RuntimeException badTree(Node node) { throw new RuntimeException(node.toString()); } private void visitStatement(Node node, int initialStackDepth) { 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 need closure code creating new function // object on stack as function statements are initialized // at script/function start. // In addition, function expressions can not be present here // at statement level, they must only be present as expressions. if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { addIndexOp(Icode_CLOSURE_STMT, fnIndex); } else { if (fnType != FunctionNode.FUNCTION_STATEMENT) { throw Kit.codeBug(); } } // For function statements or function expression statements // in scripts, we need to ensure that the result of the script // is the function if it is the last statement in the script. // For example, eval("function () {}") should return a // function, not undefined. if (!itsInFunctionFlag) { addIndexOp(Icode_CLOSURE_EXPR, fnIndex); stackChange(1); addIcode(Icode_POP_RESULT); stackChange(-1); } } break; case Token.LABEL: case Token.LOOP: case Token.BLOCK: case Token.EMPTY: case Token.WITH: updateLineNumber(node); // fall through case Token.SCRIPT: while (child != null) { visitStatement(child, initialStackDepth); 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, initialStackDepth); child = child.getNext(); } addIndexOp(Icode_LOCAL_CLEAR, local); releaseLocal(local); } break; case Token.DEBUGGER: addIcode(Icode_DEBUGGER); break; case Token.SWITCH: updateLineNumber(node); // See comments in IRFactory.createSwitch() for description // of SWITCH node { visitExpression(child, 0); for (Jump caseNode = (Jump) child.getNext(); caseNode != null; caseNode = (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 = ((Jump) node).target; visitExpression(child, 0); addGoto(target, type); stackChange(-1); } break; case Token.GOTO: { Node target = ((Jump) node).target; addGoto(target, type); } break; case Token.JSR: { Node target = ((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, initialStackDepth); 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: { Jump tryNode = (Jump) node; int exceptionObjectLocal = getLocalBlockRef(tryNode); int scopeLocal = allocLocal(); addIndexOp(Icode_SCOPE_SAVE, scopeLocal); int tryStart = iCodeTop; boolean savedFlag = itsInTryFlag; itsInTryFlag = true; while (child != null) { visitStatement(child, initialStackDepth); child = child.getNext(); } itsInTryFlag = savedFlag; Node catchTarget = tryNode.target; if (catchTarget != null) { int catchStartPC = labelTable[getTargetLabel(catchTarget)]; addExceptionHandler( tryStart, catchStartPC, catchStartPC, false, exceptionObjectLocal, scopeLocal); } Node finallyTarget = tryNode.getFinally(); if (finallyTarget != null) { int finallyStartPC = labelTable[getTargetLabel(finallyTarget)]; addExceptionHandler( tryStart, finallyStartPC, finallyStartPC, true, exceptionObjectLocal, scopeLocal); } addIndexOp(Icode_LOCAL_CLEAR, scopeLocal); releaseLocal(scopeLocal); } break; case Token.CATCH_SCOPE: { int localIndex = getLocalBlockRef(node); int scopeIndex = node.getExistingIntProp(Node.CATCH_SCOPE_PROP); String name = child.getString(); child = child.getNext(); visitExpression(child, 0); // load expression object addStringPrefix(name); addIndexPrefix(localIndex); addToken(Token.CATCH_SCOPE); addUint8(scopeIndex != 0 ? 1 : 0); stackChange(-1); } break; case Token.THROW: updateLineNumber(node); visitExpression(child, 0); addToken(Token.THROW); addUint16(lineNumber & 0xFFFF); stackChange(-1); break; case Token.RETHROW: updateLineNumber(node); addIndexOp(Token.RETHROW, getLocalBlockRef(node)); break; case Token.RETURN: updateLineNumber(node); if (node.getIntProp(Node.GENERATOR_END_PROP, 0) != 0) { if ((child == null) || (compilerEnv.getLanguageVersion() < Context.VERSION_ES6)) { // End generator function with no result, or old language version // in which generators never return a result. addIcode(Icode_GENERATOR_END); addUint16(lineNumber & 0xFFFF); } else { visitExpression(child, ECF_TAIL); addIcode(Icode_GENERATOR_RETURN); addUint16(lineNumber & 0xFFFF); stackChange(-1); } } else { if (child == null) { addIcode(Icode_RETUNDEF); } else { visitExpression(child, ECF_TAIL); addToken(Token.RETURN); stackChange(-1); } } break; case Token.RETURN_RESULT: updateLineNumber(node); addToken(Token.RETURN_RESULT); break; case Token.ENUM_INIT_KEYS: case Token.ENUM_INIT_VALUES: case Token.ENUM_INIT_ARRAY: case Token.ENUM_INIT_VALUES_IN_ORDER: visitExpression(child, 0); addIndexOp(type, getLocalBlockRef(node)); stackChange(-1); break; case Icode_GENERATOR: break; default: throw badTree(node); } if (stackDepth != initialStackDepth) { throw Kit.codeBug(); } } private void visitExpression(Node node, int contextFlags) { int type = node.getType(); Node child = node.getFirstChild(); int savedStackDepth = stackDepth; switch (type) { case Token.FUNCTION: { int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex); // See comments in visitStatement for Token.FUNCTION case if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION && fn.getFunctionType() != FunctionNode.ARROW_FUNCTION) { throw Kit.codeBug(); } addIndexOp(Icode_CLOSURE_EXPR, fnIndex); stackChange(1); } break; case Token.LOCAL_LOAD: { int localIndex = getLocalBlockRef(node); addIndexOp(Token.LOCAL_LOAD, localIndex); stackChange(1); } break; case Token.COMMA: { Node lastChild = node.getLastChild(); while (child != lastChild) { visitExpression(child, 0); addIcode(Icode_POP); stackChange(-1); child = child.getNext(); } // Preserve tail context flag if any visitExpression(child, contextFlags & ECF_TAIL); } break; case Token.USE_STACK: // Indicates that stack was modified externally, // like placed catch object stackChange(1); break; case Token.REF_CALL: case Token.CALL: case Token.NEW: { if (type == Token.NEW) { visitExpression(child, 0); } else { generateCallFunAndThis(child); } int argCount = 0; while ((child = child.getNext()) != null) { visitExpression(child, 0); ++argCount; } int callType = node.getIntProp(Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL); if (type != Token.REF_CALL && callType != Node.NON_SPECIALCALL) { // embed line number and source filename addIndexOp(Icode_CALLSPECIAL, argCount); addUint8(callType); addUint8(type == Token.NEW ? 1 : 0); addUint16(lineNumber & 0xFFFF); } else { // Only use the tail call optimization if we're not in a try // or we're not generating debug info (since the // optimization will confuse the debugger) if (type == Token.CALL && (contextFlags & ECF_TAIL) != 0 && !compilerEnv.isGenerateDebugInfo() && !itsInTryFlag) { type = Icode_TAIL_CALL; } addIndexOp(type, argCount); } // adjust stack if (type == Token.NEW) { // new: f, args -> result stackChange(-argCount); } else { // call: f, thisObj, args -> result // ref_call: f, thisObj, args -> ref stackChange(-1 - argCount); } if (argCount > itsData.itsMaxCalleeArgs) { itsData.itsMaxCalleeArgs = argCount; } } break; case Token.AND: case Token.OR: { visitExpression(child, 0); addIcode(Icode_DUP); stackChange(1); int afterSecondJumpStart = iCodeTop; int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ; addGotoOp(jump); stackChange(-1); addIcode(Icode_POP); stackChange(-1); child = child.getNext(); // Preserve tail context flag if any visitExpression(child, contextFlags & ECF_TAIL); resolveForwardGoto(afterSecondJumpStart); } break; case Token.HOOK: { Node ifThen = child.getNext(); Node ifElse = ifThen.getNext(); visitExpression(child, 0); int elseJumpStart = iCodeTop; addGotoOp(Token.IFNE); stackChange(-1); // Preserve tail context flag if any visitExpression(ifThen, contextFlags & ECF_TAIL); int afterElseJumpStart = iCodeTop; addGotoOp(Token.GOTO); resolveForwardGoto(elseJumpStart); stackDepth = savedStackDepth; // Preserve tail context flag if any visitExpression(ifElse, contextFlags & ECF_TAIL); resolveForwardGoto(afterElseJumpStart); } break; case Token.GETPROP: case Token.GETPROPNOWARN: visitExpression(child, 0); child = child.getNext(); addStringOp(type, child.getString()); break; case Token.DELPROP: boolean isName = child.getType() == Token.BINDNAME; visitExpression(child, 0); child = child.getNext(); visitExpression(child, 0); if (isName) { // special handling for delete name addIcode(Icode_DELNAME); } else { addToken(Token.DELPROP); } stackChange(-1); break; case Token.GETELEM: case Token.BITAND: case Token.BITOR: case Token.BITXOR: case Token.LSH: case Token.RSH: case Token.URSH: case Token.ADD: case Token.SUB: case Token.MOD: case Token.DIV: case Token.MUL: case Token.EXP: case Token.EQ: case Token.NE: case Token.SHEQ: case Token.SHNE: case Token.IN: case Token.INSTANCEOF: case Token.LE: case Token.LT: case Token.GE: case Token.GT: visitExpression(child, 0); child = child.getNext(); visitExpression(child, 0); addToken(type); stackChange(-1); break; case Token.POS: case Token.NEG: case Token.NOT: case Token.BITNOT: case Token.TYPEOF: case Token.VOID: visitExpression(child, 0); if (type == Token.VOID) { addIcode(Icode_POP); addIcode(Icode_UNDEF); } else { addToken(type); } break; case Token.GET_REF: case Token.DEL_REF: visitExpression(child, 0); addToken(type); break; case Token.SETPROP: case Token.SETPROP_OP: { visitExpression(child, 0); child = child.getNext(); String property = child.getString(); child = child.getNext(); if (type == Token.SETPROP_OP) { addIcode(Icode_DUP); stackChange(1); addStringOp(Token.GETPROP, property); // Compensate for the following USE_STACK stackChange(-1); } visitExpression(child, 0); addStringOp(Token.SETPROP, property); stackChange(-1); } break; case Token.SETELEM: case Token.SETELEM_OP: visitExpression(child, 0); child = child.getNext(); visitExpression(child, 0); child = child.getNext(); if (type == Token.SETELEM_OP) { addIcode(Icode_DUP2); stackChange(2); addToken(Token.GETELEM); stackChange(-1); // Compensate for the following USE_STACK stackChange(-1); } visitExpression(child, 0); addToken(Token.SETELEM); stackChange(-2); break; case Token.SET_REF: case Token.SET_REF_OP: visitExpression(child, 0); child = child.getNext(); if (type == Token.SET_REF_OP) { addIcode(Icode_DUP); stackChange(1); addToken(Token.GET_REF); // Compensate for the following USE_STACK stackChange(-1); } visitExpression(child, 0); addToken(Token.SET_REF); stackChange(-1); break; case Token.STRICT_SETNAME: case Token.SETNAME: { String name = child.getString(); visitExpression(child, 0); child = child.getNext(); visitExpression(child, 0); addStringOp(type, name); stackChange(-1); } break; case Token.SETCONST: { String name = child.getString(); visitExpression(child, 0); child = child.getNext(); visitExpression(child, 0); addStringOp(Icode_SETCONST, name); stackChange(-1); } break; case Token.TYPEOFNAME: { int index = -1; // use typeofname if an activation frame exists // since the vars all exist there instead of in jregs if (itsInFunctionFlag && !itsData.itsNeedsActivation) index = scriptOrFn.getIndexForNameNode(node); if (index == -1) { addStringOp(Icode_TYPEOFNAME, node.getString()); stackChange(1); } else { addVarOp(Token.GETVAR, index); stackChange(1); addToken(Token.TYPEOF); } } break; case Token.BINDNAME: case Token.NAME: case Token.STRING: addStringOp(type, node.getString()); stackChange(1); break; case Token.INC: case Token.DEC: visitIncDec(node, child); break; case Token.NUMBER: { double num = node.getDouble(); int inum = (int) num; if (inum == num) { if (inum == 0) { addIcode(Icode_ZERO); // Check for negative zero if (1.0 / num < 0.0) { addToken(Token.NEG); } } else if (inum == 1) { addIcode(Icode_ONE); } else if ((short) inum == inum) { addIcode(Icode_SHORTNUMBER); // write short as uin16 bit pattern addUint16(inum & 0xFFFF); } else { addIcode(Icode_INTNUMBER); addInt(inum); } } else { int index = getDoubleIndex(num); addIndexOp(Token.NUMBER, index); } stackChange(1); } break; case Token.GETVAR: { if (itsData.itsNeedsActivation) Kit.codeBug(); int index = scriptOrFn.getIndexForNameNode(node); addVarOp(Token.GETVAR, index); stackChange(1); } break; case Token.SETVAR: { if (itsData.itsNeedsActivation) Kit.codeBug(); int index = scriptOrFn.getIndexForNameNode(child); child = child.getNext(); visitExpression(child, 0); addVarOp(Token.SETVAR, index); } break; case Token.SETCONSTVAR: { if (itsData.itsNeedsActivation) Kit.codeBug(); int index = scriptOrFn.getIndexForNameNode(child); child = child.getNext(); visitExpression(child, 0); addVarOp(Token.SETCONSTVAR, index); } break; case Token.NULL: case Token.THIS: case Token.THISFN: case Token.FALSE: case Token.TRUE: addToken(type); stackChange(1); break; case Token.ENUM_NEXT: case Token.ENUM_ID: addIndexOp(type, getLocalBlockRef(node)); stackChange(1); break; case Token.BIGINT: addBigInt(node.getBigInt()); stackChange(1); break; case Token.REGEXP: { int index = node.getExistingIntProp(Node.REGEXP_PROP); addIndexOp(Token.REGEXP, index); stackChange(1); } break; case Token.ARRAYLIT: case Token.OBJECTLIT: visitLiteral(node, child); break; case Token.ARRAYCOMP: visitArrayComprehension(node, child, child.getNext()); break; case Token.REF_SPECIAL: visitExpression(child, 0); addStringOp(type, (String) node.getProp(Node.NAME_PROP)); break; case Token.REF_MEMBER: case Token.REF_NS_MEMBER: case Token.REF_NAME: case Token.REF_NS_NAME: { int memberTypeFlags = node.getIntProp(Node.MEMBER_TYPE_PROP, 0); // generate possible target, possible namespace and member int childCount = 0; do { visitExpression(child, 0); ++childCount; child = child.getNext(); } while (child != null); addIndexOp(type, memberTypeFlags); stackChange(1 - childCount); } break; case Token.DOTQUERY: { int queryPC; updateLineNumber(node); visitExpression(child, 0); addIcode(Icode_ENTERDQ); stackChange(-1); queryPC = iCodeTop; visitExpression(child.getNext(), 0); addBackwardGoto(Icode_LEAVEDQ, queryPC); } break; case Token.DEFAULTNAMESPACE: case Token.ESCXMLATTR: case Token.ESCXMLTEXT: visitExpression(child, 0); addToken(type); break; case Token.YIELD: case Token.YIELD_STAR: if (child != null) { visitExpression(child, 0); } else { addIcode(Icode_UNDEF); stackChange(1); } if (type == Token.YIELD) { addToken(Token.YIELD); } else { addIcode(Icode_YIELD_STAR); } addUint16(node.getLineno() & 0xFFFF); break; case Token.WITHEXPR: { Node enterWith = node.getFirstChild(); Node with = enterWith.getNext(); visitExpression(enterWith.getFirstChild(), 0); addToken(Token.ENTERWITH); stackChange(-1); visitExpression(with.getFirstChild(), 0); addToken(Token.LEAVEWITH); break; } case Token.TEMPLATE_LITERAL: visitTemplateLiteral(node); break; default: throw badTree(node); } if (savedStackDepth + 1 != stackDepth) { Kit.codeBug(); } } private void generateCallFunAndThis(Node left) { // Generate code to place on stack function and thisObj int type = left.getType(); switch (type) { case Token.NAME: { String name = left.getString(); // stack: ... -> ... function thisObj addStringOp(Icode_NAME_AND_THIS, name); stackChange(2); break; } case Token.GETPROP: case Token.GETELEM: { Node target = left.getFirstChild(); visitExpression(target, 0); Node id = target.getNext(); if (type == Token.GETPROP) { String property = id.getString(); // stack: ... target -> ... function thisObj addStringOp(Icode_PROP_AND_THIS, property); stackChange(1); } else { visitExpression(id, 0); // stack: ... target id -> ... function thisObj addIcode(Icode_ELEM_AND_THIS); } break; } default: // Including Token.GETVAR visitExpression(left, 0); // stack: ... value -> ... function thisObj addIcode(Icode_VALUE_AND_THIS); stackChange(1); break; } } private void visitIncDec(Node node, Node child) { int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP); int childType = child.getType(); switch (childType) { case Token.GETVAR: { if (itsData.itsNeedsActivation) Kit.codeBug(); int i = scriptOrFn.getIndexForNameNode(child); addVarOp(Icode_VAR_INC_DEC, i); addUint8(incrDecrMask); stackChange(1); break; } case Token.NAME: { String name = child.getString(); addStringOp(Icode_NAME_INC_DEC, name); addUint8(incrDecrMask); stackChange(1); break; } case Token.GETPROP: { Node object = child.getFirstChild(); visitExpression(object, 0); String property = object.getNext().getString(); addStringOp(Icode_PROP_INC_DEC, property); addUint8(incrDecrMask); break; } case Token.GETELEM: { Node object = child.getFirstChild(); visitExpression(object, 0); Node index = object.getNext(); visitExpression(index, 0); addIcode(Icode_ELEM_INC_DEC); addUint8(incrDecrMask); stackChange(-1); break; } case Token.GET_REF: { Node ref = child.getFirstChild(); visitExpression(ref, 0); addIcode(Icode_REF_INC_DEC); addUint8(incrDecrMask); break; } default: { throw badTree(node); } } } private void visitLiteral(Node node, Node child) { int type = node.getType(); int count; Object[] propertyIds = null; if (type == Token.ARRAYLIT) { count = 0; for (Node n = child; n != null; n = n.getNext()) { ++count; } } else if (type == Token.OBJECTLIT) { propertyIds = (Object[]) node.getProp(Node.OBJECT_IDS_PROP); count = propertyIds == null ? 0 : propertyIds.length; } else { throw badTree(node); } addIndexOp(Icode_LITERAL_NEW, count); stackChange(2); while (child != null) { int childType = child.getType(); if (childType == Token.GET) { visitExpression(child.getFirstChild(), 0); addIcode(Icode_LITERAL_GETTER); } else if (childType == Token.SET) { visitExpression(child.getFirstChild(), 0); addIcode(Icode_LITERAL_SETTER); } else if (childType == Token.METHOD) { visitExpression(child.getFirstChild(), 0); addIcode(Icode_LITERAL_SET); } else { visitExpression(child, 0); addIcode(Icode_LITERAL_SET); } stackChange(-1); child = child.getNext(); } if (type == Token.ARRAYLIT) { int[] skipIndexes = (int[]) node.getProp(Node.SKIP_INDEXES_PROP); if (skipIndexes == null) { addToken(Token.ARRAYLIT); } else { int index = literalIds.size(); literalIds.add(skipIndexes); addIndexOp(Icode_SPARE_ARRAYLIT, index); } } else { int index = literalIds.size(); literalIds.add(propertyIds); addIndexOp(Token.OBJECTLIT, index); } stackChange(-1); } private void visitTemplateLiteral(Node node) { int index = node.getExistingIntProp(Node.TEMPLATE_LITERAL_PROP); addIndexOp(Icode_TEMPLATE_LITERAL_CALLSITE, index); stackChange(1); } private void visitArrayComprehension(Node node, Node initStmt, Node expr) { // A bit of a hack: array comprehensions are implemented using // statement nodes for the iteration, yet they appear in an // expression context. So we pass the current stack depth to // visitStatement so it can check that the depth is not altered // by statements. visitStatement(initStmt, stackDepth); visitExpression(expr, 0); } private static int getLocalBlockRef(Node node) { Node localBlock = (Node) node.getProp(Node.LOCAL_BLOCK_PROP); return localBlock.getExistingIntProp(Node.LOCAL_PROP); } private int getTargetLabel(Node target) { int label = target.labelId(); if (label != -1) { return label; } label = labelTableTop; if (labelTable == null || label == labelTable.length) { if (labelTable == null) { labelTable = new int[MIN_LABEL_TABLE_SIZE]; } else { int[] tmp = new int[labelTable.length * 2]; System.arraycopy(labelTable, 0, tmp, 0, label); labelTable = tmp; } } labelTableTop = label + 1; labelTable[label] = -1; target.labelId(label); return label; } private void markTargetLabel(Node target) { int label = getTargetLabel(target); if (labelTable[label] != -1) { // Can mark label only once Kit.codeBug(); } labelTable[label] = iCodeTop; } private void addGoto(Node target, int gotoOp) { int label = getTargetLabel(target); if (!(label < labelTableTop)) Kit.codeBug(); int targetPC = labelTable[label]; if (targetPC != -1) { addBackwardGoto(gotoOp, targetPC); } else { int gotoPC = iCodeTop; addGotoOp(gotoOp); int top = fixupTableTop; if (fixupTable == null || top == fixupTable.length) { if (fixupTable == null) { fixupTable = new long[MIN_FIXUP_TABLE_SIZE]; } else { long[] tmp = new long[fixupTable.length * 2]; System.arraycopy(fixupTable, 0, tmp, 0, top); fixupTable = tmp; } } fixupTableTop = top + 1; fixupTable[top] = ((long) label << 32) | gotoPC; } } private void fixLabelGotos() { for (int i = 0; i < fixupTableTop; i++) { long fixup = fixupTable[i]; int label = (int) (fixup >> 32); int jumpSource = (int) fixup; int pc = labelTable[label]; if (pc == -1) { // Unlocated label throw Kit.codeBug(); } resolveGoto(jumpSource, pc); } fixupTableTop = 0; } private void addBackwardGoto(int gotoOp, int jumpPC) { int fromPC = iCodeTop; // Ensure that this is a jump backward if (fromPC <= jumpPC) throw Kit.codeBug(); addGotoOp(gotoOp); resolveGoto(fromPC, jumpPC); } private void resolveForwardGoto(int fromPC) { // Ensure that forward jump skips at least self bytecode if (iCodeTop < fromPC + 3) throw Kit.codeBug(); resolveGoto(fromPC, iCodeTop); } private void resolveGoto(int fromPC, int jumpPC) { int offset = jumpPC - fromPC; // Ensure that jumps do not overlap if (0 <= offset && offset <= 2) throw Kit.codeBug(); int offsetSite = fromPC + 1; if (offset != (short) offset) { if (itsData.longJumps == null) { itsData.longJumps = new UintMap(); } itsData.longJumps.put(offsetSite, jumpPC); offset = 0; } byte[] array = itsData.itsICode; array[offsetSite] = (byte) (offset >> 8); array[offsetSite + 1] = (byte) offset; } private void addToken(int token) { if (!Icode.validTokenCode(token)) throw Kit.codeBug(); addUint8(token); } private void addIcode(int icode) { if (!Icode.validIcode(icode)) throw Kit.codeBug(); // Write negative icode as uint8 bits addUint8(icode & 0xFF); } private void addUint8(int value) { if ((value & ~0xFF) != 0) throw Kit.codeBug(); byte[] array = itsData.itsICode; int top = iCodeTop; if (top == array.length) { array = increaseICodeCapacity(1); } array[top] = (byte) value; iCodeTop = top + 1; } private void addUint16(int value) { if ((value & ~0xFFFF) != 0) throw Kit.codeBug(); byte[] array = itsData.itsICode; int top = iCodeTop; if (top + 2 > array.length) { array = increaseICodeCapacity(2); } array[top] = (byte) (value >>> 8); array[top + 1] = (byte) value; iCodeTop = top + 2; } private void addInt(int i) { byte[] array = itsData.itsICode; int top = iCodeTop; if (top + 4 > array.length) { array = increaseICodeCapacity(4); } array[top] = (byte) (i >>> 24); array[top + 1] = (byte) (i >>> 16); array[top + 2] = (byte) (i >>> 8); array[top + 3] = (byte) i; iCodeTop = top + 4; } private int getDoubleIndex(double num) { int index = doubleTableTop; if (index == 0) { itsData.itsDoubleTable = new double[64]; } else if (itsData.itsDoubleTable.length == index) { double[] na = new double[index * 2]; System.arraycopy(itsData.itsDoubleTable, 0, na, 0, index); itsData.itsDoubleTable = na; } itsData.itsDoubleTable[index] = num; doubleTableTop = index + 1; return index; } private void addGotoOp(int gotoOp) { byte[] array = itsData.itsICode; int top = iCodeTop; if (top + 3 > array.length) { array = increaseICodeCapacity(3); } array[top] = (byte) gotoOp; // Offset would written later iCodeTop = top + 1 + 2; } private void addVarOp(int op, int varIndex) { switch (op) { case Token.SETCONSTVAR: if (varIndex < 128) { addIcode(Icode_SETCONSTVAR1); addUint8(varIndex); return; } addIndexOp(Icode_SETCONSTVAR, varIndex); return; case Token.GETVAR: case Token.SETVAR: if (varIndex < 128) { addIcode(op == Token.GETVAR ? Icode_GETVAR1 : Icode_SETVAR1); addUint8(varIndex); return; } // fallthrough case Icode_VAR_INC_DEC: addIndexOp(op, varIndex); return; } throw Kit.codeBug(); } private void addStringOp(int op, String str) { addStringPrefix(str); if (Icode.validIcode(op)) { addIcode(op); } else { addToken(op); } } private void addIndexOp(int op, int index) { addIndexPrefix(index); if (Icode.validIcode(op)) { addIcode(op); } else { addToken(op); } } private void addStringPrefix(String str) { int index = strings.get(str, -1); if (index == -1) { index = strings.size(); strings.put(str, index); } if (index < 4) { addIcode(Icode_REG_STR_C0 - index); } else if (index <= 0xFF) { addIcode(Icode_REG_STR1); addUint8(index); } else if (index <= 0xFFFF) { addIcode(Icode_REG_STR2); addUint16(index); } else { addIcode(Icode_REG_STR4); addInt(index); } } private void addBigInt(BigInteger n) { int index = bigInts.get(n, -1); if (index == -1) { index = bigInts.size(); bigInts.put(n, index); } if (index < 4) { addIcode(Icode_REG_BIGINT_C0 - index); } else if (index <= 0xFF) { addIcode(Icode_REG_BIGINT1); addUint8(index); } else if (index <= 0xFFFF) { addIcode(Icode_REG_BIGINT2); addUint16(index); } else { addIcode(Icode_REG_BIGINT4); addInt(index); } addToken(Token.BIGINT); } private void addIndexPrefix(int index) { if (index < 0) Kit.codeBug(); if (index < 6) { addIcode(Icode_REG_IND_C0 - index); } else if (index <= 0xFF) { addIcode(Icode_REG_IND1); addUint8(index); } else if (index <= 0xFFFF) { addIcode(Icode_REG_IND2); addUint16(index); } else { addIcode(Icode_REG_IND4); addInt(index); } } private void addExceptionHandler( int icodeStart, int icodeEnd, int handlerStart, boolean isFinally, int exceptionObjectLocal, int scopeLocal) { int top = exceptionTableTop; int[] table = itsData.itsExceptionTable; if (table == null) { if (top != 0) Kit.codeBug(); table = new int[Interpreter.EXCEPTION_SLOT_SIZE * 2]; itsData.itsExceptionTable = table; } else if (table.length == top) { table = new int[table.length * 2]; System.arraycopy(itsData.itsExceptionTable, 0, table, 0, top); itsData.itsExceptionTable = table; } table[top + Interpreter.EXCEPTION_TRY_START_SLOT] = icodeStart; table[top + Interpreter.EXCEPTION_TRY_END_SLOT] = icodeEnd; table[top + Interpreter.EXCEPTION_HANDLER_SLOT] = handlerStart; table[top + Interpreter.EXCEPTION_TYPE_SLOT] = isFinally ? 1 : 0; table[top + Interpreter.EXCEPTION_LOCAL_SLOT] = exceptionObjectLocal; table[top + Interpreter.EXCEPTION_SCOPE_SLOT] = scopeLocal; exceptionTableTop = top + Interpreter.EXCEPTION_SLOT_SIZE; } private byte[] increaseICodeCapacity(int extraSize) { int capacity = itsData.itsICode.length; int top = iCodeTop; if (top + extraSize <= capacity) throw Kit.codeBug(); capacity *= 2; if (top + extraSize > capacity) { capacity = top + extraSize; } byte[] array = new byte[capacity]; System.arraycopy(itsData.itsICode, 0, array, 0, top); itsData.itsICode = array; return array; } private void stackChange(int change) { if (change <= 0) { stackDepth += change; } else { int newDepth = stackDepth + change; if (newDepth > itsData.itsMaxStack) { itsData.itsMaxStack = newDepth; } stackDepth = newDepth; } } private int allocLocal() { int localSlot = localTop; ++localTop; if (localTop > itsData.itsMaxLocals) { itsData.itsMaxLocals = localTop; } return localSlot; } private void releaseLocal(int localSlot) { --localTop; if (localSlot != localTop) Kit.codeBug(); } }
⏎ org/mozilla/javascript/CodeGenerator.java
Or download all of them as a single archive file:
File name: rhino-1.7.14-sources.jar File size: 1029165 bytes Release date: 2022-01-06 Download
⇒ Example code to Test rhino-runtime-1.7.14.jar
⇐ Download Rhino JavaScript Binary Package
2022-05-03, 35586👍, 1💬
Popular Posts:
JDK 11 jdk.dynalink.jmod is the JMOD file for JDK 11 Dynamic Linking module. JDK 11 Dynamic Linking ...
How to display types defined in an XML Schema file with the xs\QueryXS.java provided in the Apache X...
How to download and install ojdbc7.jar for Oracle 12c R1? ojdbc8.jar for Oracle 12c R1 is a Java 7 a...
What Is jaxb-api-2.1.6.jar? Java Architecture for XML Binding (JAXB) is a Java API that allows Java ...
JRE 5 sunjce_provider.jar is the JAR file for JRE 5 Sun JCE Provider, which provides implementations...