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(); } } }
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); }
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); }
/// <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> /// 当指定的本地变量值为该类型的默认值时跳到指定块。 /// </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); }
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); }
/// <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); } }