Esempio n. 1
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. 2
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. 3
0
		private Node CreateBinary(int nodeType, Node left, Node right)
		{
			switch (nodeType)
			{
				case Token.ADD:
				{
					// numerical addition and string concatenation
					if (left.type == Token.STRING)
					{
						string s2;
						if (right.type == Token.STRING)
						{
							s2 = right.GetString();
						}
						else
						{
							if (right.type == Token.NUMBER)
							{
								s2 = ScriptRuntime.NumberToString(right.GetDouble(), 10);
							}
							else
							{
								break;
							}
						}
						string s1 = left.GetString();
						left.SetString(System.String.Concat(s1, s2));
						return left;
					}
					else
					{
						if (left.type == Token.NUMBER)
						{
							if (right.type == Token.NUMBER)
							{
								left.SetDouble(left.GetDouble() + right.GetDouble());
								return left;
							}
							else
							{
								if (right.type == Token.STRING)
								{
									string s1;
									string s2;
									s1 = ScriptRuntime.NumberToString(left.GetDouble(), 10);
									s2 = right.GetString();
									right.SetString(System.String.Concat(s1, s2));
									return right;
								}
							}
						}
					}
					// can't do anything if we don't know  both types - since
					// 0 + object is supposed to call toString on the object and do
					// string concantenation rather than addition
					break;
				}

				case Token.SUB:
				{
					// numerical subtraction
					if (left.type == Token.NUMBER)
					{
						double ld = left.GetDouble();
						if (right.type == Token.NUMBER)
						{
							//both numbers
							left.SetDouble(ld - right.GetDouble());
							return left;
						}
						else
						{
							if (ld == 0.0)
							{
								// first 0: 0-x -> -x
								return new Node(Token.NEG, right);
							}
						}
					}
					else
					{
						if (right.type == Token.NUMBER)
						{
							if (right.GetDouble() == 0.0)
							{
								//second 0: x - 0 -> +x
								// can not make simply x because x - 0 must be number
								return new Node(Token.POS, left);
							}
						}
					}
					break;
				}

				case Token.MUL:
				{
					// numerical multiplication
					if (left.type == Token.NUMBER)
					{
						double ld = left.GetDouble();
						if (right.type == Token.NUMBER)
						{
							//both numbers
							left.SetDouble(ld * right.GetDouble());
							return left;
						}
						else
						{
							if (ld == 1.0)
							{
								// first 1: 1 *  x -> +x
								return new Node(Token.POS, right);
							}
						}
					}
					else
					{
						if (right.type == Token.NUMBER)
						{
							if (right.GetDouble() == 1.0)
							{
								//second 1: x * 1 -> +x
								// can not make simply x because x - 0 must be number
								return new Node(Token.POS, left);
							}
						}
					}
					// can't do x*0: Infinity * 0 gives NaN, not 0
					break;
				}

				case Token.DIV:
				{
					// number division
					if (right.type == Token.NUMBER)
					{
						double rd = right.GetDouble();
						if (left.type == Token.NUMBER)
						{
							// both constants -- just divide, trust Java to handle x/0
							left.SetDouble(left.GetDouble() / rd);
							return left;
						}
						else
						{
							if (rd == 1.0)
							{
								// second 1: x/1 -> +x
								// not simply x to force number convertion
								return new Node(Token.POS, left);
							}
						}
					}
					break;
				}

				case Token.AND:
				{
					// Since x && y gives x, not false, when Boolean(x) is false,
					// and y, not Boolean(y), when Boolean(x) is true, x && y
					// can only be simplified if x is defined. See bug 309957.
					int leftStatus = IsAlwaysDefinedBoolean(left);
					if (leftStatus == ALWAYS_FALSE_BOOLEAN)
					{
						// if the first one is false, just return it
						return left;
					}
					else
					{
						if (leftStatus == ALWAYS_TRUE_BOOLEAN)
						{
							// if first is true, set to second
							return right;
						}
					}
					break;
				}

				case Token.OR:
				{
					// Since x || y gives x, not true, when Boolean(x) is true,
					// and y, not Boolean(y), when Boolean(x) is false, x || y
					// can only be simplified if x is defined. See bug 309957.
					int leftStatus = IsAlwaysDefinedBoolean(left);
					if (leftStatus == ALWAYS_TRUE_BOOLEAN)
					{
						// if the first one is true, just return it
						return left;
					}
					else
					{
						if (leftStatus == ALWAYS_FALSE_BOOLEAN)
						{
							// if first is false, set to second
							return right;
						}
					}
					break;
				}
			}
			return new Node(nodeType, left, right);
		}
Esempio n. 4
0
		// Check if Node always mean true or false in boolean context
		private static int IsAlwaysDefinedBoolean(Node node)
		{
			switch (node.GetType())
			{
				case Token.FALSE:
				case Token.NULL:
				{
					return ALWAYS_FALSE_BOOLEAN;
				}

				case Token.TRUE:
				{
					return ALWAYS_TRUE_BOOLEAN;
				}

				case Token.NUMBER:
				{
					double num = node.GetDouble();
					if (num == num && num != 0.0)
					{
						return ALWAYS_TRUE_BOOLEAN;
					}
					else
					{
						return ALWAYS_FALSE_BOOLEAN;
					}
					break;
				}
			}
			return 0;
		}
Esempio n. 5
0
		private Node CreateUnary(int nodeType, Node child)
		{
			int childType = child.GetType();
			switch (nodeType)
			{
				case Token.DELPROP:
				{
					Node n;
					if (childType == Token.NAME)
					{
						// Transform Delete(Name "a")
						//  to Delete(Bind("a"), String("a"))
						child.SetType(Token.BINDNAME);
						Node left = child;
						Node right = Node.NewString(child.GetString());
						n = new Node(nodeType, left, right);
					}
					else
					{
						if (childType == Token.GETPROP || childType == Token.GETELEM)
						{
							Node left = child.GetFirstChild();
							Node right = child.GetLastChild();
							child.RemoveChild(left);
							child.RemoveChild(right);
							n = new Node(nodeType, left, right);
						}
						else
						{
							if (childType == Token.GET_REF)
							{
								Node @ref = child.GetFirstChild();
								child.RemoveChild(@ref);
								n = new Node(Token.DEL_REF, @ref);
							}
							else
							{
								// Always evaluate delete operand, see ES5 11.4.1 & bug #726121
								n = new Node(nodeType, new Node(Token.TRUE), child);
							}
						}
					}
					return n;
				}

				case Token.TYPEOF:
				{
					if (childType == Token.NAME)
					{
						child.SetType(Token.TYPEOFNAME);
						return child;
					}
					break;
				}

				case Token.BITNOT:
				{
					if (childType == Token.NUMBER)
					{
						int value = ScriptRuntime.ToInt32(child.GetDouble());
						child.SetDouble(~value);
						return child;
					}
					break;
				}

				case Token.NEG:
				{
					if (childType == Token.NUMBER)
					{
						child.SetDouble(-child.GetDouble());
						return child;
					}
					break;
				}

				case Token.NOT:
				{
					int status = IsAlwaysDefinedBoolean(child);
					if (status != 0)
					{
						int type;
						if (status == ALWAYS_TRUE_BOOLEAN)
						{
							type = Token.FALSE;
						}
						else
						{
							type = Token.TRUE;
						}
						if (childType == Token.TRUE || childType == Token.FALSE)
						{
							child.SetType(type);
							return child;
						}
						return new Node(type);
					}
					break;
				}
			}
			return new Node(nodeType, child);
		}