📄 codegen.java
字号:
int N = directCallTargets.size(); for (int j = 0; j != N; ++j) { cfw.addField(getDirectTargetFieldName(j), mainClassSignature, ClassFileWriter.ACC_PRIVATE); } } emitRegExpInit(cfw); emitConstantDudeInitializers(cfw); return cfw.toByteArray(); } private void emitDirectConstructor(ClassFileWriter cfw, OptFunctionNode ofn) {/* we generate .. Scriptable directConstruct(<directCallArgs>) { Scriptable newInstance = createObject(cx, scope); Object val = <body-name>(cx, scope, newInstance, <directCallArgs>); if (val instanceof Scriptable) { return (Scriptable) val; } return newInstance; }*/ cfw.startMethod(getDirectCtorName(ofn.fnode), getBodyMethodSignature(ofn.fnode), (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE)); int argCount = ofn.fnode.getParamCount(); int firstLocal = (4 + argCount * 3) + 1; cfw.addALoad(0); // this cfw.addALoad(1); // cx cfw.addALoad(2); // scope cfw.addInvoke(ByteCode.INVOKEVIRTUAL, "org/mozilla/javascript/BaseFunction", "createObject", "(Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +")Lorg/mozilla/javascript/Scriptable;"); cfw.addAStore(firstLocal); cfw.addALoad(0); cfw.addALoad(1); cfw.addALoad(2); cfw.addALoad(firstLocal); for (int i = 0; i < argCount; i++) { cfw.addALoad(4 + (i * 3)); cfw.addDLoad(5 + (i * 3)); } cfw.addALoad(4 + argCount * 3); cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName, getBodyMethodName(ofn.fnode), getBodyMethodSignature(ofn.fnode)); int exitLabel = cfw.acquireLabel(); cfw.add(ByteCode.DUP); // make a copy of direct call result cfw.add(ByteCode.INSTANCEOF, "org/mozilla/javascript/Scriptable"); cfw.add(ByteCode.IFEQ, exitLabel); // cast direct call result cfw.add(ByteCode.CHECKCAST, "org/mozilla/javascript/Scriptable"); cfw.add(ByteCode.ARETURN); cfw.markLabel(exitLabel); cfw.addALoad(firstLocal); cfw.add(ByteCode.ARETURN); cfw.stopMethod((short)(firstLocal + 1)); } static boolean isGenerator(ScriptOrFnNode node) { return (node.getType() == Token.FUNCTION ) && ((FunctionNode)node).isGenerator(); } // How dispatch to generators works: // Two methods are generated corresponding to a user-written generator. // One of these creates a generator object (NativeGenerator), which is // returned to the user. The other method contains all of the body code // of the generator. // When a user calls a generator, the call() method dispatches control to // to the method that creates the NativeGenerator object. Subsequently when // the user invokes .next(), .send() or any such method on the generator // object, the resumeGenerator() below dispatches the call to the // method corresponding to the generator body. As a matter of convention // the generator body is given the name of the generator activation function // appended by "_gen". private void generateResumeGenerator(ClassFileWriter cfw) { boolean hasGenerators = false; for (int i=0; i < scriptOrFnNodes.length; i++) { if (isGenerator(scriptOrFnNodes[i])) hasGenerators = true; } // if there are no generators defined, we don't implement a // resumeGenerator(). The base class provides a default implementation. if (!hasGenerators) return; cfw.startMethod("resumeGenerator", "(Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "ILjava/lang/Object;" + "Ljava/lang/Object;)Ljava/lang/Object;", (short)(ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_FINAL)); // load arguments for dispatch to the corresponding *_gen method cfw.addALoad(0); cfw.addALoad(1); cfw.addALoad(2); cfw.addALoad(4); cfw.addALoad(5); cfw.addILoad(3); cfw.addLoadThis(); cfw.add(ByteCode.GETFIELD, cfw.getClassName(), ID_FIELD_NAME, "I"); int startSwitch = cfw.addTableSwitch(0, scriptOrFnNodes.length - 1); cfw.markTableSwitchDefault(startSwitch); int endlabel = cfw.acquireLabel(); for (int i = 0; i < scriptOrFnNodes.length; i++) { ScriptOrFnNode n = scriptOrFnNodes[i]; cfw.markTableSwitchCase(startSwitch, i, (short)6); if (isGenerator(n)) { String type = "(" + mainClassSignature + "Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "Ljava/lang/Object;" + "Ljava/lang/Object;I)Ljava/lang/Object;"; cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName, getBodyMethodName(n) + "_gen", type); cfw.add(ByteCode.ARETURN); } else { cfw.add(ByteCode.GOTO, endlabel); } } cfw.markLabel(endlabel); pushUndefined(cfw); cfw.add(ByteCode.ARETURN); // this method uses as many locals as there are arguments (hence 6) cfw.stopMethod((short)6); } private void generateCallMethod(ClassFileWriter cfw) { cfw.startMethod("call", "(Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "Lorg/mozilla/javascript/Scriptable;" + "[Ljava/lang/Object;)Ljava/lang/Object;", (short)(ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_FINAL)); // Generate code for: // if (!ScriptRuntime.hasTopCall(cx)) { // return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args); // } int nonTopCallLabel = cfw.acquireLabel(); cfw.addALoad(1); //cx cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/ScriptRuntime", "hasTopCall", "(Lorg/mozilla/javascript/Context;" +")Z"); cfw.add(ByteCode.IFNE, nonTopCallLabel); cfw.addALoad(0); cfw.addALoad(1); cfw.addALoad(2); cfw.addALoad(3); cfw.addALoad(4); cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/ScriptRuntime", "doTopCall", "(Lorg/mozilla/javascript/Callable;" +"Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +"Lorg/mozilla/javascript/Scriptable;" +"[Ljava/lang/Object;" +")Ljava/lang/Object;"); cfw.add(ByteCode.ARETURN); cfw.markLabel(nonTopCallLabel); // Now generate switch to call the real methods cfw.addALoad(0); cfw.addALoad(1); cfw.addALoad(2); cfw.addALoad(3); cfw.addALoad(4); int end = scriptOrFnNodes.length; boolean generateSwitch = (2 <= end); int switchStart = 0; int switchStackTop = 0; if (generateSwitch) { cfw.addLoadThis(); cfw.add(ByteCode.GETFIELD, cfw.getClassName(), ID_FIELD_NAME, "I"); // do switch from (1, end - 1) mapping 0 to // the default case switchStart = cfw.addTableSwitch(1, end - 1); } for (int i = 0; i != end; ++i) { ScriptOrFnNode n = scriptOrFnNodes[i]; if (generateSwitch) { if (i == 0) { cfw.markTableSwitchDefault(switchStart); switchStackTop = cfw.getStackTop(); } else { cfw.markTableSwitchCase(switchStart, i - 1, switchStackTop); } } if (n.getType() == Token.FUNCTION) { OptFunctionNode ofn = OptFunctionNode.get(n); if (ofn.isTargetOfDirectCall()) { int pcount = ofn.fnode.getParamCount(); if (pcount != 0) { // loop invariant: // stack top == arguments array from addALoad4() for (int p = 0; p != pcount; ++p) { cfw.add(ByteCode.ARRAYLENGTH); cfw.addPush(p); int undefArg = cfw.acquireLabel(); int beyond = cfw.acquireLabel(); cfw.add(ByteCode.IF_ICMPLE, undefArg); // get array[p] cfw.addALoad(4); cfw.addPush(p); cfw.add(ByteCode.AALOAD); cfw.add(ByteCode.GOTO, beyond); cfw.markLabel(undefArg); pushUndefined(cfw); cfw.markLabel(beyond); // Only one push cfw.adjustStackTop(-1); cfw.addPush(0.0); // restore invariant cfw.addALoad(4); } } } } cfw.addInvoke(ByteCode.INVOKESTATIC, mainClassName, getBodyMethodName(n), getBodyMethodSignature(n)); cfw.add(ByteCode.ARETURN); } cfw.stopMethod((short)5); // 5: this, cx, scope, js this, args[] } private void generateMain(ClassFileWriter cfw) { cfw.startMethod("main", "([Ljava/lang/String;)V", (short)(ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_STATIC)); // load new ScriptImpl() cfw.add(ByteCode.NEW, cfw.getClassName()); cfw.add(ByteCode.DUP); cfw.addInvoke(ByteCode.INVOKESPECIAL, cfw.getClassName(), "<init>", "()V"); // load 'args' cfw.add(ByteCode.ALOAD_0); // Call mainMethodClass.main(Script script, String[] args) cfw.addInvoke(ByteCode.INVOKESTATIC, mainMethodClass, "main", "(Lorg/mozilla/javascript/Script;[Ljava/lang/String;)V"); cfw.add(ByteCode.RETURN); // 1 = String[] args cfw.stopMethod((short)1); } private void generateExecute(ClassFileWriter cfw) { cfw.startMethod("exec", "(Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +")Ljava/lang/Object;", (short)(ClassFileWriter.ACC_PUBLIC | ClassFileWriter.ACC_FINAL)); final int CONTEXT_ARG = 1; final int SCOPE_ARG = 2; cfw.addLoadThis(); cfw.addALoad(CONTEXT_ARG); cfw.addALoad(SCOPE_ARG); cfw.add(ByteCode.DUP); cfw.add(ByteCode.ACONST_NULL); cfw.addInvoke(ByteCode.INVOKEVIRTUAL, cfw.getClassName(), "call", "(Lorg/mozilla/javascript/Context;" +"Lorg/mozilla/javascript/Scriptable;" +"Lorg/mozilla/javascript/Scriptable;" +"[Ljava/lang/Object;" +")Ljava/lang/Object;"); cfw.add(ByteCode.ARETURN); // 3 = this + context + scope cfw.stopMethod((short)3); } private void generateScriptCtor(ClassFileWriter cfw) { cfw.startMethod("<init>", "()V", ClassFileWriter.ACC_PUBLIC); cfw.addLoadThis(); cfw.addInvoke(ByteCode.INVOKESPECIAL, SUPER_CLASS_NAME, "<init>", "()V"); // set id to 0 cfw.addLoadThis(); cfw.addPush(0); cfw.add(ByteCode.PUTFIELD, cfw.getClassName(), ID_FIELD_NAME, "I"); cfw.add(ByteCode.RETURN); // 1 parameter = this cfw.stopMethod((short)1); } private void generateFunctionConstructor(ClassFileWriter cfw) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -