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; bool 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) { ScriptNode 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); }