AddTableSwitch() публичный Метод

public AddTableSwitch ( int low, int high ) : int
low int
high int
Результат int
Пример #1
0
		private void GenerateNativeFunctionOverrides(ClassFileWriter cfw, string encodedSource)
		{
			// Override NativeFunction.getLanguageVersion() with
			// public int getLanguageVersion() { return <version-constant>; }
			cfw.StartMethod("getLanguageVersion", "()I", ClassFileWriter.ACC_PUBLIC);
			cfw.AddPush(compilerEnv.GetLanguageVersion());
			cfw.Add(ByteCode.IRETURN);
			// 1: this and no argument or locals
			cfw.StopMethod((short)1);
			// The rest of NativeFunction overrides require specific code for each
			// script/function id
			int Do_getFunctionName = 0;
			int Do_getParamCount = 1;
			int Do_getParamAndVarCount = 2;
			int Do_getParamOrVarName = 3;
			int Do_getEncodedSource = 4;
			int Do_getParamOrVarConst = 5;
			int SWITCH_COUNT = 6;
			for (int methodIndex = 0; methodIndex != SWITCH_COUNT; ++methodIndex)
			{
				if (methodIndex == Do_getEncodedSource && encodedSource == null)
				{
					continue;
				}
				// Generate:
				//   prologue;
				//   switch over function id to implement function-specific action
				//   epilogue
				short methodLocals;
				switch (methodIndex)
				{
					case Do_getFunctionName:
					{
						methodLocals = 1;
						// Only this
						cfw.StartMethod("getFunctionName", "()Ljava/lang/String;", ClassFileWriter.ACC_PUBLIC);
						break;
					}

					case Do_getParamCount:
					{
						methodLocals = 1;
						// Only this
						cfw.StartMethod("getParamCount", "()I", ClassFileWriter.ACC_PUBLIC);
						break;
					}

					case Do_getParamAndVarCount:
					{
						methodLocals = 1;
						// Only this
						cfw.StartMethod("getParamAndVarCount", "()I", ClassFileWriter.ACC_PUBLIC);
						break;
					}

					case Do_getParamOrVarName:
					{
						methodLocals = 1 + 1;
						// this + paramOrVarIndex
						cfw.StartMethod("getParamOrVarName", "(I)Ljava/lang/String;", ClassFileWriter.ACC_PUBLIC);
						break;
					}

					case Do_getParamOrVarConst:
					{
						methodLocals = 1 + 1 + 1;
						// this + paramOrVarName
						cfw.StartMethod("getParamOrVarConst", "(I)Z", ClassFileWriter.ACC_PUBLIC);
						break;
					}

					case Do_getEncodedSource:
					{
						methodLocals = 1;
						// Only this
						cfw.StartMethod("getEncodedSource", "()Ljava/lang/String;", ClassFileWriter.ACC_PUBLIC);
						cfw.AddPush(encodedSource);
						break;
					}

					default:
					{
						throw Kit.CodeBug();
					}
				}
				int count = scriptOrFnNodes.Length;
				int switchStart = 0;
				int switchStackTop = 0;
				if (count > 1)
				{
					// Generate switch but only if there is more then one
					// script/function
					cfw.AddLoadThis();
					cfw.Add(ByteCode.GETFIELD, cfw.GetClassName(), ID_FIELD_NAME, "I");
					// do switch from 1 .. count - 1 mapping 0 to the default case
					switchStart = cfw.AddTableSwitch(1, count - 1);
				}
				for (int i = 0; i != count; ++i)
				{
					ScriptNode n = scriptOrFnNodes[i];
					if (i == 0)
					{
						if (count > 1)
						{
							cfw.MarkTableSwitchDefault(switchStart);
							switchStackTop = cfw.GetStackTop();
						}
					}
					else
					{
						cfw.MarkTableSwitchCase(switchStart, i - 1, switchStackTop);
					}
					switch (methodIndex)
					{
						case Do_getFunctionName:
						{
							// Impelemnet method-specific switch code
							// Push function name
							if (n.GetType() == Token.SCRIPT)
							{
								cfw.AddPush(string.Empty);
							}
							else
							{
								string name = ((FunctionNode)n).GetName();
								cfw.AddPush(name);
							}
							cfw.Add(ByteCode.ARETURN);
							break;
						}

						case Do_getParamCount:
						{
							// Push number of defined parameters
							cfw.AddPush(n.GetParamCount());
							cfw.Add(ByteCode.IRETURN);
							break;
						}

						case Do_getParamAndVarCount:
						{
							// Push number of defined parameters and declared variables
							cfw.AddPush(n.GetParamAndVarCount());
							cfw.Add(ByteCode.IRETURN);
							break;
						}

						case Do_getParamOrVarName:
						{
							// Push name of parameter using another switch
							// over paramAndVarCount
							int paramAndVarCount = n.GetParamAndVarCount();
							if (paramAndVarCount == 0)
							{
								// The runtime should never call the method in this
								// case but to make bytecode verifier happy return null
								// as throwing execption takes more code
								cfw.Add(ByteCode.ACONST_NULL);
								cfw.Add(ByteCode.ARETURN);
							}
							else
							{
								if (paramAndVarCount == 1)
								{
									// As above do not check for valid index but always
									// return the name of the first param
									cfw.AddPush(n.GetParamOrVarName(0));
									cfw.Add(ByteCode.ARETURN);
								}
								else
								{
									// Do switch over getParamOrVarName
									cfw.AddILoad(1);
									// param or var index
									// do switch from 1 .. paramAndVarCount - 1 mapping 0
									// to the default case
									int paramSwitchStart = cfw.AddTableSwitch(1, paramAndVarCount - 1);
									for (int j = 0; j != paramAndVarCount; ++j)
									{
										if (cfw.GetStackTop() != 0)
										{
											Kit.CodeBug();
										}
										string s = n.GetParamOrVarName(j);
										if (j == 0)
										{
											cfw.MarkTableSwitchDefault(paramSwitchStart);
										}
										else
										{
											cfw.MarkTableSwitchCase(paramSwitchStart, j - 1, 0);
										}
										cfw.AddPush(s);
										cfw.Add(ByteCode.ARETURN);
									}
								}
							}
							break;
						}

						case Do_getParamOrVarConst:
						{
							// Push name of parameter using another switch
							// over paramAndVarCount
							paramAndVarCount = n.GetParamAndVarCount();
							bool[] constness = n.GetParamAndVarConst();
							if (paramAndVarCount == 0)
							{
								// The runtime should never call the method in this
								// case but to make bytecode verifier happy return null
								// as throwing execption takes more code
								cfw.Add(ByteCode.ICONST_0);
								cfw.Add(ByteCode.IRETURN);
							}
							else
							{
								if (paramAndVarCount == 1)
								{
									// As above do not check for valid index but always
									// return the name of the first param
									cfw.AddPush(constness[0]);
									cfw.Add(ByteCode.IRETURN);
								}
								else
								{
									// Do switch over getParamOrVarName
									cfw.AddILoad(1);
									// param or var index
									// do switch from 1 .. paramAndVarCount - 1 mapping 0
									// to the default case
									int paramSwitchStart = cfw.AddTableSwitch(1, paramAndVarCount - 1);
									for (int j = 0; j != paramAndVarCount; ++j)
									{
										if (cfw.GetStackTop() != 0)
										{
											Kit.CodeBug();
										}
										if (j == 0)
										{
											cfw.MarkTableSwitchDefault(paramSwitchStart);
										}
										else
										{
											cfw.MarkTableSwitchCase(paramSwitchStart, j - 1, 0);
										}
										cfw.AddPush(constness[j]);
										cfw.Add(ByteCode.IRETURN);
									}
								}
							}
							break;
						}

						case Do_getEncodedSource:
						{
							// Push number encoded source start and end
							// to prepare for encodedSource.substring(start, end)
							cfw.AddPush(n.GetEncodedSourceStart());
							cfw.AddPush(n.GetEncodedSourceEnd());
							cfw.AddInvoke(ByteCode.INVOKEVIRTUAL, "java/lang/String", "substring", "(II)Ljava/lang/String;");
							cfw.Add(ByteCode.ARETURN);
							break;
						}

						default:
						{
							throw Kit.CodeBug();
						}
					}
				}
				cfw.StopMethod(methodLocals);
			}
		}
Пример #2
0
		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);
		}
Пример #3
0
		private void GenerateFunctionConstructor(ClassFileWriter cfw)
		{
			int SCOPE_ARG = 1;
			int CONTEXT_ARG = 2;
			int ID_ARG = 3;
			cfw.StartMethod("<init>", FUNCTION_CONSTRUCTOR_SIGNATURE, ClassFileWriter.ACC_PUBLIC);
			cfw.AddALoad(0);
			cfw.AddInvoke(ByteCode.INVOKESPECIAL, SUPER_CLASS_NAME, "<init>", "()V");
			cfw.AddLoadThis();
			cfw.AddILoad(ID_ARG);
			cfw.Add(ByteCode.PUTFIELD, cfw.GetClassName(), ID_FIELD_NAME, "I");
			cfw.AddLoadThis();
			cfw.AddALoad(CONTEXT_ARG);
			cfw.AddALoad(SCOPE_ARG);
			int start = (scriptOrFnNodes[0].GetType() == Token.SCRIPT) ? 1 : 0;
			int end = scriptOrFnNodes.Length;
			if (start == end)
			{
				throw BadTree();
			}
			bool generateSwitch = (2 <= end - start);
			int switchStart = 0;
			int switchStackTop = 0;
			if (generateSwitch)
			{
				cfw.AddILoad(ID_ARG);
				// do switch from (start + 1,  end - 1) mapping start to
				// the default case
				switchStart = cfw.AddTableSwitch(start + 1, end - 1);
			}
			for (int i = start; i != end; ++i)
			{
				if (generateSwitch)
				{
					if (i == start)
					{
						cfw.MarkTableSwitchDefault(switchStart);
						switchStackTop = cfw.GetStackTop();
					}
					else
					{
						cfw.MarkTableSwitchCase(switchStart, i - 1 - start, switchStackTop);
					}
				}
				OptFunctionNode ofn = OptFunctionNode.Get(scriptOrFnNodes[i]);
				cfw.AddInvoke(ByteCode.INVOKESPECIAL, mainClassName, GetFunctionInitMethodName(ofn), FUNCTION_INIT_SIGNATURE);
				cfw.Add(ByteCode.RETURN);
			}
			// 4 = this + scope + context + id
			cfw.StopMethod((short)4);
		}
Пример #4
0
		// 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)
		{
			bool 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_1 = 0; i_1 < scriptOrFnNodes.Length; i_1++)
			{
				ScriptNode n = scriptOrFnNodes[i_1];
				cfw.MarkTableSwitchCase(startSwitch, i_1, (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);
		}