/// <summary> /// Deletes the reference and pushes <c>true</c> if the delete succeeded, or <c>false</c> /// if the delete failed. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public void GenerateDelete(ILGenerator generator, OptimizationInfo optimizationInfo) { // Load the left-hand side and convert to an object instance. var lhs = this.GetOperand(0); lhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo); // Load the property name and convert to a string. var rhs = this.GetOperand(1); if (this.OperatorType == OperatorType.MemberAccess && rhs is NameExpression) { generator.LoadString((rhs as NameExpression).Name); } else { rhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToString(generator, rhs.ResultType); } // Call Delete() generator.LoadBoolean(optimizationInfo.StrictMode); generator.Call(ReflectionHelpers.ObjectInstance_Delete.Value); // If the return value is not wanted then pop it from the stack. //if (optimizationInfo.SuppressReturnValue == true) // generator.Pop(); }
public ConversationDataExtractor Create(bool isIrmEnabled, HashSet <PropertyDefinition> propertiesLoadedForExtractedItems, ConversationId conversationId, IConversationTree tree, bool isSmimeSupported, string domainName) { PropertyDefinition[] queriedPropertyDefinitions = (propertiesLoadedForExtractedItems != null) ? propertiesLoadedForExtractedItems.ToArray <PropertyDefinition>() : Array <PropertyDefinition> .Empty; int totalNodeCount = (tree == null) ? 0 : tree.Count; ItemPartLoader itemPartLoader = new ItemPartLoader(this.xsoFactory, this.session, isIrmEnabled, queriedPropertyDefinitions); OptimizationInfo optimizationInfo = new OptimizationInfo(conversationId, totalNodeCount); return(new ConversationDataExtractor(itemPartLoader, isIrmEnabled, optimizationInfo, isSmimeSupported, domainName)); }
/// <summary> /// Generates CIL for an increment or decrement expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> /// <param name="target"> The target to modify. </param> /// <param name="postfix"> <c>true</c> if this is the postfix version of the operator; /// <c>false</c> otherwise. </param> /// <param name="increment"> <c>true</c> if this is the increment operator; <c>false</c> if /// this is the decrement operator. </param> private void GenerateIncrementOrDecrement(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target, bool postfix, bool increment) { // Note: increment and decrement can produce a number that is out of range if the // target is of type Int32. The only time this should happen is for a loop variable // where the range has been carefully checked to make sure an out of range condition // cannot happen. // Get the target value. target.GenerateGet(generator, optimizationInfo, true); // Convert it to a number. if (target.Type != PrimitiveType.Int32) { EmitConversion.ToNumber(generator, target.Type); } // If this is PostIncrement or PostDecrement, duplicate the value so it can be produced as the return value. if (postfix) { generator.Duplicate(); } // Load the increment constant. if (target.Type == PrimitiveType.Int32) { generator.LoadInt32(1); } else { generator.LoadDouble(1.0); } // Add or subtract the constant to the target value. if (increment) { generator.Add(); } else { generator.Subtract(); } // If this is PreIncrement or PreDecrement, duplicate the value so it can be produced as the return value. if (postfix == false) { generator.Duplicate(); } // Store the value. target.GenerateSet(generator, optimizationInfo, target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number, optimizationInfo.StrictMode); }
/// <summary> /// Generates CIL for a compound assignment expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> /// <param name="target"> The target to modify. </param> private void GenerateCompoundAssignment(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target) { // Load the value to assign. var compoundOperator = new BinaryExpression(GetCompoundBaseOperator(this.OperatorType), this.GetOperand(0), this.GetOperand(1)); compoundOperator.GenerateCode(generator, optimizationInfo); // Duplicate the value so it remains on the stack afterwards. //if (optimizationInfo.SuppressReturnValue == false) generator.Duplicate(); // Store the value. target.GenerateSet(generator, optimizationInfo, compoundOperator.ResultType, optimizationInfo.StrictMode); }
/// <summary> /// Generates CIL for the expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // If a return value is not expected, generate only the side-effects. /*if (optimizationInfo.SuppressReturnValue == true) * { * this.GenerateSideEffects(generator, optimizationInfo); * return; * }*/ // Emit the condition. var condition = this.GetOperand(0); condition.GenerateCode(generator, optimizationInfo); // Convert the condition to a boolean. EmitConversion.ToBool(generator, condition.ResultType); // Branch if the condition is false. var startOfElse = generator.CreateLabel(); generator.BranchIfFalse(startOfElse); // Calculate the result type. var outputType = this.ResultType; // Emit the second operand and convert it to the result type. var operand2 = this.GetOperand(1); operand2.GenerateCode(generator, optimizationInfo); EmitConversion.Convert(generator, operand2.ResultType, outputType, optimizationInfo); // Branch to the end. var end = generator.CreateLabel(); generator.Branch(end); generator.DefineLabelPosition(startOfElse); // Emit the third operand and convert it to the result type. var operand3 = this.GetOperand(2); operand3.GenerateCode(generator, optimizationInfo); EmitConversion.Convert(generator, operand3.ResultType, outputType, optimizationInfo); // Define the end label. generator.DefineLabelPosition(end); }
/// <summary> /// Generates CIL for an assignment expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> /// <param name="target"> The target to modify. </param> private void GenerateAssignment(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target) { // Load the value to assign. var rhs = this.GetOperand(1); rhs.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. var expression = rhs as FunctionExpression; if (expression != null) { expression.GenerateDisplayName(generator, optimizationInfo, target.ToString(), false); } // Duplicate the value so it remains on the stack afterwards. //if (optimizationInfo.SuppressReturnValue == false) generator.Duplicate(); // Store the value. target.GenerateSet(generator, optimizationInfo, rhs.ResultType, optimizationInfo.StrictMode); }
/// <summary> /// Generates CIL for a compound assignment expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> /// <param name="target"> The target to modify. </param> private void GenerateCompoundAddAssignment(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target) { //var rhs = this.GetOperand(1); //if (PrimitiveTypeUtilities.IsString(rhs.ResultType) == true) //{ // // Load the value of the left-hand side and convert it to a concantenated string. // target.GenerateGet(generator, optimizationInfo, true); // EmitConversion.ToConcatenatedString(generator, target.Type); // // Transform expressions of the form "a += b + c;" into "a += b; a += c;". // List<Expression> nonAddExpressions = new List<Expression>(); // Stack<Expression> expressionStack = new Stack<Expression>(1); // expressionStack.Push(rhs); // do // { // var expression = expressionStack.Pop(); // if (expression is BinaryExpression && ((BinaryExpression)expression).OperatorType == OperatorType.Add) // { // expressionStack.Push(((BinaryExpression)expression).Right); // expressionStack.Push(((BinaryExpression)expression).Left); // } // else // nonAddExpressions.Add(expression); // } while (expressionStack.Count > 0); // foreach (var nonAddExpression in nonAddExpressions) // { // // Duplicate the ConcatenatedString instance. // generator.Duplicate(); // nonAddExpression.GenerateCode(generator, optimizationInfo); // var rhsType = nonAddExpression.ResultType; // if (rhsType == PrimitiveType.String) // { // // Concatenate. // generator.Call(ReflectionHelpers.ConcatenatedString_Append_String); // } // else if (rhsType == PrimitiveType.ConcatenatedString) // { // // Concatenate. // generator.Call(ReflectionHelpers.ConcatenatedString_Append_ConcatenatedString); // } // else // { // // Convert the operand to an object. // EmitConversion.ToAny(generator, rhsType); // // Concatenate. // generator.Call(ReflectionHelpers.ConcatenatedString_Append_Object); // } // } // if (target.Type != PrimitiveType.ConcatenatedString) // { // // Set the original variable. // generator.Duplicate(); // target.GenerateSet(generator, optimizationInfo, PrimitiveType.ConcatenatedString, optimizationInfo.StrictMode); // } //} //else //{ // Do the standard compound add. GenerateCompoundAssignment(generator, optimizationInfo, target); //} }
/// <summary> /// Generates CIL for the expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // The left hand side needs to be a variable reference or member access. var target = this.GetOperand(0) as IReferenceExpression; if (target == null) { // Emit an error message. switch (this.OperatorType) { case OperatorType.PostIncrement: case OperatorType.PostDecrement: EmitHelpers.EmitThrow(generator, "ReferenceError", "Invalid left-hand side in postfix operation", optimizationInfo); break; case OperatorType.PreIncrement: case OperatorType.PreDecrement: EmitHelpers.EmitThrow(generator, "ReferenceError", "Invalid left-hand side in prefix operation", optimizationInfo); break; default: EmitHelpers.EmitThrow(generator, "ReferenceError", "Invalid left-hand side in assignment", optimizationInfo); break; } //if (optimizationInfo.SuppressReturnValue == false) EmitHelpers.EmitDefaultValue(generator, this.ResultType); return; } // The left hand side cannot be "arguments" or "eval" in strict mode. if (optimizationInfo.StrictMode && target is NameExpression) { if (((NameExpression)target).Name == "eval") { throw new JavaScriptException(optimizationInfo.Engine, "SyntaxError", "The variable 'eval' cannot be modified in strict mode.", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName); } if (((NameExpression)target).Name == "arguments") { throw new JavaScriptException(optimizationInfo.Engine, "SyntaxError", "The variable 'arguments' cannot be modified in strict mode.", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName); } } switch (this.OperatorType) { case OperatorType.Assignment: // Standard assignment operator. GenerateAssignment(generator, optimizationInfo, target); break; case OperatorType.PostIncrement: GenerateIncrementOrDecrement(generator, optimizationInfo, target, true, true); break; case OperatorType.PostDecrement: GenerateIncrementOrDecrement(generator, optimizationInfo, target, true, false); break; case OperatorType.PreIncrement: GenerateIncrementOrDecrement(generator, optimizationInfo, target, false, true); break; case OperatorType.PreDecrement: GenerateIncrementOrDecrement(generator, optimizationInfo, target, false, false); break; case OperatorType.CompoundAdd: // Special case += GenerateCompoundAddAssignment(generator, optimizationInfo, target); break; default: // All other compound operators. GenerateCompoundAssignment(generator, optimizationInfo, target); break; } }
internal override void Set(ILGenerator generator, OptimizationInfo optimizationInfo, bool rIU, Type valueType, SetValueMethod value) { // Resolve if needed: if (Field == null && Property == null) { Resolve(valueType); } else { // Update type, potentially forcing the variable to change type // (unless it's a fixed property, in which case the value being set changes type instead): if (Property == null) { // Fixed property - var changes type: Type = valueType; } } ILLocalVariable localVar = null; // Is the return value of this set in use? // E.g. var x=obj.x=14; if (rIU) { // It's in use and 'obj.x' is not static. // Output the value twice: value(true); // If it's not static then we now have [obj][value][value] on the stack. // Calling the set method would fail (as it'll operate on the duplicated value). // So, we have to pop one off and re-add it after. if (!IsStatic) { // Note that if it's static, no 'obj' reference goes onto the stack anyway. // At this point, we have our target object followed by two copies of the value. // For the following Call/StoreField to work correctly, we must store the 2nd copy into a local. localVar = generator.DeclareVariable(valueType); // Store into the local: generator.StoreVariable(localVar); } } else { // Output the value just once: value(false); } if (_Type != valueType) { // Convert if needed: EmitConversion.Convert(generator, valueType, _Type, optimizationInfo); } if (Property != null) { // Call the set method: generator.Call(Property.SetMethod); } else { // Load the field: generator.StoreField(Field); } if (localVar != null) { // Reload the 2nd copy of the value: generator.LoadVariable(localVar); } }
/// <summary> /// Generates CIL for the expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // NOTE: this is a get reference because assignment expressions do not call this method. GenerateGet(generator, optimizationInfo, false); }
/// <summary> /// Generates CIL for the expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { this.Operand.GenerateCode(generator, optimizationInfo); }
private static bool UseOptimizeNormal(OptimizationInfo Info) { return(Info.OptimizeNormal); }
private static bool UseAlways(OptimizationInfo Info) { return(true); }
/// <summary> /// Generates CIL for the expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { EmitHelpers.LoadNewTarget(generator); }
/// <summary> /// Generates CIL for the expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // Note: we use GetRawOperand() so that grouping operators are not ignored. var operand = this.GetRawOperand(0); var functionCallExpressionOperand = operand as FunctionCallExpression; // There is only one operand, and it can be either a reference or a function call. // We need to split the operand into a function and some arguments. // If the operand is a reference, it is equivalent to a function call with no arguments. if (functionCallExpressionOperand != null) { // Emit the function instance first. var function = functionCallExpressionOperand.Target; function.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, function.ResultType); } else { // Emit the function instance first. operand.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, operand.ResultType); } // Check the object really is a function - if not, throw an exception. generator.IsInstance(typeof(Library.FunctionInstance)); generator.Duplicate(); var endOfTypeCheck = generator.CreateLabel(); generator.BranchIfNotNull(endOfTypeCheck); // Throw an nicely formatted exception. var targetValue = generator.CreateTemporaryVariable(typeof(object)); generator.StoreVariable(targetValue); EmitHelpers.LoadScriptEngine(generator); generator.LoadString("TypeError"); generator.LoadString("The new operator requires a function, found a '{0}' instead"); generator.LoadInt32(1); generator.NewArray(typeof(object)); generator.Duplicate(); generator.LoadInt32(0); generator.LoadVariable(targetValue); generator.Call(ReflectionHelpers.TypeUtilities_TypeOf.Value); generator.StoreArrayElement(typeof(object)); generator.Call(ReflectionHelpers.String_Format.Value); generator.LoadInt32(optimizationInfo.SourceSpan.StartLine); generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.LoadStringOrNull(optimizationInfo.FunctionName); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error.Value); generator.Throw(); generator.DefineLabelPosition(endOfTypeCheck); generator.ReleaseTemporaryVariable(targetValue); if (functionCallExpressionOperand != null) { // Emit an array containing the function arguments. ((FunctionCallExpression)operand).GenerateArgumentsArray(generator, optimizationInfo); } else { // Emit an empty array. generator.LoadInt32(0); generator.NewArray(typeof(object)); } // Call FunctionInstance.ConstructLateBound(argumentValues) generator.Call(ReflectionHelpers.FunctionInstance_ConstructLateBound.Value); }
/// <summary> /// Pushes the value of the reference onto the stack. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> /// <param name="throwIfUnresolvable"> <c>true</c> to throw a ReferenceError exception if /// the name is unresolvable; <c>false</c> to output <c>null</c> instead. </param> public void GenerateGet(ILGenerator generator, OptimizationInfo optimizationInfo, bool throwIfUnresolvable) { string propertyName = null; bool isArrayIndex = false; // Right-hand-side can be a property name (a.b) if (this.OperatorType == OperatorType.MemberAccess) { var rhs = this.GetOperand(1) as NameExpression; if (rhs == null) { throw new JavaScriptException(optimizationInfo.Engine, "SyntaxError", "Invalid member access", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName); } propertyName = rhs.Name; } // Or a constant indexer (a['b']) if (this.OperatorType == OperatorType.Index) { var rhs = this.GetOperand(1) as LiteralExpression; if (rhs != null && (PrimitiveTypeUtilities.IsNumeric(rhs.ResultType) || rhs.ResultType == PrimitiveType.String)) { propertyName = TypeConverter.ToString(rhs.Value); // Or a array index (a[0]) if (rhs.ResultType == PrimitiveType.Int32 || (propertyName != null && Library.ArrayInstance.ParseArrayIndex(propertyName) != uint.MaxValue)) { isArrayIndex = true; } } } if (isArrayIndex) { // Array indexer // ------------- // xxx = object[index] // Load the left-hand side and convert to an object instance. var lhs = this.GetOperand(0); lhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo); // Load the right-hand side and convert to a uint32. var rhs = this.GetOperand(1); rhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToUInt32(generator, rhs.ResultType); // Call the indexer. generator.Call(ReflectionHelpers.ObjectInstance_GetPropertyValue_Int.Value); } else if (propertyName != null) { //// Load the left-hand side and convert to an object instance. //var lhs = this.GetOperand(0); //lhs.GenerateCode(generator, optimizationInfo); //EmitConversion.ToObject(generator, lhs.ResultType); //// Call Get(string) //generator.LoadString(propertyName); //generator.Call(ReflectionHelpers.ObjectInstance_GetPropertyValue_String); // Named property access (e.g. x = y.property) // ------------------------------------------- // __object_cacheKey = null; // __object_property_cachedIndex = 0; // ... // if (__object_cacheKey != object.InlineCacheKey) // xxx = object.InlineGetPropertyValue("property", out __object_property_cachedIndex, out __object_cacheKey) // else // xxx = object.InlinePropertyValues[__object_property_cachedIndex]; // Load the left-hand side and convert to an object instance. var lhs = this.GetOperand(0); lhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo); // TODO: share these variables somehow. var cacheKey = generator.DeclareVariable(typeof(object), null); var cachedIndex = generator.DeclareVariable(typeof(int), null); // Store the object into a temp variable. var objectInstance = generator.DeclareVariable(PrimitiveType.Object, null); generator.StoreVariable(objectInstance); // if (__object_cacheKey != object.InlineCacheKey) generator.LoadVariable(cacheKey); generator.LoadVariable(objectInstance); generator.Call(ReflectionHelpers.ObjectInstance_InlineCacheKey.Value); var elseClause = generator.CreateLabel(); generator.BranchIfEqual(elseClause); // value = object.InlineGetProperty("property", out __object_property_cachedIndex, out __object_cacheKey) generator.LoadVariable(objectInstance); generator.LoadString(propertyName); generator.LoadAddressOfVariable(cachedIndex); generator.LoadAddressOfVariable(cacheKey); generator.Call(ReflectionHelpers.ObjectInstance_InlineGetPropertyValue.Value); var endOfIf = generator.CreateLabel(); generator.Branch(endOfIf); // else generator.DefineLabelPosition(elseClause); // value = object.InlinePropertyValues[__object_property_cachedIndex]; generator.LoadVariable(objectInstance); generator.Call(ReflectionHelpers.ObjectInstance_InlinePropertyValues.Value); generator.LoadVariable(cachedIndex); generator.LoadArrayElement(typeof(object)); // End of the if statement generator.DefineLabelPosition(endOfIf); } else { // Dynamic property access // ----------------------- // xxx = object.Get(x) // Load the left-hand side and convert to an object instance. var lhs = this.GetOperand(0); lhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo); // Load the property name and convert to a string. var rhs = this.GetOperand(1); rhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToString(generator, rhs.ResultType); // Call Get(string) generator.Call(ReflectionHelpers.ObjectInstance_GetPropertyValue_String.Value); } }
/// <summary> /// Generates CIL for the expression. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { //if (optimizationInfo.SuppressReturnValue == true) // return; EmitHelpers.LoadThis(generator); }
public ConversationDataExtractor(ItemPartLoader itemPartLoader, bool isIrmEnabled, OptimizationInfo optimizationInfo, bool isSmimeSupported = false, string domainName = null) { this.isIrmEnabled = isIrmEnabled; this.itemPartLoader = itemPartLoader; this.optimizationInfo = optimizationInfo; this.isSmimeSupported = isSmimeSupported; this.domainName = domainName; this.treeNodeBodyFragment = new Dictionary <StoreObjectId, KeyValuePair <BodyFragmentInfo, bool> >(); this.bodySummaryLoadedNodes = new HashSet <StoreObjectId>(); this.loadStatus = new Dictionary <KeyValuePair <ConversationBodyScanner, StoreObjectId>, ExtractionData>(); this.loadedItemParts = new Dictionary <StoreObjectId, LoadedItemPart>(); this.itemParts = new Dictionary <StoreObjectId, ItemPart>(); this.displayNameToParticipant = new Dictionary <string, Participant>(); }