ClassFileWriter A ClassFileWriter is used to write a Java class file.
ClassFileWriter A ClassFileWriter is used to write a Java class file. Methods are provided to create fields and methods, and within methods to write Java bytecodes.
Example #1
0
		private void EmitConstantDudeInitializers(ClassFileWriter cfw)
		{
			int N = itsConstantListSize;
			if (N == 0)
			{
				return;
			}
			cfw.StartMethod("<clinit>", "()V", (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_FINAL));
			double[] array = itsConstantList;
			for (int i = 0; i != N; ++i)
			{
				double num = array[i];
				string constantName = "_k" + i;
				string constantType = GetStaticConstantWrapperType(num);
				cfw.AddField(constantName, constantType, (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
				int inum = (int)num;
				if (inum == num)
				{
					cfw.AddPush(inum);
					cfw.AddInvoke(ByteCode.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
				}
				else
				{
					cfw.AddPush(num);
					AddDoubleWrap(cfw);
				}
				cfw.Add(ByteCode.PUTSTATIC, mainClassName, constantName, constantType);
			}
			cfw.Add(ByteCode.RETURN);
			cfw.StopMethod((short)0);
		}
Example #2
0
		internal virtual void PushNumberAsObject(ClassFileWriter cfw, double num)
		{
			if (num == 0.0)
			{
				if (1 / num > 0)
				{
					// +0.0
					cfw.Add(ByteCode.GETSTATIC, "org/mozilla/javascript/optimizer/OptRuntime", "zeroObj", "Ljava/lang/Double;");
				}
				else
				{
					cfw.AddPush(num);
					AddDoubleWrap(cfw);
				}
			}
			else
			{
				if (num == 1.0)
				{
					cfw.Add(ByteCode.GETSTATIC, "org/mozilla/javascript/optimizer/OptRuntime", "oneObj", "Ljava/lang/Double;");
					return;
				}
				else
				{
					if (num == -1.0)
					{
						cfw.Add(ByteCode.GETSTATIC, "org/mozilla/javascript/optimizer/OptRuntime", "minusOneObj", "Ljava/lang/Double;");
					}
					else
					{
						if (num != num)
						{
							cfw.Add(ByteCode.GETSTATIC, "org/mozilla/javascript/ScriptRuntime", "NaNobj", "Ljava/lang/Double;");
						}
						else
						{
							if (itsConstantListSize >= 2000)
							{
								// There appears to be a limit in the JVM on either the number
								// of static fields in a class or the size of the class
								// initializer. Either way, we can't have any more than 2000
								// statically init'd constants.
								cfw.AddPush(num);
								AddDoubleWrap(cfw);
							}
							else
							{
								int N = itsConstantListSize;
								int index = 0;
								if (N == 0)
								{
									itsConstantList = new double[64];
								}
								else
								{
									double[] array = itsConstantList;
									while (index != N && array[index] != num)
									{
										++index;
									}
									if (N == array.Length)
									{
										array = new double[N * 2];
										System.Array.Copy(itsConstantList, 0, array, 0, N);
										itsConstantList = array;
									}
								}
								if (index == N)
								{
									itsConstantList[N] = num;
									itsConstantListSize = N + 1;
								}
								string constantName = "_k" + index;
								string constantType = GetStaticConstantWrapperType(num);
								cfw.Add(ByteCode.GETSTATIC, mainClassName, constantName, constantType);
							}
						}
					}
				}
			}
		}
Example #3
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);
			}
		}
Example #4
0
		private void EmitRegExpInit(ClassFileWriter cfw)
		{
			// precompile all regexp literals
			int totalRegCount = 0;
			for (int i = 0; i != scriptOrFnNodes.Length; ++i)
			{
				totalRegCount += scriptOrFnNodes[i].GetRegexpCount();
			}
			if (totalRegCount == 0)
			{
				return;
			}
			cfw.StartMethod(REGEXP_INIT_METHOD_NAME, REGEXP_INIT_METHOD_SIGNATURE, (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
			cfw.AddField("_reInitDone", "Z", (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE | ClassFileWriter.ACC_VOLATILE));
			cfw.Add(ByteCode.GETSTATIC, mainClassName, "_reInitDone", "Z");
			int doInit = cfw.AcquireLabel();
			cfw.Add(ByteCode.IFEQ, doInit);
			cfw.Add(ByteCode.RETURN);
			cfw.MarkLabel(doInit);
			// get regexp proxy and store it in local slot 1
			cfw.AddALoad(0);
			// context
			cfw.AddInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/ScriptRuntime", "checkRegExpProxy", "(Lorg/mozilla/javascript/Context;" + ")Lorg/mozilla/javascript/RegExpProxy;");
			cfw.AddAStore(1);
			// proxy
			// We could apply double-checked locking here but concurrency
			// shouldn't be a problem in practice
			for (int i_1 = 0; i_1 != scriptOrFnNodes.Length; ++i_1)
			{
				ScriptNode n = scriptOrFnNodes[i_1];
				int regCount = n.GetRegexpCount();
				for (int j = 0; j != regCount; ++j)
				{
					string reFieldName = GetCompiledRegexpName(n, j);
					string reFieldType = "Ljava/lang/Object;";
					string reString = n.GetRegexpString(j);
					string reFlags = n.GetRegexpFlags(j);
					cfw.AddField(reFieldName, reFieldType, (short)(ClassFileWriter.ACC_STATIC | ClassFileWriter.ACC_PRIVATE));
					cfw.AddALoad(1);
					// proxy
					cfw.AddALoad(0);
					// context
					cfw.AddPush(reString);
					if (reFlags == null)
					{
						cfw.Add(ByteCode.ACONST_NULL);
					}
					else
					{
						cfw.AddPush(reFlags);
					}
					cfw.AddInvoke(ByteCode.INVOKEINTERFACE, "org/mozilla/javascript/RegExpProxy", "compileRegExp", "(Lorg/mozilla/javascript/Context;" + "Ljava/lang/String;Ljava/lang/String;" + ")Ljava/lang/Object;");
					cfw.Add(ByteCode.PUTSTATIC, mainClassName, reFieldName, reFieldType);
				}
			}
			cfw.AddPush(1);
			cfw.Add(ByteCode.PUTSTATIC, mainClassName, "_reInitDone", "Z");
			cfw.Add(ByteCode.RETURN);
			cfw.StopMethod((short)2);
		}
Example #5
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);
		}
Example #6
0
		private void GenerateFunctionInit(ClassFileWriter cfw, OptFunctionNode ofn)
		{
			int CONTEXT_ARG = 1;
			int SCOPE_ARG = 2;
			cfw.StartMethod(GetFunctionInitMethodName(ofn), FUNCTION_INIT_SIGNATURE, (short)(ClassFileWriter.ACC_PRIVATE | ClassFileWriter.ACC_FINAL));
			// Call NativeFunction.initScriptFunction
			cfw.AddLoadThis();
			cfw.AddALoad(CONTEXT_ARG);
			cfw.AddALoad(SCOPE_ARG);
			cfw.AddInvoke(ByteCode.INVOKEVIRTUAL, "org/mozilla/javascript/NativeFunction", "initScriptFunction", "(Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + ")V");
			// precompile all regexp literals
			if (ofn.fnode.GetRegexpCount() != 0)
			{
				cfw.AddALoad(CONTEXT_ARG);
				cfw.AddInvoke(ByteCode.INVOKESTATIC, mainClassName, REGEXP_INIT_METHOD_NAME, REGEXP_INIT_METHOD_SIGNATURE);
			}
			cfw.Add(ByteCode.RETURN);
			// 3 = (scriptThis/functionRef) + scope + context
			cfw.StopMethod((short)3);
		}
Example #7
0
		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));
			int CONTEXT_ARG = 1;
			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);
		}
Example #8
0
		internal static void PushUndefined(ClassFileWriter cfw)
		{
			cfw.Add(ByteCode.GETSTATIC, "org/mozilla/javascript/Undefined", "instance", "Ljava/lang/Object;");
		}
Example #9
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);
		}
Example #10
0
		// 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);
		}
Example #11
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);
		}
Example #12
0
		private void EmitDirectConstructor(ClassFileWriter cfw, OptFunctionNode ofn)
		{
			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));
		}
Example #13
0
		private byte[] GenerateCode(string encodedSource)
		{
			bool hasScript = (scriptOrFnNodes[0].GetType() == Token.SCRIPT);
			bool hasFunctions = (scriptOrFnNodes.Length > 1 || !hasScript);
			string sourceFile = null;
			if (compilerEnv.IsGenerateDebugInfo())
			{
				sourceFile = scriptOrFnNodes[0].GetSourceName();
			}
			ClassFileWriter cfw = new ClassFileWriter(mainClassName, SUPER_CLASS_NAME, sourceFile);
			cfw.AddField(ID_FIELD_NAME, "I", ClassFileWriter.ACC_PRIVATE);
			if (hasFunctions)
			{
				GenerateFunctionConstructor(cfw);
			}
			if (hasScript)
			{
				cfw.AddInterface("org/mozilla/javascript/Script");
				GenerateScriptCtor(cfw);
				GenerateMain(cfw);
				GenerateExecute(cfw);
			}
			GenerateCallMethod(cfw);
			GenerateResumeGenerator(cfw);
			GenerateNativeFunctionOverrides(cfw, encodedSource);
			int count = scriptOrFnNodes.Length;
			for (int i = 0; i != count; ++i)
			{
				ScriptNode n = scriptOrFnNodes[i];
				BodyCodegen bodygen = new BodyCodegen();
				bodygen.cfw = cfw;
				bodygen.codegen = this;
				bodygen.compilerEnv = compilerEnv;
				bodygen.scriptOrFn = n;
				bodygen.scriptOrFnIndex = i;
				try
				{
					bodygen.GenerateBodyCode();
				}
				catch (ClassFileWriter.ClassFileFormatException e)
				{
					throw ReportClassFileFormatException(n, e.Message);
				}
				if (n.GetType() == Token.FUNCTION)
				{
					OptFunctionNode ofn = OptFunctionNode.Get(n);
					GenerateFunctionInit(cfw, ofn);
					if (ofn.IsTargetOfDirectCall())
					{
						EmitDirectConstructor(cfw, ofn);
					}
				}
			}
			EmitRegExpInit(cfw);
			EmitConstantDudeInitializers(cfw);
			return cfw.ToByteArray();
		}
Example #14
0
			internal StackMapTable(ClassFileWriter _enclosing)
			{
				this._enclosing = _enclosing;
				this.superBlocks = null;
				this.locals = this.stack = null;
				this.workList = null;
				this.rawStackMap = null;
				this.localsTop = 0;
				this.stackTop = 0;
				this.workListTop = 0;
				this.rawStackMapTop = 0;
				this.wide = false;
			}
Example #15
0
		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);
		}
Example #16
0
		internal ConstantPool(ClassFileWriter cfw)
		{
			this.cfw = cfw;
			itsTopIndex = 1;
			// the zero'th entry is reserved
			itsPool = new byte[ConstantPoolSize];
			itsTop = 0;
		}
Example #17
0
		private static void AddDoubleWrap(ClassFileWriter cfw)
		{
			cfw.AddInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/optimizer/OptRuntime", "wrapDouble", "(D)Ljava/lang/Double;");
		}