Esempio n. 1
0
		private void VisitIncDec(Node node)
		{
			int incrDecrMask = node.GetExistingIntProp(Node.INCRDECR_PROP);
			Node child = node.GetFirstChild();
			switch (child.GetType())
			{
				case Token.GETVAR:
				{
					if (!hasVarsInRegs)
					{
						Kit.CodeBug();
					}
					bool post = ((incrDecrMask & Node.POST_FLAG) != 0);
					int varIndex = fnCurrent.GetVarIndex(child);
					short reg = varRegisters[varIndex];
					if (node.GetIntProp(Node.ISNUMBER_PROP, -1) != -1)
					{
						int offset = VarIsDirectCallParameter(varIndex) ? 1 : 0;
						cfw.AddDLoad(reg + offset);
						if (post)
						{
							cfw.Add(ByteCode.DUP2);
						}
						cfw.AddPush(1.0);
						if ((incrDecrMask & Node.DECR_FLAG) == 0)
						{
							cfw.Add(ByteCode.DADD);
						}
						else
						{
							cfw.Add(ByteCode.DSUB);
						}
						if (!post)
						{
							cfw.Add(ByteCode.DUP2);
						}
						cfw.AddDStore(reg + offset);
					}
					else
					{
						if (VarIsDirectCallParameter(varIndex))
						{
							DcpLoadAsObject(reg);
						}
						else
						{
							cfw.AddALoad(reg);
						}
						if (post)
						{
							cfw.Add(ByteCode.DUP);
						}
						AddObjectToDouble();
						cfw.AddPush(1.0);
						if ((incrDecrMask & Node.DECR_FLAG) == 0)
						{
							cfw.Add(ByteCode.DADD);
						}
						else
						{
							cfw.Add(ByteCode.DSUB);
						}
						AddDoubleWrap();
						if (!post)
						{
							cfw.Add(ByteCode.DUP);
						}
						cfw.AddAStore(reg);
						break;
					}
					break;
				}

				case Token.NAME:
				{
					cfw.AddALoad(variableObjectLocal);
					cfw.AddPush(child.GetString());
					// push name
					cfw.AddALoad(contextLocal);
					cfw.AddPush(incrDecrMask);
					AddScriptRuntimeInvoke("nameIncrDecr", "(Lorg/mozilla/javascript/Scriptable;" + "Ljava/lang/String;" + "Lorg/mozilla/javascript/Context;" + "I)Ljava/lang/Object;");
					break;
				}

				case Token.GETPROPNOWARN:
				{
					throw Kit.CodeBug();
				}

				case Token.GETPROP:
				{
					Node getPropChild = child.GetFirstChild();
					GenerateExpression(getPropChild, node);
					GenerateExpression(getPropChild.GetNext(), node);
					cfw.AddALoad(contextLocal);
					cfw.AddPush(incrDecrMask);
					AddScriptRuntimeInvoke("propIncrDecr", "(Ljava/lang/Object;" + "Ljava/lang/String;" + "Lorg/mozilla/javascript/Context;" + "I)Ljava/lang/Object;");
					break;
				}

				case Token.GETELEM:
				{
					Node elemChild = child.GetFirstChild();
					GenerateExpression(elemChild, node);
					GenerateExpression(elemChild.GetNext(), node);
					cfw.AddALoad(contextLocal);
					cfw.AddPush(incrDecrMask);
					if (elemChild.GetNext().GetIntProp(Node.ISNUMBER_PROP, -1) != -1)
					{
						AddOptRuntimeInvoke("elemIncrDecr", "(Ljava/lang/Object;" + "D" + "Lorg/mozilla/javascript/Context;" + "I" + ")Ljava/lang/Object;");
					}
					else
					{
						AddScriptRuntimeInvoke("elemIncrDecr", "(Ljava/lang/Object;" + "Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + "I" + ")Ljava/lang/Object;");
					}
					break;
				}

				case Token.GET_REF:
				{
					Node refChild = child.GetFirstChild();
					GenerateExpression(refChild, node);
					cfw.AddALoad(contextLocal);
					cfw.AddPush(incrDecrMask);
					AddScriptRuntimeInvoke("refIncrDecr", "(Lorg/mozilla/javascript/Ref;" + "Lorg/mozilla/javascript/Context;" + "I)Ljava/lang/Object;");
					break;
				}

				default:
				{
					Codegen.BadTree();
					break;
				}
			}
		}
Esempio n. 2
0
		private void GenerateExpression(Node node, Node parent)
		{
			int type = node.GetType();
			Node child = node.GetFirstChild();
			switch (type)
			{
				case Token.USE_STACK:
				{
					break;
				}

				case Token.FUNCTION:
				{
					if (fnCurrent != null || parent.GetType() != Token.SCRIPT)
					{
						int fnIndex = node.GetExistingIntProp(Node.FUNCTION_PROP);
						OptFunctionNode ofn = OptFunctionNode.Get(scriptOrFn, fnIndex);
						int t = ofn.fnode.GetFunctionType();
						if (t != FunctionNode.FUNCTION_EXPRESSION)
						{
							throw Codegen.BadTree();
						}
						VisitFunction(ofn, t);
					}
					break;
				}

				case Token.NAME:
				{
					cfw.AddALoad(contextLocal);
					cfw.AddALoad(variableObjectLocal);
					cfw.AddPush(node.GetString());
					AddScriptRuntimeInvoke("name", "(Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "Ljava/lang/String;" + ")Ljava/lang/Object;");
					break;
				}

				case Token.CALL:
				case Token.NEW:
				{
					int specialType = node.GetIntProp(Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL);
					if (specialType == Node.NON_SPECIALCALL)
					{
						OptFunctionNode target;
						target = (OptFunctionNode)node.GetProp(Node.DIRECTCALL_PROP);
						if (target != null)
						{
							VisitOptimizedCall(node, target, type, child);
						}
						else
						{
							if (type == Token.CALL)
							{
								VisitStandardCall(node, child);
							}
							else
							{
								VisitStandardNew(node, child);
							}
						}
					}
					else
					{
						VisitSpecialCall(node, type, specialType, child);
					}
					break;
				}

				case Token.REF_CALL:
				{
					GenerateFunctionAndThisObj(child, node);
					// stack: ... functionObj thisObj
					child = child.GetNext();
					GenerateCallArgArray(node, child, false);
					cfw.AddALoad(contextLocal);
					AddScriptRuntimeInvoke("callRef", "(Lorg/mozilla/javascript/Callable;" + "Lorg/mozilla/javascript/Scriptable;" + "[Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + ")Lorg/mozilla/javascript/Ref;");
					break;
				}

				case Token.NUMBER:
				{
					double num = node.GetDouble();
					if (node.GetIntProp(Node.ISNUMBER_PROP, -1) != -1)
					{
						cfw.AddPush(num);
					}
					else
					{
						codegen.PushNumberAsObject(cfw, num);
					}
					break;
				}

				case Token.STRING:
				{
					cfw.AddPush(node.GetString());
					break;
				}

				case Token.THIS:
				{
					cfw.AddALoad(thisObjLocal);
					break;
				}

				case Token.THISFN:
				{
					cfw.Add(ByteCode.ALOAD_0);
					break;
				}

				case Token.NULL:
				{
					cfw.Add(ByteCode.ACONST_NULL);
					break;
				}

				case Token.TRUE:
				{
					cfw.Add(ByteCode.GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
					break;
				}

				case Token.FALSE:
				{
					cfw.Add(ByteCode.GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
					break;
				}

				case Token.REGEXP:
				{
					// Create a new wrapper around precompiled regexp
					cfw.AddALoad(contextLocal);
					cfw.AddALoad(variableObjectLocal);
					int i = node.GetExistingIntProp(Node.REGEXP_PROP);
					cfw.Add(ByteCode.GETSTATIC, codegen.mainClassName, codegen.GetCompiledRegexpName(scriptOrFn, i), "Ljava/lang/Object;");
					cfw.AddInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/ScriptRuntime", "wrapRegExp", "(Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "Ljava/lang/Object;" + ")Lorg/mozilla/javascript/Scriptable;");
					break;
				}

				case Token.COMMA:
				{
					Node next = child.GetNext();
					while (next != null)
					{
						GenerateExpression(child, node);
						cfw.Add(ByteCode.POP);
						child = next;
						next = next.GetNext();
					}
					GenerateExpression(child, node);
					break;
				}

				case Token.ENUM_NEXT:
				case Token.ENUM_ID:
				{
					int local = GetLocalBlockRegister(node);
					cfw.AddALoad(local);
					if (type == Token.ENUM_NEXT)
					{
						AddScriptRuntimeInvoke("enumNext", "(Ljava/lang/Object;)Ljava/lang/Boolean;");
					}
					else
					{
						cfw.AddALoad(contextLocal);
						AddScriptRuntimeInvoke("enumId", "(Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + ")Ljava/lang/Object;");
					}
					break;
				}

				case Token.ARRAYLIT:
				{
					VisitArrayLiteral(node, child, false);
					break;
				}

				case Token.OBJECTLIT:
				{
					VisitObjectLiteral(node, child, false);
					break;
				}

				case Token.NOT:
				{
					int trueTarget = cfw.AcquireLabel();
					int falseTarget = cfw.AcquireLabel();
					int beyond = cfw.AcquireLabel();
					GenerateIfJump(child, node, trueTarget, falseTarget);
					cfw.MarkLabel(trueTarget);
					cfw.Add(ByteCode.GETSTATIC, "java/lang/Boolean", "FALSE", "Ljava/lang/Boolean;");
					cfw.Add(ByteCode.GOTO, beyond);
					cfw.MarkLabel(falseTarget);
					cfw.Add(ByteCode.GETSTATIC, "java/lang/Boolean", "TRUE", "Ljava/lang/Boolean;");
					cfw.MarkLabel(beyond);
					cfw.AdjustStackTop(-1);
					break;
				}

				case Token.BITNOT:
				{
					GenerateExpression(child, node);
					AddScriptRuntimeInvoke("toInt32", "(Ljava/lang/Object;)I");
					cfw.AddPush(-1);
					// implement ~a as (a ^ -1)
					cfw.Add(ByteCode.IXOR);
					cfw.Add(ByteCode.I2D);
					AddDoubleWrap();
					break;
				}

				case Token.VOID:
				{
					GenerateExpression(child, node);
					cfw.Add(ByteCode.POP);
					Codegen.PushUndefined(cfw);
					break;
				}

				case Token.TYPEOF:
				{
					GenerateExpression(child, node);
					AddScriptRuntimeInvoke("typeof", "(Ljava/lang/Object;" + ")Ljava/lang/String;");
					break;
				}

				case Token.TYPEOFNAME:
				{
					VisitTypeofname(node);
					break;
				}

				case Token.INC:
				case Token.DEC:
				{
					VisitIncDec(node);
					break;
				}

				case Token.OR:
				case Token.AND:
				{
					GenerateExpression(child, node);
					cfw.Add(ByteCode.DUP);
					AddScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z");
					int falseTarget = cfw.AcquireLabel();
					if (type == Token.AND)
					{
						cfw.Add(ByteCode.IFEQ, falseTarget);
					}
					else
					{
						cfw.Add(ByteCode.IFNE, falseTarget);
					}
					cfw.Add(ByteCode.POP);
					GenerateExpression(child.GetNext(), node);
					cfw.MarkLabel(falseTarget);
					break;
				}

				case Token.HOOK:
				{
					Node ifThen = child.GetNext();
					Node ifElse = ifThen.GetNext();
					GenerateExpression(child, node);
					AddScriptRuntimeInvoke("toBoolean", "(Ljava/lang/Object;)Z");
					int elseTarget = cfw.AcquireLabel();
					cfw.Add(ByteCode.IFEQ, elseTarget);
					short stack = cfw.GetStackTop();
					GenerateExpression(ifThen, node);
					int afterHook = cfw.AcquireLabel();
					cfw.Add(ByteCode.GOTO, afterHook);
					cfw.MarkLabel(elseTarget, stack);
					GenerateExpression(ifElse, node);
					cfw.MarkLabel(afterHook);
					break;
				}

				case Token.ADD:
				{
					GenerateExpression(child, node);
					GenerateExpression(child.GetNext(), node);
					switch (node.GetIntProp(Node.ISNUMBER_PROP, -1))
					{
						case Node.BOTH:
						{
							cfw.Add(ByteCode.DADD);
							break;
						}

						case Node.LEFT:
						{
							AddOptRuntimeInvoke("add", "(DLjava/lang/Object;)Ljava/lang/Object;");
							break;
						}

						case Node.RIGHT:
						{
							AddOptRuntimeInvoke("add", "(Ljava/lang/Object;D)Ljava/lang/Object;");
							break;
						}

						default:
						{
							if (child.GetType() == Token.STRING)
							{
								AddScriptRuntimeInvoke("add", "(Ljava/lang/CharSequence;" + "Ljava/lang/Object;" + ")Ljava/lang/CharSequence;");
							}
							else
							{
								if (child.GetNext().GetType() == Token.STRING)
								{
									AddScriptRuntimeInvoke("add", "(Ljava/lang/Object;" + "Ljava/lang/CharSequence;" + ")Ljava/lang/CharSequence;");
								}
								else
								{
									cfw.AddALoad(contextLocal);
									AddScriptRuntimeInvoke("add", "(Ljava/lang/Object;" + "Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + ")Ljava/lang/Object;");
								}
							}
							break;
						}
					}
					break;
				}

				case Token.MUL:
				{
					VisitArithmetic(node, ByteCode.DMUL, child, parent);
					break;
				}

				case Token.SUB:
				{
					VisitArithmetic(node, ByteCode.DSUB, child, parent);
					break;
				}

				case Token.DIV:
				case Token.MOD:
				{
					VisitArithmetic(node, type == Token.DIV ? ByteCode.DDIV : ByteCode.DREM, child, parent);
					break;
				}

				case Token.BITOR:
				case Token.BITXOR:
				case Token.BITAND:
				case Token.LSH:
				case Token.RSH:
				case Token.URSH:
				{
					VisitBitOp(node, type, child);
					break;
				}

				case Token.POS:
				case Token.NEG:
				{
					GenerateExpression(child, node);
					AddObjectToDouble();
					if (type == Token.NEG)
					{
						cfw.Add(ByteCode.DNEG);
					}
					AddDoubleWrap();
					break;
				}

				case Token.TO_DOUBLE:
				{
					// cnvt to double (not Double)
					GenerateExpression(child, node);
					AddObjectToDouble();
					break;
				}

				case Token.TO_OBJECT:
				{
					// convert from double
					int prop = -1;
					if (child.GetType() == Token.NUMBER)
					{
						prop = child.GetIntProp(Node.ISNUMBER_PROP, -1);
					}
					if (prop != -1)
					{
						child.RemoveProp(Node.ISNUMBER_PROP);
						GenerateExpression(child, node);
						child.PutIntProp(Node.ISNUMBER_PROP, prop);
					}
					else
					{
						GenerateExpression(child, node);
						AddDoubleWrap();
					}
					break;
				}

				case Token.IN:
				case Token.INSTANCEOF:
				case Token.LE:
				case Token.LT:
				case Token.GE:
				case Token.GT:
				{
					int trueGOTO = cfw.AcquireLabel();
					int falseGOTO = cfw.AcquireLabel();
					VisitIfJumpRelOp(node, child, trueGOTO, falseGOTO);
					AddJumpedBooleanWrap(trueGOTO, falseGOTO);
					break;
				}

				case Token.EQ:
				case Token.NE:
				case Token.SHEQ:
				case Token.SHNE:
				{
					int trueGOTO = cfw.AcquireLabel();
					int falseGOTO = cfw.AcquireLabel();
					VisitIfJumpEqOp(node, child, trueGOTO, falseGOTO);
					AddJumpedBooleanWrap(trueGOTO, falseGOTO);
					break;
				}

				case Token.GETPROP:
				case Token.GETPROPNOWARN:
				{
					VisitGetProp(node, child);
					break;
				}

				case Token.GETELEM:
				{
					GenerateExpression(child, node);
					// object
					GenerateExpression(child.GetNext(), node);
					// id
					cfw.AddALoad(contextLocal);
					if (node.GetIntProp(Node.ISNUMBER_PROP, -1) != -1)
					{
						AddScriptRuntimeInvoke("getObjectIndex", "(Ljava/lang/Object;D" + "Lorg/mozilla/javascript/Context;" + ")Ljava/lang/Object;");
					}
					else
					{
						cfw.AddALoad(variableObjectLocal);
						AddScriptRuntimeInvoke("getObjectElem", "(Ljava/lang/Object;" + "Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + ")Ljava/lang/Object;");
					}
					break;
				}

				case Token.GET_REF:
				{
					GenerateExpression(child, node);
					// reference
					cfw.AddALoad(contextLocal);
					AddScriptRuntimeInvoke("refGet", "(Lorg/mozilla/javascript/Ref;" + "Lorg/mozilla/javascript/Context;" + ")Ljava/lang/Object;");
					break;
				}

				case Token.GETVAR:
				{
					VisitGetVar(node);
					break;
				}

				case Token.SETVAR:
				{
					VisitSetVar(node, child, true);
					break;
				}

				case Token.SETNAME:
				{
					VisitSetName(node, child);
					break;
				}

				case Token.STRICT_SETNAME:
				{
					VisitStrictSetName(node, child);
					break;
				}

				case Token.SETCONST:
				{
					VisitSetConst(node, child);
					break;
				}

				case Token.SETCONSTVAR:
				{
					VisitSetConstVar(node, child, true);
					break;
				}

				case Token.SETPROP:
				case Token.SETPROP_OP:
				{
					VisitSetProp(type, node, child);
					break;
				}

				case Token.SETELEM:
				case Token.SETELEM_OP:
				{
					VisitSetElem(type, node, child);
					break;
				}

				case Token.SET_REF:
				case Token.SET_REF_OP:
				{
					GenerateExpression(child, node);
					child = child.GetNext();
					if (type == Token.SET_REF_OP)
					{
						cfw.Add(ByteCode.DUP);
						cfw.AddALoad(contextLocal);
						AddScriptRuntimeInvoke("refGet", "(Lorg/mozilla/javascript/Ref;" + "Lorg/mozilla/javascript/Context;" + ")Ljava/lang/Object;");
					}
					GenerateExpression(child, node);
					cfw.AddALoad(contextLocal);
					AddScriptRuntimeInvoke("refSet", "(Lorg/mozilla/javascript/Ref;" + "Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + ")Ljava/lang/Object;");
					break;
				}

				case Token.DEL_REF:
				{
					GenerateExpression(child, node);
					cfw.AddALoad(contextLocal);
					AddScriptRuntimeInvoke("refDel", "(Lorg/mozilla/javascript/Ref;" + "Lorg/mozilla/javascript/Context;" + ")Ljava/lang/Object;");
					break;
				}

				case Token.DELPROP:
				{
					bool isName = child.GetType() == Token.BINDNAME;
					GenerateExpression(child, node);
					child = child.GetNext();
					GenerateExpression(child, node);
					cfw.AddALoad(contextLocal);
					cfw.AddPush(isName);
					AddScriptRuntimeInvoke("delete", "(Ljava/lang/Object;" + "Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + "Z)Ljava/lang/Object;");
					break;
				}

				case Token.BINDNAME:
				{
					while (child != null)
					{
						GenerateExpression(child, node);
						child = child.GetNext();
					}
					// Generate code for "ScriptRuntime.bind(varObj, "s")"
					cfw.AddALoad(contextLocal);
					cfw.AddALoad(variableObjectLocal);
					cfw.AddPush(node.GetString());
					AddScriptRuntimeInvoke("bind", "(Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "Ljava/lang/String;" + ")Lorg/mozilla/javascript/Scriptable;");
					break;
				}

				case Token.LOCAL_LOAD:
				{
					cfw.AddALoad(GetLocalBlockRegister(node));
					break;
				}

				case Token.REF_SPECIAL:
				{
					string special = (string)node.GetProp(Node.NAME_PROP);
					GenerateExpression(child, node);
					cfw.AddPush(special);
					cfw.AddALoad(contextLocal);
					AddScriptRuntimeInvoke("specialRef", "(Ljava/lang/Object;" + "Ljava/lang/String;" + "Lorg/mozilla/javascript/Context;" + ")Lorg/mozilla/javascript/Ref;");
					break;
				}

				case Token.REF_MEMBER:
				case Token.REF_NS_MEMBER:
				case Token.REF_NAME:
				case Token.REF_NS_NAME:
				{
					int memberTypeFlags = node.GetIntProp(Node.MEMBER_TYPE_PROP, 0);
					do
					{
						// generate possible target, possible namespace and member
						GenerateExpression(child, node);
						child = child.GetNext();
					}
					while (child != null);
					cfw.AddALoad(contextLocal);
					string methodName;
					string signature;
					switch (type)
					{
						case Token.REF_MEMBER:
						{
							methodName = "memberRef";
							signature = "(Ljava/lang/Object;" + "Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + "I" + ")Lorg/mozilla/javascript/Ref;";
							break;
						}

						case Token.REF_NS_MEMBER:
						{
							methodName = "memberRef";
							signature = "(Ljava/lang/Object;" + "Ljava/lang/Object;" + "Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + "I" + ")Lorg/mozilla/javascript/Ref;";
							break;
						}

						case Token.REF_NAME:
						{
							methodName = "nameRef";
							signature = "(Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "I" + ")Lorg/mozilla/javascript/Ref;";
							cfw.AddALoad(variableObjectLocal);
							break;
						}

						case Token.REF_NS_NAME:
						{
							methodName = "nameRef";
							signature = "(Ljava/lang/Object;" + "Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + "I" + ")Lorg/mozilla/javascript/Ref;";
							cfw.AddALoad(variableObjectLocal);
							break;
						}

						default:
						{
							throw Kit.CodeBug();
						}
					}
					cfw.AddPush(memberTypeFlags);
					AddScriptRuntimeInvoke(methodName, signature);
					break;
				}

				case Token.DOTQUERY:
				{
					VisitDotQuery(node, child);
					break;
				}

				case Token.ESCXMLATTR:
				{
					GenerateExpression(child, node);
					cfw.AddALoad(contextLocal);
					AddScriptRuntimeInvoke("escapeAttributeValue", "(Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + ")Ljava/lang/String;");
					break;
				}

				case Token.ESCXMLTEXT:
				{
					GenerateExpression(child, node);
					cfw.AddALoad(contextLocal);
					AddScriptRuntimeInvoke("escapeTextValue", "(Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + ")Ljava/lang/String;");
					break;
				}

				case Token.DEFAULTNAMESPACE:
				{
					GenerateExpression(child, node);
					cfw.AddALoad(contextLocal);
					AddScriptRuntimeInvoke("setDefaultNamespace", "(Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + ")Ljava/lang/Object;");
					break;
				}

				case Token.YIELD:
				{
					GenerateYieldPoint(node, true);
					break;
				}

				case Token.WITHEXPR:
				{
					Node enterWith = child;
					Node with = enterWith.GetNext();
					Node leaveWith = with.GetNext();
					GenerateStatement(enterWith);
					GenerateExpression(with.GetFirstChild(), with);
					GenerateStatement(leaveWith);
					break;
				}

				case Token.ARRAYCOMP:
				{
					Node initStmt = child;
					Node expr = child.GetNext();
					GenerateStatement(initStmt);
					GenerateExpression(expr, node);
					break;
				}

				default:
				{
					throw new Exception("Unexpected node type " + type);
				}
			}
		}
Esempio n. 3
0
		private void GenerateStatement(Node node)
		{
			UpdateLineNumber(node);
			int type = node.GetType();
			Node child = node.GetFirstChild();
			switch (type)
			{
				case Token.LOOP:
				case Token.LABEL:
				case Token.WITH:
				case Token.SCRIPT:
				case Token.BLOCK:
				case Token.EMPTY:
				{
					// no-ops.
					if (compilerEnv.IsGenerateObserverCount())
					{
						// Need to add instruction count even for no-ops to catch
						// cases like while (1) {}
						AddInstructionCount(1);
					}
					while (child != null)
					{
						GenerateStatement(child);
						child = child.GetNext();
					}
					break;
				}

				case Token.LOCAL_BLOCK:
				{
					bool prevLocal = inLocalBlock;
					inLocalBlock = true;
					int local = GetNewWordLocal();
					if (isGenerator)
					{
						cfw.Add(ByteCode.ACONST_NULL);
						cfw.AddAStore(local);
					}
					node.PutIntProp(Node.LOCAL_PROP, local);
					while (child != null)
					{
						GenerateStatement(child);
						child = child.GetNext();
					}
					ReleaseWordLocal((short)local);
					node.RemoveProp(Node.LOCAL_PROP);
					inLocalBlock = prevLocal;
					break;
				}

				case Token.FUNCTION:
				{
					int fnIndex = node.GetExistingIntProp(Node.FUNCTION_PROP);
					OptFunctionNode ofn = OptFunctionNode.Get(scriptOrFn, fnIndex);
					int t = ofn.fnode.GetFunctionType();
					if (t == FunctionNode.FUNCTION_EXPRESSION_STATEMENT)
					{
						VisitFunction(ofn, t);
					}
					else
					{
						if (t != FunctionNode.FUNCTION_STATEMENT)
						{
							throw Codegen.BadTree();
						}
					}
					break;
				}

				case Token.TRY:
				{
					VisitTryCatchFinally((Jump)node, child);
					break;
				}

				case Token.CATCH_SCOPE:
				{
					// nothing stays on the stack on entry into a catch scope
					cfw.SetStackTop((short)0);
					int local = GetLocalBlockRegister(node);
					int scopeIndex = node.GetExistingIntProp(Node.CATCH_SCOPE_PROP);
					string name = child.GetString();
					// name of exception
					child = child.GetNext();
					GenerateExpression(child, node);
					// load expression object
					if (scopeIndex == 0)
					{
						cfw.Add(ByteCode.ACONST_NULL);
					}
					else
					{
						// Load previous catch scope object
						cfw.AddALoad(local);
					}
					cfw.AddPush(name);
					cfw.AddALoad(contextLocal);
					cfw.AddALoad(variableObjectLocal);
					AddScriptRuntimeInvoke("newCatchScope", "(Ljava/lang/Throwable;" + "Lorg/mozilla/javascript/Scriptable;" + "Ljava/lang/String;" + "Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + ")Lorg/mozilla/javascript/Scriptable;");
					cfw.AddAStore(local);
					break;
				}

				case Token.THROW:
				{
					GenerateExpression(child, node);
					if (compilerEnv.IsGenerateObserverCount())
					{
						AddInstructionCount();
					}
					GenerateThrowJavaScriptException();
					break;
				}

				case Token.RETHROW:
				{
					if (compilerEnv.IsGenerateObserverCount())
					{
						AddInstructionCount();
					}
					cfw.AddALoad(GetLocalBlockRegister(node));
					cfw.Add(ByteCode.ATHROW);
					break;
				}

				case Token.RETURN_RESULT:
				case Token.RETURN:
				{
					if (!isGenerator)
					{
						if (child != null)
						{
							GenerateExpression(child, node);
						}
						else
						{
							if (type == Token.RETURN)
							{
								Codegen.PushUndefined(cfw);
							}
							else
							{
								if (popvLocal < 0)
								{
									throw Codegen.BadTree();
								}
								cfw.AddALoad(popvLocal);
							}
						}
					}
					if (compilerEnv.IsGenerateObserverCount())
					{
						AddInstructionCount();
					}
					if (epilogueLabel == -1)
					{
						if (!hasVarsInRegs)
						{
							throw Codegen.BadTree();
						}
						epilogueLabel = cfw.AcquireLabel();
					}
					cfw.Add(ByteCode.GOTO, epilogueLabel);
					break;
				}

				case Token.SWITCH:
				{
					if (compilerEnv.IsGenerateObserverCount())
					{
						AddInstructionCount();
					}
					VisitSwitch((Jump)node, child);
					break;
				}

				case Token.ENTERWITH:
				{
					GenerateExpression(child, node);
					cfw.AddALoad(contextLocal);
					cfw.AddALoad(variableObjectLocal);
					AddScriptRuntimeInvoke("enterWith", "(Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + "Lorg/mozilla/javascript/Scriptable;" + ")Lorg/mozilla/javascript/Scriptable;");
					cfw.AddAStore(variableObjectLocal);
					IncReferenceWordLocal(variableObjectLocal);
					break;
				}

				case Token.LEAVEWITH:
				{
					cfw.AddALoad(variableObjectLocal);
					AddScriptRuntimeInvoke("leaveWith", "(Lorg/mozilla/javascript/Scriptable;" + ")Lorg/mozilla/javascript/Scriptable;");
					cfw.AddAStore(variableObjectLocal);
					DecReferenceWordLocal(variableObjectLocal);
					break;
				}

				case Token.ENUM_INIT_KEYS:
				case Token.ENUM_INIT_VALUES:
				case Token.ENUM_INIT_ARRAY:
				{
					GenerateExpression(child, node);
					cfw.AddALoad(contextLocal);
					int enumType = type == Token.ENUM_INIT_KEYS ? ScriptRuntime.ENUMERATE_KEYS : type == Token.ENUM_INIT_VALUES ? ScriptRuntime.ENUMERATE_VALUES : ScriptRuntime.ENUMERATE_ARRAY;
					cfw.AddPush(enumType);
					AddScriptRuntimeInvoke("enumInit", "(Ljava/lang/Object;" + "Lorg/mozilla/javascript/Context;" + "I" + ")Ljava/lang/Object;");
					cfw.AddAStore(GetLocalBlockRegister(node));
					break;
				}

				case Token.EXPR_VOID:
				{
					if (child.GetType() == Token.SETVAR)
					{
						VisitSetVar(child, child.GetFirstChild(), false);
					}
					else
					{
						if (child.GetType() == Token.SETCONSTVAR)
						{
							VisitSetConstVar(child, child.GetFirstChild(), false);
						}
						else
						{
							if (child.GetType() == Token.YIELD)
							{
								GenerateYieldPoint(child, false);
							}
							else
							{
								GenerateExpression(child, node);
								if (node.GetIntProp(Node.ISNUMBER_PROP, -1) != -1)
								{
									cfw.Add(ByteCode.POP2);
								}
								else
								{
									cfw.Add(ByteCode.POP);
								}
							}
						}
					}
					break;
				}

				case Token.EXPR_RESULT:
				{
					GenerateExpression(child, node);
					if (popvLocal < 0)
					{
						popvLocal = GetNewWordLocal();
					}
					cfw.AddAStore(popvLocal);
					break;
				}

				case Token.TARGET:
				{
					if (compilerEnv.IsGenerateObserverCount())
					{
						AddInstructionCount();
					}
					int label = GetTargetLabel(node);
					cfw.MarkLabel(label);
					if (compilerEnv.IsGenerateObserverCount())
					{
						SaveCurrentCodeOffset();
					}
					break;
				}

				case Token.JSR:
				case Token.GOTO:
				case Token.IFEQ:
				case Token.IFNE:
				{
					if (compilerEnv.IsGenerateObserverCount())
					{
						AddInstructionCount();
					}
					VisitGoto((Jump)node, type, child);
					break;
				}

				case Token.FINALLY:
				{
					// This is the non-exception case for a finally block. In
					// other words, since we inline finally blocks wherever
					// jsr was previously used, and jsr is only used when the
					// function is not a generator, we don't need to generate
					// this case if the function isn't a generator.
					if (!isGenerator)
					{
						break;
					}
					if (compilerEnv.IsGenerateObserverCount())
					{
						SaveCurrentCodeOffset();
					}
					// there is exactly one value on the stack when enterring
					// finally blocks: the return address (or its int encoding)
					cfw.SetStackTop((short)1);
					// Save return address in a new local
					int finallyRegister = GetNewWordLocal();
					int finallyStart = cfw.AcquireLabel();
					int finallyEnd = cfw.AcquireLabel();
					cfw.MarkLabel(finallyStart);
					GenerateIntegerWrap();
					cfw.AddAStore(finallyRegister);
					while (child != null)
					{
						GenerateStatement(child);
						child = child.GetNext();
					}
					cfw.AddALoad(finallyRegister);
					cfw.Add(ByteCode.CHECKCAST, "java/lang/Integer");
					GenerateIntegerUnwrap();
					BodyCodegen.FinallyReturnPoint ret = finallys.Get(node);
					ret.tableLabel = cfw.AcquireLabel();
					cfw.Add(ByteCode.GOTO, ret.tableLabel);
					ReleaseWordLocal((short)finallyRegister);
					cfw.MarkLabel(finallyEnd);
					break;
				}

				case Token.DEBUGGER:
				{
					break;
				}

				default:
				{
					throw Codegen.BadTree();
				}
			}
		}
Esempio n. 4
0
		private void VisitExpression(Node node, int contextFlags)
		{
			int type = node.GetType();
			Node child = node.GetFirstChild();
			int savedStackDepth = stackDepth;
			switch (type)
			{
				case Token.FUNCTION:
				{
					int fnIndex = node.GetExistingIntProp(Node.FUNCTION_PROP);
					FunctionNode fn = scriptOrFn.GetFunctionNode(fnIndex);
					// See comments in visitStatement for Token.FUNCTION case
					if (fn.GetFunctionType() != FunctionNode.FUNCTION_EXPRESSION)
					{
						throw Kit.CodeBug();
					}
					AddIndexOp(Icode_CLOSURE_EXPR, fnIndex);
					StackChange(1);
					break;
				}

				case Token.LOCAL_LOAD:
				{
					int localIndex = GetLocalBlockRef(node);
					AddIndexOp(Token.LOCAL_LOAD, localIndex);
					StackChange(1);
					break;
				}

				case Token.COMMA:
				{
					Node lastChild = node.GetLastChild();
					while (child != lastChild)
					{
						VisitExpression(child, 0);
						AddIcode(Icode_POP);
						StackChange(-1);
						child = child.GetNext();
					}
					// Preserve tail context flag if any
					VisitExpression(child, contextFlags & ECF_TAIL);
					break;
				}

				case Token.USE_STACK:
				{
					// Indicates that stack was modified externally,
					// like placed catch object
					StackChange(1);
					break;
				}

				case Token.REF_CALL:
				case Token.CALL:
				case Token.NEW:
				{
					if (type == Token.NEW)
					{
						VisitExpression(child, 0);
					}
					else
					{
						GenerateCallFunAndThis(child);
					}
					int argCount = 0;
					while ((child = child.GetNext()) != null)
					{
						VisitExpression(child, 0);
						++argCount;
					}
					int callType = node.GetIntProp(Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL);
					if (type != Token.REF_CALL && callType != Node.NON_SPECIALCALL)
					{
						// embed line number and source filename
						AddIndexOp(Icode_CALLSPECIAL, argCount);
						AddUint8(callType);
						AddUint8(type == Token.NEW ? 1 : 0);
						AddUint16(lineNumber & unchecked((int)(0xFFFF)));
					}
					else
					{
						// Only use the tail call optimization if we're not in a try
						// or we're not generating debug info (since the
						// optimization will confuse the debugger)
						if (type == Token.CALL && (contextFlags & ECF_TAIL) != 0 && !compilerEnv.IsGenerateDebugInfo() && !itsInTryFlag)
						{
							type = Icode_TAIL_CALL;
						}
						AddIndexOp(type, argCount);
					}
					// adjust stack
					if (type == Token.NEW)
					{
						// new: f, args -> result
						StackChange(-argCount);
					}
					else
					{
						// call: f, thisObj, args -> result
						// ref_call: f, thisObj, args -> ref
						StackChange(-1 - argCount);
					}
					if (argCount > itsData.itsMaxCalleeArgs)
					{
						itsData.itsMaxCalleeArgs = argCount;
					}
					break;
				}

				case Token.AND:
				case Token.OR:
				{
					VisitExpression(child, 0);
					AddIcode(Icode_DUP);
					StackChange(1);
					int afterSecondJumpStart = iCodeTop;
					int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ;
					AddGotoOp(jump);
					StackChange(-1);
					AddIcode(Icode_POP);
					StackChange(-1);
					child = child.GetNext();
					// Preserve tail context flag if any
					VisitExpression(child, contextFlags & ECF_TAIL);
					ResolveForwardGoto(afterSecondJumpStart);
					break;
				}

				case Token.HOOK:
				{
					Node ifThen = child.GetNext();
					Node ifElse = ifThen.GetNext();
					VisitExpression(child, 0);
					int elseJumpStart = iCodeTop;
					AddGotoOp(Token.IFNE);
					StackChange(-1);
					// Preserve tail context flag if any
					VisitExpression(ifThen, contextFlags & ECF_TAIL);
					int afterElseJumpStart = iCodeTop;
					AddGotoOp(Token.GOTO);
					ResolveForwardGoto(elseJumpStart);
					stackDepth = savedStackDepth;
					// Preserve tail context flag if any
					VisitExpression(ifElse, contextFlags & ECF_TAIL);
					ResolveForwardGoto(afterElseJumpStart);
					break;
				}

				case Token.GETPROP:
				case Token.GETPROPNOWARN:
				{
					VisitExpression(child, 0);
					child = child.GetNext();
					AddStringOp(type, child.GetString());
					break;
				}

				case Token.DELPROP:
				{
					bool isName = child.GetType() == Token.BINDNAME;
					VisitExpression(child, 0);
					child = child.GetNext();
					VisitExpression(child, 0);
					if (isName)
					{
						// special handling for delete name
						AddIcode(Icode_DELNAME);
					}
					else
					{
						AddToken(Token.DELPROP);
					}
					StackChange(-1);
					break;
				}

				case Token.GETELEM:
				case Token.BITAND:
				case Token.BITOR:
				case Token.BITXOR:
				case Token.LSH:
				case Token.RSH:
				case Token.URSH:
				case Token.ADD:
				case Token.SUB:
				case Token.MOD:
				case Token.DIV:
				case Token.MUL:
				case Token.EQ:
				case Token.NE:
				case Token.SHEQ:
				case Token.SHNE:
				case Token.IN:
				case Token.INSTANCEOF:
				case Token.LE:
				case Token.LT:
				case Token.GE:
				case Token.GT:
				{
					VisitExpression(child, 0);
					child = child.GetNext();
					VisitExpression(child, 0);
					AddToken(type);
					StackChange(-1);
					break;
				}

				case Token.POS:
				case Token.NEG:
				case Token.NOT:
				case Token.BITNOT:
				case Token.TYPEOF:
				case Token.VOID:
				{
					VisitExpression(child, 0);
					if (type == Token.VOID)
					{
						AddIcode(Icode_POP);
						AddIcode(Icode_UNDEF);
					}
					else
					{
						AddToken(type);
					}
					break;
				}

				case Token.GET_REF:
				case Token.DEL_REF:
				{
					VisitExpression(child, 0);
					AddToken(type);
					break;
				}

				case Token.SETPROP:
				case Token.SETPROP_OP:
				{
					VisitExpression(child, 0);
					child = child.GetNext();
					string property = child.GetString();
					child = child.GetNext();
					if (type == Token.SETPROP_OP)
					{
						AddIcode(Icode_DUP);
						StackChange(1);
						AddStringOp(Token.GETPROP, property);
						// Compensate for the following USE_STACK
						StackChange(-1);
					}
					VisitExpression(child, 0);
					AddStringOp(Token.SETPROP, property);
					StackChange(-1);
					break;
				}

				case Token.SETELEM:
				case Token.SETELEM_OP:
				{
					VisitExpression(child, 0);
					child = child.GetNext();
					VisitExpression(child, 0);
					child = child.GetNext();
					if (type == Token.SETELEM_OP)
					{
						AddIcode(Icode_DUP2);
						StackChange(2);
						AddToken(Token.GETELEM);
						StackChange(-1);
						// Compensate for the following USE_STACK
						StackChange(-1);
					}
					VisitExpression(child, 0);
					AddToken(Token.SETELEM);
					StackChange(-2);
					break;
				}

				case Token.SET_REF:
				case Token.SET_REF_OP:
				{
					VisitExpression(child, 0);
					child = child.GetNext();
					if (type == Token.SET_REF_OP)
					{
						AddIcode(Icode_DUP);
						StackChange(1);
						AddToken(Token.GET_REF);
						// Compensate for the following USE_STACK
						StackChange(-1);
					}
					VisitExpression(child, 0);
					AddToken(Token.SET_REF);
					StackChange(-1);
					break;
				}

				case Token.STRICT_SETNAME:
				case Token.SETNAME:
				{
					string name = child.GetString();
					VisitExpression(child, 0);
					child = child.GetNext();
					VisitExpression(child, 0);
					AddStringOp(type, name);
					StackChange(-1);
					break;
				}

				case Token.SETCONST:
				{
					string name = child.GetString();
					VisitExpression(child, 0);
					child = child.GetNext();
					VisitExpression(child, 0);
					AddStringOp(Icode_SETCONST, name);
					StackChange(-1);
					break;
				}

				case Token.TYPEOFNAME:
				{
					int index = -1;
					// use typeofname if an activation frame exists
					// since the vars all exist there instead of in jregs
					if (itsInFunctionFlag && !itsData.itsNeedsActivation)
					{
						index = scriptOrFn.GetIndexForNameNode(node);
					}
					if (index == -1)
					{
						AddStringOp(Icode_TYPEOFNAME, node.GetString());
						StackChange(1);
					}
					else
					{
						AddVarOp(Token.GETVAR, index);
						StackChange(1);
						AddToken(Token.TYPEOF);
					}
					break;
				}

				case Token.BINDNAME:
				case Token.NAME:
				case Token.STRING:
				{
					AddStringOp(type, node.GetString());
					StackChange(1);
					break;
				}

				case Token.INC:
				case Token.DEC:
				{
					VisitIncDec(node, child);
					break;
				}

				case Token.NUMBER:
				{
					double num = node.GetDouble();
					int inum = (int)num;
					if (inum == num)
					{
						if (inum == 0)
						{
							AddIcode(Icode_ZERO);
							// Check for negative zero
							if (1.0 / num < 0.0)
							{
								AddToken(Token.NEG);
							}
						}
						else
						{
							if (inum == 1)
							{
								AddIcode(Icode_ONE);
							}
							else
							{
								if ((short)inum == inum)
								{
									AddIcode(Icode_SHORTNUMBER);
									// write short as uin16 bit pattern
									AddUint16(inum & unchecked((int)(0xFFFF)));
								}
								else
								{
									AddIcode(Icode_INTNUMBER);
									AddInt(inum);
								}
							}
						}
					}
					else
					{
						int index = GetDoubleIndex(num);
						AddIndexOp(Token.NUMBER, index);
					}
					StackChange(1);
					break;
				}

				case Token.GETVAR:
				{
					if (itsData.itsNeedsActivation)
					{
						Kit.CodeBug();
					}
					int index = scriptOrFn.GetIndexForNameNode(node);
					AddVarOp(Token.GETVAR, index);
					StackChange(1);
					break;
				}

				case Token.SETVAR:
				{
					if (itsData.itsNeedsActivation)
					{
						Kit.CodeBug();
					}
					int index = scriptOrFn.GetIndexForNameNode(child);
					child = child.GetNext();
					VisitExpression(child, 0);
					AddVarOp(Token.SETVAR, index);
					break;
				}

				case Token.SETCONSTVAR:
				{
					if (itsData.itsNeedsActivation)
					{
						Kit.CodeBug();
					}
					int index = scriptOrFn.GetIndexForNameNode(child);
					child = child.GetNext();
					VisitExpression(child, 0);
					AddVarOp(Token.SETCONSTVAR, index);
					break;
				}

				case Token.NULL:
				case Token.THIS:
				case Token.THISFN:
				case Token.FALSE:
				case Token.TRUE:
				{
					AddToken(type);
					StackChange(1);
					break;
				}

				case Token.ENUM_NEXT:
				case Token.ENUM_ID:
				{
					AddIndexOp(type, GetLocalBlockRef(node));
					StackChange(1);
					break;
				}

				case Token.REGEXP:
				{
					int index = node.GetExistingIntProp(Node.REGEXP_PROP);
					AddIndexOp(Token.REGEXP, index);
					StackChange(1);
					break;
				}

				case Token.ARRAYLIT:
				case Token.OBJECTLIT:
				{
					VisitLiteral(node, child);
					break;
				}

				case Token.ARRAYCOMP:
				{
					VisitArrayComprehension(node, child, child.GetNext());
					break;
				}

				case Token.REF_SPECIAL:
				{
					VisitExpression(child, 0);
					AddStringOp(type, (string)node.GetProp(Node.NAME_PROP));
					break;
				}

				case Token.REF_MEMBER:
				case Token.REF_NS_MEMBER:
				case Token.REF_NAME:
				case Token.REF_NS_NAME:
				{
					int memberTypeFlags = node.GetIntProp(Node.MEMBER_TYPE_PROP, 0);
					// generate possible target, possible namespace and member
					int childCount = 0;
					do
					{
						VisitExpression(child, 0);
						++childCount;
						child = child.GetNext();
					}
					while (child != null);
					AddIndexOp(type, memberTypeFlags);
					StackChange(1 - childCount);
					break;
				}

				case Token.DOTQUERY:
				{
					int queryPC;
					UpdateLineNumber(node);
					VisitExpression(child, 0);
					AddIcode(Icode_ENTERDQ);
					StackChange(-1);
					queryPC = iCodeTop;
					VisitExpression(child.GetNext(), 0);
					AddBackwardGoto(Icode_LEAVEDQ, queryPC);
					break;
				}

				case Token.DEFAULTNAMESPACE:
				case Token.ESCXMLATTR:
				case Token.ESCXMLTEXT:
				{
					VisitExpression(child, 0);
					AddToken(type);
					break;
				}

				case Token.YIELD:
				{
					if (child != null)
					{
						VisitExpression(child, 0);
					}
					else
					{
						AddIcode(Icode_UNDEF);
						StackChange(1);
					}
					AddToken(Token.YIELD);
					AddUint16(node.GetLineno() & unchecked((int)(0xFFFF)));
					break;
				}

				case Token.WITHEXPR:
				{
					Node enterWith = node.GetFirstChild();
					Node with = enterWith.GetNext();
					VisitExpression(enterWith.GetFirstChild(), 0);
					AddToken(Token.ENTERWITH);
					StackChange(-1);
					VisitExpression(with.GetFirstChild(), 0);
					AddToken(Token.LEAVEWITH);
					break;
				}

				default:
				{
					throw BadTree(node);
				}
			}
			if (savedStackDepth + 1 != stackDepth)
			{
				Kit.CodeBug();
			}
		}
Esempio n. 5
0
		private void VisitStatement(Node node, int initialStackDepth)
		{
			int type = node.GetType();
			Node child = node.GetFirstChild();
			switch (type)
			{
				case Token.FUNCTION:
				{
					int fnIndex = node.GetExistingIntProp(Node.FUNCTION_PROP);
					int fnType = scriptOrFn.GetFunctionNode(fnIndex).GetFunctionType();
					// Only function expressions or function expression
					// statements need closure code creating new function
					// object on stack as function statements are initialized
					// at script/function start.
					// In addition, function expressions can not be present here
					// at statement level, they must only be present as expressions.
					if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT)
					{
						AddIndexOp(Icode_CLOSURE_STMT, fnIndex);
					}
					else
					{
						if (fnType != FunctionNode.FUNCTION_STATEMENT)
						{
							throw Kit.CodeBug();
						}
					}
					// For function statements or function expression statements
					// in scripts, we need to ensure that the result of the script
					// is the function if it is the last statement in the script.
					// For example, eval("function () {}") should return a
					// function, not undefined.
					if (!itsInFunctionFlag)
					{
						AddIndexOp(Icode_CLOSURE_EXPR, fnIndex);
						StackChange(1);
						AddIcode(Icode_POP_RESULT);
						StackChange(-1);
					}
					break;
				}

				case Token.LABEL:
				case Token.LOOP:
				case Token.BLOCK:
				case Token.EMPTY:
				case Token.WITH:
				{
					UpdateLineNumber(node);
					goto case Token.SCRIPT;
				}

				case Token.SCRIPT:
				{
					// fall through
					while (child != null)
					{
						VisitStatement(child, initialStackDepth);
						child = child.GetNext();
					}
					break;
				}

				case Token.ENTERWITH:
				{
					VisitExpression(child, 0);
					AddToken(Token.ENTERWITH);
					StackChange(-1);
					break;
				}

				case Token.LEAVEWITH:
				{
					AddToken(Token.LEAVEWITH);
					break;
				}

				case Token.LOCAL_BLOCK:
				{
					int local = AllocLocal();
					node.PutIntProp(Node.LOCAL_PROP, local);
					UpdateLineNumber(node);
					while (child != null)
					{
						VisitStatement(child, initialStackDepth);
						child = child.GetNext();
					}
					AddIndexOp(Icode_LOCAL_CLEAR, local);
					ReleaseLocal(local);
					break;
				}

				case Token.DEBUGGER:
				{
					AddIcode(Icode_DEBUGGER);
					break;
				}

				case Token.SWITCH:
				{
					UpdateLineNumber(node);
					// See comments in IRFactory.createSwitch() for description
					// of SWITCH node
					VisitExpression(child, 0);
					for (Jump caseNode = (Jump)child.GetNext(); caseNode != null; caseNode = (Jump)caseNode.GetNext())
					{
						if (caseNode.GetType() != Token.CASE)
						{
							throw BadTree(caseNode);
						}
						Node test = caseNode.GetFirstChild();
						AddIcode(Icode_DUP);
						StackChange(1);
						VisitExpression(test, 0);
						AddToken(Token.SHEQ);
						StackChange(-1);
						// If true, Icode_IFEQ_POP will jump and remove case
						// value from stack
						AddGoto(caseNode.target, Icode_IFEQ_POP);
						StackChange(-1);
					}
					AddIcode(Icode_POP);
					StackChange(-1);
					break;
				}

				case Token.TARGET:
				{
					MarkTargetLabel(node);
					break;
				}

				case Token.IFEQ:
				case Token.IFNE:
				{
					Node target = ((Jump)node).target;
					VisitExpression(child, 0);
					AddGoto(target, type);
					StackChange(-1);
					break;
				}

				case Token.GOTO:
				{
					Node target = ((Jump)node).target;
					AddGoto(target, type);
					break;
				}

				case Token.JSR:
				{
					Node target = ((Jump)node).target;
					AddGoto(target, Icode_GOSUB);
					break;
				}

				case Token.FINALLY:
				{
					// Account for incomming GOTOSUB address
					StackChange(1);
					int finallyRegister = GetLocalBlockRef(node);
					AddIndexOp(Icode_STARTSUB, finallyRegister);
					StackChange(-1);
					while (child != null)
					{
						VisitStatement(child, initialStackDepth);
						child = child.GetNext();
					}
					AddIndexOp(Icode_RETSUB, finallyRegister);
					break;
				}

				case Token.EXPR_VOID:
				case Token.EXPR_RESULT:
				{
					UpdateLineNumber(node);
					VisitExpression(child, 0);
					AddIcode((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT);
					StackChange(-1);
					break;
				}

				case Token.TRY:
				{
					Jump tryNode = (Jump)node;
					int exceptionObjectLocal = GetLocalBlockRef(tryNode);
					int scopeLocal = AllocLocal();
					AddIndexOp(Icode_SCOPE_SAVE, scopeLocal);
					int tryStart = iCodeTop;
					bool savedFlag = itsInTryFlag;
					itsInTryFlag = true;
					while (child != null)
					{
						VisitStatement(child, initialStackDepth);
						child = child.GetNext();
					}
					itsInTryFlag = savedFlag;
					Node catchTarget = tryNode.target;
					if (catchTarget != null)
					{
						int catchStartPC = labelTable[GetTargetLabel(catchTarget)];
						AddExceptionHandler(tryStart, catchStartPC, catchStartPC, false, exceptionObjectLocal, scopeLocal);
					}
					Node finallyTarget = tryNode.GetFinally();
					if (finallyTarget != null)
					{
						int finallyStartPC = labelTable[GetTargetLabel(finallyTarget)];
						AddExceptionHandler(tryStart, finallyStartPC, finallyStartPC, true, exceptionObjectLocal, scopeLocal);
					}
					AddIndexOp(Icode_LOCAL_CLEAR, scopeLocal);
					ReleaseLocal(scopeLocal);
					break;
				}

				case Token.CATCH_SCOPE:
				{
					int localIndex = GetLocalBlockRef(node);
					int scopeIndex = node.GetExistingIntProp(Node.CATCH_SCOPE_PROP);
					string name = child.GetString();
					child = child.GetNext();
					VisitExpression(child, 0);
					// load expression object
					AddStringPrefix(name);
					AddIndexPrefix(localIndex);
					AddToken(Token.CATCH_SCOPE);
					AddUint8(scopeIndex != 0 ? 1 : 0);
					StackChange(-1);
					break;
				}

				case Token.THROW:
				{
					UpdateLineNumber(node);
					VisitExpression(child, 0);
					AddToken(Token.THROW);
					AddUint16(lineNumber & unchecked((int)(0xFFFF)));
					StackChange(-1);
					break;
				}

				case Token.RETHROW:
				{
					UpdateLineNumber(node);
					AddIndexOp(Token.RETHROW, GetLocalBlockRef(node));
					break;
				}

				case Token.RETURN:
				{
					UpdateLineNumber(node);
					if (node.GetIntProp(Node.GENERATOR_END_PROP, 0) != 0)
					{
						// We're in a generator, so change RETURN to GENERATOR_END
						AddIcode(Icode_GENERATOR_END);
						AddUint16(lineNumber & unchecked((int)(0xFFFF)));
					}
					else
					{
						if (child != null)
						{
							VisitExpression(child, ECF_TAIL);
							AddToken(Token.RETURN);
							StackChange(-1);
						}
						else
						{
							AddIcode(Icode_RETUNDEF);
						}
					}
					break;
				}

				case Token.RETURN_RESULT:
				{
					UpdateLineNumber(node);
					AddToken(Token.RETURN_RESULT);
					break;
				}

				case Token.ENUM_INIT_KEYS:
				case Token.ENUM_INIT_VALUES:
				case Token.ENUM_INIT_ARRAY:
				{
					VisitExpression(child, 0);
					AddIndexOp(type, GetLocalBlockRef(node));
					StackChange(-1);
					break;
				}

				case Icode_GENERATOR:
				{
					break;
				}

				default:
				{
					throw BadTree(node);
				}
			}
			if (stackDepth != initialStackDepth)
			{
				throw Kit.CodeBug();
			}
		}
Esempio n. 6
0
		private void VisitIncDec(Node node, Node child)
		{
			int incrDecrMask = node.GetExistingIntProp(Node.INCRDECR_PROP);
			int childType = child.GetType();
			switch (childType)
			{
				case Token.GETVAR:
				{
					if (itsData.itsNeedsActivation)
					{
						Kit.CodeBug();
					}
					int i = scriptOrFn.GetIndexForNameNode(child);
					AddVarOp(Icode_VAR_INC_DEC, i);
					AddUint8(incrDecrMask);
					StackChange(1);
					break;
				}

				case Token.NAME:
				{
					string name = child.GetString();
					AddStringOp(Icode_NAME_INC_DEC, name);
					AddUint8(incrDecrMask);
					StackChange(1);
					break;
				}

				case Token.GETPROP:
				{
					Node @object = child.GetFirstChild();
					VisitExpression(@object, 0);
					string property = @object.GetNext().GetString();
					AddStringOp(Icode_PROP_INC_DEC, property);
					AddUint8(incrDecrMask);
					break;
				}

				case Token.GETELEM:
				{
					Node @object = child.GetFirstChild();
					VisitExpression(@object, 0);
					Node index = @object.GetNext();
					VisitExpression(index, 0);
					AddIcode(Icode_ELEM_INC_DEC);
					AddUint8(incrDecrMask);
					StackChange(-1);
					break;
				}

				case Token.GET_REF:
				{
					Node @ref = child.GetFirstChild();
					VisitExpression(@ref, 0);
					AddIcode(Icode_REF_INC_DEC);
					AddUint8(incrDecrMask);
					break;
				}

				default:
				{
					throw BadTree(node);
				}
			}
		}