/* SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. * * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #region Utf8Json License https://github.com/neuecc/Utf8Json/blob/master/LICENSE // MIT License // // Copyright (c) 2017 Yoshifumi Kawai // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #endregion using System; using System.Linq; using System.Reflection; using System.Reflection.Emit; namespace OpenSearch.Net.Utf8Json.Internal.Emit { internal struct ArgumentField { private readonly int _i; private readonly bool _ref; private readonly ILGenerator _il; public ArgumentField(ILGenerator il, int i, bool @ref = false) { _il = il; _i = i; _ref = @ref; } public ArgumentField(ILGenerator il, int i, Type type) { _il = il; _i = i; _ref = !type.IsClass && !type.IsInterface && !type.IsAbstract; } public void EmitLoad() { if (_ref) { _il.EmitLdarga(_i); } else { _il.EmitLdarg(_i); } } public void EmitStore() => _il.EmitStarg(_i); } /// /// Provides optimized generation code and helpers. /// internal static class ILGeneratorExtensions { /// /// Loads the local variable at a specific index onto the evaluation stack. /// public static void EmitLdloc(this ILGenerator il, int index) { switch (index) { case 0: il.Emit(OpCodes.Ldloc_0); break; case 1: il.Emit(OpCodes.Ldloc_1); break; case 2: il.Emit(OpCodes.Ldloc_2); break; case 3: il.Emit(OpCodes.Ldloc_3); break; default: if (index <= 255) il.Emit(OpCodes.Ldloc_S, (byte)index); else il.Emit(OpCodes.Ldloc, (short)index); break; } } public static void EmitLdloc(this ILGenerator il, LocalBuilder local) => EmitLdloc(il, local.LocalIndex); /// /// Pops the current value from the top of the evaluation stack and stores it in a the local variable list at a specified index. /// public static void EmitStloc(this ILGenerator il, int index) { switch (index) { case 0: il.Emit(OpCodes.Stloc_0); break; case 1: il.Emit(OpCodes.Stloc_1); break; case 2: il.Emit(OpCodes.Stloc_2); break; case 3: il.Emit(OpCodes.Stloc_3); break; default: if (index <= 255) { il.Emit(OpCodes.Stloc_S, (byte)index); } else { il.Emit(OpCodes.Stloc, (short)index); } break; } } public static void EmitStloc(this ILGenerator il, LocalBuilder local) => EmitStloc(il, local.LocalIndex); /// /// Loads the address of the local variable at a specific index onto the evaluation statck. /// public static void EmitLdloca(this ILGenerator il, int index) { if (index <= 255) il.Emit(OpCodes.Ldloca_S, (byte)index); else il.Emit(OpCodes.Ldloca, (short)index); } public static void EmitLdloca(this ILGenerator il, LocalBuilder local) => EmitLdloca(il, local.LocalIndex); public static void EmitTrue(this ILGenerator il) => EmitBoolean(il, true); public static void EmitFalse(this ILGenerator il) => EmitBoolean(il, false); private static void EmitBoolean(this ILGenerator il, bool value) => EmitLdc_I4(il, value ? 1 : 0); /// /// Pushes a supplied value of type int32 onto the evaluation stack as an int32. /// public static void EmitLdc_I4(this ILGenerator il, int value) { switch (value) { case -1: il.Emit(OpCodes.Ldc_I4_M1); break; case 0: il.Emit(OpCodes.Ldc_I4_0); break; case 1: il.Emit(OpCodes.Ldc_I4_1); break; case 2: il.Emit(OpCodes.Ldc_I4_2); break; case 3: il.Emit(OpCodes.Ldc_I4_3); break; case 4: il.Emit(OpCodes.Ldc_I4_4); break; case 5: il.Emit(OpCodes.Ldc_I4_5); break; case 6: il.Emit(OpCodes.Ldc_I4_6); break; case 7: il.Emit(OpCodes.Ldc_I4_7); break; case 8: il.Emit(OpCodes.Ldc_I4_8); break; default: if (value >= -128 && value <= 127) il.Emit(OpCodes.Ldc_I4_S, (sbyte)value); else il.Emit(OpCodes.Ldc_I4, value); break; } } public static void EmitUnboxOrCast(this ILGenerator il, Type type) => il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type); public static void EmitBoxOrDoNothing(this ILGenerator il, Type type) { if (type.IsValueType) il.Emit(OpCodes.Box, type); } public static void EmitLdarg(this ILGenerator il, int index) { switch (index) { case 0: il.Emit(OpCodes.Ldarg_0); break; case 1: il.Emit(OpCodes.Ldarg_1); break; case 2: il.Emit(OpCodes.Ldarg_2); break; case 3: il.Emit(OpCodes.Ldarg_3); break; default: if (index <= 255) il.Emit(OpCodes.Ldarg_S, (byte)index); else il.Emit(OpCodes.Ldarg, index); break; } } public static void EmitLoadThis(this ILGenerator il) => EmitLdarg(il, 0); public static void EmitLdarga(this ILGenerator il, int index) { if (index <= 255) il.Emit(OpCodes.Ldarga_S, (byte)index); else il.Emit(OpCodes.Ldarga, index); } public static void EmitStarg(this ILGenerator il, int index) { if (index <= 255) il.Emit(OpCodes.Starg_S, (byte)index); else il.Emit(OpCodes.Starg, index); } /// /// Helper for Pop op. /// public static void EmitPop(this ILGenerator il, int count) { for (var i = 0; i < count; i++) il.Emit(OpCodes.Pop); } public static void EmitCall(this ILGenerator il, MethodInfo methodInfo) { if (methodInfo.IsFinal || !methodInfo.IsVirtual) il.Emit(OpCodes.Call, methodInfo); else il.Emit(OpCodes.Callvirt, methodInfo); } public static void EmitLdfld(this ILGenerator il, FieldInfo fieldInfo) => il.Emit(OpCodes.Ldfld, fieldInfo); public static void EmitLdsfld(this ILGenerator il, FieldInfo fieldInfo) => il.Emit(OpCodes.Ldsfld, fieldInfo); public static void EmitRet(this ILGenerator il) => il.Emit(OpCodes.Ret); public static void EmitIntZeroReturn(this ILGenerator il) { il.EmitLdc_I4(0); il.Emit(OpCodes.Ret); } public static void EmitNullReturn(this ILGenerator il) { il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Ret); } public static void EmitULong(this ILGenerator il, ulong value) => il.Emit(OpCodes.Ldc_I8, unchecked((long)value)); public static void EmitThrowNotimplemented(this ILGenerator il) { il.Emit(OpCodes.Newobj, typeof(NotImplementedException).GetDeclaredConstructors().First(x => x.GetParameters().Length == 0)); il.Emit(OpCodes.Throw); } /// for var i = 0, i ..., i++ public static void EmitIncrementFor(this ILGenerator il, LocalBuilder conditionGreater, Action emitBody) { var loopBegin = il.DefineLabel(); var condtionLabel = il.DefineLabel(); // var i = 0 var forI = il.DeclareLocal(typeof(int)); il.EmitLdc_I4(0); il.EmitStloc(forI); il.Emit(OpCodes.Br, condtionLabel); il.MarkLabel(loopBegin); emitBody(forI); // i++ il.EmitLdloc(forI); il.EmitLdc_I4(1); il.Emit(OpCodes.Add); il.EmitStloc(forI); //// i < *** il.MarkLabel(condtionLabel); il.EmitLdloc(forI); il.EmitLdloc(conditionGreater); il.Emit(OpCodes.Blt, loopBegin); } } }