Rhino.Optimizer.Codegen.GenerateNativeFunctionOverrides C# (CSharp) Method

GenerateNativeFunctionOverrides() private method

private GenerateNativeFunctionOverrides ( ClassFileWriter cfw, string encodedSource ) : void
cfw Org.Mozilla.Classfile.ClassFileWriter
encodedSource string
return void
		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);
			}
		}