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);
}