Exemplo n.º 1
0
        private static void DifferenceCasesProcess <TString>(
            ILGenerator iLGen,
            Action <ILGenerator> emitLoadValue,
            Action <ILGenerator, TString> emitLoadItem,
            IDifferenceComparer <TString> comparer,
            Label defaultLabel,
            CaseInfo <int>[] differenceCases)
        {
            foreach (var item in differenceCases)
            {
                iLGen.MarkLabel(item.Label);

                if (item.Tag is SingleGroup <TString> singleGroup)
                {
                    if (SwitchDoNotVerify)
                    {
                        iLGen.Branch(singleGroup.Value.Label);
                    }
                    else
                    {
                        emitLoadValue(iLGen);
                        emitLoadItem(iLGen, singleGroup.Value.Value);
                        comparer.EmitEquals(iLGen);
                        iLGen.BranchTrue(singleGroup.Value.Label);

                        iLGen.Branch(defaultLabel);
                    }
                }
                else if (item.Tag is DifferenceGroup <TString> differenceGroup)
                {
                    var charCases = new CaseInfo <int> [differenceGroup.Groups.Count];

                    for (int i = 0; i < charCases.Length; i++)
                    {
                        charCases[i] = new CaseInfo <int>(differenceGroup.Groups[i].chr, iLGen.DefineLabel())
                        {
                            Tag = differenceGroup.Groups[i].group
                        };
                    }

                    Switch(iLGen, (ilGen2) =>
                    {
                        emitLoadValue(ilGen2);
                        ilGen2.LoadConstant(differenceGroup.Index);
                        comparer.EmitElementAt(iLGen);
                    }, charCases, defaultLabel);

                    DifferenceCasesProcess(iLGen, emitLoadValue, emitLoadItem, comparer, defaultLabel, charCases);
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
        }
Exemplo n.º 2
0
        private static void SwitchNumber <T>(this ILGenerator ilGen,
                                             Action <ILGenerator> emitLoadValue,
                                             Action <ILGenerator, T> emitLoadItem,
                                             CaseInfo <T>[] cases,
                                             Label defaultLabel,
                                             int begin,
                                             int index,
                                             int end)
        {
            if (begin > end)
            {
                ilGen.Branch(defaultLabel);

                return;
            }

            if (begin + 1 == end)
            {
                emitLoadValue(ilGen);
                emitLoadItem(ilGen, cases[begin].Value);
                ilGen.BranchIfEqual(cases[begin].Label);

                emitLoadValue(ilGen);
                emitLoadItem(ilGen, cases[end].Value);
                ilGen.BranchIfEqual(cases[end].Label);

                ilGen.Branch(defaultLabel);

                return;
            }

            if (begin == end)
            {
                emitLoadValue(ilGen);
                emitLoadItem(ilGen, cases[begin].Value);
                ilGen.BranchIfEqual(cases[begin].Label);

                ilGen.Branch(defaultLabel);

                return;
            }

            var greaterLabel = ilGen.DefineLabel();

            emitLoadValue(ilGen);
            emitLoadItem(ilGen, cases[index].Value);
            ilGen.BranchIfGreater(greaterLabel);

            SwitchNumber(ilGen, emitLoadValue, emitLoadItem, cases, defaultLabel, begin, (begin + index) / 2, index);

            ilGen.MarkLabel(greaterLabel);

            SwitchNumber(ilGen, emitLoadValue, emitLoadItem, cases, defaultLabel, index + 1, (index + 1 + end) / 2, end);
        }
Exemplo n.º 3
0
        private static void SwitchSequence <T>(this ILGenerator ilGen,
                                               Action <ILGenerator> emitLoadValue,
                                               CaseInfo <T>[] cases,
                                               Label defaultLabel,
                                               T offset = default)
        {
            emitLoadValue(ilGen);

            if (!TypeHelper.IsEmptyValue(offset))
            {
                if (Underlying.SizeOf <T>() <= sizeof(int))
                {
                    ilGen.LoadConstant(XConvert <int> .Convert(offset));
                }
                else
                {
                    ilGen.LoadConstant(XConvert <long> .Convert(offset));
                }

                ilGen.Subtract();
            }

            ilGen.Switch(cases.Map(item => item.Label));

            ilGen.Branch(defaultLabel);
        }
Exemplo n.º 4
0
        /// <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);
        }
Exemplo n.º 5
0
        /// <summary>
        /// 当指定的本地变量值为该类型的默认值时跳到指定块。
        /// </summary>
        /// <param name="ilGen">ilGen</param>
        /// <param name="local">本地变量</param>
        /// <param name="label">代码块</param>
        public static void BranchDefaultValue(this ILGenerator ilGen, LocalBuilder local, Label label)
        {
            var type = local.LocalType;

            if (type.IsClass ||
                type.IsInterface ||
                type.IsPointer ||
                type.IsByRef ||
                type == typeof(IntPtr) ||
                type == typeof(UIntPtr))
            {
                ilGen.LoadLocal(local);
                ilGen.BranchFalse(label);

                return;
            }

            switch (Type.GetTypeCode(type))
            {
            case TypeCode.Boolean:
            case TypeCode.Char:
            case TypeCode.SByte:
            case TypeCode.Byte:
            case TypeCode.Int16:
            case TypeCode.UInt16:
            case TypeCode.Int32:
            case TypeCode.UInt32:
            case TypeCode.Single:
            case TypeCode.Int64:
            case TypeCode.UInt64:
            case TypeCode.Double:
                ilGen.LoadLocal(local);
                ilGen.BranchFalse(label);
                return;
            }

            var size = TypeHelper.SizeOf(type);

            var labNotEmpty = ilGen.DefineLabel();

            while (size >= 4)
            {
                size -= 4;
                ilGen.LoadLocalAddress(local);

                if (size != 0)
                {
                    ilGen.LoadConstant(size);
                    ilGen.Emit(OpCodes.Add);
                }

                ilGen.Emit(OpCodes.Ldind_I4);
                ilGen.BranchTrue(labNotEmpty);
            }

            if (size >= 2)
            {
                size -= 2;
                ilGen.LoadLocalAddress(local);

                if (size != 0)
                {
                    ilGen.LoadConstant(size);
                    ilGen.Emit(OpCodes.Add);
                }

                ilGen.Emit(OpCodes.Ldind_I2);
                ilGen.BranchTrue(labNotEmpty);
            }

            if (size >= 1)
            {
                ilGen.LoadLocalAddress(local);
                ilGen.Emit(OpCodes.Ldind_I1);
                ilGen.BranchTrue(labNotEmpty);
            }

            ilGen.Branch(label);

            ilGen.MarkLabel(labNotEmpty);
        }
Exemplo n.º 6
0
        private static void SwitchObject <T>(this ILGenerator ilGen,
                                             Action <ILGenerator> emitLoadValue,
                                             Action <ILGenerator> emitLoadHashCode,
                                             Action <ILGenerator, T> emitLoadItem,
                                             IHashComparer <T> comparer,
                                             List <KeyValuePair <int, List <CaseInfo <T> > > > cases,
                                             Label defaultLabel,
                                             int begin,
                                             int index,
                                             int end)
        {
            if (begin > end)
            {
                return;
            }

            if (begin == end)
            {
                emitLoadHashCode(ilGen);
                ilGen.LoadConstant(cases[begin].Key);
                ilGen.BranchIfNotEqualUnsigned(defaultLabel);

                if (SwitchDoNotVerify && cases[begin].Value.Count == 1)
                {
                    ilGen.Branch(cases[begin].Value[0].Label);
                }
                else
                {
                    foreach (var item in cases[begin].Value)
                    {
                        emitLoadValue(ilGen);
                        emitLoadItem(ilGen, item.Value);
                        comparer.EmitEquals(ilGen);
                        ilGen.BranchTrue(item.Label);
                    }
                }

                ilGen.Branch(defaultLabel);

                return;
            }

            if (begin + 1 == end)
            {
                var endLabel = ilGen.DefineLabel();

                emitLoadHashCode(ilGen);
                ilGen.LoadConstant(cases[begin].Key);
                ilGen.BranchIfNotEqualUnsigned(endLabel);

                if (SwitchDoNotVerify && cases[begin].Value.Count == 1)
                {
                    ilGen.Branch(cases[begin].Value[0].Label);
                }
                else
                {
                    foreach (var item in cases[begin].Value)
                    {
                        emitLoadValue(ilGen);
                        emitLoadItem(ilGen, item.Value);
                        comparer.EmitEquals(ilGen);
                        ilGen.BranchTrue(item.Label);
                    }
                }

                ilGen.MarkLabel(endLabel);

                emitLoadHashCode(ilGen);
                ilGen.LoadConstant(cases[end].Key);
                ilGen.BranchIfNotEqualUnsigned(defaultLabel);

                if (SwitchDoNotVerify && cases[end].Value.Count == 1)
                {
                    ilGen.Branch(cases[end].Value[0].Label);
                }
                else
                {
                    foreach (var item in cases[end].Value)
                    {
                        emitLoadValue(ilGen);
                        emitLoadItem(ilGen, item.Value);
                        comparer.EmitEquals(ilGen);
                        ilGen.BranchTrue(item.Label);
                    }
                }

                ilGen.Branch(defaultLabel);

                return;
            }

            var greaterLabel = ilGen.DefineLabel();

            emitLoadHashCode(ilGen);
            ilGen.LoadConstant(cases[index].Key);
            ilGen.BranchIfGreater(greaterLabel);

            SwitchObject(
                ilGen,
                emitLoadValue,
                emitLoadHashCode,
                emitLoadItem,
                comparer,
                cases,
                defaultLabel,
                begin,
                (begin + index) / 2,
                index);

            ilGen.MarkLabel(greaterLabel);

            SwitchObject(
                ilGen,
                emitLoadValue,
                emitLoadHashCode,
                emitLoadItem,
                comparer,
                cases,
                defaultLabel,
                index + 1,
                (index + 1 + end) / 2,
                end);
        }
Exemplo n.º 7
0
        /// <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);
            }
        }