diff options
author | Marek Safar <marek.safar@gmail.com> | 2014-01-09 23:39:18 +0400 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2014-01-09 23:40:09 +0400 |
commit | b3f05d8b00f7fa0e7a747f2b51db68afbb9c4b1b (patch) | |
tree | e2515eca9034a71595955690775e96e14f5bb4ec /mcs/class | |
parent | 57b915d78f47f7248e1180099ceb2d3667449a33 (diff) |
[System.Core] Add dynamic interpreter
Diffstat (limited to 'mcs/class')
82 files changed, 21928 insertions, 0 deletions
diff --git a/mcs/class/Mono.Dynamic.Interpreter/Assembly/AssemblyInfo.cs b/mcs/class/Mono.Dynamic.Interpreter/Assembly/AssemblyInfo.cs new file mode 100644 index 00000000000..9613d894e82 --- /dev/null +++ b/mcs/class/Mono.Dynamic.Interpreter/Assembly/AssemblyInfo.cs @@ -0,0 +1,53 @@ +// +// AssemblyInfo.cs +// +// Authors: +// Marek Safar (marek.safar@gmail.com) +// +// Copyright (c) 2014 Xamarin Inc. (http://www.xamarin.com) +// +// 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. +// + +using System; +using System.Reflection; +using System.Resources; +using System.Security; +using System.Security.Permissions; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about the assembly + +[assembly: AssemblyTitle ("Mono.Dynamic.Interpreter.dll")] +[assembly: AssemblyDescription ("Mono.Dynamic.Interpreter.dll")] +[assembly: AssemblyDefaultAlias ("Mono.Dynamic.Interpreter.dll")] + +[assembly: AssemblyCompany (Consts.MonoCompany)] +[assembly: AssemblyProduct (Consts.MonoProduct)] +[assembly: AssemblyCopyright (Consts.MonoCopyright)] +[assembly: AssemblyVersion (Consts.FxVersion)] +[assembly: SatelliteContractVersion (Consts.FxVersion)] +[assembly: AssemblyInformationalVersion (Consts.FxFileVersion)] +[assembly: AssemblyFileVersion (Consts.FxFileVersion)] + +[assembly: CLSCompliant (true)] + diff --git a/mcs/class/Mono.Dynamic.Interpreter/Makefile b/mcs/class/Mono.Dynamic.Interpreter/Makefile new file mode 100644 index 00000000000..bb8851ac6a4 --- /dev/null +++ b/mcs/class/Mono.Dynamic.Interpreter/Makefile @@ -0,0 +1,13 @@ +thisdir = class/Mono.Dynamic.Interpreter +SUBDIRS = +include ../../build/rules.make + +LIBRARY = Mono.Dynamic.Interpreter.dll + +LIB_MCS_FLAGS = -r:System.dll -r:System.Core.dll -r:System.Numerics.dll \ + -d:FEATURE_CORE_DLR,FEATURE_NUMERICS,FEATURE_DBNULL,FEATURE_DEFAULT_PARAMETER_VALUE,FEATURE_GET_TYPE_INFO,FEATURE_VARIANCE,FEATURE_SERIALIZATION,CLR45 \ + -d:MONO_INTERPRETER \ + -delaysign -keyfile:../mono.pub + +include ../../build/library.make + diff --git a/mcs/class/Mono.Dynamic.Interpreter/Mono.Dynamic.Interpreter.dll.sources b/mcs/class/Mono.Dynamic.Interpreter/Mono.Dynamic.Interpreter.dll.sources new file mode 100644 index 00000000000..89f43a47b63 --- /dev/null +++ b/mcs/class/Mono.Dynamic.Interpreter/Mono.Dynamic.Interpreter.dll.sources @@ -0,0 +1,89 @@ +../../build/common/Consts.cs +Assembly/AssemblyInfo.cs + +../dlr/Runtime/Microsoft.Scripting/ArgumentTypeException.cs +../dlr/Runtime/Microsoft.Scripting/InvalidImplementationException.cs +../dlr/Runtime/Microsoft.Scripting/PlatformAdaptationLayer.cs +../dlr/Runtime/Microsoft.Scripting/Stubs.cs + +../dlr/Runtime/Microsoft.Scripting/Runtime/NotNullAttribute.cs +../dlr/Runtime/Microsoft.Scripting/Runtime/ParamDictionaryAttribute.cs + +../dlr/Runtime/Microsoft.Dynamic/DebugOptions.cs +../dlr/Runtime/Microsoft.Dynamic/MultiRuntimeAwareAttribute.cs +../dlr/Runtime/Microsoft.Dynamic/PerfTrack.cs + +../dlr/Runtime/Microsoft.Dynamic/Actions/Dummy.cs + +../dlr/Runtime/Microsoft.Dynamic/Ast/BinaryExpression.cs +../dlr/Runtime/Microsoft.Dynamic/Ast/ConstantExpression.cs +../dlr/Runtime/Microsoft.Dynamic/Ast/EmptyStatements.cs +../dlr/Runtime/Microsoft.Dynamic/Ast/LightLambdaExpression.cs +../dlr/Runtime/Microsoft.Dynamic/Ast/UnaryExpression.cs +../dlr/Runtime/Microsoft.Dynamic/Ast/Utils.cs + +../dlr/Runtime/Microsoft.Dynamic/Generation/CompilerHelpers.cs +../dlr/Runtime/Microsoft.Dynamic/Generation/ConstantCheck.cs +../dlr/Runtime/Microsoft.Dynamic/Generation/DelegateHelpers.cs +../dlr/Runtime/Microsoft.Dynamic/Generation/DelegateHelpers.Generated.cs + +../dlr/Runtime/Microsoft.Dynamic/Interpreter/BranchLabel.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/ILightCallSiteBinder.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/InterpretedFrame.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Interpreter.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/LightCompiler.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/LightDelegateCreator.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambda.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambda.Generated.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambdaClosureVisitor.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/LocalVariables.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/LoopCompiler.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/RuntimeVariables.cs + +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/AddInstruction.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/ArrayOperations.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/CallInstruction.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/CallInstruction.Generated.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/ControlFlowInstructions.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DivInstruction.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicInstructionN.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicInstructions.Generated.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicSplatInstruction.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/EqualInstruction.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/FieldOperations.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/GreaterThanInstruction.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/Instruction.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/InstructionFactory.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/InstructionList.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LabelInfo.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LessThanInstruction.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LocalAccess.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/NotEqualInstruction.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/NumericConvertInstruction.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/StackOperations.cs +../dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/TypeOperations.cs + +../dlr/Runtime/Microsoft.Dynamic/Math/BigIntegerV4.cs +../dlr/Runtime/Microsoft.Dynamic/Math/Complex64.cs + +../dlr/Runtime/Microsoft.Dynamic/Runtime/ArgumentArray.cs +../dlr/Runtime/Microsoft.Dynamic/Runtime/DynamicNull.cs +../dlr/Runtime/Microsoft.Dynamic/Runtime/ExceptionHelpers.cs +../dlr/Runtime/Microsoft.Dynamic/Runtime/ScriptingRuntimeHelpers.cs + +../dlr/Runtime/Microsoft.Dynamic/Utils/ArrayUtils.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/Assert.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/CacheDict.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/ContractUtils.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/CollectionExtensions.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/CollectionUtils.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/DynamicUtils.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/ExceptionUtils.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/ExceptionFactory.Generated.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/HybridReferenceDictionary.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/ListEqualityComparer.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/MathUtils.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/ReferenceEqualityComparer.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/ReflectionUtils.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/StringUtils.cs +../dlr/Runtime/Microsoft.Dynamic/Utils/TypeUtils.cs diff --git a/mcs/class/System.Core/System.Linq.Expressions.Interpret/LambdaCompiler.cs b/mcs/class/System.Core/System.Linq.Expressions.Interpret/LambdaCompiler.cs new file mode 100644 index 00000000000..23d623a633f --- /dev/null +++ b/mcs/class/System.Core/System.Linq.Expressions.Interpret/LambdaCompiler.cs @@ -0,0 +1,47 @@ +// +// LambdaCompiler.cs: System.Linq.Expression interpreter entry point +// +// Authors: Marek Safar (marek.safar@gmail.com) +// +// Copyright 2014 Xamarin Inc +// +// 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. +// +// + +using System.Runtime.CompilerServices; +#if MONO_INTERPRETER +using Microsoft.Scripting.Generation; +#endif + +namespace System.Linq.Expressions.Compiler +{ + static class LambdaCompiler + { + public static Delegate Compile (LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator) + { +#if MONO_INTERPRETER + return lambda.LightCompile (); +#else + throw new NotSupportedException ("System.Linq.Expression interpreter is missing"); +#endif + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.Core/interpreter_System.Core.dll.sources b/mcs/class/System.Core/interpreter_System.Core.dll.sources new file mode 100644 index 00000000000..5ca0d488493 --- /dev/null +++ b/mcs/class/System.Core/interpreter_System.Core.dll.sources @@ -0,0 +1,91 @@ +../dlr/Runtime/Microsoft.Scripting.Core/Actions/BinaryOperationBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/BindingRestrictions.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/CallInfo.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/CallSite.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/CallSiteBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/CallSiteHelpers.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/CallSiteOps.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/ConvertBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/CreateInstanceBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/DeleteIndexBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/DeleteMemberBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/DynamicMetaObject.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/DynamicMetaObjectBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/DynamicObject.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/ExpandoClass.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/ExpandoObject.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/GetIndexBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/GetMemberBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/IDynamicMetaObjectProvider.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/InvokeBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/InvokeMemberBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/IInvokeOnGetBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/RuleCache.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/SetIndexBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/SetMemberBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/UnaryOperationBinder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Actions/UpdateDelegates.Generated.cs + +../dlr/Runtime/Microsoft.Scripting.Core/Ast/BinaryExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/BlockExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/CatchBlock.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/ConditionalExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/ConstantExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/DebugInfoExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/DebugViewWriter.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/DefaultExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/ElementInit.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/Expression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/Expression.DebuggerProxy.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/ExpressionStringBuilder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/ExpressionType.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/ExpressionVisitor.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/GotoExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/IArgumentProvider.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/IndexExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/InvocationExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/LabelExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/LabelTarget.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/LambdaExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/ListArgumentProvider.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/ListInitExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/LoopExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/MemberAssignment.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/MemberBinding.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/MemberExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/MemberInitExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/MemberListBinding.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/MemberMemberBinding.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/MethodCallExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/NewArrayExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/NewExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/ParameterExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/RuntimeVariablesExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/SwitchCase.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/SwitchExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/SymbolDocumentInfo.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/TryExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/TypeBinaryExpression.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/TypeUtils.cs +../dlr/Runtime/Microsoft.Scripting.Core/Ast/UnaryExpression.cs + +../dlr/Runtime/Microsoft.Scripting.Core/Compiler/DebugInfoGenerator.cs +../dlr/Runtime/Microsoft.Scripting.Core/Compiler/DelegateHelpers.cs +../dlr/Runtime/Microsoft.Scripting.Core/Compiler/DelegateHelpers.Generated.cs +../dlr/Runtime/Microsoft.Scripting.Core/Compiler/Set.cs +../dlr/Runtime/Microsoft.Scripting.Core/Compiler/SymbolGuids.cs + +../dlr/Runtime/Microsoft.Scripting.Core/Utils/CacheDict.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/CollectionExtensions.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/ContractUtils.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/ExceptionFactory.Generated.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/Helpers.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/IRuntimeVariables.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/ReadOnlyCollectionBuilder.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/ReadOnlyDictionary.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/ReferenceEqualityComparer.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/ReflectionUtils.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/TrueReadOnlyCollection.cs +../dlr/Runtime/Microsoft.Scripting.Core/Utils/TypeExtensions.cs + +System.Linq.Expressions.Interpret/LambdaCompiler.cs diff --git a/mcs/class/dlr/README b/mcs/class/dlr/README new file mode 100644 index 00000000000..7ec5bea3410 --- /dev/null +++ b/mcs/class/dlr/README @@ -0,0 +1,8 @@ +This is fork of Microsoft DLR source code. The original code was published at +http://dlr.codeplex.com/ which had the code used for .NET 4.0 +System.Linq.Expression public API. Since them the code was migrated to +https://github.com/IronLanguages/main but it no longer has the goal to offer +compatible System.Linq.Expression API and we cannot use some part of it. + +We want to have minimum local changes. Importatant changes need to be marked +using easily recognizable marker (like MONO_INTERPRETER) for easier merging.
\ No newline at end of file diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Actions/Dummy.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Actions/Dummy.cs new file mode 100644 index 00000000000..880a99a8e2a --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Actions/Dummy.cs @@ -0,0 +1,5 @@ +namespace Microsoft.Scripting.Actions { + class Dummy + { + } +}
\ No newline at end of file diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/BinaryExpression.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/BinaryExpression.cs new file mode 100644 index 00000000000..10f8a9658c9 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/BinaryExpression.cs @@ -0,0 +1,133 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Reflection; +using System.Dynamic; +using Microsoft.Scripting.Utils; +using AstUtils = Microsoft.Scripting.Ast.Utils; + +namespace Microsoft.Scripting.Ast { + public static partial class Utils { +#if !MONO_INTERPRETER + /// <summary> + /// Null coalescing expression + /// {result} ::= ((tmp = {_left}) == null) ? {right} : tmp + /// '??' operator in C#. + /// </summary> + public static Expression Coalesce(Expression left, Expression right, out ParameterExpression temp) { + return CoalesceInternal(left, right, null, false, out temp); + } + + /// <summary> + /// True coalescing expression. + /// {result} ::= IsTrue(tmp = {left}) ? {right} : tmp + /// Generalized AND semantics. + /// </summary> + public static Expression CoalesceTrue(Expression left, Expression right, MethodInfo isTrue, out ParameterExpression temp) { + ContractUtils.RequiresNotNull(isTrue, "isTrue"); + return CoalesceInternal(left, right, isTrue, false, out temp); + } + + /// <summary> + /// False coalescing expression. + /// {result} ::= IsTrue(tmp = {left}) ? tmp : {right} + /// Generalized OR semantics. + /// </summary> + public static Expression CoalesceFalse(Expression left, Expression right, MethodInfo isTrue, out ParameterExpression temp) { + ContractUtils.RequiresNotNull(isTrue, "isTrue"); + return CoalesceInternal(left, right, isTrue, true, out temp); + } + + private static Expression CoalesceInternal(Expression left, Expression right, MethodInfo isTrue, bool isReverse, out ParameterExpression temp) { + ContractUtils.RequiresNotNull(left, "left"); + ContractUtils.RequiresNotNull(right, "right"); + + // A bit too strict, but on a safe side. + ContractUtils.Requires(left.Type == right.Type, "Expression types must match"); + + temp = Expression.Variable(left.Type, "tmp_left"); + + Expression condition; + if (isTrue != null) { + ContractUtils.Requires(isTrue.ReturnType == typeof(bool), "isTrue", "Predicate must return bool."); + ParameterInfo[] parameters = isTrue.GetParameters(); + ContractUtils.Requires(parameters.Length == 1, "isTrue", "Predicate must take one parameter."); + ContractUtils.Requires(isTrue.IsStatic && isTrue.IsPublic, "isTrue", "Predicate must be public and static."); + + Type pt = parameters[0].ParameterType; + ContractUtils.Requires(TypeUtils.CanAssign(pt, left.Type), "left", "Incorrect left expression type"); + condition = Expression.Call(isTrue, Expression.Assign(temp, left)); + } else { + ContractUtils.Requires(TypeUtils.CanCompareToNull(left.Type), "left", "Incorrect left expression type"); + condition = Expression.Equal(Expression.Assign(temp, left), AstUtils.Constant(null, left.Type)); + } + + Expression t, f; + if (isReverse) { + t = temp; + f = right; + } else { + t = right; + f = temp; + } + + return Expression.Condition(condition, t, f); + } + + public static Expression Coalesce(LambdaBuilder builder, Expression left, Expression right) { + ParameterExpression temp; + Expression result = Coalesce(left, right, out temp); + builder.AddHiddenVariable(temp); + return result; + } + + /// <summary> + /// True coalescing expression. + /// {result} ::= IsTrue(tmp = {left}) ? {right} : tmp + /// Generalized AND semantics. + /// </summary> + public static Expression CoalesceTrue(LambdaBuilder builder, Expression left, Expression right, MethodInfo isTrue) { + ContractUtils.RequiresNotNull(isTrue, "isTrue"); + ParameterExpression temp; + Expression result = CoalesceTrue(left, right, isTrue, out temp); + builder.AddHiddenVariable(temp); + return result; + } + + /// <summary> + /// False coalescing expression. + /// {result} ::= IsTrue(tmp = {left}) ? tmp : {right} + /// Generalized OR semantics. + /// </summary> + public static Expression CoalesceFalse(LambdaBuilder builder, Expression left, Expression right, MethodInfo isTrue) { + ContractUtils.RequiresNotNull(isTrue, "isTrue"); + ParameterExpression temp; + Expression result = CoalesceFalse(left, right, isTrue, out temp); + builder.AddHiddenVariable(temp); + return result; + } +#endif + public static BinaryExpression Update(this BinaryExpression expression, Expression left, Expression right) { + return expression.Update(left, expression.Conversion, right); + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/ConstantExpression.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/ConstantExpression.cs new file mode 100644 index 00000000000..7c75d149125 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/ConstantExpression.cs @@ -0,0 +1,226 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +#if FEATURE_NUMERICS +using BigInt = System.Numerics.BigInteger; +using Complex = System.Numerics.Complex; +#endif + +using System; +using System.Reflection; +using Microsoft.Scripting.Generation; +using Microsoft.Scripting.Math; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Ast { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces")] + public static partial class Utils { + private static readonly ConstantExpression TrueLiteral = Expression.Constant(true, typeof(bool)); + private static readonly ConstantExpression FalseLiteral = Expression.Constant(false, typeof(bool)); + private static readonly ConstantExpression NullLiteral = Expression.Constant(null, typeof(object)); + private static readonly ConstantExpression EmptyStringLiteral = Expression.Constant(String.Empty, typeof(string)); + private static readonly ConstantExpression[] IntCache = new ConstantExpression[100]; + + /// <summary> + /// Wraps the given value in a WeakReference and returns a tree that will retrieve + /// the value from the WeakReference. + /// </summary> + public static MemberExpression WeakConstant(object value) { + System.Diagnostics.Debug.Assert(!(value is Expression)); + return Expression.Property( + Constant(new WeakReference(value)), + typeof(WeakReference).GetDeclaredProperty("Target") + ); + } + + public static ConstantExpression Constant(object value, Type type) { + return Expression.Constant(value, type); + } + + // The helper API should return ConstantExpression after SymbolConstantExpression goes away + public static Expression Constant(object value) { + if (value == null) { + return NullLiteral; + } + + BigInteger bi = value as BigInteger; + if ((object)bi != null) { + return BigIntegerConstant(bi); +#if FEATURE_NUMERICS + } else if (value is BigInt) { + return BigIntConstant((BigInt)value); + } else if (value is Complex) { + return ComplexConstant((Complex)value); +#endif + } else if (value is Complex64) { + return Complex64Constant((Complex64)value); + } else if (value is Type) { + return Expression.Constant(value, typeof(Type)); + } else if (value is ConstructorInfo) { + return Expression.Constant(value, typeof(ConstructorInfo)); + } else if (value is EventInfo) { + return Expression.Constant(value, typeof(EventInfo)); + } else if (value is FieldInfo) { + return Expression.Constant(value, typeof(FieldInfo)); + } else if (value is MethodInfo) { + return Expression.Constant(value, typeof(MethodInfo)); + } else if (value is PropertyInfo) { + return Expression.Constant(value, typeof(PropertyInfo)); + } else { + Type t = value.GetType(); + if (!t.GetTypeInfo().IsEnum) { + switch (t.GetTypeCode()) { + case TypeCode.Boolean: + return (bool)value ? TrueLiteral : FalseLiteral; + case TypeCode.Int32: + int x = (int)value; + int cacheIndex = x + 2; + if (cacheIndex >= 0 && cacheIndex < IntCache.Length) { + ConstantExpression res; + if ((res = IntCache[cacheIndex]) == null) { + IntCache[cacheIndex] = res = Constant(x, typeof(int)); + } + return res; + } + break; + case TypeCode.String: + if (String.IsNullOrEmpty((string)value)) { + return EmptyStringLiteral; + } + break; + } + } + return Expression.Constant(value); + } + } + + private static Expression BigIntegerConstant(BigInteger value) { + int ival; + if (value.AsInt32(out ival)) { + return Expression.Call( + new Func<int, BigInteger>(BigInteger.Create).GetMethodInfo(), + Constant(ival) + ); + } + + long lval; + if (value.AsInt64(out lval)) { + return Expression.Call( + new Func<long, BigInteger>(BigInteger.Create).GetMethodInfo(), + Constant(lval) + ); + } + +#if !FEATURE_NUMERICS + return Expression.Call( + new Func<int, uint[], BigInteger>(CompilerHelpers.CreateBigInteger).Method, + Constant((int)value.Sign), + CreateArray<uint>(value.GetWords()) + ); +#else + return Expression.Call( + new Func<bool, byte[], BigInteger>(CompilerHelpers.CreateBigInteger).GetMethodInfo(), + Constant(value.Sign < 0), + CreateArray<byte>(value.Abs().ToByteArray()) + ); + } + + private static Expression BigIntConstant(BigInt value) { + int ival; + if (value.AsInt32(out ival)) { + return Expression.Call( + new Func<int, BigInt>(CompilerHelpers.CreateBigInt).GetMethodInfo(), + Constant(ival) + ); + } + + long lval; + if (value.AsInt64(out lval)) { + return Expression.Call( + new Func<long, BigInt>(CompilerHelpers.CreateBigInt).GetMethodInfo(), + Constant(lval) + ); + } + + return Expression.Call( + new Func<bool, byte[], BigInt>(CompilerHelpers.CreateBigInt).GetMethodInfo(), + Constant(value.Sign < 0), + CreateArray<byte>(value.Abs().ToByteArray()) + ); +#endif + } + + private static Expression CreateArray<T>(T[] array) { + // TODO: could we use blobs? + Expression[] init = new Expression[array.Length]; + for (int i = 0; i < init.Length; i++) { + init[i] = Constant(array[i]); + } + return Expression.NewArrayInit(typeof(T), init); + } + +#if FEATURE_NUMERICS + private static Expression ComplexConstant(Complex value) { + if (value.Real != 0.0) { + if (value.Imaginary() != 0.0) { + return Expression.Call( + new Func<double, double, Complex>(MathUtils.MakeComplex).GetMethodInfo(), + Constant(value.Real), + Constant(value.Imaginary()) + ); + } else { + return Expression.Call( + new Func<double, Complex>(MathUtils.MakeReal).GetMethodInfo(), + Constant(value.Real) + ); + } + } else { + return Expression.Call( + new Func<double, Complex>(MathUtils.MakeImaginary).GetMethodInfo(), + Constant(value.Imaginary()) + ); + } + } +#endif + + private static Expression Complex64Constant(Complex64 value) { + if (value.Real != 0.0) { + if (value.Imag != 0.0) { + return Expression.Call( + new Func<double, double, Complex64>(Complex64.Make).GetMethodInfo(), + Constant(value.Real), + Constant(value.Imag) + ); + } else { + return Expression.Call( + new Func<double, Complex64>(Complex64.MakeReal).GetMethodInfo(), + Constant(value.Real) + ); + } + } else { + return Expression.Call( + new Func<double, Complex64>(Complex64.MakeImaginary).GetMethodInfo(), + Constant(value.Imag) + ); + } + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/EmptyStatements.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/EmptyStatements.cs new file mode 100644 index 00000000000..0968a2ca616 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/EmptyStatements.cs @@ -0,0 +1,45 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Dynamic; + +namespace Microsoft.Scripting.Ast { + public static partial class Utils { + private static readonly DefaultExpression VoidInstance = Expression.Empty(); + + public static DefaultExpression Empty() { + return VoidInstance; + } + + public static DefaultExpression Default(Type type) { + if (type == typeof(void)) { + return Empty(); + } + return Expression.Default(type); + } + } +} + + + + + diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/LightLambdaExpression.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/LightLambdaExpression.cs new file mode 100644 index 00000000000..6b2a08e3443 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/LightLambdaExpression.cs @@ -0,0 +1,149 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Scripting.Interpreter; +using Microsoft.Scripting.Generation; + +namespace Microsoft.Scripting.Ast { + public class LightLambdaExpression : Expression { + private readonly Expression _body; + private readonly Type _retType; + private readonly string _name; + private readonly IList<ParameterExpression> _args; + + internal LightLambdaExpression(Type retType, Expression body, string name, IList<ParameterExpression> args) { + _body = body; + _name = name; + _args = args; + _retType = retType; + } + + public Expression Body { + get { + return _body; + } + } + + public string Name { + get { + return _name; + } + } + + public IList<ParameterExpression> Parameters { + get { + return _args; + } + } + + internal virtual LambdaExpression ReduceToLambdaWorker() { + throw new InvalidOperationException(); + } + + public Delegate Compile() { + return Compile(-1); + } + + public Delegate Compile(int compilationThreshold) { + return new LightCompiler(compilationThreshold).CompileTop(this).CreateDelegate(); + } + + public override ExpressionType NodeType { + get { return ExpressionType.Extension; } + } + + public override bool CanReduce { + get { return true; } + } + + public override Expression Reduce() { + return ReduceToLambdaWorker(); + } + + public Type ReturnType { + get { + return _retType; + } + } + } + + internal class TypedLightLambdaExpression : LightLambdaExpression { + private readonly Type _delegateType; + + internal TypedLightLambdaExpression(Type retType, Type delegateType, Expression body, string name, IList<ParameterExpression> args) + : base(retType, body, name, args) { + _delegateType = delegateType; + } + + internal override LambdaExpression ReduceToLambdaWorker() { + return Expression.Lambda( + _delegateType, + Body, + Name, + Parameters + ); + } + + public override Type Type { + get { return _delegateType; } + } + } + + public class LightExpression<T> : LightLambdaExpression { + internal LightExpression(Type retType, Expression body, string name, IList<ParameterExpression> args) + : base(retType, body, name, args) { + } + + public Expression<T> ReduceToLambda() { + return Expression.Lambda<T>(Body, Name, Parameters); + } + + public override Type Type { + get { return typeof(T); } + } + + public new T Compile() { + return Compile(-1); + } + + public new T Compile(int compilationThreshold) { + return (T)(object)new LightCompiler(compilationThreshold).CompileTop(this).CreateDelegate(); + } + + internal override LambdaExpression ReduceToLambdaWorker() { + return ReduceToLambda(); + } + } + + public static partial class Utils { + public static LightExpression<T> LightLambda<T>(Type retType, Expression body, string name, IList<ParameterExpression> args) { + return new LightExpression<T>(retType, body, name, args); + } + + public static LightLambdaExpression LightLambda(Type retType, Type delegateType, Expression body, string name, IList<ParameterExpression> args) { + return new TypedLightLambdaExpression(retType, delegateType, body, name, args); + } + } + +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/UnaryExpression.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/UnaryExpression.cs new file mode 100644 index 00000000000..19477b2320e --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/UnaryExpression.cs @@ -0,0 +1,82 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; +using System.Reflection; + +namespace Microsoft.Scripting.Ast { + public static partial class Utils { + /// <summary> + /// Converts an expression to a void type. + /// </summary> + /// <param name="expression">An <see cref="Expression"/> to convert to void. </param> + /// <returns>An <see cref="Expression" /> that has the <see cref="P:System.Linq.Expressions.Expression.NodeType" /> property equal to <see cref="F:System.Linq.Expressions.ExpressionType.ConvertChecked" /> and the <see cref="P:System.Linq.Expressions.UnaryExpression.Operand" /> and <see cref="P:System.Linq.Expressions.Expression.Type" /> property set to void.</returns> + public static Expression Void(Expression expression) { + ContractUtils.RequiresNotNull(expression, "expression"); + if (expression.Type == typeof(void)) { + return expression; + } + return Expression.Block(expression, Utils.Empty()); + } + + public static Expression Convert(Expression expression, Type type) { + ContractUtils.RequiresNotNull(expression, "expression"); + + if (expression.Type == type) { + return expression; + } + + if (expression.Type == typeof(void)) { + return Expression.Block(expression, Utils.Default(type)); + } + + if (type == typeof(void)) { + return Void(expression); + } + + // TODO: this is not the right level for this to be at. It should + // be pushed into languages if they really want this behavior. + if (type == typeof(object)) { + return Box(expression); + } + + return Expression.Convert(expression, type); + } + + /// <summary> + /// Returns an expression that boxes a given value. Uses boxed objects cache for Int32 and Boolean types. + /// </summary> + public static Expression Box(Expression expression) { + MethodInfo m; + if (expression.Type == typeof(int)) { + m = ScriptingRuntimeHelpers.Int32ToObjectMethod; + } else if (expression.Type == typeof(bool)) { + m = ScriptingRuntimeHelpers.BooleanToObjectMethod; + } else { + m = null; + } + + return Expression.Convert(expression, typeof(object), m); + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/Utils.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/Utils.cs new file mode 100644 index 00000000000..165a42458e8 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Ast/Utils.cs @@ -0,0 +1,111 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Reflection; +using System.Dynamic; +using Microsoft.Scripting.Utils; +using AstUtils = Microsoft.Scripting.Ast.Utils; + +namespace Microsoft.Scripting.Ast { + [Flags] + public enum ExpressionAccess { + None = 0, + Read = 1, + Write = 2, + ReadWrite = Read | Write, + } + + public static partial class Utils { + /// <summary> + /// Determines whether specified expression type represents an assignment. + /// </summary> + /// <returns> + /// True if the expression type represents an assignment. + /// </returns> + /// <remarks> + /// Note that some other nodes can also assign to variables, members or array items: + /// MemberInit, NewArrayInit, Call with ref params, New with ref params, Dynamic with ref params. + /// </remarks> + public static bool IsAssignment(this ExpressionType type) { + return IsWriteOnlyAssignment(type) || IsReadWriteAssignment(type); + } + + public static bool IsWriteOnlyAssignment(this ExpressionType type) { + return type == ExpressionType.Assign; + } + + public static bool IsReadWriteAssignment(this ExpressionType type) { + switch (type) { + // unary: + case ExpressionType.PostDecrementAssign: + case ExpressionType.PostIncrementAssign: + case ExpressionType.PreDecrementAssign: + case ExpressionType.PreIncrementAssign: + + // binary - compound: + case ExpressionType.AddAssign: + case ExpressionType.AddAssignChecked: + case ExpressionType.AndAssign: + case ExpressionType.DivideAssign: + case ExpressionType.ExclusiveOrAssign: + case ExpressionType.LeftShiftAssign: + case ExpressionType.ModuloAssign: + case ExpressionType.MultiplyAssign: + case ExpressionType.MultiplyAssignChecked: + case ExpressionType.OrAssign: + case ExpressionType.PowerAssign: + case ExpressionType.RightShiftAssign: + case ExpressionType.SubtractAssign: + case ExpressionType.SubtractAssignChecked: + return true; + } + return false; + } + + /// <summary> + /// Determines if the left child of the given expression is read or written to or both. + /// </summary> + public static ExpressionAccess GetLValueAccess(this ExpressionType type) { + if (type.IsReadWriteAssignment()) { + return ExpressionAccess.ReadWrite; + } + + if (type.IsWriteOnlyAssignment()) { + return ExpressionAccess.Write; + } + + return ExpressionAccess.Read; + } + + public static bool IsLValue(this ExpressionType type) { + // see Expression.RequiresCanWrite + switch (type) { + case ExpressionType.Index: + case ExpressionType.MemberAccess: + case ExpressionType.Parameter: + return true; + } + + return false; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/DebugOptions.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/DebugOptions.cs new file mode 100644 index 00000000000..a3aac34473a --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/DebugOptions.cs @@ -0,0 +1,76 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System.Security; +using System; + +namespace Microsoft.Scripting { + + /// <summary> + /// This class holds onto internal debugging options used in this assembly. + /// These options can be set via environment variables DLR_{option-name}. + /// Boolean options map "true" to true and other values to false. + /// + /// These options are for internal debugging only, and should not be + /// exposed through any public APIs. + /// </summary> + internal static class DebugOptions { + + private static bool ReadOption(string name) { +#if SILVERLIGHT + return false; +#else + string envVar = ReadString(name); + return envVar != null && envVar.ToLowerInvariant() == "true"; +#endif + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "name")] + private static bool ReadDebugOption(string name) { +#if DEBUG + return ReadOption(name); +#else + return false; +#endif + } + + private static string ReadString(string name) { +#if FEATURE_PROCESS + try { + return Environment.GetEnvironmentVariable("DLR_" + name); + } catch (SecurityException) { + return null; + } +#else + return null; +#endif + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "name")] + private static string ReadDebugString(string name) { +#if DEBUG + return ReadString(name); +#else + return null; +#endif + } + + private readonly static bool _trackPerformance = ReadDebugOption("TrackPerformance"); + + internal static bool TrackPerformance { + get { return _trackPerformance; } + } + } +}
\ No newline at end of file diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/CompilerHelpers.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/CompilerHelpers.cs new file mode 100644 index 00000000000..919d1b5b5e5 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/CompilerHelpers.cs @@ -0,0 +1,906 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_NUMERICS +using BigInt = System.Numerics.BigInteger; +#endif + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#endif + +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics; +using System.Dynamic; +using System.Linq; +using System.Reflection; +#if FEATURE_REFEMIT +using System.Reflection.Emit; +#endif +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Actions; +using Microsoft.Scripting.Ast; +using Microsoft.Scripting.Interpreter; +using Microsoft.Scripting.Math; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; +using AstUtils = Microsoft.Scripting.Ast.Utils; + +namespace Microsoft.Scripting.Generation { + // TODO: keep this? + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")] + public delegate void ActionRef<T0, T1>(ref T0 arg0, ref T1 arg1); + + public static class CompilerHelpers { + public static readonly MethodAttributes PublicStatic = MethodAttributes.Public | MethodAttributes.Static; + private static readonly MethodInfo _CreateInstanceMethod = typeof(ScriptingRuntimeHelpers).GetMethod("CreateInstance"); + + private static int _Counter; // for generating unique names for lambda methods + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public static object GetMissingValue(Type type) { + ContractUtils.RequiresNotNull(type, "type"); + + if (type.IsByRef) type = type.GetElementType(); + if (type.IsEnum()) return Activator.CreateInstance(type); + + switch (type.GetTypeCode()) { + default: + case TypeCode.Object: + // struct + if (type.IsSealed() && type.IsValueType()) { + return Activator.CreateInstance(type); + } else if (type == typeof(object)) { + // parameter of type object receives the actual Missing value + return Missing.Value; + } else if (!type.IsValueType()) { + return null; + } else { + throw Error.CantCreateDefaultTypeFor(type); + } + case TypeCode.Empty: + case TypeCode.DBNull: + case TypeCode.String: + return null; + + case TypeCode.Boolean: return false; + case TypeCode.Char: return '\0'; + case TypeCode.SByte: return (sbyte)0; + case TypeCode.Byte: return (byte)0; + case TypeCode.Int16: return (short)0; + case TypeCode.UInt16: return (ushort)0; + case TypeCode.Int32: return (int)0; + case TypeCode.UInt32: return (uint)0; + case TypeCode.Int64: return 0L; + case TypeCode.UInt64: return 0UL; + case TypeCode.Single: return 0.0f; + case TypeCode.Double: return 0.0D; + case TypeCode.Decimal: return (decimal)0; + case TypeCode.DateTime: return DateTime.MinValue; + } + } + + public static bool IsStatic(MethodBase mi) { + return mi.IsConstructor || mi.IsStatic; + } + + /// <summary> + /// True if the MethodBase is method which is going to construct an object + /// </summary> + public static bool IsConstructor(MethodBase mb) { + if (mb.IsConstructor) { + return true; + } + + if (mb.IsGenericMethod) { + MethodInfo mi = mb as MethodInfo; + + if (mi.GetGenericMethodDefinition() == _CreateInstanceMethod) { + return true; + } + } + + return false; + } + + public static T[] MakeRepeatedArray<T>(T item, int count) { + T[] ret = new T[count]; + for (int i = 0; i < count; i++) ret[i] = item; + return ret; + } + + public static bool IsComparisonOperator(ExpressionType op) { + switch (op) { + case ExpressionType.LessThan: return true; + case ExpressionType.LessThanOrEqual: return true; + case ExpressionType.GreaterThan: return true; + case ExpressionType.GreaterThanOrEqual: return true; + case ExpressionType.Equal: return true; + case ExpressionType.NotEqual: return true; + } + return false; + } + + /// <summary> + /// Returns the System.Type for any object, including null. The type of null + /// is represented by None.Type and all other objects just return the + /// result of Object.GetType + /// </summary> + public static Type GetType(object obj) { + if (obj == null) { + return typeof(DynamicNull); + } + + return obj.GetType(); + } + + /// <summary> + /// Simply returns a Type[] from calling GetType on each element of args. + /// </summary> + public static Type[] GetTypes(object[] args) { + Type[] types = new Type[args.Length]; + for (int i = 0; i < args.Length; i++) { + types[i] = GetType(args[i]); + } + return types; + } + + /// <summary> + /// EMITTED + /// Used by default method binder to check types of splatted arguments. + /// </summary> + public static bool TypesEqual(IList args, int start, Type[] types) { + for (int i = 0; i < types.Length; i++) { + object arg = args[start + i]; + if (types[i] != (arg != null ? arg.GetType() : null)) { + return false; + } + } + return true; + } + + public static bool CanOptimizeMethod(MethodBase method) { + if (method.ContainsGenericParameters || + method.IsProtected() || + method.IsPrivate || + !method.DeclaringType.IsVisible()) { + return false; + } + return true; + } + + /// <summary> + /// Given a MethodInfo which may be declared on a non-public type this attempts to + /// return a MethodInfo which will dispatch to the original MethodInfo but is declared + /// on a public type. + /// + /// Returns the original method if the method if a public version cannot be found. + /// </summary> + public static MethodInfo TryGetCallableMethod(Type targetType, MethodInfo method) { + if (method.DeclaringType == null || method.DeclaringType.IsVisible()) { + return method; + } + + // first try and get it from the base type we're overriding... + MethodInfo baseMethod = method.GetRuntimeBaseDefinition(); + + if (baseMethod.DeclaringType.IsVisible() || baseMethod.DeclaringType.IsInterface()) { + // We need to instantiate the method as GetBaseDefinition might return a generic definition of the base method: + if (baseMethod.IsGenericMethodDefinition) { + baseMethod = baseMethod.MakeGenericMethod(method.GetGenericArguments()); + } + return baseMethod; + } + +#if WIN8 // TODO: interface map, method handle + foreach (Type iface in targetType.GetImplementedInterfaces()) { + dynamic mapping = ((dynamic)targetType).GetInterfaceMap(iface); + for (int i = 0; i < mapping.TargetMethods.Length; i++) { + MethodInfo targetMethod = mapping.TargetMethods[i]; + if (targetMethod != null && ((dynamic)targetMethod).MethodHandle == ((dynamic)method).MethodHandle) { + return mapping.InterfaceMethods[i]; + } + } + } +#else + // maybe we can get it from an interface on the type this + // method came from... + foreach (Type iface in targetType.GetImplementedInterfaces()) { + if (iface.IsPublic()) { + InterfaceMapping mapping = targetType.GetInterfaceMap(iface); + for (int i = 0; i < mapping.TargetMethods.Length; i++) { + MethodInfo targetMethod = mapping.TargetMethods[i]; + if (targetMethod != null && targetMethod.MethodHandle == method.MethodHandle) { + return mapping.InterfaceMethods[i]; + } + } + } + } +#endif + return method; + } + + /// <summary> + /// Non-public types can have public members that we find when calling type.GetMember(...). This + /// filters out the non-visible members by attempting to resolve them to the correct visible type. + /// + /// If no correct visible type can be found then the member is not visible and we won't call it. + /// </summary> + public static IEnumerable<MemberInfo> FilterNonVisibleMembers(Type targetType, IEnumerable<MemberInfo> members) { + if (targetType.IsVisible()) { + return members; + } else { + return FilterNonVisibleMembersIterator(targetType, members); + } + } + + public static IEnumerable<MemberInfo> FilterNonVisibleMembersIterator(Type targetType, IEnumerable<MemberInfo> members) { + foreach (var member in members) { + MemberInfo visible = TryGetVisibleMember(targetType, member); + if (visible != null) { + yield return visible; + } + } + } + + public static MemberInfo TryGetVisibleMember(Type targetType, MemberInfo member) { + MethodInfo method; + PropertyInfo property; + EventInfo evnt; + + MethodInfo mi; + MemberInfo visible = null; + + if ((method = member as MethodInfo) != null) { + mi = TryGetCallableMethod(targetType, method); + if (CompilerHelpers.IsVisible(mi)) { + visible = mi; + } + } else if ((property = member as PropertyInfo) != null) { + mi = TryGetCallableMethod(targetType, property.GetGetMethod() ?? property.GetSetMethod()); + if (CompilerHelpers.IsVisible(mi)) { + visible = mi.DeclaringType.GetDeclaredProperty(property.Name); + } + } else if ((evnt = member as EventInfo) != null) { + mi = TryGetCallableMethod(targetType, evnt.GetAddMethod() ?? evnt.GetRemoveMethod() ?? evnt.GetRaiseMethod()); + if (CompilerHelpers.IsVisible(mi)) { + visible = mi.DeclaringType.GetDeclaredEvent(evnt.Name); + } + } + + // all others can't be exposed out this way + return visible; + } + +#if !WIN8 + /// <summary> + /// Sees if two MemberInfos point to the same underlying construct in IL. This + /// ignores the ReflectedType property which exists on MemberInfos which + /// causes direct comparisons to be false even if they are the same member. + /// </summary> + public static bool MemberEquals(this MemberInfo self, MemberInfo other) { + if ((self == null) != (other == null)) { + // one null, the other isn't. + return false; + } else if (self == null) { + // both null + return true; + } + + if (self.MemberType != other.MemberType) { + return false; + } + + switch (self.MemberType) { + case MemberTypes.Field: + return ((FieldInfo)self).FieldHandle.Equals(((FieldInfo)other).FieldHandle); + case MemberTypes.Method: + return ((MethodInfo)self).MethodHandle.Equals(((MethodInfo)other).MethodHandle); + case MemberTypes.Constructor: + return ((ConstructorInfo)self).MethodHandle.Equals(((ConstructorInfo)other).MethodHandle); + case MemberTypes.NestedType: + case MemberTypes.TypeInfo: + return ((Type)self).TypeHandle.Equals(((Type)other).TypeHandle); + case MemberTypes.Event: + case MemberTypes.Property: + default: + return + ((MemberInfo)self).Module == ((MemberInfo)other).Module && + ((MemberInfo)self).MetadataToken == ((MemberInfo)other).MetadataToken; + } + } +#endif + + public static bool IsVisible(MethodBase info) { + return info.IsPublic && (info.DeclaringType == null || info.DeclaringType.IsVisible()); + } + + public static bool IsVisible(FieldInfo info) { + return info.IsPublic && (info.DeclaringType == null || info.DeclaringType.IsVisible()); + } + + public static bool IsProtected(this MethodBase info) { + return info.IsFamily || info.IsFamilyOrAssembly; + } + + public static bool IsProtected(this FieldInfo info) { + return info.IsFamily || info.IsFamilyOrAssembly; + } + + public static bool IsProtected(this Type type) { + return type.GetTypeInfo().IsNestedFamily || type.GetTypeInfo().IsNestedFamORAssem; + } + + public static Type GetVisibleType(object value) { + return GetVisibleType(GetType(value)); + } + + public static Type GetVisibleType(Type t) { + while (!t.IsVisible()) { + t = t.GetBaseType(); + } + return t; + } + + public static MethodBase[] GetConstructors(Type t, bool privateBinding) { + return GetConstructors(t, privateBinding, false); + } + + public static MethodBase[] GetConstructors(Type t, bool privateBinding, bool includeProtected) { + if (t.IsArray) { + // The JIT verifier doesn't like new int[](3) even though it appears as a ctor. + // We could do better and return newarr in the future. + return new MethodBase[] { GetArrayCtor(t) }; + } + + BindingFlags bf = BindingFlags.Instance | BindingFlags.Public; + if (privateBinding || includeProtected) { + bf |= BindingFlags.NonPublic; + } + + IEnumerable<ConstructorInfo> ctors = t.GetDeclaredConstructors().WithBindingFlags(bf); + + // leave in protected ctors, even if we're not in private binding mode. + if (!privateBinding && includeProtected) { + ctors = FilterConstructorsToPublicAndProtected(ctors); + } + + if (t.IsValueType() +#if !SILVERLIGHT && !WIN8 && !WP75 + && t != typeof(ArgIterator) +#endif +) { + // structs don't define a parameterless ctor, add a generic method for that. + List<MethodBase> result = new List<MethodBase>(); + result.Add(GetStructDefaultCtor(t)); + result.AddRange(ctors.Cast<ConstructorInfo, MethodBase>()); + return result.ToArray(); + } else { + return ctors.ToArray(); + } + } + + public static IEnumerable<ConstructorInfo> FilterConstructorsToPublicAndProtected(IEnumerable<ConstructorInfo> ctors) { + foreach (var ctor in ctors) { + if (ctor.IsPublic || ctor.IsProtected()) { + yield return ctor; + } + } + } + + private static MethodBase GetStructDefaultCtor(Type t) { + return typeof(ScriptingRuntimeHelpers).GetDeclaredMethods("CreateInstance").Single().MakeGenericMethod(t); + } + + private static MethodBase GetArrayCtor(Type t) { + return typeof(ScriptingRuntimeHelpers).GetDeclaredMethods("CreateArray").Single().MakeGenericMethod(t.GetElementType()); + } + + #region Type Conversions + + public static MethodInfo GetImplicitConverter(Type fromType, Type toType) { + return GetConverter(fromType, fromType, toType, "op_Implicit") ?? GetConverter(toType, fromType, toType, "op_Implicit"); + } + + public static MethodInfo GetExplicitConverter(Type fromType, Type toType) { + return GetConverter(fromType, fromType, toType, "op_Explicit") ?? GetConverter(toType, fromType, toType, "op_Explicit"); + } + + private static MethodInfo GetConverter(Type type, Type fromType, Type toType, string opMethodName) { + foreach (MethodInfo mi in type.GetInheritedMembers(opMethodName).WithBindingFlags(BindingFlags.Public | BindingFlags.Static)) { + if ((mi.DeclaringType == null || mi.DeclaringType.IsVisible()) && mi.IsPublic && + mi.ReturnType == toType && mi.GetParameters()[0].ParameterType.IsAssignableFrom(fromType)) { + return mi; + } + } + return null; + } + + public static bool TryImplicitConversion(Object value, Type to, out object result) { + if (CompilerHelpers.TryImplicitConvert(value, to, to.GetInheritedMethods("op_Implicit").WithBindingFlags(BindingFlags.Public | BindingFlags.Static), out result)) { + return true; + } + + Type curType = CompilerHelpers.GetType(value); + do { + if (CompilerHelpers.TryImplicitConvert(value, to, curType.GetInheritedMethods("op_Implicit").WithBindingFlags(BindingFlags.Public | BindingFlags.Static), out result)) { + return true; + } + curType = curType.GetBaseType(); + } while (curType != null); + + return false; + } + + private static bool TryImplicitConvert(Object value, Type to, IEnumerable<MethodInfo> implicitConv, out object result) { + foreach (MethodInfo mi in implicitConv) { + if (to.IsValueType() == mi.ReturnType.IsValueType() && to.IsAssignableFrom(mi.ReturnType)) { + if (mi.IsStatic) { + result = mi.Invoke(null, new object[] { value }); + } else { + result = mi.Invoke(value, ArrayUtils.EmptyObjects); + } + return true; + } + } + + result = null; + return false; + } + + public static bool IsStrongBox(object target) { + Type t = CompilerHelpers.GetType(target); + + return IsStrongBox(t); + } + + public static bool IsStrongBox(Type t) { + return t.IsGenericType() && t.GetGenericTypeDefinition() == typeof(StrongBox<>); + } + + /// <summary> + /// Returns a value which indicates failure when a OldConvertToAction of ImplicitTry or + /// ExplicitTry. + /// </summary> + public static Expression GetTryConvertReturnValue(Type type) { + Expression res; + var info = type.GetTypeInfo(); + if (info.IsInterface || info.IsClass || (info.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))) { + res = AstUtils.Constant(null, type); + } else { + res = AstUtils.Constant(Activator.CreateInstance(type)); + } + + return res; + } + + public static bool HasTypeConverter(Type fromType, Type toType) { +#if FEATURE_TYPECONVERTER + TypeConverter _; + return TryGetTypeConverter(fromType, toType, out _); +#else + return false; +#endif + } + + public static bool TryApplyTypeConverter(object value, Type toType, out object result) { +#if FEATURE_TYPECONVERTER + TypeConverter converter; + if (value != null && CompilerHelpers.TryGetTypeConverter(value.GetType(), toType, out converter)) { + result = converter.ConvertFrom(value); + return true; + } else { + result = value; + return false; + } +#else + result = value; + return false; +#endif + } + +#if FEATURE_TYPECONVERTER + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static bool TryGetTypeConverter(Type fromType, Type toType, out TypeConverter converter) { + ContractUtils.RequiresNotNull(fromType, "fromType"); + ContractUtils.RequiresNotNull(toType, "toType"); + + // try available type conversions... + foreach (TypeConverterAttribute tca in toType.GetCustomAttributes(typeof(TypeConverterAttribute), true)) { + try { + converter = Activator.CreateInstance(Type.GetType(tca.ConverterTypeName)) as TypeConverter; + } catch (Exception) { + converter = null; + } + + if (converter != null && converter.CanConvertFrom(fromType)) { + return true; + } + } + + converter = null; + return false; + } +#endif + + #endregion + +#if !MONO_INTERPRETER + public static MethodBase[] GetMethodTargets(object obj) { + Type t = CompilerHelpers.GetType(obj); + + if (typeof(Delegate).IsAssignableFrom(t)) { + MethodInfo mi = t.GetMethod("Invoke"); + return new MethodBase[] { mi }; + } else if (typeof(BoundMemberTracker).IsAssignableFrom(t)) { + BoundMemberTracker bmt = obj as BoundMemberTracker; + if (bmt.BoundTo.MemberType == TrackerTypes.Method) { + } + } else if (typeof(MethodGroup).IsAssignableFrom(t)) { + } else if (typeof(MemberGroup).IsAssignableFrom(t)) { + } else { + return MakeCallSignatureForCallableObject(t); + } + + return null; + } +#endif + + private static MethodBase[] MakeCallSignatureForCallableObject(Type t) { + List<MethodBase> res = new List<MethodBase>(); + foreach (MethodInfo method in t.GetInheritedMethods("Call")) { + if (method.IsSpecialName) { + res.Add(method); + } + } + return res.ToArray(); + } + + public static Type[] GetSiteTypes(IList<Expression> arguments, Type returnType) { + int count = arguments.Count; + + Type[] ret = new Type[count + 1]; + + for (int i = 0; i < count; i++) { + ret[i] = arguments[i].Type; + } + + ret[count] = returnType; + return ret; + } + + public static Type[] GetExpressionTypes(Expression[] expressions) { + ContractUtils.RequiresNotNull(expressions, "expressions"); + + Type[] res = new Type[expressions.Length]; + for (int i = 0; i < res.Length; i++) { + ContractUtils.RequiresNotNull(expressions[i], "expressions[i]"); + + res[i] = expressions[i].Type; + } + + return res; + } + + public static Type MakeCallSiteType(params Type[] types) { + return typeof(CallSite<>).MakeGenericType(DelegateHelpers.MakeDelegate(types)); + } + + public static Type MakeCallSiteDelegateType(Type[] types) { + return DelegateHelpers.MakeDelegate(types); + } + + /// <summary> + /// Creates an interpreted delegate for the lambda. + /// </summary> + /// <param name="lambda">The lambda to compile.</param> + /// <returns>A delegate which can interpret the lambda.</returns> + public static Delegate LightCompile(this LambdaExpression lambda) { + return new LightCompiler(-1).CompileTop(lambda).CreateDelegate(); + } + + /// <summary> + /// Creates an interpreted delegate for the lambda. + /// </summary> + /// <param name="lambda">The lambda to compile.</param> + /// <param name="compilationThreshold">The number of iterations before the interpreter starts compiling</param> + /// <returns>A delegate which can interpret the lambda.</returns> + public static Delegate LightCompile(this LambdaExpression lambda, int compilationThreshold) { + return new LightCompiler(compilationThreshold).CompileTop(lambda).CreateDelegate(); + } + + /// <summary> + /// Creates an interpreted delegate for the lambda. + /// </summary> + /// <typeparam name="T">The lambda's delegate type.</typeparam> + /// <param name="lambda">The lambda to compile.</param> + /// <returns>A delegate which can interpret the lambda.</returns> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static T LightCompile<T>(this Expression<T> lambda) { + return (T)(object)LightCompile((LambdaExpression)lambda); + } + + /// <summary> + /// Creates an interpreted delegate for the lambda. + /// </summary> + /// <param name="lambda">The lambda to compile.</param> + /// <param name="compilationThreshold">The number of iterations before the interpreter starts compiling</param> + /// <returns>A delegate which can interpret the lambda.</returns> + public static T LightCompile<T>(this Expression<T> lambda, int compilationThreshold) { + return (T)(object)LightCompile((LambdaExpression)lambda, compilationThreshold); + } + +#if FEATURE_REFEMIT + /// <summary> + /// Compiles the lambda into a method definition. + /// </summary> + /// <param name="lambda">the lambda to compile</param> + /// <param name="method">A <see cref="MethodBuilder"/> which will be used to hold the lambda's IL.</param> + /// <param name="emitDebugSymbols">A parameter that indicates if debugging information should be emitted to a PDB symbol store.</param> + public static void CompileToMethod(this LambdaExpression lambda, MethodBuilder method, bool emitDebugSymbols) { +#if FEATURE_PDBEMIT + if (emitDebugSymbols) { + var module = method.Module as ModuleBuilder; + ContractUtils.Requires(module != null, "method", "MethodBuilder does not have a valid ModuleBuilder"); + lambda.CompileToMethod(method, DebugInfoGenerator.CreatePdbGenerator()); + return; + } +#endif + +#if WIN8 // TODO + ((dynamic)lambda).CompileToMethod(method); +#else + lambda.CompileToMethod(method); +#endif + } +#endif + + /// <summary> + /// Compiles the LambdaExpression. + /// + /// If the lambda is compiled with emitDebugSymbols, it will be + /// generated into a TypeBuilder. Otherwise, this method is the same as + /// calling LambdaExpression.Compile() + /// + /// This is a workaround for a CLR limitiation: DynamicMethods cannot + /// have debugging information. + /// </summary> + /// <param name="lambda">the lambda to compile</param> + /// <param name="emitDebugSymbols">true to generate a debuggable method, false otherwise</param> + /// <returns>the compiled delegate</returns> + public static T Compile<T>(this Expression<T> lambda, bool emitDebugSymbols) { +#if FEATURE_PDBEMIT && FEATURE_REFEMIT + if (emitDebugSymbols) { + return CompileToMethod(lambda, DebugInfoGenerator.CreatePdbGenerator(), true); + } +#endif + return lambda.Compile(); + } + +#if FEATURE_REFEMIT + /// <summary> + /// Compiles the LambdaExpression, emitting it into a new type, and + /// optionally making it debuggable. + /// + /// This is a workaround for a CLR limitiation: DynamicMethods cannot + /// have debugging information. + /// </summary> + /// <param name="lambda">the lambda to compile</param> + /// <param name="debugInfoGenerator">Debugging information generator used by the compiler to mark sequence points and annotate local variables.</param> + /// <param name="emitDebugSymbols">True if debug symbols (PDBs) are emitted by the <paramref name="debugInfoGenerator"/>.</param> + /// <returns>the compiled delegate</returns> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static T CompileToMethod<T>(Expression<T> lambda, DebugInfoGenerator debugInfoGenerator, bool emitDebugSymbols) { + return (T)(object)CompileToMethod((LambdaExpression)lambda, debugInfoGenerator, emitDebugSymbols); + } + + public static Delegate CompileToMethod(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator, bool emitDebugSymbols) { + string methodName = String.IsNullOrEmpty(lambda.Name) ? GetUniqueMethodName() : lambda.Name; + + var type = Snippets.Shared.DefineType(methodName, typeof(object), false, emitDebugSymbols).TypeBuilder; + var rewriter = new DebuggableCodeRewriter(type); + lambda = (LambdaExpression)rewriter.Visit(lambda); + + //Create a unique method name when the lambda doesn't have a name or the name is empty. + var method = type.DefineMethod(methodName, CompilerHelpers.PublicStatic); + + lambda.CompileToMethod(method, debugInfoGenerator); + var finished = type.CreateType(); + + rewriter.InitializeFields(finished); + + return finished.GetMethod(method.Name).CreateDelegate(lambda.Type); + } + + /// <summary> + /// Removes all live objects and places them in static fields of a type. + /// </summary> + private sealed class DebuggableCodeRewriter : DynamicExpressionVisitor { + private readonly Dictionary<object, FieldBuilder> _fields = new Dictionary<object, FieldBuilder>(ReferenceEqualityComparer<object>.Instance); + private readonly TypeBuilder _type; + private readonly HashSet<string> _methodNames = new HashSet<string>(); + + internal DebuggableCodeRewriter(TypeBuilder type) { + _type = type; + } + + internal void InitializeFields(Type type) { + foreach (var pair in _fields) { + type.GetInheritedFields(pair.Value.Name).First().SetValue(null, pair.Key); + } + } + + protected override Expression VisitLambda<T>(Expression<T> node) { + if (_methodNames.Contains(node.Name)) { + int count = _methodNames.Count; + + string newName; + do { + newName = node.Name + "$" + count++; + } while (_methodNames.Contains(newName)); + + _methodNames.Add(newName); + return Expression.Lambda<T>( + base.Visit(node.Body), + newName, + node.TailCall, + node.Parameters + ); + } else { + _methodNames.Add(node.Name); + return base.VisitLambda<T>(node); + } + } + + protected override Expression VisitExtension(Expression node) { + // LightDynamicExpressions override Visit but we want to really reduce them + // because they reduce to DynamicExpressions. + LightDynamicExpression lightDyn = node as LightDynamicExpression; + if (lightDyn != null) { + return Visit(lightDyn.Reduce()); + } + + return Visit(node.Reduce()); + } + + protected override Expression VisitConstant(ConstantExpression node) { + if (CanEmitConstant(node.Value, node.Type)) { + return node; + } + + FieldBuilder field; + if (!_fields.TryGetValue(node.Value, out field)) { + field = _type.DefineField( + "$constant" + _fields.Count, + GetVisibleType(node.Value.GetType()), + FieldAttributes.Public | FieldAttributes.Static + ); + _fields.Add(node.Value, field); + } + + Expression result = Expression.Field(null, field); + if (result.Type != node.Type) { + result = Expression.Convert(result, node.Type); + } + return result; + } + + protected override Expression VisitDynamic(DynamicExpression node) { + return Visit(Reduce(node)); + } + } +#endif + + public static string GetUniqueMethodName() { + return "lambda_method" + "$" + System.Threading.Interlocked.Increment(ref _Counter); + } + +#if FEATURE_LCG + // Matches ILGen.TryEmitConstant + public static bool CanEmitConstant(object value, Type type) { + if (value == null || CanEmitILConstant(type)) { + return true; + } + + Type t = value as Type; + if (t != null && ILGen.ShouldLdtoken(t)) { + return true; + } + + MethodBase mb = value as MethodBase; + if (mb != null && ILGen.ShouldLdtoken(mb)) { + return true; + } + + return false; + } + + // Matches ILGen.TryEmitILConstant + internal static bool CanEmitILConstant(Type type) { + switch (type.GetTypeCode()) { + case TypeCode.Boolean: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Char: + case TypeCode.Byte: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + case TypeCode.Decimal: + case TypeCode.String: + return true; + } + return false; + } +#endif + + /// <summary> + /// Reduces the provided DynamicExpression into site.Target(site, *args). + /// </summary> + public static Expression Reduce(DynamicExpression node) { + // Store the callsite as a constant + var siteConstant = AstUtils.Constant(CallSite.Create(node.DelegateType, node.Binder)); + + // ($site = siteExpr).Target.Invoke($site, *args) + var site = Expression.Variable(siteConstant.Type, "$site"); + return Expression.Block( + new[] { site }, + Expression.Call( + Expression.Field( + Expression.Assign(site, siteConstant), + siteConstant.Type.GetDeclaredField("Target") + ), + node.DelegateType.GetMethod("Invoke"), + ArrayUtils.Insert(site, node.Arguments) + ) + ); + } + + #region Factories +#if !FEATURE_NUMERICS + [CLSCompliant(false)] + public static BigInteger CreateBigInteger(int sign, uint[] data) { + return new BigInteger(sign, data); + } +#else + public static BigInteger CreateBigInteger(bool isNegative, byte[] data) { + return new BigInteger(CreateBigInt(isNegative, data)); + } + + public static BigInt CreateBigInt(int value) { + return (BigInt)value; + } + + public static BigInt CreateBigInt(long value) { + return (BigInt)value; + } + + public static BigInt CreateBigInt(bool isNegative, byte[] data) { + BigInt res = new BigInt(data); + return isNegative ? -res : res; + } + +#endif + #endregion + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/ConstantCheck.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/ConstantCheck.cs new file mode 100644 index 00000000000..89cbbfe91cc --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/ConstantCheck.cs @@ -0,0 +1,128 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System.Diagnostics; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Generation { + + public static class ConstantCheck { + + /// <summary> + /// Tests to see if the expression is a constant with the given value. + /// </summary> + /// <param name="expression">The expression to examine</param> + /// <param name="value">The constant value to check for.</param> + /// <returns>true/false</returns> + public static bool Check(Expression expression, object value) { + ContractUtils.RequiresNotNull(expression, "expression"); + return IsConstant(expression, value); + } + + + /// <summary> + /// Tests to see if the expression is a constant with the given value. + /// </summary> + /// <param name="e">The expression to examine</param> + /// <param name="value">The constant value to check for.</param> + /// <returns>true/false</returns> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] + internal static bool IsConstant(Expression e, object value) { + switch (e.NodeType) { + case ExpressionType.AndAlso: + return CheckAndAlso((BinaryExpression)e, value); + + case ExpressionType.OrElse: + return CheckOrElse((BinaryExpression)e, value); + + case ExpressionType.Constant: + return CheckConstant((ConstantExpression)e, value); + + case ExpressionType.TypeIs: + return Check((TypeBinaryExpression)e, value); + + default: + return false; + } + } + + //CONFORMING + internal static bool IsNull(Expression e) { + return IsConstant(e, null); + } + + + private static bool CheckAndAlso(BinaryExpression node, object value) { + Debug.Assert(node.NodeType == ExpressionType.AndAlso); + + if (node.Method != null) { + return false; + } + //TODO: we can propagate through conversion, but it may not worth it. + if (node.Conversion != null) { + return false; + } + + if (value is bool) { + if ((bool)value) { + return IsConstant(node.Left, true) && IsConstant(node.Right, true); + } else { + // if left isn't a constant it has to be evaluated + return IsConstant(node.Left, false); + } + } + return false; + } + + private static bool CheckOrElse(BinaryExpression node, object value) { + Debug.Assert(node.NodeType == ExpressionType.OrElse); + + if (node.Method != null) { + return false; + } + + if (value is bool) { + if ((bool)value) { + return IsConstant(node.Left, true); + } else { + return IsConstant(node.Left, false) && IsConstant(node.Right, false); + } + } + return false; + } + + private static bool CheckConstant(ConstantExpression node, object value) { + if (value == null) { + return node.Value == null; + } else { + return value.Equals(node.Value); + } + } + + private static bool Check(TypeBinaryExpression node, object value) { + // allow constant TypeIs expressions to be optimized away + if (value is bool && ((bool)value) == true) { + return node.TypeOperand.IsAssignableFrom(node.Expression.Type); + } + return false; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/DelegateHelpers.Generated.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/DelegateHelpers.Generated.cs new file mode 100644 index 00000000000..2b5bd93d0fa --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/DelegateHelpers.Generated.cs @@ -0,0 +1,110 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Linq; +using System.Diagnostics; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Generation { + internal static partial class DelegateHelpers { + + #region Generated Maximum Delegate Arity + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_max_delegate_arity from: generate_dynsites.py + + private const int MaximumArity = 17; + + // *** END GENERATED CODE *** + + #endregion + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] + internal static Type MakeDelegate(Type[] types) { + Debug.Assert(types != null && types.Length > 0); + + // Can only used predefined delegates if we have no byref types and + // the arity is small enough to fit in Func<...> or Action<...> + if (types.Length > MaximumArity || types.Any(t => t.IsByRef)) { + return MakeCustomDelegate(types); + } + + Type returnType = types[types.Length - 1]; + if (returnType == typeof(void)) { + types = types.RemoveLast(); + switch (types.Length) { + case 0: return typeof(Action); + #region Generated Delegate Action Types + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_delegate_action from: generate_dynsites.py + + case 1: return typeof(Action<>).MakeGenericType(types); + case 2: return typeof(Action<,>).MakeGenericType(types); + case 3: return typeof(Action<,,>).MakeGenericType(types); + case 4: return typeof(Action<,,,>).MakeGenericType(types); + case 5: return typeof(Action<,,,,>).MakeGenericType(types); + case 6: return typeof(Action<,,,,,>).MakeGenericType(types); + case 7: return typeof(Action<,,,,,,>).MakeGenericType(types); + case 8: return typeof(Action<,,,,,,,>).MakeGenericType(types); + case 9: return typeof(Action<,,,,,,,,>).MakeGenericType(types); + case 10: return typeof(Action<,,,,,,,,,>).MakeGenericType(types); + case 11: return typeof(Action<,,,,,,,,,,>).MakeGenericType(types); + case 12: return typeof(Action<,,,,,,,,,,,>).MakeGenericType(types); + case 13: return typeof(Action<,,,,,,,,,,,,>).MakeGenericType(types); + case 14: return typeof(Action<,,,,,,,,,,,,,>).MakeGenericType(types); + case 15: return typeof(Action<,,,,,,,,,,,,,,>).MakeGenericType(types); + case 16: return typeof(Action<,,,,,,,,,,,,,,,>).MakeGenericType(types); + + // *** END GENERATED CODE *** + + #endregion + } + } else { + switch (types.Length) { + #region Generated Delegate Func Types + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_delegate_func from: generate_dynsites.py + + case 1: return typeof(Func<>).MakeGenericType(types); + case 2: return typeof(Func<,>).MakeGenericType(types); + case 3: return typeof(Func<,,>).MakeGenericType(types); + case 4: return typeof(Func<,,,>).MakeGenericType(types); + case 5: return typeof(Func<,,,,>).MakeGenericType(types); + case 6: return typeof(Func<,,,,,>).MakeGenericType(types); + case 7: return typeof(Func<,,,,,,>).MakeGenericType(types); + case 8: return typeof(Func<,,,,,,,>).MakeGenericType(types); + case 9: return typeof(Func<,,,,,,,,>).MakeGenericType(types); + case 10: return typeof(Func<,,,,,,,,,>).MakeGenericType(types); + case 11: return typeof(Func<,,,,,,,,,,>).MakeGenericType(types); + case 12: return typeof(Func<,,,,,,,,,,,>).MakeGenericType(types); + case 13: return typeof(Func<,,,,,,,,,,,,>).MakeGenericType(types); + case 14: return typeof(Func<,,,,,,,,,,,,,>).MakeGenericType(types); + case 15: return typeof(Func<,,,,,,,,,,,,,,>).MakeGenericType(types); + case 16: return typeof(Func<,,,,,,,,,,,,,,,>).MakeGenericType(types); + case 17: return typeof(Func<,,,,,,,,,,,,,,,,>).MakeGenericType(types); + + // *** END GENERATED CODE *** + + #endregion + } + } + throw Assert.Unreachable; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/DelegateHelpers.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/DelegateHelpers.cs new file mode 100644 index 00000000000..b2ef101c769 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Generation/DelegateHelpers.cs @@ -0,0 +1,87 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Reflection; +#if FEATURE_REFEMIT +using System.Reflection.Emit; +#endif +using System.Threading; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Generation { + internal static partial class DelegateHelpers { + + private static Dictionary<ICollection<Type>, Type> _DelegateTypes; + + private static Type MakeCustomDelegate(Type[] types) { + if (_DelegateTypes == null) { + Interlocked.CompareExchange( + ref _DelegateTypes, + new Dictionary<ICollection<Type>, Type>(ListEqualityComparer<Type>.Instance), + null + ); + } + + bool found; + Type type; + + // + // LOCK to retrieve the delegate type, if any + // + + lock (_DelegateTypes) { + found = _DelegateTypes.TryGetValue(types, out type); + } + + if (!found && type != null) { + return type; + } + + // + // Create new delegate type + // + + type = MakeNewCustomDelegate(types); + + // + // LOCK to insert new delegate into the cache. If we already have one (racing threads), use the one from the cache + // + + lock (_DelegateTypes) { + Type conflict; + if (_DelegateTypes.TryGetValue(types, out conflict) && conflict != null) { + type = conflict; + } else { + _DelegateTypes[types] = type; + } + } + + return type; + } + + private static Type MakeNewCustomDelegate(Type[] types) { +#if FEATURE_REFEMIT + Type returnType = types[types.Length - 1]; + Type[] parameters = types.RemoveLast(); + + return Snippets.Shared.DefineDelegate("Delegate" + types.Length, returnType, parameters); +#else + throw new NotSupportedException("Signature not supported on this platform"); +#endif + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/BranchLabel.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/BranchLabel.cs new file mode 100644 index 00000000000..de0b6db37c4 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/BranchLabel.cs @@ -0,0 +1,108 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Diagnostics; +using System.Collections.Generic; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal struct RuntimeLabel { + public readonly int Index; + public readonly int StackDepth; + public readonly int ContinuationStackDepth; + + public RuntimeLabel(int index, int continuationStackDepth, int stackDepth) { + Index = index; + ContinuationStackDepth = continuationStackDepth; + StackDepth = stackDepth; + } + + public override string ToString() { + return String.Format("->{0} C({1}) S({2})", Index, ContinuationStackDepth, StackDepth); + } + } + + public sealed class BranchLabel { + internal const int UnknownIndex = Int32.MinValue; + internal const int UnknownDepth = Int32.MinValue; + + internal int _labelIndex = UnknownIndex; + internal int _targetIndex = UnknownIndex; + internal int _stackDepth = UnknownDepth; + internal int _continuationStackDepth = UnknownDepth; + + // Offsets of forward branching instructions targetting this label + // that need to be updated after we emit the label. + private List<int> _forwardBranchFixups; + + public BranchLabel() { + } + + internal int LabelIndex { + get { return _labelIndex; } + set { _labelIndex = value; } + } + + internal bool HasRuntimeLabel { + get { return _labelIndex != UnknownIndex; } + } + + internal int TargetIndex { + get { return _targetIndex; } + } + + internal RuntimeLabel ToRuntimeLabel() { + Debug.Assert(_targetIndex != UnknownIndex && _stackDepth != UnknownDepth && _continuationStackDepth != UnknownDepth); + return new RuntimeLabel(_targetIndex, _continuationStackDepth, _stackDepth); + } + + internal void Mark(InstructionList instructions) { + ContractUtils.Requires(_targetIndex == UnknownIndex && _stackDepth == UnknownDepth && _continuationStackDepth == UnknownDepth); + + _stackDepth = instructions.CurrentStackDepth; + _continuationStackDepth = instructions.CurrentContinuationsDepth; + _targetIndex = instructions.Count; + + if (_forwardBranchFixups != null) { + foreach (var branchIndex in _forwardBranchFixups) { + FixupBranch(instructions, branchIndex); + } + _forwardBranchFixups = null; + } + } + + internal void AddBranch(InstructionList instructions, int branchIndex) { + Debug.Assert(((_targetIndex == UnknownIndex) == (_stackDepth == UnknownDepth))); + Debug.Assert(((_targetIndex == UnknownIndex) == (_continuationStackDepth == UnknownDepth))); + + if (_targetIndex == UnknownIndex) { + if (_forwardBranchFixups == null) { + _forwardBranchFixups = new List<int>(); + } + _forwardBranchFixups.Add(branchIndex); + } else { + FixupBranch(instructions, branchIndex); + } + } + + internal void FixupBranch(InstructionList instructions, int branchIndex) { + Debug.Assert(_targetIndex != UnknownIndex); + instructions.FixupBranch(branchIndex, _targetIndex - branchIndex); + } + } + + +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/ILightCallSiteBinder.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/ILightCallSiteBinder.cs new file mode 100644 index 00000000000..8535961f86b --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/ILightCallSiteBinder.cs @@ -0,0 +1,34 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; +using System.Reflection; +using Microsoft.Scripting.Interpreter; +using System.Runtime.CompilerServices; +using System.Collections.Generic; + +namespace Microsoft.Scripting.Interpreter { + public interface ILightCallSiteBinder { + bool AcceptsArgumentArray { get; } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/AddInstruction.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/AddInstruction.cs new file mode 100644 index 00000000000..c6b7eb8d829 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/AddInstruction.cs @@ -0,0 +1,243 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Diagnostics; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal abstract class AddInstruction : Instruction { + private static Instruction _Int16, _Int32, _Int64, _UInt16, _UInt32, _UInt64, _Single, _Double; + + public override int ConsumedStack { get { return 2; } } + public override int ProducedStack { get { return 1; } } + + private AddInstruction() { + } + + internal sealed class AddInt32 : AddInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = ScriptingRuntimeHelpers.Int32ToObject(unchecked((Int32)l + (Int32)r)); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddInt16 : AddInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Int16)unchecked((Int16)l + (Int16)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddInt64 : AddInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Int64)unchecked((Int64)l + (Int64)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddUInt16 : AddInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (UInt16)unchecked((UInt16)l + (UInt16)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddUInt32 : AddInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (UInt32)unchecked((UInt32)l + (UInt32)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddUInt64 : AddInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (UInt64)unchecked((Int16)l + (Int16)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddSingle : AddInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Single)((Single)l + (Single)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddDouble : AddInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Double)l + (Double)r; + frame.StackIndex--; + return +1; + } + } + + public static Instruction Create(Type type) { + Debug.Assert(!type.IsEnum()); + switch (type.GetTypeCode()) { + case TypeCode.Int16: return _Int16 ?? (_Int16 = new AddInt16()); + case TypeCode.Int32: return _Int32 ?? (_Int32 = new AddInt32()); + case TypeCode.Int64: return _Int64 ?? (_Int64 = new AddInt64()); + case TypeCode.UInt16: return _UInt16 ?? (_UInt16 = new AddUInt16()); + case TypeCode.UInt32: return _UInt32 ?? (_UInt32 = new AddUInt32()); + case TypeCode.UInt64: return _UInt64 ?? (_UInt64 = new AddUInt64()); + case TypeCode.Single: return _Single ?? (_Single = new AddSingle()); + case TypeCode.Double: return _Double ?? (_Double = new AddDouble()); + + default: + throw Assert.Unreachable; + } + } + + public override string ToString() { + return "Add()"; + } + } + + internal abstract class AddOvfInstruction : Instruction { + private static Instruction _Int16, _Int32, _Int64, _UInt16, _UInt32, _UInt64, _Single, _Double; + + public override int ConsumedStack { get { return 2; } } + public override int ProducedStack { get { return 1; } } + + private AddOvfInstruction() { + } + + internal sealed class AddOvfInt32 : AddOvfInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = ScriptingRuntimeHelpers.Int32ToObject(checked((Int32)l + (Int32)r)); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddOvfInt16 : AddOvfInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Int16)checked((Int16)l + (Int16)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddOvfInt64 : AddOvfInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Int64)checked((Int64)l + (Int64)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddOvfUInt16 : AddOvfInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (UInt16)checked((UInt16)l + (UInt16)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddOvfUInt32 : AddOvfInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (UInt32)checked((UInt32)l + (UInt32)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddOvfUInt64 : AddOvfInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (UInt64)checked((Int16)l + (Int16)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddOvfSingle : AddOvfInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Single)((Single)l + (Single)r); + frame.StackIndex--; + return +1; + } + } + + internal sealed class AddOvfDouble : AddOvfInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Double)l + (Double)r; + frame.StackIndex--; + return +1; + } + } + + public static Instruction Create(Type type) { + Debug.Assert(!type.IsEnum()); + switch (type.GetTypeCode()) { + case TypeCode.Int16: return _Int16 ?? (_Int16 = new AddOvfInt16()); + case TypeCode.Int32: return _Int32 ?? (_Int32 = new AddOvfInt32()); + case TypeCode.Int64: return _Int64 ?? (_Int64 = new AddOvfInt64()); + case TypeCode.UInt16: return _UInt16 ?? (_UInt16 = new AddOvfUInt16()); + case TypeCode.UInt32: return _UInt32 ?? (_UInt32 = new AddOvfUInt32()); + case TypeCode.UInt64: return _UInt64 ?? (_UInt64 = new AddOvfUInt64()); + case TypeCode.Single: return _Single ?? (_Single = new AddOvfSingle()); + case TypeCode.Double: return _Double ?? (_Double = new AddOvfDouble()); + + default: + throw Assert.Unreachable; + } + } + + public override string ToString() { + return "AddOvf()"; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/ArrayOperations.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/ArrayOperations.cs new file mode 100644 index 00000000000..0c5a9e16a7b --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/ArrayOperations.cs @@ -0,0 +1,111 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; + +namespace Microsoft.Scripting.Interpreter { + public sealed class NewArrayInitInstruction<TElement> : Instruction { + private readonly int _elementCount; + + internal NewArrayInitInstruction(int elementCount) { + _elementCount = elementCount; + } + + public override int ConsumedStack { get { return _elementCount; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + TElement[] array = new TElement[_elementCount]; + for (int i = _elementCount - 1; i >= 0; i--) { + array[i] = (TElement)frame.Pop(); + } + frame.Push(array); + return +1; + } + } + + public sealed class NewArrayInstruction<TElement> : Instruction { + internal NewArrayInstruction() { } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + int length = (int)frame.Pop(); + frame.Push(new TElement[length]); + return +1; + } + } + + public sealed class NewArrayBoundsInstruction : Instruction { + private readonly Type _elementType; + private readonly int _rank; + + internal NewArrayBoundsInstruction(Type elementType, int rank) { + _elementType = elementType; + _rank = rank; + } + + public override int ConsumedStack { get { return _rank; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + var lengths = new int[_rank]; + for (int i = _rank - 1; i >= 0; i--) { + lengths[i] = (int)frame.Pop(); + } + var array = Array.CreateInstance(_elementType, lengths); + frame.Push(array); + return +1; + } + } + + public sealed class GetArrayItemInstruction<TElement> : Instruction { + internal GetArrayItemInstruction() { } + + public override int ConsumedStack { get { return 2; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + int index = (int)frame.Pop(); + TElement[] array = (TElement[])frame.Pop(); + frame.Push(array[index]); + return +1; + } + + public override string InstructionName { + get { return "GetArrayItem"; } + } + } + + public sealed class SetArrayItemInstruction<TElement> : Instruction { + internal SetArrayItemInstruction() { } + + public override int ConsumedStack { get { return 3; } } + public override int ProducedStack { get { return 0; } } + + public override int Run(InterpretedFrame frame) { + TElement value = (TElement)frame.Pop(); + int index = (int)frame.Pop(); + TElement[] array = (TElement[])frame.Pop(); + array[index] = value; + return +1; + } + + public override string InstructionName { + get { return "SetArrayItem"; } + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/CallInstruction.Generated.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/CallInstruction.Generated.cs new file mode 100644 index 00000000000..19163eedc6e --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/CallInstruction.Generated.cs @@ -0,0 +1,905 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Threading; +using Microsoft.Scripting.Utils; +using Microsoft.Scripting.Generation; +using Microsoft.Scripting.Runtime; + +using System.Dynamic; + +namespace Microsoft.Scripting.Interpreter { + #region Generated Reflected Caller + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_all from: generate_reflected_calls.py + + public partial class CallInstruction { + private const int MaxHelpers = 10; + private const int MaxArgs = 3; + + public virtual object InvokeInstance(object instance, params object[] args) { + switch(args.Length) { + case 0: return Invoke(instance); + case 1: return Invoke(instance, args[0]); + case 2: return Invoke(instance, args[0], args[1]); + case 3: return Invoke(instance, args[0], args[1], args[2]); + case 4: return Invoke(instance, args[0], args[1], args[2], args[3]); + case 5: return Invoke(instance, args[0], args[1], args[2], args[3], args[4]); + case 6: return Invoke(instance, args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: return Invoke(instance, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + case 8: return Invoke(instance, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); + default: throw new InvalidOperationException(); + } + } + + public virtual object Invoke(params object[] args) { + switch(args.Length) { + case 0: return Invoke(); + case 1: return Invoke(args[0]); + case 2: return Invoke(args[0], args[1]); + case 3: return Invoke(args[0], args[1], args[2]); + case 4: return Invoke(args[0], args[1], args[2], args[3]); + case 5: return Invoke(args[0], args[1], args[2], args[3], args[4]); + case 6: return Invoke(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: return Invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + case 8: return Invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); + case 9: return Invoke(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); + default: throw new InvalidOperationException(); + } + } + + public virtual object Invoke() { throw new InvalidOperationException(); } + public virtual object Invoke(object arg0) { throw new InvalidOperationException(); } + public virtual object Invoke(object arg0, object arg1) { throw new InvalidOperationException(); } + public virtual object Invoke(object arg0, object arg1, object arg2) { throw new InvalidOperationException(); } + public virtual object Invoke(object arg0, object arg1, object arg2, object arg3) { throw new InvalidOperationException(); } + public virtual object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4) { throw new InvalidOperationException(); } + public virtual object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5) { throw new InvalidOperationException(); } + public virtual object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6) { throw new InvalidOperationException(); } + public virtual object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7) { throw new InvalidOperationException(); } + public virtual object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8) { throw new InvalidOperationException(); } + + /// <summary> + /// Fast creation works if we have a known primitive types for the entire + /// method siganture. If we have any non-primitive types then FastCreate + /// falls back to SlowCreate which works for all types. + /// + /// Fast creation is fast because it avoids using reflection (MakeGenericType + /// and Activator.CreateInstance) to create the types. It does this through + /// calling a series of generic methods picking up each strong type of the + /// signature along the way. When it runs out of types it news up the + /// appropriate CallInstruction with the strong-types that have been built up. + /// + /// One relaxation is that for return types which are non-primitive types + /// we can fallback to object due to relaxed delegates. + /// </summary> + private static CallInstruction FastCreate(MethodInfo target, ParameterInfo[] pi) { + Type t = TryGetParameterOrReturnType(target, pi, 0); + if (t == null) { + return new ActionCallInstruction(target); + } + + if (t.IsEnum()) return SlowCreate(target, pi); + switch (t.GetTypeCode()) { + case TypeCode.Object: { + if (t != typeof(object) && (IndexIsNotReturnType(0, target, pi) || t.IsValueType())) { + // if we're on the return type relaxed delegates makes it ok to use object + goto default; + } + return FastCreate<Object>(target, pi); + } + case TypeCode.Int16: return FastCreate<Int16>(target, pi); + case TypeCode.Int32: return FastCreate<Int32>(target, pi); + case TypeCode.Int64: return FastCreate<Int64>(target, pi); + case TypeCode.Boolean: return FastCreate<Boolean>(target, pi); + case TypeCode.Char: return FastCreate<Char>(target, pi); + case TypeCode.Byte: return FastCreate<Byte>(target, pi); + case TypeCode.Decimal: return FastCreate<Decimal>(target, pi); + case TypeCode.DateTime: return FastCreate<DateTime>(target, pi); + case TypeCode.Double: return FastCreate<Double>(target, pi); + case TypeCode.Single: return FastCreate<Single>(target, pi); + case TypeCode.UInt16: return FastCreate<UInt16>(target, pi); + case TypeCode.UInt32: return FastCreate<UInt32>(target, pi); + case TypeCode.UInt64: return FastCreate<UInt64>(target, pi); + case TypeCode.String: return FastCreate<String>(target, pi); + case TypeCode.SByte: return FastCreate<SByte>(target, pi); + default: return SlowCreate(target, pi); + } + } + + private static CallInstruction FastCreate<T0>(MethodInfo target, ParameterInfo[] pi) { + Type t = TryGetParameterOrReturnType(target, pi, 1); + if (t == null) { + if (target.ReturnType == typeof(void)) { + return new ActionCallInstruction<T0>(target); + } + return new FuncCallInstruction<T0>(target); + } + + if (t.IsEnum()) return SlowCreate(target, pi); + switch (t.GetTypeCode()) { + case TypeCode.Object: { + if (t != typeof(object) && (IndexIsNotReturnType(1, target, pi) || t.IsValueType())) { + // if we're on the return type relaxed delegates makes it ok to use object + goto default; + } + return FastCreate<T0, Object>(target, pi); + } + case TypeCode.Int16: return FastCreate<T0, Int16>(target, pi); + case TypeCode.Int32: return FastCreate<T0, Int32>(target, pi); + case TypeCode.Int64: return FastCreate<T0, Int64>(target, pi); + case TypeCode.Boolean: return FastCreate<T0, Boolean>(target, pi); + case TypeCode.Char: return FastCreate<T0, Char>(target, pi); + case TypeCode.Byte: return FastCreate<T0, Byte>(target, pi); + case TypeCode.Decimal: return FastCreate<T0, Decimal>(target, pi); + case TypeCode.DateTime: return FastCreate<T0, DateTime>(target, pi); + case TypeCode.Double: return FastCreate<T0, Double>(target, pi); + case TypeCode.Single: return FastCreate<T0, Single>(target, pi); + case TypeCode.UInt16: return FastCreate<T0, UInt16>(target, pi); + case TypeCode.UInt32: return FastCreate<T0, UInt32>(target, pi); + case TypeCode.UInt64: return FastCreate<T0, UInt64>(target, pi); + case TypeCode.String: return FastCreate<T0, String>(target, pi); + case TypeCode.SByte: return FastCreate<T0, SByte>(target, pi); + default: return SlowCreate(target, pi); + } + } + + private static CallInstruction FastCreate<T0, T1>(MethodInfo target, ParameterInfo[] pi) { + Type t = TryGetParameterOrReturnType(target, pi, 2); + if (t == null) { + if (target.ReturnType == typeof(void)) { + return new ActionCallInstruction<T0, T1>(target); + } + return new FuncCallInstruction<T0, T1>(target); + } + + if (t.IsEnum()) return SlowCreate(target, pi); + switch (t.GetTypeCode()) { + case TypeCode.Object: { + Debug.Assert(pi.Length == 2); + if (t.IsValueType()) goto default; + + return new FuncCallInstruction<T0, T1, Object>(target); + } + case TypeCode.Int16: return new FuncCallInstruction<T0, T1, Int16>(target); + case TypeCode.Int32: return new FuncCallInstruction<T0, T1, Int32>(target); + case TypeCode.Int64: return new FuncCallInstruction<T0, T1, Int64>(target); + case TypeCode.Boolean: return new FuncCallInstruction<T0, T1, Boolean>(target); + case TypeCode.Char: return new FuncCallInstruction<T0, T1, Char>(target); + case TypeCode.Byte: return new FuncCallInstruction<T0, T1, Byte>(target); + case TypeCode.Decimal: return new FuncCallInstruction<T0, T1, Decimal>(target); + case TypeCode.DateTime: return new FuncCallInstruction<T0, T1, DateTime>(target); + case TypeCode.Double: return new FuncCallInstruction<T0, T1, Double>(target); + case TypeCode.Single: return new FuncCallInstruction<T0, T1, Single>(target); + case TypeCode.UInt16: return new FuncCallInstruction<T0, T1, UInt16>(target); + case TypeCode.UInt32: return new FuncCallInstruction<T0, T1, UInt32>(target); + case TypeCode.UInt64: return new FuncCallInstruction<T0, T1, UInt64>(target); + case TypeCode.String: return new FuncCallInstruction<T0, T1, String>(target); + case TypeCode.SByte: return new FuncCallInstruction<T0, T1, SByte>(target); + default: return SlowCreate(target, pi); + } + } + + private static Type GetHelperType(MethodInfo info, Type[] arrTypes) { + Type t; + if (info.ReturnType == typeof(void)) { + switch (arrTypes.Length) { + case 0: t = typeof(ActionCallInstruction); break; + case 1: t = typeof(ActionCallInstruction<>).MakeGenericType(arrTypes); break; + case 2: t = typeof(ActionCallInstruction<,>).MakeGenericType(arrTypes); break; + case 3: t = typeof(ActionCallInstruction<,,>).MakeGenericType(arrTypes); break; + case 4: t = typeof(ActionCallInstruction<,,,>).MakeGenericType(arrTypes); break; + case 5: t = typeof(ActionCallInstruction<,,,,>).MakeGenericType(arrTypes); break; + case 6: t = typeof(ActionCallInstruction<,,,,,>).MakeGenericType(arrTypes); break; + case 7: t = typeof(ActionCallInstruction<,,,,,,>).MakeGenericType(arrTypes); break; + case 8: t = typeof(ActionCallInstruction<,,,,,,,>).MakeGenericType(arrTypes); break; + case 9: t = typeof(ActionCallInstruction<,,,,,,,,>).MakeGenericType(arrTypes); break; + default: throw new InvalidOperationException(); + } + } else { + switch (arrTypes.Length) { + case 1: t = typeof(FuncCallInstruction<>).MakeGenericType(arrTypes); break; + case 2: t = typeof(FuncCallInstruction<,>).MakeGenericType(arrTypes); break; + case 3: t = typeof(FuncCallInstruction<,,>).MakeGenericType(arrTypes); break; + case 4: t = typeof(FuncCallInstruction<,,,>).MakeGenericType(arrTypes); break; + case 5: t = typeof(FuncCallInstruction<,,,,>).MakeGenericType(arrTypes); break; + case 6: t = typeof(FuncCallInstruction<,,,,,>).MakeGenericType(arrTypes); break; + case 7: t = typeof(FuncCallInstruction<,,,,,,>).MakeGenericType(arrTypes); break; + case 8: t = typeof(FuncCallInstruction<,,,,,,,>).MakeGenericType(arrTypes); break; + case 9: t = typeof(FuncCallInstruction<,,,,,,,,>).MakeGenericType(arrTypes); break; + case 10: t = typeof(FuncCallInstruction<,,,,,,,,,>).MakeGenericType(arrTypes); break; + default: throw new InvalidOperationException(); + } + } + return t; + } + public static MethodInfo CacheFunc<TRet>(Func<TRet> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new FuncCallInstruction<TRet>(method); + } + return info; + } + + public static MethodInfo CacheFunc<T0, TRet>(Func<T0, TRet> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new FuncCallInstruction<T0, TRet>(method); + } + return info; + } + + public static MethodInfo CacheFunc<T0, T1, TRet>(Func<T0, T1, TRet> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new FuncCallInstruction<T0, T1, TRet>(method); + } + return info; + } + + public static MethodInfo CacheFunc<T0, T1, T2, TRet>(Func<T0, T1, T2, TRet> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new FuncCallInstruction<T0, T1, T2, TRet>(method); + } + return info; + } + + public static MethodInfo CacheFunc<T0, T1, T2, T3, TRet>(Func<T0, T1, T2, T3, TRet> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new FuncCallInstruction<T0, T1, T2, T3, TRet>(method); + } + return info; + } + + public static MethodInfo CacheFunc<T0, T1, T2, T3, T4, TRet>(Func<T0, T1, T2, T3, T4, TRet> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new FuncCallInstruction<T0, T1, T2, T3, T4, TRet>(method); + } + return info; + } + + public static MethodInfo CacheFunc<T0, T1, T2, T3, T4, T5, TRet>(Func<T0, T1, T2, T3, T4, T5, TRet> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new FuncCallInstruction<T0, T1, T2, T3, T4, T5, TRet>(method); + } + return info; + } + + public static MethodInfo CacheFunc<T0, T1, T2, T3, T4, T5, T6, TRet>(Func<T0, T1, T2, T3, T4, T5, T6, TRet> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new FuncCallInstruction<T0, T1, T2, T3, T4, T5, T6, TRet>(method); + } + return info; + } + + public static MethodInfo CacheFunc<T0, T1, T2, T3, T4, T5, T6, T7, TRet>(Func<T0, T1, T2, T3, T4, T5, T6, T7, TRet> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new FuncCallInstruction<T0, T1, T2, T3, T4, T5, T6, T7, TRet>(method); + } + return info; + } + + public static MethodInfo CacheFunc<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new FuncCallInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>(method); + } + return info; + } + + public static MethodInfo CacheAction(Action method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new ActionCallInstruction(method); + } + return info; + } + + public static MethodInfo CacheAction<T0>(Action<T0> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new ActionCallInstruction<T0>(method); + } + return info; + } + + public static MethodInfo CacheAction<T0, T1>(Action<T0, T1> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new ActionCallInstruction<T0, T1>(method); + } + return info; + } + + public static MethodInfo CacheAction<T0, T1, T2>(Action<T0, T1, T2> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new ActionCallInstruction<T0, T1, T2>(method); + } + return info; + } + + public static MethodInfo CacheAction<T0, T1, T2, T3>(Action<T0, T1, T2, T3> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new ActionCallInstruction<T0, T1, T2, T3>(method); + } + return info; + } + + public static MethodInfo CacheAction<T0, T1, T2, T3, T4>(Action<T0, T1, T2, T3, T4> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new ActionCallInstruction<T0, T1, T2, T3, T4>(method); + } + return info; + } + + public static MethodInfo CacheAction<T0, T1, T2, T3, T4, T5>(Action<T0, T1, T2, T3, T4, T5> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new ActionCallInstruction<T0, T1, T2, T3, T4, T5>(method); + } + return info; + } + + public static MethodInfo CacheAction<T0, T1, T2, T3, T4, T5, T6>(Action<T0, T1, T2, T3, T4, T5, T6> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new ActionCallInstruction<T0, T1, T2, T3, T4, T5, T6>(method); + } + return info; + } + + public static MethodInfo CacheAction<T0, T1, T2, T3, T4, T5, T6, T7>(Action<T0, T1, T2, T3, T4, T5, T6, T7> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new ActionCallInstruction<T0, T1, T2, T3, T4, T5, T6, T7>(method); + } + return info; + } + + public static MethodInfo CacheAction<T0, T1, T2, T3, T4, T5, T6, T7, T8>(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> method) { + var info = method.GetMethodInfo(); + lock (_cache) { + _cache[info] = new ActionCallInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8>(method); + } + return info; + } + + } + + internal sealed class ActionCallInstruction : CallInstruction { + private readonly Action _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 0; } } + + public ActionCallInstruction(Action target) { + _target = target; + } + + public ActionCallInstruction(MethodInfo target) { + _target = (Action)target.CreateDelegate(typeof(Action)); + } + + public override object Invoke() { + _target(); + return null; + } + + public override int Run(InterpretedFrame frame) { + _target(); + frame.StackIndex -= 0; + return 1; + } + } + + internal sealed class ActionCallInstruction<T0> : CallInstruction { + private readonly Action<T0> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 1; } } + + public ActionCallInstruction(Action<T0> target) { + _target = target; + } + + public ActionCallInstruction(MethodInfo target) { + _target = (Action<T0>)target.CreateDelegate(typeof(Action<T0>)); + } + + public override object Invoke(object arg0) { + _target(arg0 != null ? (T0)arg0 : default(T0)); + return null; + } + + public override int Run(InterpretedFrame frame) { + _target((T0)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 1; + return 1; + } + } + + internal sealed class ActionCallInstruction<T0, T1> : CallInstruction { + private readonly Action<T0, T1> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 2; } } + + public ActionCallInstruction(Action<T0, T1> target) { + _target = target; + } + + public ActionCallInstruction(MethodInfo target) { + _target = (Action<T0, T1>)target.CreateDelegate(typeof(Action<T0, T1>)); + } + + public override object Invoke(object arg0, object arg1) { + _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1)); + return null; + } + + public override int Run(InterpretedFrame frame) { + _target((T0)frame.Data[frame.StackIndex - 2], (T1)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 2; + return 1; + } + } + + internal sealed class ActionCallInstruction<T0, T1, T2> : CallInstruction { + private readonly Action<T0, T1, T2> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 3; } } + + public ActionCallInstruction(Action<T0, T1, T2> target) { + _target = target; + } + + public ActionCallInstruction(MethodInfo target) { + _target = (Action<T0, T1, T2>)target.CreateDelegate(typeof(Action<T0, T1, T2>)); + } + + public override object Invoke(object arg0, object arg1, object arg2) { + _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2)); + return null; + } + + public override int Run(InterpretedFrame frame) { + _target((T0)frame.Data[frame.StackIndex - 3], (T1)frame.Data[frame.StackIndex - 2], (T2)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 3; + return 1; + } + } + + internal sealed class ActionCallInstruction<T0, T1, T2, T3> : CallInstruction { + private readonly Action<T0, T1, T2, T3> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 4; } } + + public ActionCallInstruction(Action<T0, T1, T2, T3> target) { + _target = target; + } + + public ActionCallInstruction(MethodInfo target) { + _target = (Action<T0, T1, T2, T3>)target.CreateDelegate(typeof(Action<T0, T1, T2, T3>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3) { + _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3)); + return null; + } + + public override int Run(InterpretedFrame frame) { + _target((T0)frame.Data[frame.StackIndex - 4], (T1)frame.Data[frame.StackIndex - 3], (T2)frame.Data[frame.StackIndex - 2], (T3)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 4; + return 1; + } + } + + internal sealed class ActionCallInstruction<T0, T1, T2, T3, T4> : CallInstruction { + private readonly Action<T0, T1, T2, T3, T4> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 5; } } + + public ActionCallInstruction(Action<T0, T1, T2, T3, T4> target) { + _target = target; + } + + public ActionCallInstruction(MethodInfo target) { + _target = (Action<T0, T1, T2, T3, T4>)target.CreateDelegate(typeof(Action<T0, T1, T2, T3, T4>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4) { + _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3), arg4 != null ? (T4)arg4 : default(T4)); + return null; + } + + public override int Run(InterpretedFrame frame) { + _target((T0)frame.Data[frame.StackIndex - 5], (T1)frame.Data[frame.StackIndex - 4], (T2)frame.Data[frame.StackIndex - 3], (T3)frame.Data[frame.StackIndex - 2], (T4)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 5; + return 1; + } + } + + internal sealed class ActionCallInstruction<T0, T1, T2, T3, T4, T5> : CallInstruction { + private readonly Action<T0, T1, T2, T3, T4, T5> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 6; } } + + public ActionCallInstruction(Action<T0, T1, T2, T3, T4, T5> target) { + _target = target; + } + + public ActionCallInstruction(MethodInfo target) { + _target = (Action<T0, T1, T2, T3, T4, T5>)target.CreateDelegate(typeof(Action<T0, T1, T2, T3, T4, T5>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5) { + _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3), arg4 != null ? (T4)arg4 : default(T4), arg5 != null ? (T5)arg5 : default(T5)); + return null; + } + + public override int Run(InterpretedFrame frame) { + _target((T0)frame.Data[frame.StackIndex - 6], (T1)frame.Data[frame.StackIndex - 5], (T2)frame.Data[frame.StackIndex - 4], (T3)frame.Data[frame.StackIndex - 3], (T4)frame.Data[frame.StackIndex - 2], (T5)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 6; + return 1; + } + } + + internal sealed class ActionCallInstruction<T0, T1, T2, T3, T4, T5, T6> : CallInstruction { + private readonly Action<T0, T1, T2, T3, T4, T5, T6> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 7; } } + + public ActionCallInstruction(Action<T0, T1, T2, T3, T4, T5, T6> target) { + _target = target; + } + + public ActionCallInstruction(MethodInfo target) { + _target = (Action<T0, T1, T2, T3, T4, T5, T6>)target.CreateDelegate(typeof(Action<T0, T1, T2, T3, T4, T5, T6>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6) { + _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3), arg4 != null ? (T4)arg4 : default(T4), arg5 != null ? (T5)arg5 : default(T5), arg6 != null ? (T6)arg6 : default(T6)); + return null; + } + + public override int Run(InterpretedFrame frame) { + _target((T0)frame.Data[frame.StackIndex - 7], (T1)frame.Data[frame.StackIndex - 6], (T2)frame.Data[frame.StackIndex - 5], (T3)frame.Data[frame.StackIndex - 4], (T4)frame.Data[frame.StackIndex - 3], (T5)frame.Data[frame.StackIndex - 2], (T6)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 7; + return 1; + } + } + + internal sealed class ActionCallInstruction<T0, T1, T2, T3, T4, T5, T6, T7> : CallInstruction { + private readonly Action<T0, T1, T2, T3, T4, T5, T6, T7> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 8; } } + + public ActionCallInstruction(Action<T0, T1, T2, T3, T4, T5, T6, T7> target) { + _target = target; + } + + public ActionCallInstruction(MethodInfo target) { + _target = (Action<T0, T1, T2, T3, T4, T5, T6, T7>)target.CreateDelegate(typeof(Action<T0, T1, T2, T3, T4, T5, T6, T7>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7) { + _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3), arg4 != null ? (T4)arg4 : default(T4), arg5 != null ? (T5)arg5 : default(T5), arg6 != null ? (T6)arg6 : default(T6), arg7 != null ? (T7)arg7 : default(T7)); + return null; + } + + public override int Run(InterpretedFrame frame) { + _target((T0)frame.Data[frame.StackIndex - 8], (T1)frame.Data[frame.StackIndex - 7], (T2)frame.Data[frame.StackIndex - 6], (T3)frame.Data[frame.StackIndex - 5], (T4)frame.Data[frame.StackIndex - 4], (T5)frame.Data[frame.StackIndex - 3], (T6)frame.Data[frame.StackIndex - 2], (T7)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 8; + return 1; + } + } + + internal sealed class ActionCallInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8> : CallInstruction { + private readonly Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 9; } } + + public ActionCallInstruction(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8> target) { + _target = target; + } + + public ActionCallInstruction(MethodInfo target) { + _target = (Action<T0, T1, T2, T3, T4, T5, T6, T7, T8>)target.CreateDelegate(typeof(Action<T0, T1, T2, T3, T4, T5, T6, T7, T8>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8) { + _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3), arg4 != null ? (T4)arg4 : default(T4), arg5 != null ? (T5)arg5 : default(T5), arg6 != null ? (T6)arg6 : default(T6), arg7 != null ? (T7)arg7 : default(T7), arg8 != null ? (T8)arg8 : default(T8)); + return null; + } + + public override int Run(InterpretedFrame frame) { + _target((T0)frame.Data[frame.StackIndex - 9], (T1)frame.Data[frame.StackIndex - 8], (T2)frame.Data[frame.StackIndex - 7], (T3)frame.Data[frame.StackIndex - 6], (T4)frame.Data[frame.StackIndex - 5], (T5)frame.Data[frame.StackIndex - 4], (T6)frame.Data[frame.StackIndex - 3], (T7)frame.Data[frame.StackIndex - 2], (T8)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 9; + return 1; + } + } + + internal sealed class FuncCallInstruction<TRet> : CallInstruction { + private readonly Func<TRet> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 0; } } + + public FuncCallInstruction(Func<TRet> target) { + _target = target; + } + + public FuncCallInstruction(MethodInfo target) { + _target = (Func<TRet>)target.CreateDelegate(typeof(Func<TRet>)); + } + + public override object Invoke() { + return _target(); + } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 0] = _target(); + frame.StackIndex -= -1; + return 1; + } + } + + internal sealed class FuncCallInstruction<T0, TRet> : CallInstruction { + private readonly Func<T0, TRet> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 1; } } + + public FuncCallInstruction(Func<T0, TRet> target) { + _target = target; + } + + public FuncCallInstruction(MethodInfo target) { + _target = (Func<T0, TRet>)target.CreateDelegate(typeof(Func<T0, TRet>)); + } + + public override object Invoke(object arg0) { + return _target(arg0 != null ? (T0)arg0 : default(T0)); + } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 1] = _target((T0)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 0; + return 1; + } + } + + internal sealed class FuncCallInstruction<T0, T1, TRet> : CallInstruction { + private readonly Func<T0, T1, TRet> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 2; } } + + public FuncCallInstruction(Func<T0, T1, TRet> target) { + _target = target; + } + + public FuncCallInstruction(MethodInfo target) { + _target = (Func<T0, T1, TRet>)target.CreateDelegate(typeof(Func<T0, T1, TRet>)); + } + + public override object Invoke(object arg0, object arg1) { + return _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1)); + } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 2] = _target((T0)frame.Data[frame.StackIndex - 2], (T1)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 1; + return 1; + } + } + + internal sealed class FuncCallInstruction<T0, T1, T2, TRet> : CallInstruction { + private readonly Func<T0, T1, T2, TRet> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 3; } } + + public FuncCallInstruction(Func<T0, T1, T2, TRet> target) { + _target = target; + } + + public FuncCallInstruction(MethodInfo target) { + _target = (Func<T0, T1, T2, TRet>)target.CreateDelegate(typeof(Func<T0, T1, T2, TRet>)); + } + + public override object Invoke(object arg0, object arg1, object arg2) { + return _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2)); + } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 3] = _target((T0)frame.Data[frame.StackIndex - 3], (T1)frame.Data[frame.StackIndex - 2], (T2)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 2; + return 1; + } + } + + internal sealed class FuncCallInstruction<T0, T1, T2, T3, TRet> : CallInstruction { + private readonly Func<T0, T1, T2, T3, TRet> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 4; } } + + public FuncCallInstruction(Func<T0, T1, T2, T3, TRet> target) { + _target = target; + } + + public FuncCallInstruction(MethodInfo target) { + _target = (Func<T0, T1, T2, T3, TRet>)target.CreateDelegate(typeof(Func<T0, T1, T2, T3, TRet>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3) { + return _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3)); + } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 4] = _target((T0)frame.Data[frame.StackIndex - 4], (T1)frame.Data[frame.StackIndex - 3], (T2)frame.Data[frame.StackIndex - 2], (T3)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 3; + return 1; + } + } + + internal sealed class FuncCallInstruction<T0, T1, T2, T3, T4, TRet> : CallInstruction { + private readonly Func<T0, T1, T2, T3, T4, TRet> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 5; } } + + public FuncCallInstruction(Func<T0, T1, T2, T3, T4, TRet> target) { + _target = target; + } + + public FuncCallInstruction(MethodInfo target) { + _target = (Func<T0, T1, T2, T3, T4, TRet>)target.CreateDelegate(typeof(Func<T0, T1, T2, T3, T4, TRet>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4) { + return _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3), arg4 != null ? (T4)arg4 : default(T4)); + } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 5] = _target((T0)frame.Data[frame.StackIndex - 5], (T1)frame.Data[frame.StackIndex - 4], (T2)frame.Data[frame.StackIndex - 3], (T3)frame.Data[frame.StackIndex - 2], (T4)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 4; + return 1; + } + } + + internal sealed class FuncCallInstruction<T0, T1, T2, T3, T4, T5, TRet> : CallInstruction { + private readonly Func<T0, T1, T2, T3, T4, T5, TRet> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 6; } } + + public FuncCallInstruction(Func<T0, T1, T2, T3, T4, T5, TRet> target) { + _target = target; + } + + public FuncCallInstruction(MethodInfo target) { + _target = (Func<T0, T1, T2, T3, T4, T5, TRet>)target.CreateDelegate(typeof(Func<T0, T1, T2, T3, T4, T5, TRet>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5) { + return _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3), arg4 != null ? (T4)arg4 : default(T4), arg5 != null ? (T5)arg5 : default(T5)); + } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 6] = _target((T0)frame.Data[frame.StackIndex - 6], (T1)frame.Data[frame.StackIndex - 5], (T2)frame.Data[frame.StackIndex - 4], (T3)frame.Data[frame.StackIndex - 3], (T4)frame.Data[frame.StackIndex - 2], (T5)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 5; + return 1; + } + } + + internal sealed class FuncCallInstruction<T0, T1, T2, T3, T4, T5, T6, TRet> : CallInstruction { + private readonly Func<T0, T1, T2, T3, T4, T5, T6, TRet> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 7; } } + + public FuncCallInstruction(Func<T0, T1, T2, T3, T4, T5, T6, TRet> target) { + _target = target; + } + + public FuncCallInstruction(MethodInfo target) { + _target = (Func<T0, T1, T2, T3, T4, T5, T6, TRet>)target.CreateDelegate(typeof(Func<T0, T1, T2, T3, T4, T5, T6, TRet>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6) { + return _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3), arg4 != null ? (T4)arg4 : default(T4), arg5 != null ? (T5)arg5 : default(T5), arg6 != null ? (T6)arg6 : default(T6)); + } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 7] = _target((T0)frame.Data[frame.StackIndex - 7], (T1)frame.Data[frame.StackIndex - 6], (T2)frame.Data[frame.StackIndex - 5], (T3)frame.Data[frame.StackIndex - 4], (T4)frame.Data[frame.StackIndex - 3], (T5)frame.Data[frame.StackIndex - 2], (T6)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 6; + return 1; + } + } + + internal sealed class FuncCallInstruction<T0, T1, T2, T3, T4, T5, T6, T7, TRet> : CallInstruction { + private readonly Func<T0, T1, T2, T3, T4, T5, T6, T7, TRet> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 8; } } + + public FuncCallInstruction(Func<T0, T1, T2, T3, T4, T5, T6, T7, TRet> target) { + _target = target; + } + + public FuncCallInstruction(MethodInfo target) { + _target = (Func<T0, T1, T2, T3, T4, T5, T6, T7, TRet>)target.CreateDelegate(typeof(Func<T0, T1, T2, T3, T4, T5, T6, T7, TRet>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7) { + return _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3), arg4 != null ? (T4)arg4 : default(T4), arg5 != null ? (T5)arg5 : default(T5), arg6 != null ? (T6)arg6 : default(T6), arg7 != null ? (T7)arg7 : default(T7)); + } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 8] = _target((T0)frame.Data[frame.StackIndex - 8], (T1)frame.Data[frame.StackIndex - 7], (T2)frame.Data[frame.StackIndex - 6], (T3)frame.Data[frame.StackIndex - 5], (T4)frame.Data[frame.StackIndex - 4], (T5)frame.Data[frame.StackIndex - 3], (T6)frame.Data[frame.StackIndex - 2], (T7)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 7; + return 1; + } + } + + internal sealed class FuncCallInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet> : CallInstruction { + private readonly Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet> _target; + public override MethodInfo Info { get { return _target.GetMethodInfo(); } } + public override int ArgumentCount { get { return 9; } } + + public FuncCallInstruction(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet> target) { + _target = target; + } + + public FuncCallInstruction(MethodInfo target) { + _target = (Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>)target.CreateDelegate(typeof(Func<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>)); + } + + public override object Invoke(object arg0, object arg1, object arg2, object arg3, object arg4, object arg5, object arg6, object arg7, object arg8) { + return _target(arg0 != null ? (T0)arg0 : default(T0), arg1 != null ? (T1)arg1 : default(T1), arg2 != null ? (T2)arg2 : default(T2), arg3 != null ? (T3)arg3 : default(T3), arg4 != null ? (T4)arg4 : default(T4), arg5 != null ? (T5)arg5 : default(T5), arg6 != null ? (T6)arg6 : default(T6), arg7 != null ? (T7)arg7 : default(T7), arg8 != null ? (T8)arg8 : default(T8)); + } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 9] = _target((T0)frame.Data[frame.StackIndex - 9], (T1)frame.Data[frame.StackIndex - 8], (T2)frame.Data[frame.StackIndex - 7], (T3)frame.Data[frame.StackIndex - 6], (T4)frame.Data[frame.StackIndex - 5], (T5)frame.Data[frame.StackIndex - 4], (T6)frame.Data[frame.StackIndex - 3], (T7)frame.Data[frame.StackIndex - 2], (T8)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 8; + return 1; + } + } + + internal sealed partial class MethodInfoCallInstruction : CallInstruction { + public override object Invoke() { + return InvokeWorker(); + } + public override object Invoke(object arg0) { + return InvokeWorker(arg0); + } + public override object Invoke(object arg0, object arg1) { + return InvokeWorker(arg0, arg1); + } + } + + // *** END GENERATED CODE *** + + #endregion +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/CallInstruction.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/CallInstruction.cs new file mode 100644 index 00000000000..fc69ed342e3 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/CallInstruction.cs @@ -0,0 +1,296 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ +using System; +using System.Collections.Generic; +using System.Reflection; +#if FEATURE_REFEMIT +using System.Reflection.Emit; +#endif +using System.Security; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + public abstract partial class CallInstruction : Instruction { + public abstract MethodInfo Info { get; } + + /// <summary> + /// The number of arguments including "this" for instance methods. + /// </summary> + public abstract int ArgumentCount { get; } + + #region Construction + + internal CallInstruction() { } + + private static readonly Dictionary<MethodInfo, CallInstruction> _cache = new Dictionary<MethodInfo, CallInstruction>(); + + /// <exception cref="SecurityException">Instruction can't be created due to insufficient privileges.</exception> + public static CallInstruction Create(MethodInfo info) { + return Create(info, info.GetParameters()); + } + + /// <exception cref="SecurityException">Instruction can't be created due to insufficient privileges.</exception> + public static CallInstruction Create(MethodInfo info, ParameterInfo[] parameters) { + int argumentCount = parameters.Length; + if (!info.IsStatic) { + argumentCount++; + } + + // A workaround for CLR bug #796414 (Unable to create delegates for Array.Get/Set): + // T[]::Address - not supported by ETs due to T& return value + if (info.DeclaringType != null && info.DeclaringType.IsArray && (info.Name == "Get" || info.Name == "Set")) { + return GetArrayAccessor(info, argumentCount); + } + + if (ReflectionUtils.IsDynamicMethod(info) || !info.IsStatic && info.DeclaringType.IsValueType()) { + return new MethodInfoCallInstruction(info, argumentCount); + } + + if (argumentCount >= MaxHelpers) { + // no delegate for this size, fallback to reflection invoke + return new MethodInfoCallInstruction(info, argumentCount); + } + + foreach (ParameterInfo pi in parameters) { + if (pi.ParameterType.IsByRef) { + // we don't support ref args via generics. + return new MethodInfoCallInstruction(info, argumentCount); + } + } + + // see if we've created one w/ a delegate + CallInstruction res; + if (ShouldCache(info)) { + lock (_cache) { + if (_cache.TryGetValue(info, out res)) { + return res; + } + } + } + + // create it + try { + if (argumentCount < MaxArgs) { + res = FastCreate(info, parameters); + } else { + res = SlowCreate(info, parameters); + } + } catch (TargetInvocationException tie) { + if (!(tie.InnerException is NotSupportedException)) { + throw tie.InnerException; + } + + res = new MethodInfoCallInstruction(info, argumentCount); + } catch (NotSupportedException) { + // if Delegate.CreateDelegate can't handle the method fallback to + // the slow reflection version. For example this can happen w/ + // a generic method defined on an interface and implemented on a class or + // a virtual generic method. + res = new MethodInfoCallInstruction(info, argumentCount); + } + + // cache it for future users if it's a reasonable method to cache + if (ShouldCache(info)) { + lock (_cache) { + _cache[info] = res; + } + } + + return res; + } + + private static CallInstruction GetArrayAccessor(MethodInfo info, int argumentCount) { + Type arrayType = info.DeclaringType; + bool isGetter = info.Name == "Get"; + switch (arrayType.GetArrayRank()) { + case 1: + return Create(isGetter ? + arrayType.GetMethod("GetValue", new[] { typeof(int)}) : + new Action<Array, int, object>(ArrayItemSetter1).GetMethodInfo() + ); + + case 2: + return Create(isGetter ? + arrayType.GetMethod("GetValue", new[] { typeof(int), typeof(int) }) : + new Action<Array, int, int, object>(ArrayItemSetter2).GetMethodInfo() + ); + + case 3: + return Create(isGetter ? + arrayType.GetMethod("GetValue", new[] { typeof(int), typeof(int), typeof(int) }) : + new Action<Array, int, int, int, object>(ArrayItemSetter3).GetMethodInfo() + ); + + default: + return new MethodInfoCallInstruction(info, argumentCount); + } + } + + public static void ArrayItemSetter1(Array array, int index0, object value) { + array.SetValue(value, index0); + } + + public static void ArrayItemSetter2(Array array, int index0, int index1, object value) { + array.SetValue(value, index0, index1); + } + + public static void ArrayItemSetter3(Array array, int index0, int index1, int index2, object value) { + array.SetValue(value, index0, index1, index2); + } + + private static bool ShouldCache(MethodInfo info) { + return !ReflectionUtils.IsDynamicMethod(info); + } + + /// <summary> + /// Gets the next type or null if no more types are available. + /// </summary> + private static Type TryGetParameterOrReturnType(MethodInfo target, ParameterInfo[] pi, int index) { + if (!target.IsStatic) { + index--; + if (index < 0) { + return target.DeclaringType; + } + } + + if (index < pi.Length) { + // next in signature + return pi[index].ParameterType; + } + + if (target.ReturnType == typeof(void) || index > pi.Length) { + // no more parameters + return null; + } + + // last parameter on Invoke is return type + return target.ReturnType; + } + + private static bool IndexIsNotReturnType(int index, MethodInfo target, ParameterInfo[] pi) { + return pi.Length != index || (pi.Length == index && !target.IsStatic); + } + + /// <summary> + /// Uses reflection to create new instance of the appropriate ReflectedCaller + /// </summary> + private static CallInstruction SlowCreate(MethodInfo info, ParameterInfo[] pis) { + List<Type> types = new List<Type>(); + if (!info.IsStatic) types.Add(info.DeclaringType); + foreach (ParameterInfo pi in pis) { + types.Add(pi.ParameterType); + } + if (info.ReturnType != typeof(void)) { + types.Add(info.ReturnType); + } + Type[] arrTypes = types.ToArray(); + + return (CallInstruction)Activator.CreateInstance(GetHelperType(info, arrTypes), info); + } + + #endregion + + #region Instruction + + public sealed override int ProducedStack { get { return Info.ReturnType == typeof(void) ? 0 : 1; } } + public sealed override int ConsumedStack { get { return ArgumentCount; } } + + public sealed override string InstructionName { + get { return "Call"; } + } + + public override string ToString() { + return "Call(" + Info + ")"; + } + + #endregion + } + + internal sealed partial class MethodInfoCallInstruction : CallInstruction { + private readonly MethodInfo _target; + private readonly int _argumentCount; + + public override MethodInfo Info { get { return _target; } } + public override int ArgumentCount { get { return _argumentCount; } } + + internal MethodInfoCallInstruction(MethodInfo target, int argumentCount) { + _target = target; + _argumentCount = argumentCount; + } + + public override object Invoke(params object[] args) { + return InvokeWorker(args); + } + + public override object InvokeInstance(object instance, params object[] args) { + if (_target.IsStatic) { + try { + return _target.Invoke(null, args); + } catch (TargetInvocationException e) { + throw ExceptionHelpers.UpdateForRethrow(e.InnerException); + } + } + + try { + return _target.Invoke(instance, args); + } catch (TargetInvocationException e) { + throw ExceptionHelpers.UpdateForRethrow(e.InnerException); + } + } + + private object InvokeWorker(params object[] args) { + if (_target.IsStatic) { + try { + return _target.Invoke(null, args); + } catch (TargetInvocationException e) { + throw ExceptionHelpers.UpdateForRethrow(e.InnerException); + } + } + + try { + return _target.Invoke(args[0], GetNonStaticArgs(args)); + } catch (TargetInvocationException e) { + throw ExceptionHelpers.UpdateForRethrow(e.InnerException); + } + } + + private static object[] GetNonStaticArgs(object[] args) { + object[] newArgs = new object[args.Length - 1]; + for (int i = 0; i < newArgs.Length; i++) { + newArgs[i] = args[i + 1]; + } + return newArgs; + } + + public sealed override int Run(InterpretedFrame frame) { + int first = frame.StackIndex - _argumentCount; + object[] args = new object[_argumentCount]; + for (int i = 0; i < args.Length; i++) { + args[i] = frame.Data[first + i]; + } + + object ret = Invoke(args); + if (_target.ReturnType != typeof(void)) { + frame.Data[first] = ret; + frame.StackIndex = first + 1; + } else { + frame.StackIndex = first; + } + return 1; + } + } + +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/ControlFlowInstructions.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/ControlFlowInstructions.cs new file mode 100644 index 00000000000..376488e08f9 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/ControlFlowInstructions.cs @@ -0,0 +1,595 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_TASKS +using System.Threading.Tasks; +#endif + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#endif + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.Scripting.Ast; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + using LoopFunc = Func<object[], StrongBox<object>[], InterpretedFrame, int>; + + internal abstract class OffsetInstruction : Instruction { + internal const int Unknown = Int32.MinValue; + internal const int CacheSize = 32; + + // the offset to jump to (relative to this instruction): + protected int _offset = Unknown; + + public int Offset { get { return _offset; } } + public abstract Instruction[] Cache { get; } + + public Instruction Fixup(int offset) { + Debug.Assert(_offset == Unknown && offset != Unknown); + _offset = offset; + + var cache = Cache; + if (cache != null && offset >= 0 && offset < cache.Length) { + return cache[offset] ?? (cache[offset] = this); + } + + return this; + } + + public override string ToDebugString(int instructionIndex, object cookie, Func<int, int> labelIndexer, IList<object> objects) { + return ToString() + (_offset != Unknown ? " -> " + (instructionIndex + _offset).ToString() : ""); + } + + public override string ToString() { + return InstructionName + (_offset == Unknown ? "(?)" : "(" + _offset + ")"); + } + } + + internal sealed class BranchFalseInstruction : OffsetInstruction { + private static Instruction[] _cache; + + public override Instruction[] Cache { + get { + if (_cache == null) { + _cache = new Instruction[CacheSize]; + } + return _cache; + } + } + + internal BranchFalseInstruction() { + } + + public override int ConsumedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + Debug.Assert(_offset != Unknown); + + if (!(bool)frame.Pop()) { + return _offset; + } + + return +1; + } + } + + internal sealed class BranchTrueInstruction : OffsetInstruction { + private static Instruction[] _cache; + + public override Instruction[] Cache { + get { + if (_cache == null) { + _cache = new Instruction[CacheSize]; + } + return _cache; + } + } + + internal BranchTrueInstruction() { + } + + public override int ConsumedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + Debug.Assert(_offset != Unknown); + + if ((bool)frame.Pop()) { + return _offset; + } + + return +1; + } + } + + internal sealed class CoalescingBranchInstruction : OffsetInstruction { + private static Instruction[] _cache; + + public override Instruction[] Cache { + get { + if (_cache == null) { + _cache = new Instruction[CacheSize]; + } + return _cache; + } + } + + internal CoalescingBranchInstruction() { + } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + Debug.Assert(_offset != Unknown); + + if (frame.Peek() != null) { + return _offset; + } + + return +1; + } + } + + internal class BranchInstruction : OffsetInstruction { + private static Instruction[][][] _caches; + + public override Instruction[] Cache { + get { + if (_caches == null) { + _caches = new Instruction[2][][] { new Instruction[2][], new Instruction[2][] }; + } + return _caches[ConsumedStack][ProducedStack] ?? (_caches[ConsumedStack][ProducedStack] = new Instruction[CacheSize]); + } + } + + internal readonly bool _hasResult; + internal readonly bool _hasValue; + + internal BranchInstruction() + : this(false, false) { + } + + public BranchInstruction(bool hasResult, bool hasValue) { + _hasResult = hasResult; + _hasValue = hasValue; + } + + public override int ConsumedStack { + get { return _hasValue ? 1 : 0; } + } + + public override int ProducedStack { + get { return _hasResult ? 1 : 0; } + } + + public override int Run(InterpretedFrame frame) { + Debug.Assert(_offset != Unknown); + + return _offset; + } + } + + internal abstract class IndexedBranchInstruction : Instruction { + protected const int CacheSize = 32; + + internal readonly int _labelIndex; + + public IndexedBranchInstruction(int labelIndex) { + _labelIndex = labelIndex; + } + + public RuntimeLabel GetLabel(InterpretedFrame frame) { + return frame.Interpreter._labels[_labelIndex]; + } + + public override string ToDebugString(int instructionIndex, object cookie, Func<int, int> labelIndexer, IList<object> objects) { + int targetIndex = labelIndexer(_labelIndex); + return ToString() + (targetIndex != BranchLabel.UnknownIndex ? " -> " + targetIndex.ToString() : ""); + } + + public override string ToString() { + return InstructionName + "[" + _labelIndex + "]"; + } + } + + /// <summary> + /// This instruction implements a goto expression that can jump out of any expression. + /// It pops values (arguments) from the evaluation stack that the expression tree nodes in between + /// the goto expression and the target label node pushed and not consumed yet. + /// A goto expression can jump into a node that evaluates arguments only if it carries + /// a value and jumps right after the first argument (the carried value will be used as the first argument). + /// Goto can jump into an arbitrary child of a BlockExpression since the block doesn’t accumulate values + /// on evaluation stack as its child expressions are being evaluated. + /// + /// Goto needs to execute any finally blocks on the way to the target label. + /// <example> + /// { + /// f(1, 2, try { g(3, 4, try { goto L } finally { ... }, 6) } finally { ... }, 7, 8) + /// L: ... + /// } + /// </example> + /// The goto expression here jumps to label L while having 4 items on evaluation stack (1, 2, 3 and 4). + /// The jump needs to execute both finally blocks, the first one on stack level 4 the + /// second one on stack level 2. So, it needs to jump the first finally block, pop 2 items from the stack, + /// run second finally block and pop another 2 items from the stack and set instruction pointer to label L. + /// + /// Goto also needs to rethrow ThreadAbortException iff it jumps out of a catch handler and + /// the current thread is in "abort requested" state. + /// </summary> + internal sealed class GotoInstruction : IndexedBranchInstruction { + private const int Variants = 4; + private static readonly GotoInstruction[] Cache = new GotoInstruction[Variants * CacheSize]; + + private readonly bool _hasResult; + + // TODO: We can remember hasValue in label and look it up when calculating stack balance. That would save some cache. + private readonly bool _hasValue; + + // The values should technically be Consumed = 1, Produced = 1 for gotos that target a label whose continuation depth + // is different from the current continuation depth. However, in case of forward gotos, we don't not know that is the + // case until the label is emitted. By then the consumed and produced stack information is useless. + // The important thing here is that the stack balance is 0. + public override int ConsumedContinuations { get { return 0; } } + public override int ProducedContinuations { get { return 0; } } + + public override int ConsumedStack { + get { return _hasValue ? 1 : 0; } + } + + public override int ProducedStack { + get { return _hasResult ? 1 : 0; } + } + + private GotoInstruction(int targetIndex, bool hasResult, bool hasValue) + : base(targetIndex) { + _hasResult = hasResult; + _hasValue = hasValue; + } + + internal static GotoInstruction Create(int labelIndex, bool hasResult, bool hasValue) { + if (labelIndex < CacheSize) { + var index = Variants * labelIndex | (hasResult ? 2 : 0) | (hasValue ? 1 : 0); + return Cache[index] ?? (Cache[index] = new GotoInstruction(labelIndex, hasResult, hasValue)); + } + return new GotoInstruction(labelIndex, hasResult, hasValue); + } + + public override int Run(InterpretedFrame frame) { + // Are we jumping out of catch/finally while aborting the current thread? + Interpreter.AbortThreadIfRequested(frame, _labelIndex); + + // goto the target label or the current finally continuation: + return frame.Goto(_labelIndex, _hasValue ? frame.Pop() : Interpreter.NoValue); + } + } + + internal sealed class EnterTryFinallyInstruction : IndexedBranchInstruction { + private readonly static EnterTryFinallyInstruction[] Cache = new EnterTryFinallyInstruction[CacheSize]; + + public override int ProducedContinuations { get { return 1; } } + + private EnterTryFinallyInstruction(int targetIndex) + : base(targetIndex) { + } + + internal static EnterTryFinallyInstruction Create(int labelIndex) { + if (labelIndex < CacheSize) { + return Cache[labelIndex] ?? (Cache[labelIndex] = new EnterTryFinallyInstruction(labelIndex)); + } + return new EnterTryFinallyInstruction(labelIndex); + } + + public override int Run(InterpretedFrame frame) { + // Push finally. + frame.PushContinuation(_labelIndex); + return 1; + } + } + + /// <summary> + /// The first instruction of finally block. + /// </summary> + internal sealed class EnterFinallyInstruction : Instruction { + internal static readonly Instruction Instance = new EnterFinallyInstruction(); + + public override int ProducedStack { get { return 2; } } + public override int ConsumedContinuations { get { return 1; } } + + private EnterFinallyInstruction() { + } + + public override int Run(InterpretedFrame frame) { + frame.PushPendingContinuation(); + frame.RemoveContinuation(); + return 1; + } + } + + /// <summary> + /// The last instruction of finally block. + /// </summary> + internal sealed class LeaveFinallyInstruction : Instruction { + internal static readonly Instruction Instance = new LeaveFinallyInstruction(); + + public override int ConsumedStack { get { return 2; } } + + private LeaveFinallyInstruction() { + } + + public override int Run(InterpretedFrame frame) { + frame.PopPendingContinuation(); + + // jump to goto target or to the next finally: + return frame.YieldToPendingContinuation(); + } + } + + // no-op: we need this just to balance the stack depth. + internal sealed class EnterExceptionHandlerInstruction : Instruction { + internal static readonly EnterExceptionHandlerInstruction Void = new EnterExceptionHandlerInstruction(false); + internal static readonly EnterExceptionHandlerInstruction NonVoid = new EnterExceptionHandlerInstruction(true); + + // True if try-expression is non-void. + private readonly bool _hasValue; + + private EnterExceptionHandlerInstruction(bool hasValue) { + _hasValue = hasValue; + } + + // If an exception is throws in try-body the expression result of try-body is not evaluated and loaded to the stack. + // So the stack doesn't contain the try-body's value when we start executing the handler. + // However, while emitting instructions try block falls thru the catch block with a value on stack. + // We need to declare it consumed so that the stack state upon entry to the handler corresponds to the real + // stack depth after throw jumped to this catch block. + public override int ConsumedStack { get { return _hasValue ? 1 : 0; } } + + // A variable storing the current exception is pushed to the stack by exception handling. + // Catch handlers: The value is immediately popped and stored into a local. + // Fault handlers: The value is kept on stack during fault handler evaluation. + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + // nop (the exception value is pushed by the interpreter in HandleCatch) + return 1; + } + } + + /// <summary> + /// The last instruction of a catch exception handler. + /// </summary> + internal sealed class LeaveExceptionHandlerInstruction : IndexedBranchInstruction { + private static LeaveExceptionHandlerInstruction[] Cache = new LeaveExceptionHandlerInstruction[2 * CacheSize]; + + private readonly bool _hasValue; + + // The catch block yields a value if the body is non-void. This value is left on the stack. + public override int ConsumedStack { + get { return _hasValue ? 1 : 0; } + } + + public override int ProducedStack { + get { return _hasValue ? 1 : 0; } + } + + private LeaveExceptionHandlerInstruction(int labelIndex, bool hasValue) + : base(labelIndex) { + _hasValue = hasValue; + } + + internal static LeaveExceptionHandlerInstruction Create(int labelIndex, bool hasValue) { + if (labelIndex < CacheSize) { + int index = (2 * labelIndex) | (hasValue ? 1 : 0); + return Cache[index] ?? (Cache[index] = new LeaveExceptionHandlerInstruction(labelIndex, hasValue)); + } + return new LeaveExceptionHandlerInstruction(labelIndex, hasValue); + } + + public override int Run(InterpretedFrame frame) { + // CLR rethrows ThreadAbortException when leaving catch handler if abort is requested on the current thread. + Interpreter.AbortThreadIfRequested(frame, _labelIndex); + return GetLabel(frame).Index - frame.InstructionIndex; + } + } + + /// <summary> + /// The last instruction of a fault exception handler. + /// </summary> + internal sealed class LeaveFaultInstruction : Instruction { + internal static readonly Instruction NonVoid = new LeaveFaultInstruction(true); + internal static readonly Instruction Void = new LeaveFaultInstruction(false); + + private readonly bool _hasValue; + + // The fault block has a value if the body is non-void, but the value is never used. + // We compile the body of a fault block as void. + // However, we keep the exception object that was pushed upon entering the fault block on the stack during execution of the block + // and pop it at the end. + public override int ConsumedStack { + get { return 1; } + } + + // While emitting instructions a non-void try-fault expression is expected to produce a value. + public override int ProducedStack { + get { return _hasValue ? 1 : 0; } + } + + private LeaveFaultInstruction(bool hasValue) { + _hasValue = hasValue; + } + + public override int Run(InterpretedFrame frame) { + // TODO: ThreadAbortException ? + + object exception = frame.Pop(); + ExceptionHandler handler; + return frame.Interpreter.GotoHandler(frame, exception, out handler); + } + } + + + internal sealed class ThrowInstruction : Instruction { + internal static readonly ThrowInstruction Throw = new ThrowInstruction(true, false); + internal static readonly ThrowInstruction VoidThrow = new ThrowInstruction(false, false); + internal static readonly ThrowInstruction Rethrow = new ThrowInstruction(true, true); + internal static readonly ThrowInstruction VoidRethrow = new ThrowInstruction(false, true); + + private readonly bool _hasResult, _rethrow; + + private ThrowInstruction(bool hasResult, bool isRethrow) { + _hasResult = hasResult; + _rethrow = isRethrow; + } + + public override int ProducedStack { + get { return _hasResult ? 1 : 0; } + } + + public override int ConsumedStack { + get { + return 1; + } + } + + public override int Run(InterpretedFrame frame) { + var ex = (Exception)frame.Pop(); + if (_rethrow) { + ExceptionHandler handler; + return frame.Interpreter.GotoHandler(frame, ex, out handler); + } + throw ex; + } + } + + internal sealed class SwitchInstruction : Instruction { + private readonly Dictionary<int, int> _cases; + + internal SwitchInstruction(Dictionary<int, int> cases) { + Assert.NotNull(cases); + _cases = cases; + } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 0; } } + + public override int Run(InterpretedFrame frame) { + int target; + return _cases.TryGetValue((int)frame.Pop(), out target) ? target : 1; + } + } + + internal sealed class EnterLoopInstruction : Instruction { + private readonly int _instructionIndex; + private Dictionary<ParameterExpression, LocalVariable> _variables; + private Dictionary<ParameterExpression, LocalVariable> _closureVariables; + private LoopExpression _loop; + private int _loopEnd; + private int _compilationThreshold; + + internal EnterLoopInstruction(LoopExpression loop, LocalVariables locals, int compilationThreshold, int instructionIndex) { + _loop = loop; + _variables = locals.CopyLocals(); + _closureVariables = locals.ClosureVariables; + _compilationThreshold = compilationThreshold; + _instructionIndex = instructionIndex; + } + + internal void FinishLoop(int loopEnd) { + _loopEnd = loopEnd; + } + + public override int Run(InterpretedFrame frame) { + // Don't lock here, it's a frequently hit path. + // + // There could be multiple threads racing, but that is okay. + // Two bad things can happen: + // * We miss decrements (some thread sets the counter forward) + // * We might enter the "if" branch more than once. + // + // The first is okay, it just means we take longer to compile. + // The second we explicitly guard against inside of Compile(). + // + // We can't miss 0. The first thread that writes -1 must have read 0 and hence start compilation. + if (unchecked(_compilationThreshold--) == 0) { +#if SILVERLIGHT + if (PlatformAdaptationLayer.IsCompactFramework) { + _compilationThreshold = Int32.MaxValue; + return 1; + } +#endif + if (frame.Interpreter.CompileSynchronously) { + Compile(frame); + } else { + // Kick off the compile on another thread so this one can keep going, + // Compile method backpatches the instruction when finished so we don't need to await the task. +#if FEATURE_TASKS + new Task(Compile, frame).Start(); +#else + ThreadPool.QueueUserWorkItem(Compile, frame); +#endif + } + } + return 1; + } + + private bool Compiled { + get { return _loop == null; } + } + + private void Compile(object frameObj) { + if (Compiled) { + return; + } + + lock (this) { + if (Compiled) { + return; + } + + PerfTrack.NoteEvent(PerfTrack.Categories.Compiler, "Interpreted loop compiled"); + + InterpretedFrame frame = (InterpretedFrame)frameObj; + var compiler = new LoopCompiler(_loop, frame.Interpreter.LabelMapping, _variables, _closureVariables, _instructionIndex, _loopEnd); + var instructions = frame.Interpreter.Instructions.Instructions; + + // replace this instruction with an optimized one: + Interlocked.Exchange(ref instructions[_instructionIndex], new CompiledLoopInstruction(compiler.CreateDelegate())); + + // invalidate this instruction, some threads may still hold on it: + _loop = null; + _variables = null; + _closureVariables = null; + } + } + } + + internal sealed class CompiledLoopInstruction : Instruction { + private readonly LoopFunc _compiledLoop; + + public CompiledLoopInstruction(LoopFunc compiledLoop) { + Assert.NotNull(compiledLoop); + _compiledLoop = compiledLoop; + } + + public override int Run(InterpretedFrame frame) { + return _compiledLoop(frame.Data, frame.Closure, frame); + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DivInstruction.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DivInstruction.cs new file mode 100644 index 00000000000..08ed47926b5 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DivInstruction.cs @@ -0,0 +1,132 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Diagnostics; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal abstract class DivInstruction : Instruction { + private static Instruction _Int16, _Int32, _Int64, _UInt16, _UInt32, _UInt64, _Single, _Double; + + public override int ConsumedStack { get { return 2; } } + public override int ProducedStack { get { return 1; } } + + private DivInstruction() { + } + + internal sealed class DivInt32 : DivInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = ScriptingRuntimeHelpers.Int32ToObject((Int32)l / (Int32)r); + frame.StackIndex--; + return 1; + } + } + + internal sealed class DivInt16 : DivInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Int16)((Int16)l / (Int16)r); + frame.StackIndex--; + return 1; + } + } + + internal sealed class DivInt64 : DivInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Int64)((Int64)l / (Int64)r); + frame.StackIndex--; + return 1; + } + } + + internal sealed class DivUInt16 : DivInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (UInt16)((UInt16)l / (UInt16)r); + frame.StackIndex--; + return 1; + } + } + + internal sealed class DivUInt32 : DivInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (UInt32)((UInt32)l / (UInt32)r); + frame.StackIndex--; + return 1; + } + } + + internal sealed class DivUInt64 : DivInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (UInt64)((Int16)l / (Int16)r); + frame.StackIndex--; + return 1; + } + } + + internal sealed class DivSingle : DivInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Single)((Single)l / (Single)r); + frame.StackIndex--; + return 1; + } + } + + internal sealed class DivDouble : DivInstruction { + public override int Run(InterpretedFrame frame) { + object l = frame.Data[frame.StackIndex - 2]; + object r = frame.Data[frame.StackIndex - 1]; + frame.Data[frame.StackIndex - 2] = (Double)l / (Double)r; + frame.StackIndex--; + return 1; + } + } + + public static Instruction Create(Type type) { + Debug.Assert(!type.IsEnum()); + switch (type.GetTypeCode()) { + case TypeCode.Int16: return _Int16 ?? (_Int16 = new DivInt16()); + case TypeCode.Int32: return _Int32 ?? (_Int32 = new DivInt32()); + case TypeCode.Int64: return _Int64 ?? (_Int64 = new DivInt64()); + case TypeCode.UInt16: return _UInt16 ?? (_UInt16 = new DivUInt16()); + case TypeCode.UInt32: return _UInt32 ?? (_UInt32 = new DivUInt32()); + case TypeCode.UInt64: return _UInt64 ?? (_UInt64 = new DivUInt64()); + case TypeCode.Single: return _Single ?? (_Single = new DivSingle()); + case TypeCode.Double: return _Double ?? (_Double = new DivDouble()); + + default: + throw Assert.Unreachable; + } + } + + public override string ToString() { + return "Div()"; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicInstructionN.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicInstructionN.cs new file mode 100644 index 00000000000..70576695132 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicInstructionN.cs @@ -0,0 +1,76 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Reflection; + +using Microsoft.Scripting.Utils; +using System.Security; + +namespace Microsoft.Scripting.Interpreter { + internal sealed partial class DynamicInstructionN : Instruction { + private readonly CallInstruction _targetInvocationInstruction; + private readonly object _targetDelegate; + private readonly CallSite _site; + private readonly int _argumentCount; + private readonly bool _isVoid; + + public DynamicInstructionN(Type delegateType, CallSite site) { + var methodInfo = delegateType.GetMethod("Invoke"); + var parameters = methodInfo.GetParameters(); + + // <Delegate>.Invoke is ok to target by a delegate in partial trust (SecurityException is not thrown): + _targetInvocationInstruction = CallInstruction.Create(methodInfo, parameters); + _site = site; + _argumentCount = parameters.Length - 1; + _targetDelegate = site.GetType().GetInheritedFields("Target").First().GetValue(site); + } + + public DynamicInstructionN(Type delegateType, CallSite site, bool isVoid) + : this(delegateType, site) { + _isVoid = isVoid; + } + + public override int ProducedStack { get { return _isVoid ? 0 : 1; } } + public override int ConsumedStack { get { return _argumentCount; } } + + public override int Run(InterpretedFrame frame) { + int first = frame.StackIndex - _argumentCount; + object[] args = new object[1 + _argumentCount]; + args[0] = _site; + for (int i = 0; i < _argumentCount; i++) { + args[1 + i] = frame.Data[first + i]; + } + + object ret = _targetInvocationInstruction.InvokeInstance(_targetDelegate, args); + if (_isVoid) { + frame.StackIndex = first; + } else { + frame.Data[first] = ret; + frame.StackIndex = first + 1; + } + + return 1; + } + + public override string ToString() { + return "DynamicInstructionN(" + _site + ")"; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicInstructions.Generated.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicInstructions.Generated.cs new file mode 100644 index 00000000000..c98b957f6ce --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicInstructions.Generated.cs @@ -0,0 +1,509 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + + +using System; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal partial class DynamicInstructionN { + internal static Type GetDynamicInstructionType(Type delegateType) { + Type[] argTypes = delegateType.GetGenericArguments(); + if (argTypes.Length == 0) return null; + Type genericType; + Type[] newArgTypes = ArrayUtils.RemoveFirst(argTypes); + switch (newArgTypes.Length) { + #region Generated Dynamic Instruction Types + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_types from: generate_dynamic_instructions.py + + case 1: genericType = typeof(DynamicInstruction<>); break; + case 2: genericType = typeof(DynamicInstruction<,>); break; + case 3: genericType = typeof(DynamicInstruction<,,>); break; + case 4: genericType = typeof(DynamicInstruction<,,,>); break; + case 5: genericType = typeof(DynamicInstruction<,,,,>); break; + case 6: genericType = typeof(DynamicInstruction<,,,,,>); break; + case 7: genericType = typeof(DynamicInstruction<,,,,,,>); break; + case 8: genericType = typeof(DynamicInstruction<,,,,,,,>); break; + case 9: genericType = typeof(DynamicInstruction<,,,,,,,,>); break; + case 10: genericType = typeof(DynamicInstruction<,,,,,,,,,>); break; + case 11: genericType = typeof(DynamicInstruction<,,,,,,,,,,>); break; + case 12: genericType = typeof(DynamicInstruction<,,,,,,,,,,,>); break; + case 13: genericType = typeof(DynamicInstruction<,,,,,,,,,,,,>); break; + case 14: genericType = typeof(DynamicInstruction<,,,,,,,,,,,,,>); break; + case 15: genericType = typeof(DynamicInstruction<,,,,,,,,,,,,,,>); break; + case 16: genericType = typeof(DynamicInstruction<,,,,,,,,,,,,,,,>); break; + + // *** END GENERATED CODE *** + + #endregion + default: + throw Assert.Unreachable; + } + + return genericType.MakeGenericType(newArgTypes); + } + + internal static Instruction CreateUntypedInstruction(CallSiteBinder binder, int argCount) { + // DLR Ref.Emits an UpdateAndExecute delegate for sites with more than 10 parameters + if (argCount > 10 && PlatformAdaptationLayer.IsCompactFramework) { + return null; + } + + switch (argCount) { + #region Generated Untyped Dynamic Instructions + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_untyped from: generate_dynamic_instructions.py + + case 0: return DynamicInstruction<object>.Factory(binder); + case 1: return DynamicInstruction<object, object>.Factory(binder); + case 2: return DynamicInstruction<object, object, object>.Factory(binder); + case 3: return DynamicInstruction<object, object, object, object>.Factory(binder); + case 4: return DynamicInstruction<object, object, object, object, object>.Factory(binder); + case 5: return DynamicInstruction<object, object, object, object, object, object>.Factory(binder); + case 6: return DynamicInstruction<object, object, object, object, object, object, object>.Factory(binder); + case 7: return DynamicInstruction<object, object, object, object, object, object, object, object>.Factory(binder); + case 8: return DynamicInstruction<object, object, object, object, object, object, object, object, object>.Factory(binder); + case 9: return DynamicInstruction<object, object, object, object, object, object, object, object, object, object>.Factory(binder); + case 10: return DynamicInstruction<object, object, object, object, object, object, object, object, object, object, object>.Factory(binder); + case 11: return DynamicInstruction<object, object, object, object, object, object, object, object, object, object, object, object>.Factory(binder); + case 12: return DynamicInstruction<object, object, object, object, object, object, object, object, object, object, object, object, object>.Factory(binder); + case 13: return DynamicInstruction<object, object, object, object, object, object, object, object, object, object, object, object, object, object>.Factory(binder); + case 14: return DynamicInstruction<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>.Factory(binder); + case 15: return DynamicInstruction<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>.Factory(binder); + + // *** END GENERATED CODE *** + + #endregion + + default: return null; + } + } + } + + #region Generated Dynamic Instructions + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_instructions from: generate_dynamic_instructions.py + + internal class DynamicInstruction<TRet> : Instruction { + private CallSite<Func<CallSite,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<TRet>(CallSite<Func<CallSite,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 0; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 0] = _site.Target(_site); + frame.StackIndex -= -1; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,TRet> : Instruction { + private CallSite<Func<CallSite,T0,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,TRet>(CallSite<Func<CallSite,T0,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 1] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 1]); + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,TRet>(CallSite<Func<CallSite,T0,T1,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 2; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 2] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 2], (T1)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 1; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,TRet>(CallSite<Func<CallSite,T0,T1,T2,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 3; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 3] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 3], (T1)frame.Data[frame.StackIndex - 2], (T2)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 2; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 4; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 4] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 4], (T1)frame.Data[frame.StackIndex - 3], (T2)frame.Data[frame.StackIndex - 2], (T3)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 3; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 5; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 5] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 5], (T1)frame.Data[frame.StackIndex - 4], (T2)frame.Data[frame.StackIndex - 3], (T3)frame.Data[frame.StackIndex - 2], (T4)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 4; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,T5,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,T5,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 6; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 6] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 6], (T1)frame.Data[frame.StackIndex - 5], (T2)frame.Data[frame.StackIndex - 4], (T3)frame.Data[frame.StackIndex - 3], (T4)frame.Data[frame.StackIndex - 2], (T5)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 5; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 7; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 7] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 7], (T1)frame.Data[frame.StackIndex - 6], (T2)frame.Data[frame.StackIndex - 5], (T3)frame.Data[frame.StackIndex - 4], (T4)frame.Data[frame.StackIndex - 3], (T5)frame.Data[frame.StackIndex - 2], (T6)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 6; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 8; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 8] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 8], (T1)frame.Data[frame.StackIndex - 7], (T2)frame.Data[frame.StackIndex - 6], (T3)frame.Data[frame.StackIndex - 5], (T4)frame.Data[frame.StackIndex - 4], (T5)frame.Data[frame.StackIndex - 3], (T6)frame.Data[frame.StackIndex - 2], (T7)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 7; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 9; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 9] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 9], (T1)frame.Data[frame.StackIndex - 8], (T2)frame.Data[frame.StackIndex - 7], (T3)frame.Data[frame.StackIndex - 6], (T4)frame.Data[frame.StackIndex - 5], (T5)frame.Data[frame.StackIndex - 4], (T6)frame.Data[frame.StackIndex - 3], (T7)frame.Data[frame.StackIndex - 2], (T8)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 8; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 10; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 10] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 10], (T1)frame.Data[frame.StackIndex - 9], (T2)frame.Data[frame.StackIndex - 8], (T3)frame.Data[frame.StackIndex - 7], (T4)frame.Data[frame.StackIndex - 6], (T5)frame.Data[frame.StackIndex - 5], (T6)frame.Data[frame.StackIndex - 4], (T7)frame.Data[frame.StackIndex - 3], (T8)frame.Data[frame.StackIndex - 2], (T9)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 9; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 11; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 11] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 11], (T1)frame.Data[frame.StackIndex - 10], (T2)frame.Data[frame.StackIndex - 9], (T3)frame.Data[frame.StackIndex - 8], (T4)frame.Data[frame.StackIndex - 7], (T5)frame.Data[frame.StackIndex - 6], (T6)frame.Data[frame.StackIndex - 5], (T7)frame.Data[frame.StackIndex - 4], (T8)frame.Data[frame.StackIndex - 3], (T9)frame.Data[frame.StackIndex - 2], (T10)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 10; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 12; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 12] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 12], (T1)frame.Data[frame.StackIndex - 11], (T2)frame.Data[frame.StackIndex - 10], (T3)frame.Data[frame.StackIndex - 9], (T4)frame.Data[frame.StackIndex - 8], (T5)frame.Data[frame.StackIndex - 7], (T6)frame.Data[frame.StackIndex - 6], (T7)frame.Data[frame.StackIndex - 5], (T8)frame.Data[frame.StackIndex - 4], (T9)frame.Data[frame.StackIndex - 3], (T10)frame.Data[frame.StackIndex - 2], (T11)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 11; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 13; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 13] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 13], (T1)frame.Data[frame.StackIndex - 12], (T2)frame.Data[frame.StackIndex - 11], (T3)frame.Data[frame.StackIndex - 10], (T4)frame.Data[frame.StackIndex - 9], (T5)frame.Data[frame.StackIndex - 8], (T6)frame.Data[frame.StackIndex - 7], (T7)frame.Data[frame.StackIndex - 6], (T8)frame.Data[frame.StackIndex - 5], (T9)frame.Data[frame.StackIndex - 4], (T10)frame.Data[frame.StackIndex - 3], (T11)frame.Data[frame.StackIndex - 2], (T12)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 12; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 14; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 14] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 14], (T1)frame.Data[frame.StackIndex - 13], (T2)frame.Data[frame.StackIndex - 12], (T3)frame.Data[frame.StackIndex - 11], (T4)frame.Data[frame.StackIndex - 10], (T5)frame.Data[frame.StackIndex - 9], (T6)frame.Data[frame.StackIndex - 8], (T7)frame.Data[frame.StackIndex - 7], (T8)frame.Data[frame.StackIndex - 6], (T9)frame.Data[frame.StackIndex - 5], (T10)frame.Data[frame.StackIndex - 4], (T11)frame.Data[frame.StackIndex - 3], (T12)frame.Data[frame.StackIndex - 2], (T13)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 13; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + internal class DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,TRet> : Instruction { + private CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,TRet>> _site; + + public static Instruction Factory(CallSiteBinder binder) { + return new DynamicInstruction<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,TRet>(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,TRet>>.Create(binder)); + } + + private DynamicInstruction(CallSite<Func<CallSite,T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,TRet>> site) { + _site = site; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return 15; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex - 15] = _site.Target(_site, (T0)frame.Data[frame.StackIndex - 15], (T1)frame.Data[frame.StackIndex - 14], (T2)frame.Data[frame.StackIndex - 13], (T3)frame.Data[frame.StackIndex - 12], (T4)frame.Data[frame.StackIndex - 11], (T5)frame.Data[frame.StackIndex - 10], (T6)frame.Data[frame.StackIndex - 9], (T7)frame.Data[frame.StackIndex - 8], (T8)frame.Data[frame.StackIndex - 7], (T9)frame.Data[frame.StackIndex - 6], (T10)frame.Data[frame.StackIndex - 5], (T11)frame.Data[frame.StackIndex - 4], (T12)frame.Data[frame.StackIndex - 3], (T13)frame.Data[frame.StackIndex - 2], (T14)frame.Data[frame.StackIndex - 1]); + frame.StackIndex -= 14; + return 1; + } + + public override string ToString() { + return "Dynamic(" + _site.Binder.ToString() + ")"; + } + } + + + // *** END GENERATED CODE *** + + #endregion + + +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicSplatInstruction.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicSplatInstruction.cs new file mode 100644 index 00000000000..b2426e7b414 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/DynamicSplatInstruction.cs @@ -0,0 +1,55 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Reflection; + +using Microsoft.Scripting.Utils; +using Microsoft.Scripting.Ast; +using Microsoft.Scripting.Runtime; + +namespace Microsoft.Scripting.Interpreter { + /// <summary> + /// Implements dynamic call site with many arguments. Wraps the arguments into <see cref="ArgumentArray"/>. + /// </summary> + internal sealed partial class DynamicSplatInstruction : Instruction { + private readonly CallSite<Func<CallSite, ArgumentArray, object>> _site; + private readonly int _argumentCount; + + internal DynamicSplatInstruction(int argumentCount, CallSite<Func<CallSite, ArgumentArray, object>> site) { + _site = site; + _argumentCount = argumentCount; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return _argumentCount; } } + + public override int Run(InterpretedFrame frame) { + int first = frame.StackIndex - _argumentCount; + object ret = _site.Target(_site, new ArgumentArray(frame.Data, first, _argumentCount)); + frame.Data[first] = ret; + frame.StackIndex = first + 1; + + return 1; + } + + public override string ToString() { + return "DynamicSplatInstruction(" + _site + ")"; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/EqualInstruction.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/EqualInstruction.cs new file mode 100644 index 00000000000..e4edde9bab2 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/EqualInstruction.cs @@ -0,0 +1,161 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal abstract class EqualInstruction : Instruction { + // Perf: EqualityComparer<T> but is 3/2 to 2 times slower. + private static Instruction _Reference, _Boolean, _SByte, _Int16, _Char, _Int32, _Int64, _Byte, _UInt16, _UInt32, _UInt64, _Single, _Double; + + public override int ConsumedStack { get { return 2; } } + public override int ProducedStack { get { return 1; } } + + private EqualInstruction() { + } + + internal sealed class EqualBoolean : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Boolean)frame.Pop()) == ((Boolean)frame.Pop())); + return +1; + } + } + + internal sealed class EqualSByte : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((SByte)frame.Pop()) == ((SByte)frame.Pop())); + return +1; + } + } + + internal sealed class EqualInt16 : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Int16)frame.Pop()) == ((Int16)frame.Pop())); + return +1; + } + } + + internal sealed class EqualChar : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Char)frame.Pop()) == ((Char)frame.Pop())); + return +1; + } + } + + internal sealed class EqualInt32 : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Int32)frame.Pop()) == ((Int32)frame.Pop())); + return +1; + } + } + + internal sealed class EqualInt64 : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Int64)frame.Pop()) == ((Int64)frame.Pop())); + return +1; + } + } + + internal sealed class EqualByte : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Byte)frame.Pop()) == ((Byte)frame.Pop())); + return +1; + } + } + + internal sealed class EqualUInt16 : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((UInt16)frame.Pop()) == ((UInt16)frame.Pop())); + return +1; + } + } + + internal sealed class EqualUInt32 : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((UInt32)frame.Pop()) == ((UInt32)frame.Pop())); + return +1; + } + } + + internal sealed class EqualUInt64 : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((UInt64)frame.Pop()) == ((UInt64)frame.Pop())); + return +1; + } + } + + internal sealed class EqualSingle : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Single)frame.Pop()) == ((Single)frame.Pop())); + return +1; + } + } + + internal sealed class EqualDouble : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Double)frame.Pop()) == ((Double)frame.Pop())); + return +1; + } + } + + internal sealed class EqualReference : EqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(frame.Pop() == frame.Pop()); + return +1; + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public static Instruction Create(Type type) { + // Boxed enums can be unboxed as their underlying types: + switch ((type.IsEnum() ? Enum.GetUnderlyingType(type) : type).GetTypeCode()) { + case TypeCode.Boolean: return _Boolean ?? (_Boolean = new EqualBoolean()); + case TypeCode.SByte: return _SByte ?? (_SByte = new EqualSByte()); + case TypeCode.Byte: return _Byte ?? (_Byte = new EqualByte()); + case TypeCode.Char: return _Char ?? (_Char = new EqualChar()); + case TypeCode.Int16: return _Int16 ?? (_Int16 = new EqualInt16()); + case TypeCode.Int32: return _Int32 ?? (_Int32 = new EqualInt32()); + case TypeCode.Int64: return _Int64 ?? (_Int64 = new EqualInt64()); + + case TypeCode.UInt16: return _UInt16 ?? (_UInt16 = new EqualInt16()); + case TypeCode.UInt32: return _UInt32 ?? (_UInt32 = new EqualInt32()); + case TypeCode.UInt64: return _UInt64 ?? (_UInt64 = new EqualInt64()); + + case TypeCode.Single: return _Single ?? (_Single = new EqualSingle()); + case TypeCode.Double: return _Double ?? (_Double = new EqualDouble()); + + case TypeCode.Object: + if (!type.IsValueType()) { + return _Reference ?? (_Reference = new EqualReference()); + } + // TODO: Nullable<T> + throw new NotImplementedException(); + + default: + throw new NotImplementedException(); + } + } + + public override string ToString() { + return "Equal()"; + } + } +}
\ No newline at end of file diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/FieldOperations.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/FieldOperations.cs new file mode 100644 index 00000000000..4bb8ec65c46 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/FieldOperations.cs @@ -0,0 +1,94 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal sealed class LoadStaticFieldInstruction : Instruction { + private readonly FieldInfo _field; + + public LoadStaticFieldInstruction(FieldInfo field) { + Debug.Assert(field.IsStatic); + _field = field; + } + + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + frame.Push(_field.GetValue(null)); + return +1; + } + } + + internal sealed class LoadFieldInstruction : Instruction { + private readonly FieldInfo _field; + + public LoadFieldInstruction(FieldInfo field) { + Assert.NotNull(field); + _field = field; + } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + frame.Push(_field.GetValue(frame.Pop())); + return +1; + } + } + + internal sealed class StoreFieldInstruction : Instruction { + private readonly FieldInfo _field; + + public StoreFieldInstruction(FieldInfo field) { + Assert.NotNull(field); + _field = field; + } + + public override int ConsumedStack { get { return 2; } } + public override int ProducedStack { get { return 0; } } + + public override int Run(InterpretedFrame frame) { + object value = frame.Pop(); + object self = frame.Pop(); + _field.SetValue(self, value); + return +1; + } + } + + internal sealed class StoreStaticFieldInstruction : Instruction { + private readonly FieldInfo _field; + + public StoreStaticFieldInstruction(FieldInfo field) { + Assert.NotNull(field); + _field = field; + } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 0; } } + + public override int Run(InterpretedFrame frame) { + object value = frame.Pop(); + _field.SetValue(null, value); + return +1; + } + } +}
\ No newline at end of file diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/GreaterThanInstruction.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/GreaterThanInstruction.cs new file mode 100644 index 00000000000..a35f16b0e34 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/GreaterThanInstruction.cs @@ -0,0 +1,146 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal abstract class GreaterThanInstruction : Instruction { + private static Instruction _SByte, _Int16, _Char, _Int32, _Int64, _Byte, _UInt16, _UInt32, _UInt64, _Single, _Double; + + public override int ConsumedStack { get { return 2; } } + public override int ProducedStack { get { return 1; } } + + private GreaterThanInstruction() { + } + + internal sealed class GreaterThanSByte : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + SByte right = (SByte)frame.Pop(); + frame.Push(((SByte)frame.Pop()) > right); + return +1; + } + } + + internal sealed class GreaterThanInt16 : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + Int16 right = (Int16)frame.Pop(); + frame.Push(((Int16)frame.Pop()) > right); + return +1; + } + } + + internal sealed class GreaterThanChar : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + Char right = (Char)frame.Pop(); + frame.Push(((Char)frame.Pop()) > right); + return +1; + } + } + + internal sealed class GreaterThanInt32 : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + Int32 right = (Int32)frame.Pop(); + frame.Push(((Int32)frame.Pop()) > right); + return +1; + } + } + + internal sealed class GreaterThanInt64 : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + Int64 right = (Int64)frame.Pop(); + frame.Push(((Int64)frame.Pop()) > right); + return +1; + } + } + + internal sealed class GreaterThanByte : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + Byte right = (Byte)frame.Pop(); + frame.Push(((Byte)frame.Pop()) > right); + return +1; + } + } + + internal sealed class GreaterThanUInt16 : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + UInt16 right = (UInt16)frame.Pop(); + frame.Push(((UInt16)frame.Pop()) > right); + return +1; + } + } + + internal sealed class GreaterThanUInt32 : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + UInt32 right = (UInt32)frame.Pop(); + frame.Push(((UInt32)frame.Pop()) > right); + return +1; + } + } + + internal sealed class GreaterThanUInt64 : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + UInt64 right = (UInt64)frame.Pop(); + frame.Push(((UInt64)frame.Pop()) > right); + return +1; + } + } + + internal sealed class GreaterThanSingle : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + Single right = (Single)frame.Pop(); + frame.Push(((Single)frame.Pop()) > right); + return +1; + } + } + + internal sealed class GreaterThanDouble : GreaterThanInstruction { + public override int Run(InterpretedFrame frame) { + Double right = (Double)frame.Pop(); + frame.Push(((Double)frame.Pop()) > right); + return +1; + } + } + + public static Instruction Create(Type type) { + Debug.Assert(!type.IsEnum()); + switch (type.GetTypeCode()) { + case TypeCode.SByte: return _SByte ?? (_SByte = new GreaterThanSByte()); + case TypeCode.Byte: return _Byte ?? (_Byte = new GreaterThanByte()); + case TypeCode.Char: return _Char ?? (_Char = new GreaterThanChar()); + case TypeCode.Int16: return _Int16 ?? (_Int16 = new GreaterThanInt16()); + case TypeCode.Int32: return _Int32 ?? (_Int32 = new GreaterThanInt32()); + case TypeCode.Int64: return _Int64 ?? (_Int64 = new GreaterThanInt64()); + case TypeCode.UInt16: return _UInt16 ?? (_UInt16 = new GreaterThanUInt16()); + case TypeCode.UInt32: return _UInt32 ?? (_UInt32 = new GreaterThanUInt32()); + case TypeCode.UInt64: return _UInt64 ?? (_UInt64 = new GreaterThanUInt64()); + case TypeCode.Single: return _Single ?? (_Single = new GreaterThanSingle()); + case TypeCode.Double: return _Double ?? (_Double = new GreaterThanDouble()); + + default: + throw Assert.Unreachable; + } + } + + public override string ToString() { + return "GreaterThan()"; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/Instruction.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/Instruction.cs new file mode 100644 index 00000000000..28267ec2a58 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/Instruction.cs @@ -0,0 +1,73 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + public interface IInstructionProvider { + void AddInstructions(LightCompiler compiler); + } + + public abstract partial class Instruction { + public virtual int ConsumedStack { get { return 0; } } + public virtual int ProducedStack { get { return 0; } } + public virtual int ConsumedContinuations { get { return 0; } } + public virtual int ProducedContinuations { get { return 0; } } + + public int StackBalance { + get { return ProducedStack - ConsumedStack; } + } + + public int ContinuationsBalance { + get { return ProducedContinuations - ConsumedContinuations; } + } + + public abstract int Run(InterpretedFrame frame); + + public virtual string InstructionName { + get { return GetType().Name.Replace("Instruction", ""); } + } + + public override string ToString() { + return InstructionName + "()"; + } + + public virtual string ToDebugString(int instructionIndex, object cookie, Func<int, int> labelIndexer, IList<object> objects) { + return ToString(); + } + + public virtual object GetDebugCookie(LightCompiler compiler) { + return null; + } + } + + internal sealed class NotInstruction : Instruction { + public static readonly Instruction Instance = new NotInstruction(); + + private NotInstruction() { } + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 1; } } + public override int Run(InterpretedFrame frame) { + frame.Push((bool)frame.Pop() ? ScriptingRuntimeHelpers.False : ScriptingRuntimeHelpers.True); + return +1; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/InstructionFactory.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/InstructionFactory.cs new file mode 100644 index 00000000000..ca0be0924d3 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/InstructionFactory.cs @@ -0,0 +1,115 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_NUMERICS +using BigInt = System.Numerics.BigInteger; +#endif + +using System; +using System.Collections.Generic; + +using Microsoft.Scripting.Math; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + public abstract class InstructionFactory { + // TODO: weak table for types in a collectible assembly? + private static Dictionary<Type, InstructionFactory> _factories; + + internal static InstructionFactory GetFactory(Type type) { + if (_factories == null) { + _factories = new Dictionary<Type, InstructionFactory>() { + { typeof(object), InstructionFactory<object>.Factory }, + { typeof(bool), InstructionFactory<bool>.Factory }, + { typeof(byte), InstructionFactory<byte>.Factory }, + { typeof(sbyte), InstructionFactory<sbyte>.Factory }, + { typeof(short), InstructionFactory<short>.Factory }, + { typeof(ushort), InstructionFactory<ushort>.Factory }, + { typeof(int), InstructionFactory<int>.Factory }, + { typeof(uint), InstructionFactory<uint>.Factory }, + { typeof(long), InstructionFactory<long>.Factory }, + { typeof(ulong), InstructionFactory<ulong>.Factory }, + { typeof(float), InstructionFactory<float>.Factory }, + { typeof(double), InstructionFactory<double>.Factory }, + { typeof(char), InstructionFactory<char>.Factory }, + { typeof(string), InstructionFactory<string>.Factory }, +#if FEATURE_NUMERICS + { typeof(BigInt), InstructionFactory<BigInt>.Factory }, +#endif + { typeof(BigInteger), InstructionFactory<BigInteger>.Factory } + }; + } + + lock (_factories) { + InstructionFactory factory; + if (!_factories.TryGetValue(type, out factory)) { + factory = (InstructionFactory)typeof(InstructionFactory<>).MakeGenericType(type).GetDeclaredField("Factory").GetValue(null); + _factories[type] = factory; + } + return factory; + } + } + + internal protected abstract Instruction GetArrayItem(); + internal protected abstract Instruction SetArrayItem(); + internal protected abstract Instruction TypeIs(); + internal protected abstract Instruction TypeAs(); + internal protected abstract Instruction DefaultValue(); + internal protected abstract Instruction NewArray(); + internal protected abstract Instruction NewArrayInit(int elementCount); + } + + public sealed class InstructionFactory<T> : InstructionFactory { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly InstructionFactory Factory = new InstructionFactory<T>(); + + private Instruction _getArrayItem; + private Instruction _setArrayItem; + private Instruction _typeIs; + private Instruction _defaultValue; + private Instruction _newArray; + private Instruction _typeAs; + + private InstructionFactory() { } + + internal protected override Instruction GetArrayItem() { + return _getArrayItem ?? (_getArrayItem = new GetArrayItemInstruction<T>()); + } + + internal protected override Instruction SetArrayItem() { + return _setArrayItem ?? (_setArrayItem = new SetArrayItemInstruction<T>()); + } + + internal protected override Instruction TypeIs() { + return _typeIs ?? (_typeIs = new TypeIsInstruction<T>()); + } + + internal protected override Instruction TypeAs() { + return _typeAs ?? (_typeAs = new TypeAsInstruction<T>()); + } + + internal protected override Instruction DefaultValue() { + return _defaultValue ?? (_defaultValue = new DefaultValueInstruction<T>()); + } + + internal protected override Instruction NewArray() { + return _newArray ?? (_newArray = new NewArrayInstruction<T>()); + } + + internal protected override Instruction NewArrayInit(int elementCount) { + return new NewArrayInitInstruction<T>(elementCount); + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/InstructionList.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/InstructionList.cs new file mode 100644 index 00000000000..c605977208d --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/InstructionList.cs @@ -0,0 +1,1001 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ +// Enables instruction counting and displaying stats at process exit. +// #define STATS + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Security; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] + [DebuggerTypeProxy(typeof(InstructionArray.DebugView))] + public struct InstructionArray { + internal readonly int MaxStackDepth; + internal readonly int MaxContinuationDepth; + internal readonly Instruction[] Instructions; + internal readonly object[] Objects; + internal readonly RuntimeLabel[] Labels; + + // list of (instruction index, cookie) sorted by instruction index: + internal readonly List<KeyValuePair<int, object>> DebugCookies; + + internal InstructionArray(int maxStackDepth, int maxContinuationDepth, Instruction[] instructions, + object[] objects, RuntimeLabel[] labels, List<KeyValuePair<int, object>> debugCookies) { + + MaxStackDepth = maxStackDepth; + MaxContinuationDepth = maxContinuationDepth; + Instructions = instructions; + DebugCookies = debugCookies; + Objects = objects; + Labels = labels; + } + + internal int Length { + get { return Instructions.Length; } + } + + #region Debug View + + internal sealed class DebugView { + private readonly InstructionArray _array; + + public DebugView(InstructionArray array) { + _array = array; + + } + + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public InstructionList.DebugView.InstructionView[]/*!*/ A0 { + get { + return InstructionList.DebugView.GetInstructionViews( + _array.Instructions, + _array.Objects, + (index) => _array.Labels[index].Index, + _array.DebugCookies + ); + } + } + } + + #endregion + } + + [DebuggerTypeProxy(typeof(InstructionList.DebugView))] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] + public sealed class InstructionList { + private readonly List<Instruction> _instructions = new List<Instruction>(); + private List<object> _objects; + + private int _currentStackDepth; + private int _maxStackDepth; + private int _currentContinuationsDepth; + private int _maxContinuationDepth; + private int _runtimeLabelCount; + private List<BranchLabel> _labels; + + // list of (instruction index, cookie) sorted by instruction index: + private List<KeyValuePair<int, object>> _debugCookies = null; + + #region Debug View + + internal sealed class DebugView { + private readonly InstructionList _list; + + public DebugView(InstructionList list) { + _list = list; + } + + [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] + public InstructionView[]/*!*/ A0 { + get { + return GetInstructionViews( + _list._instructions, + _list._objects, + (index) => _list._labels[index].TargetIndex, + _list._debugCookies + ); + } + } + + internal static InstructionView[] GetInstructionViews(IList<Instruction> instructions, IList<object> objects, + Func<int, int> labelIndexer, IList<KeyValuePair<int, object>> debugCookies) { + + var result = new List<InstructionView>(); + int index = 0; + int stackDepth = 0; + int continuationsDepth = 0; + + var cookieEnumerator = (debugCookies != null ? debugCookies : new KeyValuePair<int, object>[0]).GetEnumerator(); + var hasCookie = cookieEnumerator.MoveNext(); + + for (int i = 0; i < instructions.Count; i++) { + object cookie = null; + while (hasCookie && cookieEnumerator.Current.Key == i) { + cookie = cookieEnumerator.Current.Value; + hasCookie = cookieEnumerator.MoveNext(); + } + + int stackDiff = instructions[i].StackBalance; + int contDiff = instructions[i].ContinuationsBalance; + string name = instructions[i].ToDebugString(i, cookie, labelIndexer, objects); + result.Add(new InstructionView(instructions[i], name, i, stackDepth, continuationsDepth)); + + index++; + stackDepth += stackDiff; + continuationsDepth += contDiff; + } + return result.ToArray(); + } + + [DebuggerDisplay("{GetValue(),nq}", Name = "{GetName(),nq}", Type = "{GetDisplayType(), nq}")] + internal struct InstructionView { + private readonly int _index; + private readonly int _stackDepth; + private readonly int _continuationsDepth; + private readonly string _name; + private readonly Instruction _instruction; + + internal string GetName() { + return _index.ToString() + + (_continuationsDepth == 0 ? "" : " C(" + _continuationsDepth.ToString() + ")") + + (_stackDepth == 0 ? "" : " S(" + _stackDepth.ToString() + ")"); + } + + internal string GetValue() { + return _name; + } + + internal string GetDisplayType() { + return _instruction.ContinuationsBalance.ToString() + "/" + _instruction.StackBalance.ToString(); + } + + public InstructionView(Instruction instruction, string name, int index, int stackDepth, int continuationsDepth) { + _instruction = instruction; + _name = name; + _index = index; + _stackDepth = stackDepth; + _continuationsDepth = continuationsDepth; + } + } + } + + #endregion + + #region Core Emit Ops + + public void Emit(Instruction instruction) { + _instructions.Add(instruction); + UpdateStackDepth(instruction); + } + + private void UpdateStackDepth(Instruction instruction) { + Debug.Assert(instruction.ConsumedStack >= 0 && instruction.ProducedStack >= 0 && + instruction.ConsumedContinuations >= 0 && instruction.ProducedContinuations >= 0); + + _currentStackDepth -= instruction.ConsumedStack; + Debug.Assert(_currentStackDepth >= 0); + _currentStackDepth += instruction.ProducedStack; + if (_currentStackDepth > _maxStackDepth) { + _maxStackDepth = _currentStackDepth; + } + + _currentContinuationsDepth -= instruction.ConsumedContinuations; + Debug.Assert(_currentContinuationsDepth >= 0); + _currentContinuationsDepth += instruction.ProducedContinuations; + if (_currentContinuationsDepth > _maxContinuationDepth) { + _maxContinuationDepth = _currentContinuationsDepth; + } + } + + /// <summary> + /// Attaches a cookie to the last emitted instruction. + /// </summary> + [Conditional("DEBUG")] + public void SetDebugCookie(object cookie) { +#if DEBUG + if (_debugCookies == null) { + _debugCookies = new List<KeyValuePair<int, object>>(); + } + + Debug.Assert(Count > 0); + _debugCookies.Add(new KeyValuePair<int, object>(Count - 1, cookie)); +#endif + } + + public int Count { + get { return _instructions.Count; } + } + + public int CurrentStackDepth { + get { return _currentStackDepth; } + } + + public int CurrentContinuationsDepth { + get { return _currentContinuationsDepth; } + } + + public int MaxStackDepth { + get { return _maxStackDepth; } + } + + internal Instruction GetInstruction(int index) { + return _instructions[index]; + } + +#if STATS + private static Dictionary<string, int> _executedInstructions = new Dictionary<string, int>(); + private static Dictionary<string, Dictionary<object, bool>> _instances = new Dictionary<string, Dictionary<object, bool>>(); + + static InstructionList() { + AppDomain.CurrentDomain.ProcessExit += new EventHandler((_, __) => { + PerfTrack.DumpHistogram(_executedInstructions); + Console.WriteLine("-- Total executed: {0}", _executedInstructions.Values.Aggregate(0, (sum, value) => sum + value)); + Console.WriteLine("-----"); + + var referenced = new Dictionary<string, int>(); + int total = 0; + foreach (var entry in _instances) { + referenced[entry.Key] = entry.Value.Count; + total += entry.Value.Count; + } + + PerfTrack.DumpHistogram(referenced); + Console.WriteLine("-- Total referenced: {0}", total); + Console.WriteLine("-----"); + }); + } +#endif + public InstructionArray ToArray() { +#if STATS + lock (_executedInstructions) { + _instructions.ForEach((instr) => { + int value = 0; + var name = instr.GetType().Name; + _executedInstructions.TryGetValue(name, out value); + _executedInstructions[name] = value + 1; + + Dictionary<object, bool> dict; + if (!_instances.TryGetValue(name, out dict)) { + _instances[name] = dict = new Dictionary<object, bool>(); + } + dict[instr] = true; + }); + } +#endif + return new InstructionArray( + _maxStackDepth, + _maxContinuationDepth, + _instructions.ToArray(), + (_objects != null) ? _objects.ToArray() : null, + BuildRuntimeLabels(), + _debugCookies + ); + } + + #endregion + + #region Stack Operations + + private const int PushIntMinCachedValue = -100; + private const int PushIntMaxCachedValue = 100; + private const int CachedObjectCount = 256; + + private static Instruction _null; + private static Instruction _true; + private static Instruction _false; + private static Instruction[] _ints; + private static Instruction[] _loadObjectCached; + + public void EmitLoad(object value) { + EmitLoad(value, null); + } + + public void EmitLoad(bool value) { + if ((bool)value) { + Emit(_true ?? (_true = new LoadObjectInstruction(value))); + } else { + Emit(_false ?? (_false = new LoadObjectInstruction(value))); + } + } + + public void EmitLoad(object value, Type type) { + if (value == null) { + Emit(_null ?? (_null = new LoadObjectInstruction(null))); + return; + } + + if (type == null || type.IsValueType()) { + if (value is bool) { + EmitLoad((bool)value); + return; + } + + if (value is int) { + int i = (int)value; + if (i >= PushIntMinCachedValue && i <= PushIntMaxCachedValue) { + if (_ints == null) { + _ints = new Instruction[PushIntMaxCachedValue - PushIntMinCachedValue + 1]; + } + i -= PushIntMinCachedValue; + Emit(_ints[i] ?? (_ints[i] = new LoadObjectInstruction(value))); + return; + } + } + } + + if (_objects == null) { + _objects = new List<object>(); + if (_loadObjectCached == null) { + _loadObjectCached = new Instruction[CachedObjectCount]; + } + } + + if (_objects.Count < _loadObjectCached.Length) { + uint index = (uint)_objects.Count; + _objects.Add(value); + Emit(_loadObjectCached[index] ?? (_loadObjectCached[index] = new LoadCachedObjectInstruction(index))); + } else { + Emit(new LoadObjectInstruction(value)); + } + } + + public void EmitDup() { + Emit(DupInstruction.Instance); + } + + public void EmitPop() { + Emit(PopInstruction.Instance); + } + + #endregion + + #region Locals + + internal void SwitchToBoxed(int index, int instructionIndex) { + var instruction = _instructions[instructionIndex] as IBoxableInstruction; + + if (instruction != null) { + var newInstruction = instruction.BoxIfIndexMatches(index); + if (newInstruction != null) { + _instructions[instructionIndex] = newInstruction; + } + } + } + + private const int LocalInstrCacheSize = 64; + + private static Instruction[] _loadLocal; + private static Instruction[] _loadLocalBoxed; + private static Instruction[] _loadLocalFromClosure; + private static Instruction[] _loadLocalFromClosureBoxed; + private static Instruction[] _assignLocal; + private static Instruction[] _storeLocal; + private static Instruction[] _assignLocalBoxed; + private static Instruction[] _storeLocalBoxed; + private static Instruction[] _assignLocalToClosure; + private static Instruction[] _initReference; + private static Instruction[] _initImmutableRefBox; + private static Instruction[] _parameterBox; + private static Instruction[] _parameter; + + public void EmitLoadLocal(int index) { + if (_loadLocal == null) { + _loadLocal = new Instruction[LocalInstrCacheSize]; + } + + if (index < _loadLocal.Length) { + Emit(_loadLocal[index] ?? (_loadLocal[index] = new LoadLocalInstruction(index))); + } else { + Emit(new LoadLocalInstruction(index)); + } + } + + public void EmitLoadLocalBoxed(int index) { + Emit(LoadLocalBoxed(index)); + } + + internal static Instruction LoadLocalBoxed(int index) { + if (_loadLocalBoxed == null) { + _loadLocalBoxed = new Instruction[LocalInstrCacheSize]; + } + + if (index < _loadLocalBoxed.Length) { + return _loadLocalBoxed[index] ?? (_loadLocalBoxed[index] = new LoadLocalBoxedInstruction(index)); + } else { + return new LoadLocalBoxedInstruction(index); + } + } + + public void EmitLoadLocalFromClosure(int index) { + if (_loadLocalFromClosure == null) { + _loadLocalFromClosure = new Instruction[LocalInstrCacheSize]; + } + + if (index < _loadLocalFromClosure.Length) { + Emit(_loadLocalFromClosure[index] ?? (_loadLocalFromClosure[index] = new LoadLocalFromClosureInstruction(index))); + } else { + Emit(new LoadLocalFromClosureInstruction(index)); + } + } + + public void EmitLoadLocalFromClosureBoxed(int index) { + if (_loadLocalFromClosureBoxed == null) { + _loadLocalFromClosureBoxed = new Instruction[LocalInstrCacheSize]; + } + + if (index < _loadLocalFromClosureBoxed.Length) { + Emit(_loadLocalFromClosureBoxed[index] ?? (_loadLocalFromClosureBoxed[index] = new LoadLocalFromClosureBoxedInstruction(index))); + } else { + Emit(new LoadLocalFromClosureBoxedInstruction(index)); + } + } + + public void EmitAssignLocal(int index) { + if (_assignLocal == null) { + _assignLocal = new Instruction[LocalInstrCacheSize]; + } + + if (index < _assignLocal.Length) { + Emit(_assignLocal[index] ?? (_assignLocal[index] = new AssignLocalInstruction(index))); + } else { + Emit(new AssignLocalInstruction(index)); + } + } + + public void EmitStoreLocal(int index) { + if (_storeLocal == null) { + _storeLocal = new Instruction[LocalInstrCacheSize]; + } + + if (index < _storeLocal.Length) { + Emit(_storeLocal[index] ?? (_storeLocal[index] = new StoreLocalInstruction(index))); + } else { + Emit(new StoreLocalInstruction(index)); + } + } + + public void EmitAssignLocalBoxed(int index) { + Emit(AssignLocalBoxed(index)); + } + + internal static Instruction AssignLocalBoxed(int index) { + if (_assignLocalBoxed == null) { + _assignLocalBoxed = new Instruction[LocalInstrCacheSize]; + } + + if (index < _assignLocalBoxed.Length) { + return _assignLocalBoxed[index] ?? (_assignLocalBoxed[index] = new AssignLocalBoxedInstruction(index)); + } else { + return new AssignLocalBoxedInstruction(index); + } + } + + public void EmitStoreLocalBoxed(int index) { + Emit(StoreLocalBoxed(index)); + } + + internal static Instruction StoreLocalBoxed(int index) { + if (_storeLocalBoxed == null) { + _storeLocalBoxed = new Instruction[LocalInstrCacheSize]; + } + + if (index < _storeLocalBoxed.Length) { + return _storeLocalBoxed[index] ?? (_storeLocalBoxed[index] = new StoreLocalBoxedInstruction(index)); + } else { + return new StoreLocalBoxedInstruction(index); + } + } + + public void EmitAssignLocalToClosure(int index) { + if (_assignLocalToClosure == null) { + _assignLocalToClosure = new Instruction[LocalInstrCacheSize]; + } + + if (index < _assignLocalToClosure.Length) { + Emit(_assignLocalToClosure[index] ?? (_assignLocalToClosure[index] = new AssignLocalToClosureInstruction(index))); + } else { + Emit(new AssignLocalToClosureInstruction(index)); + } + } + + public void EmitStoreLocalToClosure(int index) { + EmitAssignLocalToClosure(index); + EmitPop(); + } + + public void EmitInitializeLocal(int index, Type type) { + object value = ScriptingRuntimeHelpers.GetPrimitiveDefaultValue(type); + if (value != null) { + Emit(new InitializeLocalInstruction.ImmutableValue(index, value)); + } else if (type.IsValueType()) { + Emit(new InitializeLocalInstruction.MutableValue(index, type)); + } else { + Emit(InitReference(index)); + } + } + + internal void EmitInitializeParameter(int index) { + Emit(Parameter(index)); + } + + internal static Instruction Parameter(int index) { + if (_parameter == null) { + _parameter = new Instruction[LocalInstrCacheSize]; + } + + if (index < _parameter.Length) { + return _parameter[index] ?? (_parameter[index] = new InitializeLocalInstruction.Parameter(index)); + } + + return new InitializeLocalInstruction.Parameter(index); + } + + internal static Instruction ParameterBox(int index) { + if (_parameterBox == null) { + _parameterBox = new Instruction[LocalInstrCacheSize]; + } + + if (index < _parameterBox.Length) { + return _parameterBox[index] ?? (_parameterBox[index] = new InitializeLocalInstruction.ParameterBox(index)); + } + + return new InitializeLocalInstruction.ParameterBox(index); + } + + internal static Instruction InitReference(int index) { + if (_initReference == null) { + _initReference = new Instruction[LocalInstrCacheSize]; + } + + if (index < _initReference.Length) { + return _initReference[index] ?? (_initReference[index] = new InitializeLocalInstruction.Reference(index)); + } + + return new InitializeLocalInstruction.Reference(index); + } + + internal static Instruction InitImmutableRefBox(int index) { + if (_initImmutableRefBox == null) { + _initImmutableRefBox = new Instruction[LocalInstrCacheSize]; + } + + if (index < _initImmutableRefBox.Length) { + return _initImmutableRefBox[index] ?? (_initImmutableRefBox[index] = new InitializeLocalInstruction.ImmutableBox(index, null)); + } + + return new InitializeLocalInstruction.ImmutableBox(index, null); + } + + public void EmitNewRuntimeVariables(int count) { + Emit(new RuntimeVariablesInstruction(count)); + } + + #endregion + + #region Array Operations + + public void EmitGetArrayItem(Type arrayType) { + Type elementType = arrayType.GetElementType(); + if (elementType.IsClass() || elementType.IsInterface()) { + Emit(InstructionFactory<object>.Factory.GetArrayItem()); + } else { + Emit(InstructionFactory.GetFactory(elementType).GetArrayItem()); + } + } + + public void EmitSetArrayItem(Type arrayType) { + Type elementType = arrayType.GetElementType(); + if (elementType.IsClass() || elementType.IsInterface()) { + Emit(InstructionFactory<object>.Factory.SetArrayItem()); + } else { + Emit(InstructionFactory.GetFactory(elementType).SetArrayItem()); + } + } + + public void EmitNewArray(Type elementType) { + Emit(InstructionFactory.GetFactory(elementType).NewArray()); + } + + public void EmitNewArrayBounds(Type elementType, int rank) { + Emit(new NewArrayBoundsInstruction(elementType, rank)); + } + + public void EmitNewArrayInit(Type elementType, int elementCount) { + Emit(InstructionFactory.GetFactory(elementType).NewArrayInit(elementCount)); + } + + #endregion + + #region Arithmetic Operations + + public void EmitAdd(Type type, bool @checked) { + if (@checked) { + Emit(AddOvfInstruction.Create(type)); + } else { + Emit(AddInstruction.Create(type)); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")] + public void EmitSub(Type type, bool @checked) { + throw new NotSupportedException(); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")] + public void EmitMul(Type type, bool @checked) { + throw new NotSupportedException(); + } + + public void EmitDiv(Type type) { + Emit(DivInstruction.Create(type)); + } + + #endregion + + #region Comparisons + + public void EmitEqual(Type type) { + Emit(EqualInstruction.Create(type)); + } + + public void EmitNotEqual(Type type) { + Emit(NotEqualInstruction.Create(type)); + } + + public void EmitLessThan(Type type) { + Emit(LessThanInstruction.Create(type)); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")] + public void EmitLessThanOrEqual(Type type) { + throw new NotSupportedException(); + } + + public void EmitGreaterThan(Type type) { + Emit(GreaterThanInstruction.Create(type)); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters")] + public void EmitGreaterThanOrEqual(Type type) { + throw new NotSupportedException(); + } + + #endregion + + #region Conversions + + public void EmitNumericConvertChecked(TypeCode from, TypeCode to) { + Emit(new NumericConvertInstruction.Checked(from, to)); + } + + public void EmitNumericConvertUnchecked(TypeCode from, TypeCode to) { + Emit(new NumericConvertInstruction.Unchecked(from, to)); + } + + #endregion + + #region Boolean Operators + + public void EmitNot() { + Emit(NotInstruction.Instance); + } + + #endregion + + #region Types + + public void EmitDefaultValue(Type type) { + Emit(InstructionFactory.GetFactory(type).DefaultValue()); + } + + public void EmitNew(ConstructorInfo constructorInfo) { + Emit(new NewInstruction(constructorInfo)); + } + + internal void EmitCreateDelegate(LightDelegateCreator creator) { + Emit(new CreateDelegateInstruction(creator)); + } + + public void EmitTypeEquals() { + Emit(TypeEqualsInstruction.Instance); + } + + public void EmitTypeIs(Type type) { + Emit(InstructionFactory.GetFactory(type).TypeIs()); + } + + public void EmitTypeAs(Type type) { + Emit(InstructionFactory.GetFactory(type).TypeAs()); + } + + #endregion + + #region Fields and Methods + + private static readonly Dictionary<FieldInfo, Instruction> _loadFields = new Dictionary<FieldInfo, Instruction>(); + + public void EmitLoadField(FieldInfo field) { + Emit(GetLoadField(field)); + } + + private Instruction GetLoadField(FieldInfo field) { + lock (_loadFields) { + Instruction instruction; + if (!_loadFields.TryGetValue(field, out instruction)) { + if (field.IsStatic) { + instruction = new LoadStaticFieldInstruction(field); + } else { + instruction = new LoadFieldInstruction(field); + } + _loadFields.Add(field, instruction); + } + return instruction; + } + } + + public void EmitStoreField(FieldInfo field) { + if (field.IsStatic) { + Emit(new StoreStaticFieldInstruction(field)); + } else { + Emit(new StoreFieldInstruction(field)); + } + } + + #endregion + + #region Dynamic + + public void EmitDynamic(Type type, CallSiteBinder binder) { + Emit(CreateDynamicInstruction(type, binder)); + } + + #region Generated Dynamic InstructionList Factory + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_instructionlist_factory from: generate_dynamic_instructions.py + + public void EmitDynamic<T0, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, T5, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, TRet>.Factory(binder)); + } + + public void EmitDynamic<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>(CallSiteBinder binder) { + Emit(DynamicInstruction<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, TRet>.Factory(binder)); + } + + + // *** END GENERATED CODE *** + + #endregion + + private static Dictionary<Type, Func<CallSiteBinder, Instruction>> _factories = + new Dictionary<Type, Func<CallSiteBinder, Instruction>>(); + + /// <exception cref="SecurityException">Instruction can't be created due to insufficient privileges.</exception> + internal static Instruction CreateDynamicInstruction(Type delegateType, CallSiteBinder binder) { + Func<CallSiteBinder, Instruction> factory; + lock (_factories) { + if (!_factories.TryGetValue(delegateType, out factory)) { + if (delegateType.GetMethod("Invoke").ReturnType == typeof(void)) { + // TODO: We should generally support void returning binders but the only + // ones that exist are delete index/member who's perf isn't that critical. + return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder), true); + } + + Type instructionType = DynamicInstructionN.GetDynamicInstructionType(delegateType); + if (instructionType == null) { + return new DynamicInstructionN(delegateType, CallSite.Create(delegateType, binder)); + } + + factory = (Func<CallSiteBinder, Instruction>)instructionType.GetMethod("Factory").CreateDelegate(typeof(Func<CallSiteBinder, Instruction>)); + _factories[delegateType] = factory; + } + } + return factory(binder); + } + + #endregion + + #region Control Flow + + private static readonly RuntimeLabel[] EmptyRuntimeLabels = new RuntimeLabel[] { new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0) }; + + private RuntimeLabel[] BuildRuntimeLabels() { + if (_runtimeLabelCount == 0) { + return EmptyRuntimeLabels; + } + + var result = new RuntimeLabel[_runtimeLabelCount + 1]; + foreach (BranchLabel label in _labels) { + if (label.HasRuntimeLabel) { + result[label.LabelIndex] = label.ToRuntimeLabel(); + } + } + // "return and rethrow" label: + result[result.Length - 1] = new RuntimeLabel(Interpreter.RethrowOnReturn, 0, 0); + return result; + } + + public BranchLabel MakeLabel() { + if (_labels == null) { + _labels = new List<BranchLabel>(); + } + + var label = new BranchLabel(); + _labels.Add(label); + return label; + } + + internal void FixupBranch(int branchIndex, int offset) { + _instructions[branchIndex] = ((OffsetInstruction)_instructions[branchIndex]).Fixup(offset); + } + + private int EnsureLabelIndex(BranchLabel label) { + if (label.HasRuntimeLabel) { + return label.LabelIndex; + } + + label.LabelIndex = _runtimeLabelCount; + _runtimeLabelCount++; + return label.LabelIndex; + } + + public int MarkRuntimeLabel() { + BranchLabel handlerLabel = MakeLabel(); + MarkLabel(handlerLabel); + return EnsureLabelIndex(handlerLabel); + } + + public void MarkLabel(BranchLabel label) { + label.Mark(this); + } + + public void EmitGoto(BranchLabel label, bool hasResult, bool hasValue) { + Emit(GotoInstruction.Create(EnsureLabelIndex(label), hasResult, hasValue)); + } + + private void EmitBranch(OffsetInstruction instruction, BranchLabel label) { + Emit(instruction); + label.AddBranch(this, Count - 1); + } + + public void EmitBranch(BranchLabel label) { + EmitBranch(new BranchInstruction(), label); + } + + public void EmitBranch(BranchLabel label, bool hasResult, bool hasValue) { + EmitBranch(new BranchInstruction(hasResult, hasValue), label); + } + + public void EmitCoalescingBranch(BranchLabel leftNotNull) { + EmitBranch(new CoalescingBranchInstruction(), leftNotNull); + } + + public void EmitBranchTrue(BranchLabel elseLabel) { + EmitBranch(new BranchTrueInstruction(), elseLabel); + } + + public void EmitBranchFalse(BranchLabel elseLabel) { + EmitBranch(new BranchFalseInstruction(), elseLabel); + } + + public void EmitThrow() { + Emit(ThrowInstruction.Throw); + } + + public void EmitThrowVoid() { + Emit(ThrowInstruction.VoidThrow); + } + + public void EmitRethrow() { + Emit(ThrowInstruction.Rethrow); + } + + public void EmitRethrowVoid() { + Emit(ThrowInstruction.VoidRethrow); + } + + public void EmitEnterTryFinally(BranchLabel finallyStartLabel) { + Emit(EnterTryFinallyInstruction.Create(EnsureLabelIndex(finallyStartLabel))); + } + + public void EmitEnterFinally() { + Emit(EnterFinallyInstruction.Instance); + } + + public void EmitLeaveFinally() { + Emit(LeaveFinallyInstruction.Instance); + } + + public void EmitLeaveFault(bool hasValue) { + Emit(hasValue ? LeaveFaultInstruction.NonVoid : LeaveFaultInstruction.Void); + } + + public void EmitEnterExceptionHandlerNonVoid() { + Emit(EnterExceptionHandlerInstruction.NonVoid); + } + + public void EmitEnterExceptionHandlerVoid() { + Emit(EnterExceptionHandlerInstruction.Void); + } + + public void EmitLeaveExceptionHandler(bool hasValue, BranchLabel tryExpressionEndLabel) { + Emit(LeaveExceptionHandlerInstruction.Create(EnsureLabelIndex(tryExpressionEndLabel), hasValue)); + } + + public void EmitSwitch(Dictionary<int, int> cases) { + Emit(new SwitchInstruction(cases)); + } + + #endregion + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LabelInfo.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LabelInfo.cs new file mode 100644 index 00000000000..2517a85baf1 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LabelInfo.cs @@ -0,0 +1,309 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +#if FEATURE_REFEMIT +using System.Reflection.Emit; +#endif +using System.Text; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + + /// <summary> + /// Contains compiler state corresponding to a LabelTarget + /// See also LabelScopeInfo. + /// </summary> + internal sealed class LabelInfo { + // The tree node representing this label + private readonly LabelTarget _node; + + // The BranchLabel label, will be mutated if Node is redefined + private BranchLabel _label; + + // The blocks where this label is defined. If it has more than one item, + // the blocks can't be jumped to except from a child block + // If there's only 1 block (the common case) it's stored here, if there's multiple blocks it's stored + // as a HashSet<LabelScopeInfo> + private object _definitions; + + // Blocks that jump to this block + private readonly List<LabelScopeInfo> _references = new List<LabelScopeInfo>(); + + // True if at least one jump is across blocks + // If we have any jump across blocks to this label, then the + // LabelTarget can only be defined in one place + private bool _acrossBlockJump; + + internal LabelInfo(LabelTarget node) { + _node = node; + } + + internal BranchLabel GetLabel(LightCompiler compiler) { + EnsureLabel(compiler); + return _label; + } + + internal void Reference(LabelScopeInfo block) { + _references.Add(block); + if (HasDefinitions) { + ValidateJump(block); + } + } + + internal void Define(LabelScopeInfo block) { + // Prevent the label from being shadowed, which enforces cleaner + // trees. Also we depend on this for simplicity (keeping only one + // active IL Label per LabelInfo) + for (LabelScopeInfo j = block; j != null; j = j.Parent) { + if (j.ContainsTarget(_node)) { + throw new InvalidOperationException(String.Format("Label target already defined: {0}", _node.Name)); + } + } + + AddDefinition(block); + block.AddLabelInfo(_node, this); + + // Once defined, validate all jumps + if (HasDefinitions && !HasMultipleDefinitions) { + foreach (var r in _references) { + ValidateJump(r); + } + } else { + // Was just redefined, if we had any across block jumps, they're + // now invalid + if (_acrossBlockJump) { + throw new InvalidOperationException("Ambiguous jump"); + } + // For local jumps, we need a new IL label + // This is okay because: + // 1. no across block jumps have been made or will be made + // 2. we don't allow the label to be shadowed + _label = null; + } + } + + private void ValidateJump(LabelScopeInfo reference) { + // look for a simple jump out + for (LabelScopeInfo j = reference; j != null; j = j.Parent) { + if (DefinedIn(j)) { + // found it, jump is valid! + return; + } + if (j.Kind == LabelScopeKind.Filter) { + break; + } + } + + _acrossBlockJump = true; + + if (HasMultipleDefinitions) { + throw new InvalidOperationException(String.Format("Ambiguous jump {0}", _node.Name)); + } + + // We didn't find an outward jump. Look for a jump across blocks + LabelScopeInfo def = FirstDefinition(); + LabelScopeInfo common = CommonNode(def, reference, b => b.Parent); + + // Validate that we aren't jumping across a finally + for (LabelScopeInfo j = reference; j != common; j = j.Parent) { + if (j.Kind == LabelScopeKind.Filter) { + throw new InvalidOperationException("Control cannot leave filter test"); + } + } + + // Valdiate that we aren't jumping into a catch or an expression + for (LabelScopeInfo j = def; j != common; j = j.Parent) { + if (!j.CanJumpInto) { + if (j.Kind == LabelScopeKind.Expression) { + throw new InvalidOperationException("Control cannot enter an expression"); + } else { + throw new InvalidOperationException("Control cannot enter try"); + } + } + } + } + + internal void ValidateFinish() { + // Make sure that if this label was jumped to, it is also defined + if (_references.Count > 0 && !HasDefinitions) { + throw new InvalidOperationException("label target undefined"); + } + } + + private void EnsureLabel(LightCompiler compiler) { + if (_label == null) { + _label = compiler.Instructions.MakeLabel(); + } + } + + private bool DefinedIn(LabelScopeInfo scope) { + if (_definitions == scope) { + return true; + } + + HashSet<LabelScopeInfo> definitions = _definitions as HashSet<LabelScopeInfo>; + if (definitions != null) { + return definitions.Contains(scope); + } + return false; + } + + private bool HasDefinitions { + get { + return _definitions != null; + } + } + + private LabelScopeInfo FirstDefinition() { + LabelScopeInfo scope = _definitions as LabelScopeInfo; + if (scope != null) { + return scope; + } + return ((HashSet<LabelScopeInfo>)_definitions).First(); + } + + private void AddDefinition(LabelScopeInfo scope) { + if (_definitions == null) { + _definitions = scope; + } else { + HashSet<LabelScopeInfo> set = _definitions as HashSet<LabelScopeInfo>; + if(set == null) { + _definitions = set = new HashSet<LabelScopeInfo>() { (LabelScopeInfo)_definitions }; + } + set.Add(scope); + } + } + + private bool HasMultipleDefinitions { + get { + return _definitions is HashSet<LabelScopeInfo>; + } + } + + internal static T CommonNode<T>(T first, T second, Func<T, T> parent) where T : class { + var cmp = EqualityComparer<T>.Default; + if (cmp.Equals(first, second)) { + return first; + } + var set = new HashSet<T>(cmp); + for (T t = first; t != null; t = parent(t)) { + set.Add(t); + } + for (T t = second; t != null; t = parent(t)) { + if (set.Contains(t)) { + return t; + } + } + return null; + } + } + + public enum LabelScopeKind { + // any "statement like" node that can be jumped into + Statement, + + // these correspond to the node of the same name + Block, + Switch, + Lambda, + Try, + + // these correspond to the part of the try block we're in + Catch, + Finally, + Filter, + + // the catch-all value for any other expression type + // (means we can't jump into it) + Expression, + } + + // + // Tracks scoping information for LabelTargets. Logically corresponds to a + // "label scope". Even though we have arbitrary goto support, we still need + // to track what kinds of nodes that gotos are jumping through, both to + // emit property IL ("leave" out of a try block), and for validation, and + // to allow labels to be duplicated in the tree, as long as the jumps are + // considered "up only" jumps. + // + // We create one of these for every Expression that can be jumped into, as + // well as creating them for the first expression we can't jump into. The + // "Kind" property indicates what kind of scope this is. + // + internal sealed class LabelScopeInfo { + private HybridReferenceDictionary<LabelTarget, LabelInfo> Labels; // lazily allocated, we typically use this only once every 6th-7th block + internal readonly LabelScopeKind Kind; + internal readonly LabelScopeInfo Parent; + + internal LabelScopeInfo(LabelScopeInfo parent, LabelScopeKind kind) { + Parent = parent; + Kind = kind; + } + + /// <summary> + /// Returns true if we can jump into this node + /// </summary> + internal bool CanJumpInto { + get { + switch (Kind) { + case LabelScopeKind.Block: + case LabelScopeKind.Statement: + case LabelScopeKind.Switch: + case LabelScopeKind.Lambda: + return true; + } + return false; + } + } + + + internal bool ContainsTarget(LabelTarget target) { + if (Labels == null) { + return false; + } + + return Labels.ContainsKey(target); + } + + internal bool TryGetLabelInfo(LabelTarget target, out LabelInfo info) { + if (Labels == null) { + info = null; + return false; + } + + return Labels.TryGetValue(target, out info); + } + + internal void AddLabelInfo(LabelTarget target, LabelInfo info) { + Debug.Assert(CanJumpInto); + + if (Labels == null) { + Labels = new HybridReferenceDictionary<LabelTarget, LabelInfo>(); + } + + Labels[target] = info; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LessThanInstruction.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LessThanInstruction.cs new file mode 100644 index 00000000000..2875e8bf9cd --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LessThanInstruction.cs @@ -0,0 +1,146 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + public abstract class LessThanInstruction : Instruction { + private static Instruction _SByte, _Int16, _Char, _Int32, _Int64, _Byte, _UInt16, _UInt32, _UInt64, _Single, _Double; + + public override int ConsumedStack { get { return 2; } } + public override int ProducedStack { get { return 1; } } + + private LessThanInstruction() { + } + + internal sealed class LessThanSByte : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + SByte right = (SByte)frame.Pop(); + frame.Push(((SByte)frame.Pop()) < right); + return +1; + } + } + + internal sealed class LessThanInt16 : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + Int16 right = (Int16)frame.Pop(); + frame.Push(((Int16)frame.Pop()) < right); + return +1; + } + } + + internal sealed class LessThanChar : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + Char right = (Char)frame.Pop(); + frame.Push(((Char)frame.Pop()) < right); + return +1; + } + } + + internal sealed class LessThanInt32 : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + Int32 right = (Int32)frame.Pop(); + frame.Push(((Int32)frame.Pop()) < right); + return +1; + } + } + + internal sealed class LessThanInt64 : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + Int64 right = (Int64)frame.Pop(); + frame.Push(((Int64)frame.Pop()) < right); + return +1; + } + } + + internal sealed class LessThanByte : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + Byte right = (Byte)frame.Pop(); + frame.Push(((Byte)frame.Pop()) < right); + return +1; + } + } + + internal sealed class LessThanUInt16 : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + UInt16 right = (UInt16)frame.Pop(); + frame.Push(((UInt16)frame.Pop()) < right); + return +1; + } + } + + internal sealed class LessThanUInt32 : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + UInt32 right = (UInt32)frame.Pop(); + frame.Push(((UInt32)frame.Pop()) < right); + return +1; + } + } + + internal sealed class LessThanUInt64 : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + UInt64 right = (UInt64)frame.Pop(); + frame.Push(((UInt64)frame.Pop()) < right); + return +1; + } + } + + internal sealed class LessThanSingle : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + Single right = (Single)frame.Pop(); + frame.Push(((Single)frame.Pop()) < right); + return +1; + } + } + + internal sealed class LessThanDouble : LessThanInstruction { + public override int Run(InterpretedFrame frame) { + Double right = (Double)frame.Pop(); + frame.Push(((Double)frame.Pop()) < right); + return +1; + } + } + + public static Instruction Create(Type type) { + Debug.Assert(!type.IsEnum()); + switch (type.GetTypeCode()) { + case TypeCode.SByte: return _SByte ?? (_SByte = new LessThanSByte()); + case TypeCode.Byte: return _Byte ?? (_Byte = new LessThanByte()); + case TypeCode.Char: return _Char ?? (_Char = new LessThanChar()); + case TypeCode.Int16: return _Int16 ?? (_Int16 = new LessThanInt16()); + case TypeCode.Int32: return _Int32 ?? (_Int32 = new LessThanInt32()); + case TypeCode.Int64: return _Int64 ?? (_Int64 = new LessThanInt64()); + case TypeCode.UInt16: return _UInt16 ?? (_UInt16 = new LessThanUInt16()); + case TypeCode.UInt32: return _UInt32 ?? (_UInt32 = new LessThanUInt32()); + case TypeCode.UInt64: return _UInt64 ?? (_UInt64 = new LessThanUInt64()); + case TypeCode.Single: return _Single ?? (_Single = new LessThanSingle()); + case TypeCode.Double: return _Double ?? (_Double = new LessThanDouble()); + + default: + throw Assert.Unreachable; + } + } + + public override string ToString() { + return "LessThan()"; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LocalAccess.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LocalAccess.cs new file mode 100644 index 00000000000..bc0709553d1 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/LocalAccess.cs @@ -0,0 +1,374 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Runtime; +using System.Collections.Generic; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal interface IBoxableInstruction { + Instruction BoxIfIndexMatches(int index); + } + + internal abstract class LocalAccessInstruction : Instruction { + internal readonly int _index; + + protected LocalAccessInstruction(int index) { + _index = index; + } + + public override string ToDebugString(int instructionIndex, object cookie, Func<int, int> labelIndexer, IList<object> objects) { + return cookie == null ? + InstructionName + "(" + _index + ")" : + InstructionName + "(" + cookie + ": " + _index + ")"; + } + } + + #region Load + + internal sealed class LoadLocalInstruction : LocalAccessInstruction, IBoxableInstruction { + internal LoadLocalInstruction(int index) + : base(index) { + } + + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex++] = frame.Data[_index]; + //frame.Push(frame.Data[_index]); + return +1; + } + + public Instruction BoxIfIndexMatches(int index) { + return (index == _index) ? InstructionList.LoadLocalBoxed(index) : null; + } + } + + internal sealed class LoadLocalBoxedInstruction : LocalAccessInstruction { + internal LoadLocalBoxedInstruction(int index) + : base(index) { + } + + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + var box = (StrongBox<object>)frame.Data[_index]; + frame.Data[frame.StackIndex++] = box.Value; + return +1; + } + } + + internal sealed class LoadLocalFromClosureInstruction : LocalAccessInstruction { + internal LoadLocalFromClosureInstruction(int index) + : base(index) { + } + + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + var box = frame.Closure[_index]; + frame.Data[frame.StackIndex++] = box.Value; + return +1; + } + } + + internal sealed class LoadLocalFromClosureBoxedInstruction : LocalAccessInstruction { + internal LoadLocalFromClosureBoxedInstruction(int index) + : base(index) { + } + + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + var box = frame.Closure[_index]; + frame.Data[frame.StackIndex++] = box; + return +1; + } + } + + #endregion + + #region Store, Assign + + internal sealed class AssignLocalInstruction : LocalAccessInstruction, IBoxableInstruction { + internal AssignLocalInstruction(int index) + : base(index) { + } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[_index] = frame.Peek(); + return +1; + } + + public Instruction BoxIfIndexMatches(int index) { + return (index == _index) ? InstructionList.AssignLocalBoxed(index) : null; + } + } + + internal sealed class StoreLocalInstruction : LocalAccessInstruction, IBoxableInstruction { + internal StoreLocalInstruction(int index) + : base(index) { + } + + public override int ConsumedStack { get { return 1; } } + public override int Run(InterpretedFrame frame) { + frame.Data[_index] = frame.Data[--frame.StackIndex]; + //frame.Data[_index] = frame.Pop(); + return +1; + } + + public Instruction BoxIfIndexMatches(int index) { + return (index == _index) ? InstructionList.StoreLocalBoxed(index) : null; + } + } + + internal sealed class AssignLocalBoxedInstruction : LocalAccessInstruction { + internal AssignLocalBoxedInstruction(int index) + : base(index) { + } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + var box = (StrongBox<object>)frame.Data[_index]; + box.Value = frame.Peek(); + return +1; + } + } + + internal sealed class StoreLocalBoxedInstruction : LocalAccessInstruction { + internal StoreLocalBoxedInstruction(int index) + : base(index) { + } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 0; } } + + public override int Run(InterpretedFrame frame) { + var box = (StrongBox<object>)frame.Data[_index]; + box.Value = frame.Data[--frame.StackIndex]; + return +1; + } + } + + internal sealed class AssignLocalToClosureInstruction : LocalAccessInstruction { + internal AssignLocalToClosureInstruction(int index) + : base(index) { + } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + var box = frame.Closure[_index]; + box.Value = frame.Peek(); + return +1; + } + } + + #endregion + + #region Initialize + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1012:AbstractTypesShouldNotHaveConstructors")] + internal abstract class InitializeLocalInstruction : LocalAccessInstruction { + internal InitializeLocalInstruction(int index) + : base(index) { + } + + internal sealed class Reference : InitializeLocalInstruction, IBoxableInstruction { + internal Reference(int index) + : base(index) { + } + + public override int Run(InterpretedFrame frame) { + frame.Data[_index] = null; + return 1; + } + + public Instruction BoxIfIndexMatches(int index) { + return (index == _index) ? InstructionList.InitImmutableRefBox(index) : null; + } + + public override string InstructionName { + get { return "InitRef"; } + } + } + + internal sealed class ImmutableValue : InitializeLocalInstruction, IBoxableInstruction { + private readonly object _defaultValue; + + internal ImmutableValue(int index, object defaultValue) + : base(index) { + _defaultValue = defaultValue; + } + + public override int Run(InterpretedFrame frame) { + frame.Data[_index] = _defaultValue; + return 1; + } + + public Instruction BoxIfIndexMatches(int index) { + return (index == _index) ? new ImmutableBox(index, _defaultValue) : null; + } + + public override string InstructionName { + get { return "InitImmutableValue"; } + } + } + + internal sealed class ImmutableBox : InitializeLocalInstruction { + // immutable value: + private readonly object _defaultValue; + + internal ImmutableBox(int index, object defaultValue) + : base(index) { + _defaultValue = defaultValue; + } + + public override int Run(InterpretedFrame frame) { + frame.Data[_index] = new StrongBox<object>(_defaultValue); + return 1; + } + + public override string InstructionName { + get { return "InitImmutableBox"; } + } + } + + internal sealed class ParameterBox : InitializeLocalInstruction { + public ParameterBox(int index) + : base(index) { + } + + public override int Run(InterpretedFrame frame) { + frame.Data[_index] = new StrongBox<object>(frame.Data[_index]); + return 1; + } + + } + + internal sealed class Parameter : InitializeLocalInstruction, IBoxableInstruction { + internal Parameter(int index) + : base(index) { + } + + public override int Run(InterpretedFrame frame) { + // nop + return 1; + } + + public Instruction BoxIfIndexMatches(int index) { + if (index == _index) { + return InstructionList.ParameterBox(index); + } + return null; + } + + public override string InstructionName { + get { return "InitParameter"; } + } + } + + internal sealed class MutableValue : InitializeLocalInstruction, IBoxableInstruction { + private readonly Type _type; + + internal MutableValue(int index, Type type) + : base(index) { + _type = type; + } + + public override int Run(InterpretedFrame frame) { + try { + frame.Data[_index] = Activator.CreateInstance(_type); + } catch (TargetInvocationException e) { + ExceptionHelpers.UpdateForRethrow(e.InnerException); + throw e.InnerException; + } + + return 1; + } + + public Instruction BoxIfIndexMatches(int index) { + return (index == _index) ? new MutableBox(index, _type) : null; + } + + public override string InstructionName { + get { return "InitMutableValue"; } + } + } + + internal sealed class MutableBox : InitializeLocalInstruction { + private readonly Type _type; + + internal MutableBox(int index, Type type) + : base(index) { + _type = type; + } + + public override int Run(InterpretedFrame frame) { + frame.Data[_index] = new StrongBox<object>(Activator.CreateInstance(_type)); + return 1; + } + + public override string InstructionName { + get { return "InitMutableBox"; } + } + } + } + + #endregion + + #region RuntimeVariables + + internal sealed class RuntimeVariablesInstruction : Instruction { + private readonly int _count; + + public RuntimeVariablesInstruction(int count) { + _count = count; + } + + public override int ProducedStack { get { return 1; } } + public override int ConsumedStack { get { return _count; } } + + public override int Run(InterpretedFrame frame) { + var ret = new IStrongBox[_count]; + for (int i = ret.Length - 1; i >= 0; i--) { + ret[i] = (IStrongBox)frame.Pop(); + } + frame.Push(RuntimeVariables.Create(ret)); + return +1; + } + + public override string ToString() { + return "GetRuntimeVariables()"; + } + } + + #endregion +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/NotEqualInstruction.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/NotEqualInstruction.cs new file mode 100644 index 00000000000..f7da9f46dd3 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/NotEqualInstruction.cs @@ -0,0 +1,162 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal abstract class NotEqualInstruction : Instruction { + // Perf: EqualityComparer<T> but is 3/2 to 2 times slower. + private static Instruction _Reference, _Boolean, _SByte, _Int16, _Char, _Int32, _Int64, _Byte, _UInt16, _UInt32, _UInt64, _Single, _Double; + + public override int ConsumedStack { get { return 2; } } + public override int ProducedStack { get { return 1; } } + + private NotEqualInstruction() { + } + + internal sealed class NotEqualBoolean : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Boolean)frame.Pop()) != ((Boolean)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualSByte : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((SByte)frame.Pop()) != ((SByte)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualInt16 : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Int16)frame.Pop()) != ((Int16)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualChar : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Char)frame.Pop()) != ((Char)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualInt32 : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Int32)frame.Pop()) != ((Int32)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualInt64 : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Int64)frame.Pop()) != ((Int64)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualByte : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Byte)frame.Pop()) != ((Byte)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualUInt16 : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((UInt16)frame.Pop()) != ((UInt16)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualUInt32 : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((UInt32)frame.Pop()) != ((UInt32)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualUInt64 : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((UInt64)frame.Pop()) != ((UInt64)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualSingle : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Single)frame.Pop()) != ((Single)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualDouble : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(((Double)frame.Pop()) != ((Double)frame.Pop())); + return +1; + } + } + + internal sealed class NotEqualReference : NotEqualInstruction { + public override int Run(InterpretedFrame frame) { + frame.Push(frame.Pop() != frame.Pop()); + return +1; + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + public static Instruction Create(Type type) { + // Boxed enums can be unboxed as their underlying types: + switch ((type.IsEnum() ? Enum.GetUnderlyingType(type) : type).GetTypeCode()) { + case TypeCode.Boolean: return _Boolean ?? (_Boolean = new NotEqualBoolean()); + case TypeCode.SByte: return _SByte ?? (_SByte = new NotEqualSByte()); + case TypeCode.Byte: return _Byte ?? (_Byte = new NotEqualByte()); + case TypeCode.Char: return _Char ?? (_Char = new NotEqualChar()); + case TypeCode.Int16: return _Int16 ?? (_Int16 = new NotEqualInt16()); + case TypeCode.Int32: return _Int32 ?? (_Int32 = new NotEqualInt32()); + case TypeCode.Int64: return _Int64 ?? (_Int64 = new NotEqualInt64()); + + case TypeCode.UInt16: return _UInt16 ?? (_UInt16 = new NotEqualInt16()); + case TypeCode.UInt32: return _UInt32 ?? (_UInt32 = new NotEqualInt32()); + case TypeCode.UInt64: return _UInt64 ?? (_UInt64 = new NotEqualInt64()); + + case TypeCode.Single: return _Single ?? (_Single = new NotEqualSingle()); + case TypeCode.Double: return _Double ?? (_Double = new NotEqualDouble()); + + case TypeCode.Object: + if (!type.IsValueType()) { + return _Reference ?? (_Reference = new NotEqualReference()); + } + // TODO: Nullable<T> + throw new NotImplementedException(); + + default: + throw new NotImplementedException(); + } + } + + public override string ToString() { + return "NotEqual()"; + } + } +} + diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/NumericConvertInstruction.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/NumericConvertInstruction.cs new file mode 100644 index 00000000000..e42515f5083 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/NumericConvertInstruction.cs @@ -0,0 +1,254 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal abstract class NumericConvertInstruction : Instruction { + internal readonly TypeCode _from, _to; + + protected NumericConvertInstruction(TypeCode from, TypeCode to) { + _from = from; + _to = to; + } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 1; } } + + public override string ToString() { + return InstructionName + "(" + _from + "->" + _to + ")"; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public sealed class Unchecked : NumericConvertInstruction { + public override string InstructionName { get { return "UncheckedConvert"; } } + + public Unchecked(TypeCode from, TypeCode to) + : base(from, to) { + } + + public override int Run(InterpretedFrame frame) { + frame.Push(Convert(frame.Pop())); + return +1; + } + + private object Convert(object obj) { + switch (_from) { + case TypeCode.Byte: return ConvertInt32((Byte)obj); + case TypeCode.SByte: return ConvertInt32((SByte)obj); + case TypeCode.Int16: return ConvertInt32((Int16)obj); + case TypeCode.Char: return ConvertInt32((Char)obj); + case TypeCode.Int32: return ConvertInt32((Int32)obj); + case TypeCode.Int64: return ConvertInt64((Int64)obj); + case TypeCode.UInt16: return ConvertInt32((UInt16)obj); + case TypeCode.UInt32: return ConvertInt64((UInt32)obj); + case TypeCode.UInt64: return ConvertUInt64((UInt64)obj); + case TypeCode.Single: return ConvertDouble((Single)obj); + case TypeCode.Double: return ConvertDouble((Double)obj); + default: throw Assert.Unreachable; + } + } + + private object ConvertInt32(int obj) { + unchecked { + switch (_to) { + case TypeCode.Byte: return (Byte)obj; + case TypeCode.SByte: return (SByte)obj; + case TypeCode.Int16: return (Int16)obj; + case TypeCode.Char: return (Char)obj; + case TypeCode.Int32: return (Int32)obj; + case TypeCode.Int64: return (Int64)obj; + case TypeCode.UInt16: return (UInt16)obj; + case TypeCode.UInt32: return (UInt32)obj; + case TypeCode.UInt64: return (UInt64)obj; + case TypeCode.Single: return (Single)obj; + case TypeCode.Double: return (Double)obj; + default: throw Assert.Unreachable; + } + } + } + + private object ConvertInt64(Int64 obj) { + unchecked { + switch (_to) { + case TypeCode.Byte: return (Byte)obj; + case TypeCode.SByte: return (SByte)obj; + case TypeCode.Int16: return (Int16)obj; + case TypeCode.Char: return (Char)obj; + case TypeCode.Int32: return (Int32)obj; + case TypeCode.Int64: return (Int64)obj; + case TypeCode.UInt16: return (UInt16)obj; + case TypeCode.UInt32: return (UInt32)obj; + case TypeCode.UInt64: return (UInt64)obj; + case TypeCode.Single: return (Single)obj; + case TypeCode.Double: return (Double)obj; + default: throw Assert.Unreachable; + } + } + } + + private object ConvertUInt64(UInt64 obj) { + unchecked { + switch (_to) { + case TypeCode.Byte: return (Byte)obj; + case TypeCode.SByte: return (SByte)obj; + case TypeCode.Int16: return (Int16)obj; + case TypeCode.Char: return (Char)obj; + case TypeCode.Int32: return (Int32)obj; + case TypeCode.Int64: return (Int64)obj; + case TypeCode.UInt16: return (UInt16)obj; + case TypeCode.UInt32: return (UInt32)obj; + case TypeCode.UInt64: return (UInt64)obj; + case TypeCode.Single: return (Single)obj; + case TypeCode.Double: return (Double)obj; + default: throw Assert.Unreachable; + } + } + } + + private object ConvertDouble(Double obj) { + unchecked { + switch (_to) { + case TypeCode.Byte: return (Byte)obj; + case TypeCode.SByte: return (SByte)obj; + case TypeCode.Int16: return (Int16)obj; + case TypeCode.Char: return (Char)obj; + case TypeCode.Int32: return (Int32)obj; + case TypeCode.Int64: return (Int64)obj; + case TypeCode.UInt16: return (UInt16)obj; + case TypeCode.UInt32: return (UInt32)obj; + case TypeCode.UInt64: return (UInt64)obj; + case TypeCode.Single: return (Single)obj; + case TypeCode.Double: return (Double)obj; + default: throw Assert.Unreachable; + } + } + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] + public sealed class Checked : NumericConvertInstruction { + public override string InstructionName { get { return "CheckedConvert"; } } + + public Checked(TypeCode from, TypeCode to) + : base(from, to) { + } + + public override int Run(InterpretedFrame frame) { + frame.Push(Convert(frame.Pop())); + return +1; + } + + private object Convert(object obj) { + switch (_from) { + case TypeCode.Byte: return ConvertInt32((Byte)obj); + case TypeCode.SByte: return ConvertInt32((SByte)obj); + case TypeCode.Int16: return ConvertInt32((Int16)obj); + case TypeCode.Char: return ConvertInt32((Char)obj); + case TypeCode.Int32: return ConvertInt32((Int32)obj); + case TypeCode.Int64: return ConvertInt64((Int64)obj); + case TypeCode.UInt16: return ConvertInt32((UInt16)obj); + case TypeCode.UInt32: return ConvertInt64((UInt32)obj); + case TypeCode.UInt64: return ConvertUInt64((UInt64)obj); + case TypeCode.Single: return ConvertDouble((Single)obj); + case TypeCode.Double: return ConvertDouble((Double)obj); + default: throw Assert.Unreachable; + } + } + + private object ConvertInt32(int obj) { + checked { + switch (_to) { + case TypeCode.Byte: return (Byte)obj; + case TypeCode.SByte: return (SByte)obj; + case TypeCode.Int16: return (Int16)obj; + case TypeCode.Char: return (Char)obj; + case TypeCode.Int32: return (Int32)obj; + case TypeCode.Int64: return (Int64)obj; + case TypeCode.UInt16: return (UInt16)obj; + case TypeCode.UInt32: return (UInt32)obj; + case TypeCode.UInt64: return (UInt64)obj; + case TypeCode.Single: return (Single)obj; + case TypeCode.Double: return (Double)obj; + default: throw Assert.Unreachable; + } + } + } + + private object ConvertInt64(Int64 obj) { + checked { + switch (_to) { + case TypeCode.Byte: return (Byte)obj; + case TypeCode.SByte: return (SByte)obj; + case TypeCode.Int16: return (Int16)obj; + case TypeCode.Char: return (Char)obj; + case TypeCode.Int32: return (Int32)obj; + case TypeCode.Int64: return (Int64)obj; + case TypeCode.UInt16: return (UInt16)obj; + case TypeCode.UInt32: return (UInt32)obj; + case TypeCode.UInt64: return (UInt64)obj; + case TypeCode.Single: return (Single)obj; + case TypeCode.Double: return (Double)obj; + default: throw Assert.Unreachable; + } + } + } + + private object ConvertUInt64(UInt64 obj) { + checked { + switch (_to) { + case TypeCode.Byte: return (Byte)obj; + case TypeCode.SByte: return (SByte)obj; + case TypeCode.Int16: return (Int16)obj; + case TypeCode.Char: return (Char)obj; + case TypeCode.Int32: return (Int32)obj; + case TypeCode.Int64: return (Int64)obj; + case TypeCode.UInt16: return (UInt16)obj; + case TypeCode.UInt32: return (UInt32)obj; + case TypeCode.UInt64: return (UInt64)obj; + case TypeCode.Single: return (Single)obj; + case TypeCode.Double: return (Double)obj; + default: throw Assert.Unreachable; + } + } + } + + private object ConvertDouble(Double obj) { + checked { + switch (_to) { + case TypeCode.Byte: return (Byte)obj; + case TypeCode.SByte: return (SByte)obj; + case TypeCode.Int16: return (Int16)obj; + case TypeCode.Char: return (Char)obj; + case TypeCode.Int32: return (Int32)obj; + case TypeCode.Int64: return (Int64)obj; + case TypeCode.UInt16: return (UInt16)obj; + case TypeCode.UInt32: return (UInt32)obj; + case TypeCode.UInt64: return (UInt64)obj; + case TypeCode.Single: return (Single)obj; + case TypeCode.Double: return (Double)obj; + default: throw Assert.Unreachable; + } + } + } + } + } +}
\ No newline at end of file diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/StackOperations.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/StackOperations.cs new file mode 100644 index 00000000000..e2c9e7d1ab7 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/StackOperations.cs @@ -0,0 +1,117 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System.Collections.Generic; +using System; +using System.Diagnostics; +using Microsoft.Scripting.Utils; +namespace Microsoft.Scripting.Interpreter { + internal sealed class LoadObjectInstruction : Instruction { + private readonly object _value; + + internal LoadObjectInstruction(object value) { + _value = value; + } + + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex++] = _value; + return +1; + } + + public override string ToString() { + return "LoadObject(" + (_value ?? "null") + ")"; + } + } + + internal sealed class LoadCachedObjectInstruction : Instruction { + private readonly uint _index; + + internal LoadCachedObjectInstruction(uint index) { + _index = index; + } + + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex++] = frame.Interpreter._objects[_index]; + return +1; + } + + public override string ToDebugString(int instructionIndex, object cookie, Func<int, int> labelIndexer, IList<object> objects) { + return String.Format("LoadCached({0}: {1})", _index, objects[(int)_index]); + } + + public override string ToString() { + return "LoadCached(" + _index + ")"; + } + } + + internal sealed class PopInstruction : Instruction { + internal static readonly PopInstruction Instance = new PopInstruction(); + + private PopInstruction() { } + + public override int ConsumedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + frame.Pop(); + return +1; + } + + public override string ToString() { + return "Pop()"; + } + } + + // NOTE: Consider caching if used frequently + internal sealed class PopNInstruction : Instruction { + private readonly int _n; + + internal PopNInstruction(int n) { + _n = n; + } + + public override int ConsumedStack { get { return _n; } } + + public override int Run(InterpretedFrame frame) { + frame.Pop(_n); + return +1; + } + + public override string ToString() { + return "Pop(" + _n + ")"; + } + } + + internal sealed class DupInstruction : Instruction { + internal readonly static DupInstruction Instance = new DupInstruction(); + + private DupInstruction() { } + + public override int ConsumedStack { get { return 0; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + frame.Data[frame.StackIndex++] = frame.Peek(); + return +1; + } + + public override string ToString() { + return "Dup()"; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/TypeOperations.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/TypeOperations.cs new file mode 100644 index 00000000000..320deb5b3a6 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Instructions/TypeOperations.cs @@ -0,0 +1,163 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + internal sealed class CreateDelegateInstruction : Instruction { + private readonly LightDelegateCreator _creator; + + internal CreateDelegateInstruction(LightDelegateCreator delegateCreator) { + _creator = delegateCreator; + } + + public override int ConsumedStack { get { return _creator.Interpreter.ClosureSize; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + StrongBox<object>[] closure; + if (ConsumedStack > 0) { + closure = new StrongBox<object>[ConsumedStack]; + for (int i = closure.Length - 1; i >= 0; i--) { + closure[i] = (StrongBox<object>)frame.Pop(); + } + } else { + closure = null; + } + + Delegate d = _creator.CreateDelegate(closure); + + frame.Push(d); + return +1; + } + } + + internal sealed class NewInstruction : Instruction { + private readonly ConstructorInfo _constructor; + private readonly int _argCount; + + public NewInstruction(ConstructorInfo constructor) { + _constructor = constructor; + _argCount = constructor.GetParameters().Length; + + } + public override int ConsumedStack { get { return _argCount; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + object[] args = new object[_argCount]; + for (int i = _argCount - 1; i >= 0; i--) { + args[i] = frame.Pop(); + } + + object ret; + try { + ret = _constructor.Invoke(args); + } catch (TargetInvocationException e) { + ExceptionHelpers.UpdateForRethrow(e.InnerException); + throw e.InnerException; + } + + frame.Push(ret); + return +1; + } + + public override string ToString() { + return "New " + _constructor.DeclaringType.Name + "(" + _constructor + ")"; + } + } + + internal sealed class DefaultValueInstruction<T> : Instruction { + internal DefaultValueInstruction() { } + + public override int ConsumedStack { get { return 0; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + frame.Push(default(T)); + return +1; + } + + public override string ToString() { + return "New " + typeof(T); + } + } + + internal sealed class TypeIsInstruction<T> : Instruction { + internal TypeIsInstruction() { } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + // unfortunately Type.IsInstanceOfType() is 35-times slower than "is T" so we use generic code: + frame.Push(ScriptingRuntimeHelpers.BooleanToObject(frame.Pop() is T)); + return +1; + } + + public override string ToString() { + return "TypeIs " + typeof(T).Name; + } + } + + internal sealed class TypeAsInstruction<T> : Instruction { + internal TypeAsInstruction() { } + + public override int ConsumedStack { get { return 1; } } + public override int ProducedStack { get { return 1; } } + + public override int Run(InterpretedFrame frame) { + // can't use as w/o generic constraint + object value = frame.Pop(); + if (value is T) { + frame.Push(value); + } else { + frame.Push(null); + } + return +1; + } + + public override string ToString() { + return "TypeAs " + typeof(T).Name; + } + } + + internal sealed class TypeEqualsInstruction : Instruction { + public static readonly TypeEqualsInstruction Instance = new TypeEqualsInstruction(); + + public override int ConsumedStack { get { return 2; } } + public override int ProducedStack { get { return 1; } } + + private TypeEqualsInstruction() { + } + + public override int Run(InterpretedFrame frame) { + object type = frame.Pop(); + object obj = frame.Pop(); + frame.Push(ScriptingRuntimeHelpers.BooleanToObject(obj != null && (object)obj.GetType() == type)); + return +1; + } + + public override string InstructionName { + get { return "TypeEquals()"; } + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/InterpretedFrame.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/InterpretedFrame.cs new file mode 100644 index 00000000000..cd3a0784842 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/InterpretedFrame.cs @@ -0,0 +1,297 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.Scripting.Utils; +using Microsoft.Scripting.Runtime; + +namespace Microsoft.Scripting.Interpreter { +#if CLR45 + using InterpretedFrameThreadLocal = ThreadLocal<InterpretedFrame>; +#else + using InterpretedFrameThreadLocal = Microsoft.Scripting.Utils.ThreadLocal<InterpretedFrame>; +#endif + + public sealed class InterpretedFrame { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly InterpretedFrameThreadLocal CurrentFrame = new InterpretedFrameThreadLocal(); + + internal readonly Interpreter Interpreter; + internal InterpretedFrame _parent; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] + private int[] _continuations; + private int _continuationIndex; + private int _pendingContinuation; + private object _pendingValue; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] + public readonly object[] Data; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] + public readonly StrongBox<object>[] Closure; + + public int StackIndex; + public int InstructionIndex; + + // When a ThreadAbortException is raised from interpreted code this is the first frame that caught it. + // No handlers within this handler re-abort the current thread when left. + public ExceptionHandler CurrentAbortHandler; + + internal InterpretedFrame(Interpreter interpreter, StrongBox<object>[] closure) { + Interpreter = interpreter; + StackIndex = interpreter.LocalCount; + Data = new object[StackIndex + interpreter.Instructions.MaxStackDepth]; + + int c = interpreter.Instructions.MaxContinuationDepth; + if (c > 0) { + _continuations = new int[c]; + } + + Closure = closure; + } + + public DebugInfo GetDebugInfo(int instructionIndex) { + return DebugInfo.GetMatchingDebugInfo(Interpreter._debugInfos, instructionIndex); + } + + public string Name { + get { return Interpreter._name; } + } + + #region Data Stack Operations + + public void Push(object value) { + Data[StackIndex++] = value; + } + + public void Push(bool value) { + Data[StackIndex++] = value ? ScriptingRuntimeHelpers.True : ScriptingRuntimeHelpers.False; + } + + public void Push(int value) { + Data[StackIndex++] = ScriptingRuntimeHelpers.Int32ToObject(value); + } + + public object Pop() { + return Data[--StackIndex]; + } + + public object Pop(int n) { + int si = StackIndex - n; + StackIndex = si; + return Data[si]; + } + + internal void SetStackDepth(int depth) { + StackIndex = Interpreter.LocalCount + depth; + } + + public object Peek() { + return Data[StackIndex - 1]; + } + + public void Dup() { + int i = StackIndex; + Data[i] = Data[i - 1]; + StackIndex = i + 1; + } + + #endregion + + #region Stack Trace + + public InterpretedFrame Parent { + get { return _parent; } + } + + public static bool IsInterpretedFrame(MethodBase method) { + ContractUtils.RequiresNotNull(method, "method"); + return method.DeclaringType == typeof(Interpreter) && method.Name == "Run"; + } + +#if FEATURE_STACK_TRACE + /// <summary> + /// A single interpreted frame might be represented by multiple subsequent Interpreter.Run CLR frames. + /// This method filters out the duplicate CLR frames. + /// </summary> + public static IEnumerable<StackFrame> GroupStackFrames(IEnumerable<StackFrame> stackTrace) { + bool inInterpretedFrame = false; + foreach (StackFrame frame in stackTrace) { + if (InterpretedFrame.IsInterpretedFrame(frame.GetMethod())) { + if (inInterpretedFrame) { + continue; + } + inInterpretedFrame = true; + } else { + inInterpretedFrame = false; + } + yield return frame; + } + } +#endif + + public IEnumerable<InterpretedFrameInfo> GetStackTraceDebugInfo() { + var frame = this; + do { + yield return new InterpretedFrameInfo(frame.Name, frame.GetDebugInfo(frame.InstructionIndex)); + frame = frame.Parent; + } while (frame != null); + } + + internal void SaveTraceToException(Exception exception) { + if (exception.GetData(typeof(InterpretedFrameInfo)) == null) { + exception.SetData(typeof(InterpretedFrameInfo), new List<InterpretedFrameInfo>(GetStackTraceDebugInfo()).ToArray()); + } + } + + public static InterpretedFrameInfo[] GetExceptionStackTrace(Exception exception) { + return exception.GetData(typeof(InterpretedFrameInfo)) as InterpretedFrameInfo[]; + } + +#if DEBUG + internal string[] Trace { + get { + var trace = new List<string>(); + var frame = this; + do { + trace.Add(frame.Name); + frame = frame.Parent; + } while (frame != null); + return trace.ToArray(); + } + } +#endif + +#if CLR45 + internal InterpretedFrameThreadLocal Enter() { + var currentFrame = InterpretedFrame.CurrentFrame; + _parent = currentFrame.Value; + currentFrame.Value = this; + return currentFrame; + } + + internal void Leave(InterpretedFrameThreadLocal currentFrame) { + currentFrame.Value = _parent; + } +#else + internal InterpretedFrameThreadLocal.StorageInfo Enter() { + var currentFrame = InterpretedFrame.CurrentFrame.GetStorageInfo(); + _parent = currentFrame.Value; + currentFrame.Value = this; + return currentFrame; + } + + internal void Leave(InterpretedFrameThreadLocal.StorageInfo currentFrame) { + currentFrame.Value = _parent; + } +#endif + #endregion + + #region Continuations + + public void RemoveContinuation() { + _continuationIndex--; + } + + public void PushContinuation(int continuation) { + _continuations[_continuationIndex++] = continuation; + } + + public int YieldToCurrentContinuation() { + var target = Interpreter._labels[_continuations[_continuationIndex - 1]]; + SetStackDepth(target.StackDepth); + return target.Index - InstructionIndex; + } + + public int YieldToPendingContinuation() { + Debug.Assert(_pendingContinuation >= 0); + + RuntimeLabel pendingTarget = Interpreter._labels[_pendingContinuation]; + + // the current continuation might have higher priority (continuationIndex is the depth of the current continuation): + if (pendingTarget.ContinuationStackDepth < _continuationIndex) { + RuntimeLabel currentTarget = Interpreter._labels[_continuations[_continuationIndex - 1]]; + SetStackDepth(currentTarget.StackDepth); + return currentTarget.Index - InstructionIndex; + } + + SetStackDepth(pendingTarget.StackDepth); + if (_pendingValue != Interpreter.NoValue) { + Data[StackIndex - 1] = _pendingValue; + } + return pendingTarget.Index - InstructionIndex; + } + + internal void PushPendingContinuation() { + Push(_pendingContinuation); + Push(_pendingValue); +#if DEBUG + _pendingContinuation = -1; +#endif + } + + internal void PopPendingContinuation() { + _pendingValue = Pop(); + _pendingContinuation = (int)Pop(); + } + + private static MethodInfo _Goto; + private static MethodInfo _VoidGoto; + + internal static MethodInfo GotoMethod { + get { return _Goto ?? (_Goto = typeof(InterpretedFrame).GetMethod("Goto")); } + } + + internal static MethodInfo VoidGotoMethod { + get { return _VoidGoto ?? (_VoidGoto = typeof(InterpretedFrame).GetMethod("VoidGoto")); } + } + + public int VoidGoto(int labelIndex) { + return Goto(labelIndex, Interpreter.NoValue); + } + + public int Goto(int labelIndex, object value) { + // TODO: we know this at compile time (except for compiled loop): + RuntimeLabel target = Interpreter._labels[labelIndex]; + if (_continuationIndex == target.ContinuationStackDepth) { + SetStackDepth(target.StackDepth); + if (value != Interpreter.NoValue) { + Data[StackIndex - 1] = value; + } + return target.Index - InstructionIndex; + } + + // if we are in the middle of executing jump we forget the previous target and replace it by a new one: + _pendingContinuation = labelIndex; + _pendingValue = value; + return YieldToCurrentContinuation(); + } + + #endregion + + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Interpreter.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Interpreter.cs new file mode 100644 index 00000000000..81c7d5b043f --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/Interpreter.cs @@ -0,0 +1,262 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Threading; + +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; +using System.Diagnostics; +using System.Collections.Generic; + +namespace Microsoft.Scripting.Interpreter { + /// <summary> + /// A simple forth-style stack machine for executing Expression trees + /// without the need to compile to IL and then invoke the JIT. This trades + /// off much faster compilation time for a slower execution performance. + /// For code that is only run a small number of times this can be a + /// sweet spot. + /// + /// The core loop in the interpreter is the RunInstructions method. + /// </summary> + internal sealed class Interpreter { + internal static readonly object NoValue = new object(); + internal const int RethrowOnReturn = Int32.MaxValue; + + // zero: sync compilation + // negative: default + internal readonly int _compilationThreshold; + + private readonly int _localCount; + private readonly HybridReferenceDictionary<LabelTarget, BranchLabel> _labelMapping; + private readonly Dictionary<ParameterExpression, LocalVariable> _closureVariables; + + private readonly InstructionArray _instructions; + internal readonly object[] _objects; + internal readonly RuntimeLabel[] _labels; + + internal readonly string _name; + private readonly ExceptionHandler[] _handlers; + internal readonly DebugInfo[] _debugInfos; + + internal Interpreter(string name, LocalVariables locals, HybridReferenceDictionary<LabelTarget, BranchLabel> labelMapping, + InstructionArray instructions, ExceptionHandler[] handlers, DebugInfo[] debugInfos, int compilationThreshold) { + + _name = name; + _localCount = locals.LocalCount; + _closureVariables = locals.ClosureVariables; + + _instructions = instructions; + _objects = instructions.Objects; + _labels = instructions.Labels; + _labelMapping = labelMapping; + + _handlers = handlers; + _debugInfos = debugInfos; + _compilationThreshold = compilationThreshold; + } + + internal int ClosureSize { + get { + if (_closureVariables == null) { + return 0; + } + return _closureVariables.Count; + } + } + + internal int LocalCount { + get { + return _localCount; + } + } + + internal bool CompileSynchronously { + get { return _compilationThreshold <= 1; } + } + + internal InstructionArray Instructions { + get { return _instructions; } + } + + internal Dictionary<ParameterExpression, LocalVariable> ClosureVariables { + get { return _closureVariables; } + } + + internal HybridReferenceDictionary<LabelTarget, BranchLabel> LabelMapping { + get { return _labelMapping; } + } + + /// <summary> + /// Runs instructions within the given frame. + /// </summary> + /// <remarks> + /// Interpreted stack frames are linked via Parent reference so that each CLR frame of this method corresponds + /// to an interpreted stack frame in the chain. It is therefore possible to combine CLR stack traces with + /// interpreted stack traces by aligning interpreted frames to the frames of this method. + /// Each group of subsequent frames of Run method corresponds to a single interpreted frame. + /// </remarks> + [SpecialName, MethodImpl(MethodImplOptions.NoInlining)] + public void Run(InterpretedFrame frame) { + while (true) { + try { + var instructions = _instructions.Instructions; + int index = frame.InstructionIndex; + while (index < instructions.Length) { + index += instructions[index].Run(frame); + frame.InstructionIndex = index; + } + return; + } catch (Exception exception) { + switch (HandleException(frame, exception)) { + case ExceptionHandlingResult.Rethrow: throw; + case ExceptionHandlingResult.Continue: continue; + case ExceptionHandlingResult.Return: return; + } + } + } + } + + private ExceptionHandlingResult HandleException(InterpretedFrame frame, Exception exception) { + frame.SaveTraceToException(exception); + ExceptionHandler handler; + frame.InstructionIndex += GotoHandler(frame, exception, out handler); + + if (handler == null || handler.IsFault) { + // run finally/fault blocks: + Run(frame); + + // a finally block can throw an exception caught by a handler, which cancels the previous exception: + if (frame.InstructionIndex == RethrowOnReturn) { + return ExceptionHandlingResult.Rethrow; + } + return ExceptionHandlingResult.Return; + } + +#if FEATURE_THREAD + // stay in the current catch so that ThreadAbortException is not rethrown by CLR: + var abort = exception as ThreadAbortException; + if (abort != null) { + _anyAbortException = abort; + frame.CurrentAbortHandler = handler; + } +#endif + while (true) { + try { + var instructions = _instructions.Instructions; + int index = frame.InstructionIndex; + + while (index < instructions.Length) { + var curInstr = instructions[index]; + + index += curInstr.Run(frame); + frame.InstructionIndex = index; + + if (curInstr is LeaveExceptionHandlerInstruction) { + // we've completed handling of this exception + return ExceptionHandlingResult.Continue; + } + } + + if (frame.InstructionIndex == RethrowOnReturn) { + return ExceptionHandlingResult.Rethrow; + } + + return ExceptionHandlingResult.Return; + } catch (Exception nestedException) { + switch (HandleException(frame, nestedException)) { + case ExceptionHandlingResult.Rethrow: throw; + case ExceptionHandlingResult.Continue: continue; + case ExceptionHandlingResult.Return: return ExceptionHandlingResult.Return; + default: throw Assert.Unreachable; + } + } + } + } + + enum ExceptionHandlingResult { + Rethrow, + Continue, + Return + } + +#if FEATURE_THREAD + // To get to the current AbortReason object on Thread.CurrentThread + // we need to use ExceptionState property of any ThreadAbortException instance. + [ThreadStatic] + private static ThreadAbortException _anyAbortException = null; + + internal static void AbortThreadIfRequested(InterpretedFrame frame, int targetLabelIndex) { + var abortHandler = frame.CurrentAbortHandler; + if (abortHandler != null && !abortHandler.IsInside(frame.Interpreter._labels[targetLabelIndex].Index)) { + frame.CurrentAbortHandler = null; + + var currentThread = Thread.CurrentThread; + if ((currentThread.ThreadState & System.Threading.ThreadState.AbortRequested) != 0) { + Debug.Assert(_anyAbortException != null); + +#if FEATURE_EXCEPTION_STATE + // The current abort reason needs to be preserved. + currentThread.Abort(_anyAbortException.ExceptionState); +#else + currentThread.Abort(); +#endif + } + } + } +#else + internal static void AbortThreadIfRequested(InterpretedFrame frame, int targetLabelIndex) { + // nop + } +#endif + + internal ExceptionHandler GetBestHandler(int instructionIndex, Type exceptionType) { + ExceptionHandler best = null; + foreach (var handler in _handlers) { + if (handler.Matches(exceptionType, instructionIndex)) { + if (handler.IsBetterThan(best)) { + best = handler; + } + } + } + return best; + } + + internal int ReturnAndRethrowLabelIndex { + get { + // the last label is "return and rethrow" label: + Debug.Assert(_labels[_labels.Length - 1].Index == RethrowOnReturn); + return _labels.Length - 1; + } + } + + internal int GotoHandler(InterpretedFrame frame, object exception, out ExceptionHandler handler) { + handler = GetBestHandler(frame.InstructionIndex, exception.GetType()); + if (handler == null) { + return frame.Goto(ReturnAndRethrowLabelIndex, Interpreter.NoValue); + } else { + return frame.Goto(handler.LabelIndex, exception); + } + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightCompiler.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightCompiler.cs new file mode 100644 index 00000000000..cf88b40df59 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightCompiler.cs @@ -0,0 +1,1645 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +using Microsoft.Scripting.Ast; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Linq; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +#if FEATURE_REFEMIT +using System.Reflection.Emit; +#endif + +using AstUtils = Microsoft.Scripting.Ast.Utils; +using Microsoft.Scripting.Utils; +using Microsoft.Scripting.Runtime; +using System.Security; + +namespace Microsoft.Scripting.Interpreter { + public sealed class ExceptionHandler { + public readonly Type ExceptionType; + public readonly int StartIndex; + public readonly int EndIndex; + public readonly int LabelIndex; + public readonly int HandlerStartIndex; + + public bool IsFault { get { return ExceptionType == null; } } + + internal ExceptionHandler(int start, int end, int labelIndex, int handlerStartIndex, Type exceptionType) { + StartIndex = start; + EndIndex = end; + LabelIndex = labelIndex; + ExceptionType = exceptionType; + HandlerStartIndex = handlerStartIndex; + } + + public bool Matches(Type exceptionType, int index) { + if (index >= StartIndex && index < EndIndex) { + if (ExceptionType == null || ExceptionType.IsAssignableFrom(exceptionType)) { + return true; + } + } + return false; + } + + public bool IsBetterThan(ExceptionHandler other) { + if (other == null) return true; + + if (StartIndex == other.StartIndex && EndIndex == other.EndIndex) { + return HandlerStartIndex < other.HandlerStartIndex; + } + + if (StartIndex > other.StartIndex) { + Debug.Assert(EndIndex <= other.EndIndex); + return true; + } else if (EndIndex < other.EndIndex) { + Debug.Assert(StartIndex == other.StartIndex); + return true; + } else { + return false; + } + } + + internal bool IsInside(int index) { + return index >= StartIndex && index < EndIndex; + } + + public override string ToString() { + return String.Format("{0} [{1}-{2}] [{3}->]", + (IsFault ? "fault" : "catch(" + ExceptionType.Name + ")"), + StartIndex, EndIndex, + HandlerStartIndex + ); + } + } + + [Serializable] + public class DebugInfo { + // TODO: readonly + + public int StartLine, EndLine; + public int Index; + public string FileName; + public bool IsClear; + private static readonly DebugInfoComparer _debugComparer = new DebugInfoComparer(); + + private class DebugInfoComparer : IComparer<DebugInfo> { + //We allow comparison between int and DebugInfo here + int IComparer<DebugInfo>.Compare(DebugInfo d1, DebugInfo d2) { + if (d1.Index > d2.Index) return 1; + else if (d1.Index == d2.Index) return 0; + else return -1; + } + } + + public static DebugInfo GetMatchingDebugInfo(DebugInfo[] debugInfos, int index) { + //Create a faked DebugInfo to do the search + DebugInfo d = new DebugInfo { Index = index }; + + //to find the closest debug info before the current index + + int i = Array.BinarySearch<DebugInfo>(debugInfos, d, _debugComparer); + if (i < 0) { + //~i is the index for the first bigger element + //if there is no bigger element, ~i is the length of the array + i = ~i; + if (i == 0) { + return null; + } + //return the last one that is smaller + i = i - 1; + } + + return debugInfos[i]; + } + + public override string ToString() { + if (IsClear) { + return String.Format("{0}: clear", Index); + } else { + return String.Format("{0}: [{1}-{2}] '{3}'", Index, StartLine, EndLine, FileName); + } + } + } + + // TODO: + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] + [Serializable] + public struct InterpretedFrameInfo { + public readonly string MethodName; + + // TODO: + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public readonly DebugInfo DebugInfo; + + public InterpretedFrameInfo(string methodName, DebugInfo info) { + MethodName = methodName; + DebugInfo = info; + } + + public override string ToString() { + return MethodName + (DebugInfo != null ? ": " + DebugInfo.ToString() : null); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] + public sealed class LightCompiler { + internal const int DefaultCompilationThreshold = 32; + + // zero: sync compilation + private readonly int _compilationThreshold; + + private readonly InstructionList _instructions; + private readonly LocalVariables _locals = new LocalVariables(); + + private readonly List<ExceptionHandler> _handlers = new List<ExceptionHandler>(); + + private readonly List<DebugInfo> _debugInfos = new List<DebugInfo>(); + private readonly HybridReferenceDictionary<LabelTarget, LabelInfo> _treeLabels = new HybridReferenceDictionary<LabelTarget, LabelInfo>(); + private LabelScopeInfo _labelBlock = new LabelScopeInfo(null, LabelScopeKind.Lambda); + + private readonly Stack<ParameterExpression> _exceptionForRethrowStack = new Stack<ParameterExpression>(); + + // Set to true to force compiliation of this lambda. + // This disables the interpreter for this lambda. We still need to + // walk it, however, to resolve variables closed over from the parent + // lambdas (because they may be interpreted). + private bool _forceCompile; + + private readonly LightCompiler _parent; + + private static LocalDefinition[] EmptyLocals = new LocalDefinition[0]; + + internal LightCompiler(int compilationThreshold) { + _instructions = new InstructionList(); + _compilationThreshold = compilationThreshold < 0 ? DefaultCompilationThreshold : compilationThreshold; + } + + private LightCompiler(LightCompiler parent) + : this(parent._compilationThreshold) { + _parent = parent; + } + + public InstructionList Instructions { + get { return _instructions; } + } + + public LocalVariables Locals { + get { return _locals; } + } + + internal static Expression Unbox(Expression strongBoxExpression) { + return Expression.Field(strongBoxExpression, typeof(StrongBox<object>).GetDeclaredField("Value")); + } + + internal LightDelegateCreator CompileTop(LambdaExpression node) { + foreach (var p in node.Parameters) { + var local = _locals.DefineLocal(p, 0); + _instructions.EmitInitializeParameter(local.Index); + } + + Compile(node.Body); + + // pop the result of the last expression: + if (node.Body.Type != typeof(void) && node.ReturnType == typeof(void)) { + _instructions.EmitPop(); + } + + Debug.Assert(_instructions.CurrentStackDepth == (node.ReturnType != typeof(void) ? 1 : 0)); + + return new LightDelegateCreator(MakeInterpreter(node.Name), node); + } + + internal LightDelegateCreator CompileTop(LightLambdaExpression node) { + foreach (var p in node.Parameters) { + var local = _locals.DefineLocal(p, 0); + _instructions.EmitInitializeParameter(local.Index); + } + + Compile(node.Body); + + // pop the result of the last expression: + if (node.Body.Type != typeof(void) && node.ReturnType == typeof(void)) { + _instructions.EmitPop(); + } + + Debug.Assert(_instructions.CurrentStackDepth == (node.ReturnType != typeof(void) ? 1 : 0)); + + return new LightDelegateCreator(MakeInterpreter(node.Name), node); + } + + private Interpreter MakeInterpreter(string lambdaName) { + if (_forceCompile) { + return null; + } + + var handlers = _handlers.ToArray(); + var debugInfos = _debugInfos.ToArray(); + + return new Interpreter(lambdaName, _locals, GetBranchMapping(), _instructions.ToArray(), handlers, debugInfos, _compilationThreshold); + } + + + private void CompileConstantExpression(Expression expr) { + var node = (ConstantExpression)expr; + _instructions.EmitLoad(node.Value, node.Type); + } + + private void CompileDefaultExpression(Expression expr) { + CompileDefaultExpression(expr.Type); + } + + private void CompileDefaultExpression(Type type) { + if (type != typeof(void)) { + if (type.IsValueType()) { + object value = ScriptingRuntimeHelpers.GetPrimitiveDefaultValue(type); + if (value != null) { + _instructions.EmitLoad(value); + } else { + _instructions.EmitDefaultValue(type); + } + } else { + _instructions.EmitLoad(null); + } + } + } + + private LocalVariable EnsureAvailableForClosure(ParameterExpression expr) { + LocalVariable local; + if (_locals.TryGetLocalOrClosure(expr, out local)) { + if (!local.InClosure && !local.IsBoxed) { + _locals.Box(expr, _instructions); + } + return local; + } else if (_parent != null) { + _parent.EnsureAvailableForClosure(expr); + return _locals.AddClosureVariable(expr); + } else { + throw new InvalidOperationException("unbound variable: " + expr); + } + } + + private void EnsureVariable(ParameterExpression variable) { + if (!_locals.ContainsVariable(variable)) { + EnsureAvailableForClosure(variable); + } + } + + private LocalVariable ResolveLocal(ParameterExpression variable) { + LocalVariable local; + if (!_locals.TryGetLocalOrClosure(variable, out local)) { + local = EnsureAvailableForClosure(variable); + } + return local; + } + + public void CompileGetVariable(ParameterExpression variable) { + LocalVariable local = ResolveLocal(variable); + + if (local.InClosure) { + _instructions.EmitLoadLocalFromClosure(local.Index); + } else if (local.IsBoxed) { + _instructions.EmitLoadLocalBoxed(local.Index); + } else { + _instructions.EmitLoadLocal(local.Index); + } + + _instructions.SetDebugCookie(variable.Name); + } + + public void CompileGetBoxedVariable(ParameterExpression variable) { + LocalVariable local = ResolveLocal(variable); + + if (local.InClosure) { + _instructions.EmitLoadLocalFromClosureBoxed(local.Index); + } else { + Debug.Assert(local.IsBoxed); + _instructions.EmitLoadLocal(local.Index); + } + + _instructions.SetDebugCookie(variable.Name); + } + + public void CompileSetVariable(ParameterExpression variable, bool isVoid) { + LocalVariable local = ResolveLocal(variable); + + if (local.InClosure) { + if (isVoid) { + _instructions.EmitStoreLocalToClosure(local.Index); + } else { + _instructions.EmitAssignLocalToClosure(local.Index); + } + } else if (local.IsBoxed) { + if (isVoid) { + _instructions.EmitStoreLocalBoxed(local.Index); + } else { + _instructions.EmitAssignLocalBoxed(local.Index); + } + } else { + if (isVoid) { + _instructions.EmitStoreLocal(local.Index); + } else { + _instructions.EmitAssignLocal(local.Index); + } + } + + _instructions.SetDebugCookie(variable.Name); + } + + public void CompileParameterExpression(Expression expr) { + var node = (ParameterExpression)expr; + CompileGetVariable(node); + } + + private void CompileBlockExpression(Expression expr, bool asVoid) { + var node = (BlockExpression)expr; + var end = CompileBlockStart(node); + + var lastExpression = node.Expressions[node.Expressions.Count - 1]; + Compile(lastExpression, asVoid); + CompileBlockEnd(end); + } + + private LocalDefinition[] CompileBlockStart(BlockExpression node) { + var start = _instructions.Count; + + LocalDefinition[] locals; + var variables = node.Variables; + if (variables.Count != 0) { + // TODO: basic flow analysis so we don't have to initialize all + // variables. + locals = new LocalDefinition[variables.Count]; + int localCnt = 0; + foreach (var variable in variables) { + var local = _locals.DefineLocal(variable, start); + locals[localCnt++] = local; + + _instructions.EmitInitializeLocal(local.Index, variable.Type); + _instructions.SetDebugCookie(variable.Name); + } + } else { + locals = EmptyLocals; + } + + for (int i = 0; i < node.Expressions.Count - 1; i++) { + CompileAsVoid(node.Expressions[i]); + } + return locals; + } + + private void CompileBlockEnd(LocalDefinition[] locals) { + foreach (var local in locals) { + _locals.UndefineLocal(local, _instructions.Count); + } + } + + private void CompileIndexExpression(Expression expr) { + var index = (IndexExpression)expr; + + // instance: + if (index.Object != null) { + Compile(index.Object); + } + + // indexes, byref args not allowed. + foreach (var arg in index.Arguments) { + Compile(arg); + } + + if (index.Indexer != null) { + EmitCall(index.Indexer.GetGetMethod(true)); + } else if (index.Arguments.Count != 1) { + EmitCall(index.Object.Type.GetMethod("Get", BindingFlags.Public | BindingFlags.Instance)); + } else { + _instructions.EmitGetArrayItem(index.Object.Type); + } + } + + private void CompileIndexAssignment(BinaryExpression node, bool asVoid) { + var index = (IndexExpression)node.Left; + + if (!asVoid) { + throw new NotImplementedException(); + } + + // instance: + if (index.Object != null) { + Compile(index.Object); + } + + // indexes, byref args not allowed. + foreach (var arg in index.Arguments) { + Compile(arg); + } + + // value: + Compile(node.Right); + + if (index.Indexer != null) { + EmitCall(index.Indexer.GetSetMethod(true)); + } else if (index.Arguments.Count != 1) { + EmitCall(index.Object.Type.GetMethod("Set", BindingFlags.Public | BindingFlags.Instance)); + } else { + _instructions.EmitSetArrayItem(index.Object.Type); + } + } + + private void CompileMemberAssignment(BinaryExpression node, bool asVoid) { + var member = (MemberExpression)node.Left; + + PropertyInfo pi = member.Member as PropertyInfo; + if (pi != null) { + var method = pi.GetSetMethod(true); + Compile(member.Expression); + Compile(node.Right); + + int start = _instructions.Count; + if (!asVoid) { + LocalDefinition local = _locals.DefineLocal(Expression.Parameter(node.Right.Type), start); + _instructions.EmitAssignLocal(local.Index); + EmitCall(method); + _instructions.EmitLoadLocal(local.Index); + _locals.UndefineLocal(local, _instructions.Count); + } else { + EmitCall(method); + } + return; + } + + FieldInfo fi = member.Member as FieldInfo; + if (fi != null) { + if (member.Expression != null) { + Compile(member.Expression); + } + Compile(node.Right); + + int start = _instructions.Count; + if (!asVoid) { + LocalDefinition local = _locals.DefineLocal(Expression.Parameter(node.Right.Type), start); + _instructions.EmitAssignLocal(local.Index); + _instructions.EmitStoreField(fi); + _instructions.EmitLoadLocal(local.Index); + _locals.UndefineLocal(local, _instructions.Count); + } else { + _instructions.EmitStoreField(fi); + } + return; + } + + throw new NotImplementedException(); + } + + private void CompileVariableAssignment(BinaryExpression node, bool asVoid) { + this.Compile(node.Right); + + var target = (ParameterExpression)node.Left; + CompileSetVariable(target, asVoid); + } + + private void CompileAssignBinaryExpression(Expression expr, bool asVoid) { + var node = (BinaryExpression)expr; + + switch (node.Left.NodeType) { + case ExpressionType.Index: + CompileIndexAssignment(node, asVoid); + break; + + case ExpressionType.MemberAccess: + CompileMemberAssignment(node, asVoid); + break; + + case ExpressionType.Parameter: + case ExpressionType.Extension: + CompileVariableAssignment(node, asVoid); + break; + + default: + throw new InvalidOperationException("Invalid lvalue for assignment: " + node.Left.NodeType); + } + } + + private void CompileBinaryExpression(Expression expr) { + var node = (BinaryExpression)expr; + + if (node.Method != null) { + Compile(node.Left); + Compile(node.Right); + EmitCall(node.Method); + } else { + switch (node.NodeType) { + case ExpressionType.ArrayIndex: + Debug.Assert(node.Right.Type == typeof(int)); + Compile(node.Left); + Compile(node.Right); + _instructions.EmitGetArrayItem(node.Left.Type); + return; + + case ExpressionType.Add: + case ExpressionType.AddChecked: + case ExpressionType.Subtract: + case ExpressionType.SubtractChecked: + case ExpressionType.Multiply: + case ExpressionType.MultiplyChecked: + case ExpressionType.Divide: + CompileArithmetic(node.NodeType, node.Left, node.Right); + return; + + case ExpressionType.Equal: + CompileEqual(node.Left, node.Right); + return; + + case ExpressionType.NotEqual: + CompileNotEqual(node.Left, node.Right); + return; + + case ExpressionType.LessThan: + case ExpressionType.LessThanOrEqual: + case ExpressionType.GreaterThan: + case ExpressionType.GreaterThanOrEqual: + CompileComparison(node.NodeType, node.Left, node.Right); + return; + + default: + throw new NotImplementedException(node.NodeType.ToString()); + } + } + } + + private void CompileEqual(Expression left, Expression right) { + Debug.Assert(left.Type == right.Type || !left.Type.IsValueType() && !right.Type.IsValueType()); + Compile(left); + Compile(right); + _instructions.EmitEqual(left.Type); + } + + private void CompileNotEqual(Expression left, Expression right) { + Debug.Assert(left.Type == right.Type || !left.Type.IsValueType() && !right.Type.IsValueType()); + Compile(left); + Compile(right); + _instructions.EmitNotEqual(left.Type); + } + + private void CompileComparison(ExpressionType nodeType, Expression left, Expression right) { + Debug.Assert(left.Type == right.Type && TypeUtils.IsNumeric(left.Type)); + + // TODO: + // if (TypeUtils.IsNullableType(left.Type) && liftToNull) ... + + Compile(left); + Compile(right); + + switch (nodeType) { + case ExpressionType.LessThan: _instructions.EmitLessThan(left.Type); break; + case ExpressionType.LessThanOrEqual: _instructions.EmitLessThanOrEqual(left.Type); break; + case ExpressionType.GreaterThan: _instructions.EmitGreaterThan(left.Type); break; + case ExpressionType.GreaterThanOrEqual: _instructions.EmitGreaterThanOrEqual(left.Type); break; + default: throw Assert.Unreachable; + } + } + + private void CompileArithmetic(ExpressionType nodeType, Expression left, Expression right) { + Debug.Assert(left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)); + Compile(left); + Compile(right); + switch (nodeType) { + case ExpressionType.Add: _instructions.EmitAdd(left.Type, false); break; + case ExpressionType.AddChecked: _instructions.EmitAdd(left.Type, true); break; + case ExpressionType.Subtract: _instructions.EmitSub(left.Type, false); break; + case ExpressionType.SubtractChecked: _instructions.EmitSub(left.Type, true); break; + case ExpressionType.Multiply: _instructions.EmitMul(left.Type, false); break; + case ExpressionType.MultiplyChecked: _instructions.EmitMul(left.Type, true); break; + case ExpressionType.Divide: _instructions.EmitDiv(left.Type); break; + default: throw Assert.Unreachable; + } + } + + private void CompileConvertUnaryExpression(Expression expr) { + var node = (UnaryExpression)expr; + if (node.Method != null) { + Compile(node.Operand); + + // We should be able to ignore Int32ToObject + if (node.Method != Runtime.ScriptingRuntimeHelpers.Int32ToObjectMethod) { + EmitCall(node.Method); + } + } else if (node.Type == typeof(void)) { + CompileAsVoid(node.Operand); + } else { + Compile(node.Operand); + CompileConvertToType(node.Operand.Type, node.Type, node.NodeType == ExpressionType.ConvertChecked); + } + } + + private void CompileConvertToType(Type typeFrom, Type typeTo, bool isChecked) { + Debug.Assert(typeFrom != typeof(void) && typeTo != typeof(void)); + + if (TypeUtils.AreEquivalent(typeTo, typeFrom)) { + return; + } + + TypeCode from = typeFrom.GetTypeCode(); + TypeCode to = typeTo.GetTypeCode(); + if (TypeUtils.IsNumeric(from) && TypeUtils.IsNumeric(to)) { + if (isChecked) { + _instructions.EmitNumericConvertChecked(from, to); + } else { + _instructions.EmitNumericConvertUnchecked(from, to); + } + return; + } + + // TODO: Conversions to a super-class or implemented interfaces are no-op. + // A conversion to a non-implemented interface or an unrelated class, etc. should fail. + return; + } + + private void CompileNotExpression(UnaryExpression node) { + if (node.Operand.Type == typeof(bool)) { + Compile(node.Operand); + _instructions.EmitNot(); + } else { + throw new NotImplementedException(); + } + } + + private void CompileUnaryExpression(Expression expr) { + var node = (UnaryExpression)expr; + + if (node.Method != null) { + Compile(node.Operand); + EmitCall(node.Method); + } else { + switch (node.NodeType) { + case ExpressionType.Not: + CompileNotExpression(node); + return; + case ExpressionType.TypeAs: + CompileTypeAsExpression(node); + return; + default: + throw new NotImplementedException(node.NodeType.ToString()); + } + } + } + + private void CompileAndAlsoBinaryExpression(Expression expr) { + CompileLogicalBinaryExpression(expr, true); + } + + private void CompileOrElseBinaryExpression(Expression expr) { + CompileLogicalBinaryExpression(expr, false); + } + + private void CompileLogicalBinaryExpression(Expression expr, bool andAlso) { + var node = (BinaryExpression)expr; + if (node.Method != null) { + throw new NotImplementedException(); + } + + Debug.Assert(node.Left.Type == node.Right.Type); + + if (node.Left.Type == typeof(bool)) { + var elseLabel = _instructions.MakeLabel(); + var endLabel = _instructions.MakeLabel(); + Compile(node.Left); + if (andAlso) { + _instructions.EmitBranchFalse(elseLabel); + } else { + _instructions.EmitBranchTrue(elseLabel); + } + Compile(node.Right); + _instructions.EmitBranch(endLabel, false, true); + _instructions.MarkLabel(elseLabel); + _instructions.EmitLoad(!andAlso); + _instructions.MarkLabel(endLabel); + return; + } + + Debug.Assert(node.Left.Type == typeof(bool?)); + throw new NotImplementedException(); + } + + private void CompileConditionalExpression(Expression expr, bool asVoid) { + var node = (ConditionalExpression)expr; + Compile(node.Test); + + if (node.IfTrue == AstUtils.Empty()) { + var endOfFalse = _instructions.MakeLabel(); + _instructions.EmitBranchTrue(endOfFalse); + Compile(node.IfFalse, asVoid); + _instructions.MarkLabel(endOfFalse); + } else { + var endOfTrue = _instructions.MakeLabel(); + _instructions.EmitBranchFalse(endOfTrue); + Compile(node.IfTrue, asVoid); + + if (node.IfFalse != AstUtils.Empty()) { + var endOfFalse = _instructions.MakeLabel(); + _instructions.EmitBranch(endOfFalse, false, !asVoid); + _instructions.MarkLabel(endOfTrue); + Compile(node.IfFalse, asVoid); + _instructions.MarkLabel(endOfFalse); + } else { + _instructions.MarkLabel(endOfTrue); + } + } + } + + #region Loops + + private void CompileLoopExpression(Expression expr) { + var node = (LoopExpression)expr; + var enterLoop = new EnterLoopInstruction(node, _locals, _compilationThreshold, _instructions.Count); + + PushLabelBlock(LabelScopeKind.Statement); + LabelInfo breakLabel = DefineLabel(node.BreakLabel); + LabelInfo continueLabel = DefineLabel(node.ContinueLabel); + + _instructions.MarkLabel(continueLabel.GetLabel(this)); + + // emit loop body: + _instructions.Emit(enterLoop); + CompileAsVoid(node.Body); + + // emit loop branch: + _instructions.EmitBranch(continueLabel.GetLabel(this), expr.Type != typeof(void), false); + + _instructions.MarkLabel(breakLabel.GetLabel(this)); + + PopLabelBlock(LabelScopeKind.Statement); + + enterLoop.FinishLoop(_instructions.Count); + } + + #endregion + + private void CompileSwitchExpression(Expression expr) { + var node = (SwitchExpression)expr; + + // Currently only supports int test values, with no method + if (node.SwitchValue.Type != typeof(int) || node.Comparison != null) { + throw new NotImplementedException(); + } + + // Test values must be constant + if (!node.Cases.All(c => c.TestValues.All(t => t is ConstantExpression))) { + throw new NotImplementedException(); + } + LabelInfo end = DefineLabel(null); + bool hasValue = node.Type != typeof(void); + + Compile(node.SwitchValue); + var caseDict = new Dictionary<int, int>(); + int switchIndex = _instructions.Count; + _instructions.EmitSwitch(caseDict); + + if (node.DefaultBody != null) { + Compile(node.DefaultBody); + } else { + Debug.Assert(!hasValue); + } + _instructions.EmitBranch(end.GetLabel(this), false, hasValue); + + for (int i = 0; i < node.Cases.Count; i++) { + var switchCase = node.Cases[i]; + + int caseOffset = _instructions.Count - switchIndex; + foreach (ConstantExpression testValue in switchCase.TestValues) { + caseDict[(int)testValue.Value] = caseOffset; + } + + Compile(switchCase.Body); + + if (i < node.Cases.Count - 1) { + _instructions.EmitBranch(end.GetLabel(this), false, hasValue); + } + } + + _instructions.MarkLabel(end.GetLabel(this)); + } + + private void CompileLabelExpression(Expression expr) { + var node = (LabelExpression)expr; + + // If we're an immediate child of a block, our label will already + // be defined. If not, we need to define our own block so this + // label isn't exposed except to its own child expression. + LabelInfo label = null; + + if (_labelBlock.Kind == LabelScopeKind.Block) { + _labelBlock.TryGetLabelInfo(node.Target, out label); + + // We're in a block but didn't find our label, try switch + if (label == null && _labelBlock.Parent.Kind == LabelScopeKind.Switch) { + _labelBlock.Parent.TryGetLabelInfo(node.Target, out label); + } + + // if we're in a switch or block, we should've found the label + Debug.Assert(label != null); + } + + if (label == null) { + label = DefineLabel(node.Target); + } + + if (node.DefaultValue != null) { + if (node.Target.Type == typeof(void)) { + CompileAsVoid(node.DefaultValue); + } else { + Compile(node.DefaultValue); + } + } + + _instructions.MarkLabel(label.GetLabel(this)); + } + + private void CompileGotoExpression(Expression expr) { + var node = (GotoExpression)expr; + var labelInfo = ReferenceLabel(node.Target); + + if (node.Value != null) { + Compile(node.Value); + } + + _instructions.EmitGoto(labelInfo.GetLabel(this), node.Type != typeof(void), node.Value != null && node.Value.Type != typeof(void)); + } + + public BranchLabel GetBranchLabel(LabelTarget target) { + return ReferenceLabel(target).GetLabel(this); + } + + public void PushLabelBlock(LabelScopeKind type) { + _labelBlock = new LabelScopeInfo(_labelBlock, type); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "kind")] + public void PopLabelBlock(LabelScopeKind kind) { + Debug.Assert(_labelBlock != null && _labelBlock.Kind == kind); + _labelBlock = _labelBlock.Parent; + } + + private LabelInfo EnsureLabel(LabelTarget node) { + LabelInfo result; + if (!_treeLabels.TryGetValue(node, out result)) { + _treeLabels[node] = result = new LabelInfo(node); + } + return result; + } + + private LabelInfo ReferenceLabel(LabelTarget node) { + LabelInfo result = EnsureLabel(node); + result.Reference(_labelBlock); + return result; + } + + internal LabelInfo DefineLabel(LabelTarget node) { + if (node == null) { + return new LabelInfo(null); + } + LabelInfo result = EnsureLabel(node); + result.Define(_labelBlock); + return result; + } + + private bool TryPushLabelBlock(Expression node) { + // Anything that is "statement-like" -- e.g. has no associated + // stack state can be jumped into, with the exception of try-blocks + // We indicate this by a "Block" + // + // Otherwise, we push an "Expression" to indicate that it can't be + // jumped into + switch (node.NodeType) { + default: + if (_labelBlock.Kind != LabelScopeKind.Expression) { + PushLabelBlock(LabelScopeKind.Expression); + return true; + } + return false; + case ExpressionType.Label: + // LabelExpression is a bit special, if it's directly in a + // block it becomes associate with the block's scope. Same + // thing if it's in a switch case body. + if (_labelBlock.Kind == LabelScopeKind.Block) { + var label = ((LabelExpression)node).Target; + if (_labelBlock.ContainsTarget(label)) { + return false; + } + if (_labelBlock.Parent.Kind == LabelScopeKind.Switch && + _labelBlock.Parent.ContainsTarget(label)) { + return false; + } + } + PushLabelBlock(LabelScopeKind.Statement); + return true; + case ExpressionType.Block: + PushLabelBlock(LabelScopeKind.Block); + // Labels defined immediately in the block are valid for + // the whole block. + if (_labelBlock.Parent.Kind != LabelScopeKind.Switch) { + DefineBlockLabels(node); + } + return true; + case ExpressionType.Switch: + PushLabelBlock(LabelScopeKind.Switch); + // Define labels inside of the switch cases so theyare in + // scope for the whole switch. This allows "goto case" and + // "goto default" to be considered as local jumps. + var @switch = (SwitchExpression)node; + foreach (SwitchCase c in @switch.Cases) { + DefineBlockLabels(c.Body); + } + DefineBlockLabels(@switch.DefaultBody); + return true; + + // Remove this when Convert(Void) goes away. + case ExpressionType.Convert: + if (node.Type != typeof(void)) { + // treat it as an expression + goto default; + } + PushLabelBlock(LabelScopeKind.Statement); + return true; + + case ExpressionType.Conditional: + case ExpressionType.Loop: + case ExpressionType.Goto: + PushLabelBlock(LabelScopeKind.Statement); + return true; + } + } + + private void DefineBlockLabels(Expression node) { + var block = node as BlockExpression; + if (block == null) { + return; + } + + for (int i = 0, n = block.Expressions.Count; i < n; i++) { + Expression e = block.Expressions[i]; + + var label = e as LabelExpression; + if (label != null) { + DefineLabel(label.Target); + } + } + } + + private HybridReferenceDictionary<LabelTarget, BranchLabel> GetBranchMapping() { + var newLabelMapping = new HybridReferenceDictionary<LabelTarget, BranchLabel>(_treeLabels.Count); + foreach (var kvp in _treeLabels) { + newLabelMapping[kvp.Key] = kvp.Value.GetLabel(this); + } + return newLabelMapping; + } + + private void CompileThrowUnaryExpression(Expression expr, bool asVoid) { + var node = (UnaryExpression)expr; + + if (node.Operand == null) { + CompileParameterExpression(_exceptionForRethrowStack.Peek()); + if (asVoid) { + _instructions.EmitRethrowVoid(); + } else { + _instructions.EmitRethrow(); + } + } else { + Compile(node.Operand); + if (asVoid) { + _instructions.EmitThrowVoid(); + } else { + _instructions.EmitThrow(); + } + } + + } + + // TODO: remove (replace by true fault support) + private bool EndsWithRethrow(Expression expr) { + if (expr.NodeType == ExpressionType.Throw) { + var node = (UnaryExpression)expr; + return node.Operand == null; + } + + BlockExpression block = expr as BlockExpression; + if (block != null) { + return EndsWithRethrow(block.Expressions[block.Expressions.Count - 1]); + } + return false; + } + + + // TODO: remove (replace by true fault support) + private void CompileAsVoidRemoveRethrow(Expression expr) { + int stackDepth = _instructions.CurrentStackDepth; + + if (expr.NodeType == ExpressionType.Throw) { + Debug.Assert(((UnaryExpression)expr).Operand == null); + return; + } + + var node = (BlockExpression)expr; + var end = CompileBlockStart(node); + + CompileAsVoidRemoveRethrow(node.Expressions[node.Expressions.Count - 1]); + + Debug.Assert(stackDepth == _instructions.CurrentStackDepth); + + CompileBlockEnd(end); + } + + private void CompileTryExpression(Expression expr) { + var node = (TryExpression)expr; + + BranchLabel end = _instructions.MakeLabel(); + BranchLabel gotoEnd = _instructions.MakeLabel(); + + int tryStart = _instructions.Count; + + BranchLabel startOfFinally = null; + if (node.Finally != null) { + startOfFinally = _instructions.MakeLabel(); + _instructions.EmitEnterTryFinally(startOfFinally); + } + + PushLabelBlock(LabelScopeKind.Try); + Compile(node.Body); + + bool hasValue = node.Body.Type != typeof(void); + int tryEnd = _instructions.Count; + + // handlers jump here: + _instructions.MarkLabel(gotoEnd); + _instructions.EmitGoto(end, hasValue, hasValue); + + // keep the result on the stack: + if (node.Handlers.Count > 0) { + // TODO: emulates faults (replace by true fault support) + if (node.Finally == null && node.Handlers.Count == 1) { + var handler = node.Handlers[0]; + if (handler.Filter == null && handler.Test == typeof(Exception) && handler.Variable == null) { + if (EndsWithRethrow(handler.Body)) { + if (hasValue) { + _instructions.EmitEnterExceptionHandlerNonVoid(); + } else { + _instructions.EmitEnterExceptionHandlerVoid(); + } + + // at this point the stack balance is prepared for the hidden exception variable: + int handlerLabel = _instructions.MarkRuntimeLabel(); + int handlerStart = _instructions.Count; + + CompileAsVoidRemoveRethrow(handler.Body); + _instructions.EmitLeaveFault(hasValue); + _instructions.MarkLabel(end); + + _handlers.Add(new ExceptionHandler(tryStart, tryEnd, handlerLabel, handlerStart, null)); + PopLabelBlock(LabelScopeKind.Try); + return; + } + } + } + + foreach (var handler in node.Handlers) { + PushLabelBlock(LabelScopeKind.Catch); + + if (handler.Filter != null) { + //PushLabelBlock(LabelScopeKind.Filter); + throw new NotImplementedException(); + //PopLabelBlock(LabelScopeKind.Filter); + } + + var parameter = handler.Variable ?? Expression.Parameter(handler.Test); + + var local = _locals.DefineLocal(parameter, _instructions.Count); + _exceptionForRethrowStack.Push(parameter); + + // add a stack balancing nop instruction (exception handling pushes the current exception): + if (hasValue) { + _instructions.EmitEnterExceptionHandlerNonVoid(); + } else { + _instructions.EmitEnterExceptionHandlerVoid(); + } + + // at this point the stack balance is prepared for the hidden exception variable: + int handlerLabel = _instructions.MarkRuntimeLabel(); + int handlerStart = _instructions.Count; + + CompileSetVariable(parameter, true); + Compile(handler.Body); + + _exceptionForRethrowStack.Pop(); + + // keep the value of the body on the stack: + Debug.Assert(hasValue == (handler.Body.Type != typeof(void))); + _instructions.EmitLeaveExceptionHandler(hasValue, gotoEnd); + + _handlers.Add(new ExceptionHandler(tryStart, tryEnd, handlerLabel, handlerStart, handler.Test)); + + PopLabelBlock(LabelScopeKind.Catch); + + _locals.UndefineLocal(local, _instructions.Count); + } + + if (node.Fault != null) { + throw new NotImplementedException(); + } + } + + if (node.Finally != null) { + PushLabelBlock(LabelScopeKind.Finally); + + _instructions.MarkLabel(startOfFinally); + _instructions.EmitEnterFinally(); + CompileAsVoid(node.Finally); + _instructions.EmitLeaveFinally(); + + PopLabelBlock(LabelScopeKind.Finally); + } + + _instructions.MarkLabel(end); + + PopLabelBlock(LabelScopeKind.Try); + } + + private void CompileDynamicExpression(Expression expr) { + var node = (DynamicExpression)expr; + + foreach (var arg in node.Arguments) { + Compile(arg); + } + + _instructions.EmitDynamic(node.DelegateType, node.Binder); + } + + private void CompileMethodCallExpression(Expression expr) { + var node = (MethodCallExpression)expr; + + var parameters = node.Method.GetParameters(); + + // TODO: + // Support pass by reference. + // Note that LoopCompiler needs to be updated too. + + // force compilation for now for ref types + // also could be a mutable value type, Delegate.CreateDelegate and MethodInfo.Invoke both can't handle this, we + // need to generate code. + if (!CollectionUtils.TrueForAll(parameters, (p) => !p.ParameterType.IsByRef) || + (!node.Method.IsStatic && node.Method.DeclaringType.IsValueType() && !node.Method.DeclaringType.IsPrimitive())) { + _forceCompile = true; + } + + // CF bug workaround + // TODO: can we do better if the delegate targets LightLambda.Run* method? + if (PlatformAdaptationLayer.IsCompactFramework && + node.Method.Name == "Invoke" && typeof(Delegate).IsAssignableFrom(node.Object.Type) && !node.Method.IsStatic) { + + Compile( + AstUtils.Convert( + Expression.Call( + node.Object, + node.Object.Type.GetMethod("DynamicInvoke"), + Expression.NewArrayInit(typeof(object), node.Arguments.Map((e) => AstUtils.Convert(e, typeof(object)))) + ), + node.Type + ) + ); + + } else { + if (!node.Method.IsStatic) { + Compile(node.Object); + } + + foreach (var arg in node.Arguments) { + Compile(arg); + } + + EmitCall(node.Method, parameters); + } + } + + public void EmitCall(MethodInfo method) { + EmitCall(method, method.GetParameters()); + } + + public void EmitCall(MethodInfo method, ParameterInfo[] parameters) { + Instruction instruction; + + try { + instruction = CallInstruction.Create(method, parameters); + } catch (SecurityException) { + _forceCompile = true; + + _instructions.Emit(new PopNInstruction((method.IsStatic ? 0 : 1) + parameters.Length)); + if (method.ReturnType != typeof(void)) { + _instructions.EmitLoad(null); + } + + return; + } + + _instructions.Emit(instruction); + } + + private void CompileNewExpression(Expression expr) { + var node = (NewExpression)expr; + + if (node.Constructor != null) { + var parameters = node.Constructor.GetParameters(); + if (!CollectionUtils.TrueForAll(parameters, (p) => !p.ParameterType.IsByRef) +#if FEATURE_LCG + || node.Constructor.DeclaringType == typeof(DynamicMethod) +#endif + ) { + _forceCompile = true; + } + } + + if (node.Constructor != null) { + foreach (var arg in node.Arguments) { + this.Compile(arg); + } + _instructions.EmitNew(node.Constructor); + } else { + Debug.Assert(expr.Type.IsValueType()); + _instructions.EmitDefaultValue(node.Type); + } + } + + private void CompileMemberExpression(Expression expr) { + var node = (MemberExpression)expr; + + var member = node.Member; + FieldInfo fi = member as FieldInfo; + if (fi != null) { + if (fi.IsLiteral) { + _instructions.EmitLoad(fi.GetRawConstantValue(), fi.FieldType); + } else if (fi.IsStatic) { + if (fi.IsInitOnly) { + _instructions.EmitLoad(fi.GetValue(null), fi.FieldType); + } else { + _instructions.EmitLoadField(fi); + } + } else { + Compile(node.Expression); + _instructions.EmitLoadField(fi); + } + return; + } + + PropertyInfo pi = member as PropertyInfo; + if (pi != null) { + var method = pi.GetGetMethod(true); + if (node.Expression != null) { + Compile(node.Expression); + } + EmitCall(method); + return; + } + + + throw new System.NotImplementedException(); + } + + private void CompileNewArrayExpression(Expression expr) { + var node = (NewArrayExpression)expr; + + foreach (var arg in node.Expressions) { + Compile(arg); + } + + Type elementType = node.Type.GetElementType(); + int rank = node.Expressions.Count; + + if (node.NodeType == ExpressionType.NewArrayInit) { + _instructions.EmitNewArrayInit(elementType, rank); + } else if (node.NodeType == ExpressionType.NewArrayBounds) { + if (rank == 1) { + _instructions.EmitNewArray(elementType); + } else { + _instructions.EmitNewArrayBounds(elementType, rank); + } + } else { + throw new System.NotImplementedException(); + } + } + + private void CompileExtensionExpression(Expression expr) { + var instructionProvider = expr as IInstructionProvider; + if (instructionProvider != null) { + instructionProvider.AddInstructions(this); + return; + } + + if (expr.CanReduce) { + Compile(expr.Reduce()); + } else { + throw new System.NotImplementedException(); + } + } + + + private void CompileDebugInfoExpression(Expression expr) { + var node = (DebugInfoExpression)expr; + int start = _instructions.Count; + var info = new DebugInfo() + { + Index = start, + FileName = node.Document.FileName, + StartLine = node.StartLine, + EndLine = node.EndLine, + IsClear = node.IsClear + }; + _debugInfos.Add(info); + } + + private void CompileRuntimeVariablesExpression(Expression expr) { + // Generates IRuntimeVariables for all requested variables + var node = (RuntimeVariablesExpression)expr; + foreach (var variable in node.Variables) { + EnsureAvailableForClosure(variable); + CompileGetBoxedVariable(variable); + } + + _instructions.EmitNewRuntimeVariables(node.Variables.Count); + } + + + private void CompileLambdaExpression(Expression expr) { + var node = (LambdaExpression)expr; + var compiler = new LightCompiler(this); + var creator = compiler.CompileTop(node); + + if (compiler._locals.ClosureVariables != null) { + foreach (ParameterExpression variable in compiler._locals.ClosureVariables.Keys) { + CompileGetBoxedVariable(variable); + } + } + _instructions.EmitCreateDelegate(creator); + } + + private void CompileCoalesceBinaryExpression(Expression expr) { + var node = (BinaryExpression)expr; + + if (TypeUtils.IsNullableType(node.Left.Type)) { + throw new NotImplementedException(); + } else if (node.Conversion != null) { + throw new NotImplementedException(); + } else { + var leftNotNull = _instructions.MakeLabel(); + Compile(node.Left); + _instructions.EmitCoalescingBranch(leftNotNull); + _instructions.EmitPop(); + Compile(node.Right); + _instructions.MarkLabel(leftNotNull); + } + } + + private void CompileInvocationExpression(Expression expr) { + var node = (InvocationExpression)expr; + + // TODO: LambdaOperand optimization (see compiler) + if (typeof(LambdaExpression).IsAssignableFrom(node.Expression.Type)) { + throw new System.NotImplementedException(); + } + + // TODO: do not create a new Call Expression + if (PlatformAdaptationLayer.IsCompactFramework) { + // Workaround for a bug in Compact Framework + Compile( + AstUtils.Convert( + Expression.Call( + node.Expression, + node.Expression.Type.GetMethod("DynamicInvoke"), + Expression.NewArrayInit(typeof(object), node.Arguments.Map((e) => AstUtils.Convert(e, typeof(object)))) + ), + node.Type + ) + ); + } else { + CompileMethodCallExpression(Expression.Call(node.Expression, node.Expression.Type.GetMethod("Invoke"), node.Arguments)); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "expr")] + private void CompileListInitExpression(Expression expr) { + throw new System.NotImplementedException(); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "expr")] + private void CompileMemberInitExpression(Expression expr) { + throw new System.NotImplementedException(); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "expr")] + private void CompileQuoteUnaryExpression(Expression expr) { + throw new System.NotImplementedException(); + } + + private void CompileUnboxUnaryExpression(Expression expr) { + var node = (UnaryExpression)expr; + // unboxing is a nop: + Compile(node.Operand); + } + + private void CompileTypeEqualExpression(Expression expr) { + Debug.Assert(expr.NodeType == ExpressionType.TypeEqual); + var node = (TypeBinaryExpression)expr; + + Compile(node.Expression); + _instructions.EmitLoad(node.TypeOperand); + _instructions.EmitTypeEquals(); + } + + private void CompileTypeAsExpression(UnaryExpression node) { + Compile(node.Operand); + _instructions.EmitTypeAs(node.Type); + } + + private void CompileTypeIsExpression(Expression expr) { + Debug.Assert(expr.NodeType == ExpressionType.TypeIs); + var node = (TypeBinaryExpression)expr; + + Compile(node.Expression); + + // use TypeEqual for sealed types: + if (node.TypeOperand.IsSealed()) { + _instructions.EmitLoad(node.TypeOperand); + _instructions.EmitTypeEquals(); + } else { + _instructions.EmitTypeIs(node.TypeOperand); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "expr")] + private void CompileReducibleExpression(Expression expr) { + throw new System.NotImplementedException(); + } + + internal void Compile(Expression expr, bool asVoid) { + if (asVoid) { + CompileAsVoid(expr); + } else { + Compile(expr); + } + } + + internal void CompileAsVoid(Expression expr) { + bool pushLabelBlock = TryPushLabelBlock(expr); + int startingStackDepth = _instructions.CurrentStackDepth; + switch (expr.NodeType) { + case ExpressionType.Assign: + CompileAssignBinaryExpression(expr, true); + break; + + case ExpressionType.Block: + CompileBlockExpression(expr, true); + break; + + case ExpressionType.Throw: + CompileThrowUnaryExpression(expr, true); + break; + + case ExpressionType.Constant: + case ExpressionType.Default: + case ExpressionType.Parameter: + // no-op + break; + + default: + CompileNoLabelPush(expr); + if (expr.Type != typeof(void)) { + _instructions.EmitPop(); + } + break; + } + Debug.Assert(_instructions.CurrentStackDepth == startingStackDepth); + if (pushLabelBlock) { + PopLabelBlock(_labelBlock.Kind); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] + private void CompileNoLabelPush(Expression expr) { + int startingStackDepth = _instructions.CurrentStackDepth; + switch (expr.NodeType) { + case ExpressionType.Add: CompileBinaryExpression(expr); break; + case ExpressionType.AddChecked: CompileBinaryExpression(expr); break; + case ExpressionType.And: CompileBinaryExpression(expr); break; + case ExpressionType.AndAlso: CompileAndAlsoBinaryExpression(expr); break; + case ExpressionType.ArrayLength: CompileUnaryExpression(expr); break; + case ExpressionType.ArrayIndex: CompileBinaryExpression(expr); break; + case ExpressionType.Call: CompileMethodCallExpression(expr); break; + case ExpressionType.Coalesce: CompileCoalesceBinaryExpression(expr); break; + case ExpressionType.Conditional: CompileConditionalExpression(expr, expr.Type == typeof(void)); break; + case ExpressionType.Constant: CompileConstantExpression(expr); break; + case ExpressionType.Convert: CompileConvertUnaryExpression(expr); break; + case ExpressionType.ConvertChecked: CompileConvertUnaryExpression(expr); break; + case ExpressionType.Divide: CompileBinaryExpression(expr); break; + case ExpressionType.Equal: CompileBinaryExpression(expr); break; + case ExpressionType.ExclusiveOr: CompileBinaryExpression(expr); break; + case ExpressionType.GreaterThan: CompileBinaryExpression(expr); break; + case ExpressionType.GreaterThanOrEqual: CompileBinaryExpression(expr); break; + case ExpressionType.Invoke: CompileInvocationExpression(expr); break; + case ExpressionType.Lambda: CompileLambdaExpression(expr); break; + case ExpressionType.LeftShift: CompileBinaryExpression(expr); break; + case ExpressionType.LessThan: CompileBinaryExpression(expr); break; + case ExpressionType.LessThanOrEqual: CompileBinaryExpression(expr); break; + case ExpressionType.ListInit: CompileListInitExpression(expr); break; + case ExpressionType.MemberAccess: CompileMemberExpression(expr); break; + case ExpressionType.MemberInit: CompileMemberInitExpression(expr); break; + case ExpressionType.Modulo: CompileBinaryExpression(expr); break; + case ExpressionType.Multiply: CompileBinaryExpression(expr); break; + case ExpressionType.MultiplyChecked: CompileBinaryExpression(expr); break; + case ExpressionType.Negate: CompileUnaryExpression(expr); break; + case ExpressionType.UnaryPlus: CompileUnaryExpression(expr); break; + case ExpressionType.NegateChecked: CompileUnaryExpression(expr); break; + case ExpressionType.New: CompileNewExpression(expr); break; + case ExpressionType.NewArrayInit: CompileNewArrayExpression(expr); break; + case ExpressionType.NewArrayBounds: CompileNewArrayExpression(expr); break; + case ExpressionType.Not: CompileUnaryExpression(expr); break; + case ExpressionType.NotEqual: CompileBinaryExpression(expr); break; + case ExpressionType.Or: CompileBinaryExpression(expr); break; + case ExpressionType.OrElse: CompileOrElseBinaryExpression(expr); break; + case ExpressionType.Parameter: CompileParameterExpression(expr); break; + case ExpressionType.Power: CompileBinaryExpression(expr); break; + case ExpressionType.Quote: CompileQuoteUnaryExpression(expr); break; + case ExpressionType.RightShift: CompileBinaryExpression(expr); break; + case ExpressionType.Subtract: CompileBinaryExpression(expr); break; + case ExpressionType.SubtractChecked: CompileBinaryExpression(expr); break; + case ExpressionType.TypeAs: CompileUnaryExpression(expr); break; + case ExpressionType.TypeIs: CompileTypeIsExpression(expr); break; + case ExpressionType.Assign: CompileAssignBinaryExpression(expr, expr.Type == typeof(void)); break; + case ExpressionType.Block: CompileBlockExpression(expr, expr.Type == typeof(void)); break; + case ExpressionType.DebugInfo: CompileDebugInfoExpression(expr); break; + case ExpressionType.Decrement: CompileUnaryExpression(expr); break; + case ExpressionType.Dynamic: CompileDynamicExpression(expr); break; + case ExpressionType.Default: CompileDefaultExpression(expr); break; + case ExpressionType.Extension: CompileExtensionExpression(expr); break; + case ExpressionType.Goto: CompileGotoExpression(expr); break; + case ExpressionType.Increment: CompileUnaryExpression(expr); break; + case ExpressionType.Index: CompileIndexExpression(expr); break; + case ExpressionType.Label: CompileLabelExpression(expr); break; + case ExpressionType.RuntimeVariables: CompileRuntimeVariablesExpression(expr); break; + case ExpressionType.Loop: CompileLoopExpression(expr); break; + case ExpressionType.Switch: CompileSwitchExpression(expr); break; + case ExpressionType.Throw: CompileThrowUnaryExpression(expr, expr.Type == typeof(void)); break; + case ExpressionType.Try: CompileTryExpression(expr); break; + case ExpressionType.Unbox: CompileUnboxUnaryExpression(expr); break; + case ExpressionType.TypeEqual: CompileTypeEqualExpression(expr); break; + case ExpressionType.OnesComplement: CompileUnaryExpression(expr); break; + case ExpressionType.IsTrue: CompileUnaryExpression(expr); break; + case ExpressionType.IsFalse: CompileUnaryExpression(expr); break; + case ExpressionType.AddAssign: + case ExpressionType.AndAssign: + case ExpressionType.DivideAssign: + case ExpressionType.ExclusiveOrAssign: + case ExpressionType.LeftShiftAssign: + case ExpressionType.ModuloAssign: + case ExpressionType.MultiplyAssign: + case ExpressionType.OrAssign: + case ExpressionType.PowerAssign: + case ExpressionType.RightShiftAssign: + case ExpressionType.SubtractAssign: + case ExpressionType.AddAssignChecked: + case ExpressionType.MultiplyAssignChecked: + case ExpressionType.SubtractAssignChecked: + case ExpressionType.PreIncrementAssign: + case ExpressionType.PreDecrementAssign: + case ExpressionType.PostIncrementAssign: + case ExpressionType.PostDecrementAssign: + CompileReducibleExpression(expr); break; + default: throw Assert.Unreachable; + }; + Debug.Assert(_instructions.CurrentStackDepth == startingStackDepth + (expr.Type == typeof(void) ? 0 : 1)); + } + + public void Compile(Expression expr) { + bool pushLabelBlock = TryPushLabelBlock(expr); + CompileNoLabelPush(expr); + if (pushLabelBlock) { + PopLabelBlock(_labelBlock.Kind); + } + } + + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightDelegateCreator.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightDelegateCreator.cs new file mode 100644 index 00000000000..18ce7b90010 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightDelegateCreator.cs @@ -0,0 +1,194 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +using Microsoft.Scripting.Ast; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.Scripting.Generation; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + + /// <summary> + /// Manages creation of interpreted delegates. These delegates will get + /// compiled if they are executed often enough. + /// </summary> + internal sealed class LightDelegateCreator { + // null if we are forced to compile + private readonly Interpreter _interpreter; + private readonly Expression _lambda; + + // Adaptive compilation support: + private Type _compiledDelegateType; + private Delegate _compiled; + private readonly object _compileLock = new object(); + + internal LightDelegateCreator(Interpreter interpreter, LambdaExpression lambda) { + Assert.NotNull(lambda); + _interpreter = interpreter; + _lambda = lambda; + } + + internal LightDelegateCreator(Interpreter interpreter, LightLambdaExpression lambda) { + Assert.NotNull(lambda); + _interpreter = interpreter; + _lambda = lambda; + } + + internal Interpreter Interpreter { + get { return _interpreter; } + } + + private bool HasClosure { + get { return _interpreter != null && _interpreter.ClosureSize > 0; } + } + + internal bool HasCompiled { + get { return _compiled != null; } + } + + /// <summary> + /// true if the compiled delegate has the same type as the lambda; + /// false if the type was changed for interpretation. + /// </summary> + internal bool SameDelegateType { + get { return _compiledDelegateType == DelegateType; } + } + + internal Delegate CreateDelegate() { + return CreateDelegate(null); + } + + internal Delegate CreateDelegate(StrongBox<object>[] closure) { + if (_compiled != null) { + // If the delegate type we want is not a Func/Action, we can't + // use the compiled code directly. So instead just fall through + // and create an interpreted LightLambda, which will pick up + // the compiled delegate on its first run. + // + // Ideally, we would just rebind the compiled delegate using + // Delegate.CreateDelegate. Unfortunately, it doesn't work on + // dynamic methods. + if (SameDelegateType) { + return CreateCompiledDelegate(closure); + } + } + + if (_interpreter == null) { + // We can't interpret, so force a compile + Compile(null); + Delegate compiled = CreateCompiledDelegate(closure); + Debug.Assert(compiled.GetType() == DelegateType); + return compiled; + } + + // Otherwise, we'll create an interpreted LightLambda + return new LightLambda(this, closure, _interpreter._compilationThreshold).MakeDelegate(DelegateType); + } + + private Type DelegateType { + get { + LambdaExpression le = _lambda as LambdaExpression; + if (le != null) { + return le.Type; + } + + return ((LightLambdaExpression)_lambda).Type; + } + } + + /// <summary> + /// Used by LightLambda to get the compiled delegate. + /// </summary> + internal Delegate CreateCompiledDelegate(StrongBox<object>[] closure) { + Debug.Assert(HasClosure == (closure != null)); + + if (HasClosure) { + // We need to apply the closure to get the actual delegate. + var applyClosure = (Func<StrongBox<object>[], Delegate>)_compiled; + return applyClosure(closure); + } + return _compiled; + } + + /// <summary> + /// Create a compiled delegate for the LightLambda, and saves it so + /// future calls to Run will execute the compiled code instead of + /// interpreting. + /// </summary> + internal void Compile(object state) { + if (_compiled != null) { + return; + } + + // Compilation is expensive, we only want to do it once. + lock (_compileLock) { + if (_compiled != null) { + return; + } + + PerfTrack.NoteEvent(PerfTrack.Categories.Compiler, "Interpreted lambda compiled"); + + // Interpreter needs a standard delegate type. + // So change the lambda's delegate type to Func<...> or + // Action<...> so it can be called from the LightLambda.Run + // methods. + LambdaExpression lambda = (_lambda as LambdaExpression) ?? (LambdaExpression)((LightLambdaExpression)_lambda).Reduce(); + if (_interpreter != null) { + _compiledDelegateType = GetFuncOrAction(lambda); + lambda = Expression.Lambda(_compiledDelegateType, lambda.Body, lambda.Name, lambda.Parameters); + } + + if (HasClosure) { + _compiled = LightLambdaClosureVisitor.BindLambda(lambda, _interpreter.ClosureVariables); + } else { + _compiled = lambda.Compile(); + } + } + } + + private static Type GetFuncOrAction(LambdaExpression lambda) { + Type delegateType; + bool isVoid = lambda.ReturnType == typeof(void); + + if (isVoid && lambda.Parameters.Count == 2 && + lambda.Parameters[0].IsByRef && lambda.Parameters[1].IsByRef) { + return typeof(ActionRef<,>).MakeGenericType(lambda.Parameters.Map(p => p.Type)); + } else { + Type[] types = lambda.Parameters.Map(p => p.IsByRef ? p.Type.MakeByRefType() : p.Type); + if (isVoid) { + if (Expression.TryGetActionType(types, out delegateType)) { + return delegateType; + } + } else { + types = types.AddLast(lambda.ReturnType); + if (Expression.TryGetFuncType(types, out delegateType)) { + return delegateType; + } + } + return lambda.Type; + } + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambda.Generated.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambda.Generated.cs new file mode 100644 index 00000000000..b3b42a30463 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambda.Generated.cs @@ -0,0 +1,724 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + + +using System; +using System.Runtime.CompilerServices; +using System.Reflection; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + public partial class LightLambda { + #region Generated LightLambda Run Methods + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_run_methods from: generate_dynamic_instructions.py + + internal const int MaxParameters = 16; + internal TRet Run0<TRet>() { + if (_compiled != null || TryGetCompiled()) { + return ((Func<TRet>)_compiled)(); + } + + var frame = MakeFrame(); + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid0() { + if (_compiled != null || TryGetCompiled()) { + ((Action)_compiled)(); + return; + } + + var frame = MakeFrame(); + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun0<TRet>(LightLambda lambda) { + return new Func<TRet>(lambda.Run0<TRet>); + } + internal static Delegate MakeRunVoid0(LightLambda lambda) { + return new Action(lambda.RunVoid0); + } + internal TRet Run1<T0,TRet>(T0 arg0) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,TRet>)_compiled)(arg0); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid1<T0>(T0 arg0) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0>)_compiled)(arg0); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun1<T0,TRet>(LightLambda lambda) { + return new Func<T0,TRet>(lambda.Run1<T0,TRet>); + } + internal static Delegate MakeRunVoid1<T0>(LightLambda lambda) { + return new Action<T0>(lambda.RunVoid1<T0>); + } + internal TRet Run2<T0,T1,TRet>(T0 arg0,T1 arg1) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,TRet>)_compiled)(arg0, arg1); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid2<T0,T1>(T0 arg0,T1 arg1) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1>)_compiled)(arg0, arg1); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun2<T0,T1,TRet>(LightLambda lambda) { + return new Func<T0,T1,TRet>(lambda.Run2<T0,T1,TRet>); + } + internal static Delegate MakeRunVoid2<T0,T1>(LightLambda lambda) { + return new Action<T0,T1>(lambda.RunVoid2<T0,T1>); + } + internal TRet Run3<T0,T1,T2,TRet>(T0 arg0,T1 arg1,T2 arg2) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,TRet>)_compiled)(arg0, arg1, arg2); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid3<T0,T1,T2>(T0 arg0,T1 arg1,T2 arg2) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2>)_compiled)(arg0, arg1, arg2); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun3<T0,T1,T2,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,TRet>(lambda.Run3<T0,T1,T2,TRet>); + } + internal static Delegate MakeRunVoid3<T0,T1,T2>(LightLambda lambda) { + return new Action<T0,T1,T2>(lambda.RunVoid3<T0,T1,T2>); + } + internal TRet Run4<T0,T1,T2,T3,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,TRet>)_compiled)(arg0, arg1, arg2, arg3); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid4<T0,T1,T2,T3>(T0 arg0,T1 arg1,T2 arg2,T3 arg3) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3>)_compiled)(arg0, arg1, arg2, arg3); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun4<T0,T1,T2,T3,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,TRet>(lambda.Run4<T0,T1,T2,T3,TRet>); + } + internal static Delegate MakeRunVoid4<T0,T1,T2,T3>(LightLambda lambda) { + return new Action<T0,T1,T2,T3>(lambda.RunVoid4<T0,T1,T2,T3>); + } + internal TRet Run5<T0,T1,T2,T3,T4,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid5<T0,T1,T2,T3,T4>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4>)_compiled)(arg0, arg1, arg2, arg3, arg4); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun5<T0,T1,T2,T3,T4,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,TRet>(lambda.Run5<T0,T1,T2,T3,T4,TRet>); + } + internal static Delegate MakeRunVoid5<T0,T1,T2,T3,T4>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4>(lambda.RunVoid5<T0,T1,T2,T3,T4>); + } + internal TRet Run6<T0,T1,T2,T3,T4,T5,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,T5,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid6<T0,T1,T2,T3,T4,T5>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4,T5>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun6<T0,T1,T2,T3,T4,T5,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,T5,TRet>(lambda.Run6<T0,T1,T2,T3,T4,T5,TRet>); + } + internal static Delegate MakeRunVoid6<T0,T1,T2,T3,T4,T5>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4,T5>(lambda.RunVoid6<T0,T1,T2,T3,T4,T5>); + } + internal TRet Run7<T0,T1,T2,T3,T4,T5,T6,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,T5,T6,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid7<T0,T1,T2,T3,T4,T5,T6>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4,T5,T6>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun7<T0,T1,T2,T3,T4,T5,T6,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,T5,T6,TRet>(lambda.Run7<T0,T1,T2,T3,T4,T5,T6,TRet>); + } + internal static Delegate MakeRunVoid7<T0,T1,T2,T3,T4,T5,T6>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4,T5,T6>(lambda.RunVoid7<T0,T1,T2,T3,T4,T5,T6>); + } + internal TRet Run8<T0,T1,T2,T3,T4,T5,T6,T7,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,T5,T6,T7,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid8<T0,T1,T2,T3,T4,T5,T6,T7>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4,T5,T6,T7>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun8<T0,T1,T2,T3,T4,T5,T6,T7,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,T5,T6,T7,TRet>(lambda.Run8<T0,T1,T2,T3,T4,T5,T6,T7,TRet>); + } + internal static Delegate MakeRunVoid8<T0,T1,T2,T3,T4,T5,T6,T7>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4,T5,T6,T7>(lambda.RunVoid8<T0,T1,T2,T3,T4,T5,T6,T7>); + } + internal TRet Run9<T0,T1,T2,T3,T4,T5,T6,T7,T8,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid9<T0,T1,T2,T3,T4,T5,T6,T7,T8>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4,T5,T6,T7,T8>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun9<T0,T1,T2,T3,T4,T5,T6,T7,T8,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,TRet>(lambda.Run9<T0,T1,T2,T3,T4,T5,T6,T7,T8,TRet>); + } + internal static Delegate MakeRunVoid9<T0,T1,T2,T3,T4,T5,T6,T7,T8>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4,T5,T6,T7,T8>(lambda.RunVoid9<T0,T1,T2,T3,T4,T5,T6,T7,T8>); + } + internal TRet Run10<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid10<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun10<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,TRet>(lambda.Run10<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,TRet>); + } + internal static Delegate MakeRunVoid10<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9>(lambda.RunVoid10<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9>); + } + internal TRet Run11<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + frame.Data[10] = arg10; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid11<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + frame.Data[10] = arg10; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun11<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,TRet>(lambda.Run11<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,TRet>); + } + internal static Delegate MakeRunVoid11<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10>(lambda.RunVoid11<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10>); + } + internal TRet Run12<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + frame.Data[10] = arg10; + frame.Data[11] = arg11; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid12<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + frame.Data[10] = arg10; + frame.Data[11] = arg11; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun12<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,TRet>(lambda.Run12<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,TRet>); + } + internal static Delegate MakeRunVoid12<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11>(lambda.RunVoid12<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11>); + } + internal TRet Run13<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + frame.Data[10] = arg10; + frame.Data[11] = arg11; + frame.Data[12] = arg12; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid13<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + frame.Data[10] = arg10; + frame.Data[11] = arg11; + frame.Data[12] = arg12; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun13<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,TRet>(lambda.Run13<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,TRet>); + } + internal static Delegate MakeRunVoid13<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12>(lambda.RunVoid13<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12>); + } + internal TRet Run14<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + frame.Data[10] = arg10; + frame.Data[11] = arg11; + frame.Data[12] = arg12; + frame.Data[13] = arg13; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid14<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + frame.Data[10] = arg10; + frame.Data[11] = arg11; + frame.Data[12] = arg12; + frame.Data[13] = arg13; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun14<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,TRet>(lambda.Run14<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,TRet>); + } + internal static Delegate MakeRunVoid14<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13>(lambda.RunVoid14<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13>); + } + internal TRet Run15<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,TRet>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13,T14 arg14) { + if (_compiled != null || TryGetCompiled()) { + return ((Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,TRet>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + frame.Data[10] = arg10; + frame.Data[11] = arg11; + frame.Data[12] = arg12; + frame.Data[13] = arg13; + frame.Data[14] = arg14; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + return (TRet)frame.Pop(); + } + + internal void RunVoid15<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14>(T0 arg0,T1 arg1,T2 arg2,T3 arg3,T4 arg4,T5 arg5,T6 arg6,T7 arg7,T8 arg8,T9 arg9,T10 arg10,T11 arg11,T12 arg12,T13 arg13,T14 arg14) { + if (_compiled != null || TryGetCompiled()) { + ((Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14>)_compiled)(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + return; + } + + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + frame.Data[2] = arg2; + frame.Data[3] = arg3; + frame.Data[4] = arg4; + frame.Data[5] = arg5; + frame.Data[6] = arg6; + frame.Data[7] = arg7; + frame.Data[8] = arg8; + frame.Data[9] = arg9; + frame.Data[10] = arg10; + frame.Data[11] = arg11; + frame.Data[12] = arg12; + frame.Data[13] = arg13; + frame.Data[14] = arg14; + var current = frame.Enter(); + try { _interpreter.Run(frame); } finally { frame.Leave(current); } + } + + internal static Delegate MakeRun15<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,TRet>(LightLambda lambda) { + return new Func<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,TRet>(lambda.Run15<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14,TRet>); + } + internal static Delegate MakeRunVoid15<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14>(LightLambda lambda) { + return new Action<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14>(lambda.RunVoid15<T0,T1,T2,T3,T4,T5,T6,T7,T8,T9,T10,T11,T12,T13,T14>); + } + + // *** END GENERATED CODE *** + + #endregion + + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambda.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambda.cs new file mode 100644 index 00000000000..94982bfa24b --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambda.cs @@ -0,0 +1,272 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_TASKS +using System.Threading.Tasks; +#endif + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Reflection; +#if FEATURE_REFEMIT +using System.Reflection.Emit; +#endif +using System.Runtime.CompilerServices; +using System.Security; +using System.Threading; + +using Microsoft.Scripting.Generation; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +using AstUtils = Microsoft.Scripting.Ast.Utils; + +namespace Microsoft.Scripting.Interpreter { + + public sealed class LightLambdaCompileEventArgs : EventArgs { + public Delegate Compiled { get; private set; } + + internal LightLambdaCompileEventArgs(Delegate compiled) { + Compiled = compiled; + } + } + + public partial class LightLambda { + private readonly StrongBox<object>[] _closure; + private readonly Interpreter _interpreter; + private static readonly CacheDict<Type, Func<LightLambda, Delegate>> _runCache = new CacheDict<Type, Func<LightLambda, Delegate>>(100); + + // Adaptive compilation support + private readonly LightDelegateCreator _delegateCreator; + private Delegate _compiled; + private int _compilationThreshold; + + /// <summary> + /// Provides notification that the LightLambda has been compiled. + /// </summary> + public event EventHandler<LightLambdaCompileEventArgs> Compile; + + internal LightLambda(LightDelegateCreator delegateCreator, StrongBox<object>[] closure, int compilationThreshold) { + _delegateCreator = delegateCreator; + _closure = closure; + _interpreter = delegateCreator.Interpreter; + _compilationThreshold = compilationThreshold; + } + + private static Func<LightLambda, Delegate> GetRunDelegateCtor(Type delegateType) { + lock (_runCache) { + Func<LightLambda, Delegate> fastCtor; + if (_runCache.TryGetValue(delegateType, out fastCtor)) { + return fastCtor; + } + return MakeRunDelegateCtor(delegateType); + } + } + + private static Func<LightLambda, Delegate> MakeRunDelegateCtor(Type delegateType) { + var method = delegateType.GetMethod("Invoke"); + var paramInfos = method.GetParameters(); + Type[] paramTypes; + string name = "Run"; + + if (paramInfos.Length >= MaxParameters) { + return null; + } + + if (method.ReturnType == typeof(void)) { + name += "Void"; + paramTypes = new Type[paramInfos.Length]; + } else { + paramTypes = new Type[paramInfos.Length + 1]; + paramTypes[paramTypes.Length - 1] = method.ReturnType; + } + + MethodInfo runMethod; + + if (method.ReturnType == typeof(void) && paramTypes.Length == 2 && + paramInfos[0].ParameterType.IsByRef && paramInfos[1].ParameterType.IsByRef) { + runMethod = typeof(LightLambda).GetMethod("RunVoidRef2", BindingFlags.NonPublic | BindingFlags.Instance); + paramTypes[0] = paramInfos[0].ParameterType.GetElementType(); + paramTypes[1] = paramInfos[1].ParameterType.GetElementType(); + } else if (method.ReturnType == typeof(void) && paramTypes.Length == 0) { + runMethod = typeof(LightLambda).GetMethod("RunVoid0", BindingFlags.NonPublic | BindingFlags.Instance); + } else { + for (int i = 0; i < paramInfos.Length; i++) { + paramTypes[i] = paramInfos[i].ParameterType; + if (paramTypes[i].IsByRef) { + return null; + } + } + + if (DelegateHelpers.MakeDelegate(paramTypes) == delegateType) { + name = "Make" + name + paramInfos.Length; + + MethodInfo ctorMethod = typeof(LightLambda).GetMethod(name, BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(paramTypes); + return _runCache[delegateType] = (Func<LightLambda, Delegate>)ctorMethod.CreateDelegate(typeof(Func<LightLambda, Delegate>)); + } + + runMethod = typeof(LightLambda).GetMethod(name + paramInfos.Length, BindingFlags.NonPublic | BindingFlags.Instance); + } + +#if FEATURE_LCG && !SILVERLIGHT && !WP75 + try { + DynamicMethod dm = new DynamicMethod("FastCtor", typeof(Delegate), new[] { typeof(LightLambda) }, typeof(LightLambda), true); + var ilgen = dm.GetILGenerator(); + ilgen.Emit(OpCodes.Ldarg_0); + ilgen.Emit(OpCodes.Ldftn, runMethod.IsGenericMethodDefinition ? runMethod.MakeGenericMethod(paramTypes) : runMethod); + ilgen.Emit(OpCodes.Newobj, delegateType.GetConstructor(new[] { typeof(object), typeof(IntPtr) })); + ilgen.Emit(OpCodes.Ret); + return _runCache[delegateType] = (Func<LightLambda, Delegate>)dm.CreateDelegate(typeof(Func<LightLambda, Delegate>)); + } catch (SecurityException) { + } +#endif + + // we don't have permission for restricted skip visibility dynamic methods, use the slower Delegate.CreateDelegate. + var targetMethod = runMethod.IsGenericMethodDefinition ? runMethod.MakeGenericMethod(paramTypes) : runMethod; + return _runCache[delegateType] = lambda => targetMethod.CreateDelegate(delegateType, lambda); + } + + //TODO enable sharing of these custom delegates + private Delegate CreateCustomDelegate(Type delegateType) { + PerfTrack.NoteEvent(PerfTrack.Categories.Compiler, "Synchronously compiling a custom delegate"); + + var method = delegateType.GetMethod("Invoke"); + var paramInfos = method.GetParameters(); + var parameters = new ParameterExpression[paramInfos.Length]; + var parametersAsObject = new Expression[paramInfos.Length]; + for (int i = 0; i < paramInfos.Length; i++) { + ParameterExpression parameter = Expression.Parameter(paramInfos[i].ParameterType, paramInfos[i].Name); + parameters[i] = parameter; + parametersAsObject[i] = Expression.Convert(parameter, typeof(object)); + } + + var data = Expression.NewArrayInit(typeof(object), parametersAsObject); + var self = AstUtils.Constant(this); + var runMethod = typeof(LightLambda).GetMethod("Run"); + var body = Expression.Convert(Expression.Call(self, runMethod, data), method.ReturnType); + var lambda = Expression.Lambda(delegateType, body, parameters); + return lambda.Compile(); + } + + internal Delegate MakeDelegate(Type delegateType) { + Func<LightLambda, Delegate> fastCtor = GetRunDelegateCtor(delegateType); + if (fastCtor != null) { + return fastCtor(this); + } else { + return CreateCustomDelegate(delegateType); + } + } + + private bool TryGetCompiled() { + // Use the compiled delegate if available. + if (_delegateCreator.HasCompiled) { + _compiled = _delegateCreator.CreateCompiledDelegate(_closure); + + // Send it to anyone who's interested. + var compileEvent = Compile; + if (compileEvent != null && _delegateCreator.SameDelegateType) { + compileEvent(this, new LightLambdaCompileEventArgs(_compiled)); + } + + return true; + } + + // Don't lock here, it's a frequently hit path. + // + // There could be multiple threads racing, but that is okay. + // Two bad things can happen: + // * We miss decrements (some thread sets the counter forward) + // * We might enter the "if" branch more than once. + // + // The first is okay, it just means we take longer to compile. + // The second we explicitly guard against inside of Compile(). + // + // We can't miss 0. The first thread that writes -1 must have read 0 and hence start compilation. + if (unchecked(_compilationThreshold--) == 0) { +#if SILVERLIGHT + if (PlatformAdaptationLayer.IsCompactFramework) { + _compilationThreshold = Int32.MaxValue; + return false; + } +#endif + if (_interpreter.CompileSynchronously) { + _delegateCreator.Compile(null); + return TryGetCompiled(); + } else { + // Kick off the compile on another thread so this one can keep going +#if FEATURE_TASKS + new Task(_delegateCreator.Compile, null).Start(); +#else + ThreadPool.QueueUserWorkItem(_delegateCreator.Compile, null); +#endif + } + } + + return false; + } + + private InterpretedFrame MakeFrame() { + return new InterpretedFrame(_interpreter, _closure); + } + + internal void RunVoidRef2<T0, T1>(ref T0 arg0, ref T1 arg1) { + if (_compiled != null || TryGetCompiled()) { + ((ActionRef<T0, T1>)_compiled)(ref arg0, ref arg1); + return; + } + + // copy in and copy out for today... + var frame = MakeFrame(); + frame.Data[0] = arg0; + frame.Data[1] = arg1; + var currentFrame = frame.Enter(); + try { + _interpreter.Run(frame); + } finally { + frame.Leave(currentFrame); + arg0 = (T0)frame.Data[0]; + arg1 = (T1)frame.Data[1]; + } + } + + + public object Run(params object[] arguments) { + if (_compiled != null || TryGetCompiled()) { + try { + return _compiled.DynamicInvoke(arguments); + } catch (TargetInvocationException e) { + throw ExceptionHelpers.UpdateForRethrow(e.InnerException); + } + } + + var frame = MakeFrame(); + for (int i = 0; i < arguments.Length; i++) { + frame.Data[i] = arguments[i]; + } + var currentFrame = frame.Enter(); + try { + _interpreter.Run(frame); + } finally { + frame.Leave(currentFrame); + } + return frame.Pop(); + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambdaClosureVisitor.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambdaClosureVisitor.cs new file mode 100644 index 00000000000..e779e414855 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LightLambdaClosureVisitor.cs @@ -0,0 +1,260 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Utils; +using AstUtils = Microsoft.Scripting.Ast.Utils; + +namespace Microsoft.Scripting.Interpreter { + + /// <summary> + /// Visits a LambdaExpression, replacing the constants with direct accesses + /// to their StrongBox fields. This is very similar to what + /// ExpressionQuoter does for LambdaCompiler. + /// + /// Also inserts debug information tracking similar to what the interpreter + /// would do. + /// </summary> + internal sealed class LightLambdaClosureVisitor : ExpressionVisitor { + /// <summary> + /// Local variable mapping. + /// </summary> + private readonly Dictionary<ParameterExpression, LocalVariable> _closureVars; + + /// <summary> + /// The variable that holds onto the StrongBox{object}[] closure from + /// the interpreter + /// </summary> + private readonly ParameterExpression _closureArray; + + /// <summary> + /// A stack of variables that are defined in nested scopes. We search + /// this first when resolving a variable in case a nested scope shadows + /// one of our variable instances. + /// </summary> + private readonly Stack<HashSet<ParameterExpression>> _shadowedVars = new Stack<HashSet<ParameterExpression>>(); + + private LightLambdaClosureVisitor(Dictionary<ParameterExpression, LocalVariable> closureVariables, ParameterExpression closureArray) { + Assert.NotNull(closureVariables, closureArray); + _closureArray = closureArray; + _closureVars = closureVariables; + } + + /// <summary> + /// Walks the lambda and produces a higher order function, which can be + /// used to bind the lambda to a closure array from the interpreter. + /// </summary> + /// <param name="lambda">The lambda to bind.</param> + /// <param name="closureVariables">Variables which are being accessed defined in the outer scope.</param> + /// <returns>A delegate that can be called to produce a delegate bound to the passed in closure array.</returns> + internal static Func<StrongBox<object>[], Delegate> BindLambda(LambdaExpression lambda, Dictionary<ParameterExpression, LocalVariable> closureVariables) { + // 1. Create rewriter + var closure = Expression.Parameter(typeof(StrongBox<object>[]), "closure"); + var visitor = new LightLambdaClosureVisitor(closureVariables, closure); + + // 2. Visit the lambda + lambda = (LambdaExpression)visitor.Visit(lambda); + + // 3. Create a higher-order function which fills in the parameters + var result = Expression.Lambda<Func<StrongBox<object>[], Delegate>>(lambda, closure); + + // 4. Compile it + return result.Compile(); + } + + #region closures + + protected override Expression VisitLambda<T>(Expression<T> node) { + _shadowedVars.Push(new HashSet<ParameterExpression>(node.Parameters)); + Expression b = Visit(node.Body); + _shadowedVars.Pop(); + if (b == node.Body) { + return node; + } + return Expression.Lambda<T>(b, node.Name, node.TailCall, node.Parameters); + } + + protected override Expression VisitBlock(BlockExpression node) { + if (node.Variables.Count > 0) { + _shadowedVars.Push(new HashSet<ParameterExpression>(node.Variables)); + } + var b = Visit(node.Expressions); + if (node.Variables.Count > 0) { + _shadowedVars.Pop(); + } + if (b == node.Expressions) { + return node; + } + return Expression.Block(node.Variables, b); + } + + protected override CatchBlock VisitCatchBlock(CatchBlock node) { + if (node.Variable != null) { + _shadowedVars.Push(new HashSet<ParameterExpression>(new[] { node.Variable })); + } + Expression b = Visit(node.Body); + Expression f = Visit(node.Filter); + if (node.Variable != null) { + _shadowedVars.Pop(); + } + if (b == node.Body && f == node.Filter) { + return node; + } + return Expression.MakeCatchBlock(node.Test, node.Variable, b, f); + } + + protected override Expression VisitRuntimeVariables(RuntimeVariablesExpression node) { + int count = node.Variables.Count; + var boxes = new List<Expression>(); + var vars = new List<ParameterExpression>(); + var indexes = new int[count]; + for (int i = 0; i < count; i++) { + Expression box = GetClosureItem(node.Variables[i], false); + if (box == null) { + indexes[i] = vars.Count; + vars.Add(node.Variables[i]); + } else { + indexes[i] = -1 - boxes.Count; + boxes.Add(box); + } + } + + // No variables were rewritten. Just return the original node. + if (boxes.Count == 0) { + return node; + } + + var boxesArray = Expression.NewArrayInit(typeof(IStrongBox), boxes); + + // All of them were rewritten. Just return the array, wrapped in a + // read-only collection. + if (vars.Count == 0) { + return Expression.Invoke( + Expression.Constant((Func<IStrongBox[], IRuntimeVariables>)RuntimeVariables.Create), + boxesArray + ); + } + + // Otherwise, we need to return an object that merges them + Func<IRuntimeVariables, IRuntimeVariables, int[], IRuntimeVariables> helper = MergedRuntimeVariables.Create; + return Expression.Invoke(AstUtils.Constant(helper), Expression.RuntimeVariables(vars), boxesArray, AstUtils.Constant(indexes)); + } + + protected override Expression VisitParameter(ParameterExpression node) { + Expression closureItem = GetClosureItem(node, true); + if (closureItem == null) { + return node; + } + // Convert can go away if we switch to strongly typed StrongBox + return Ast.Utils.Convert(closureItem, node.Type); + } + + protected override Expression VisitBinary(BinaryExpression node) { + if (node.NodeType == ExpressionType.Assign && + node.Left.NodeType == ExpressionType.Parameter) { + + var variable = (ParameterExpression)node.Left; + Expression closureItem = GetClosureItem(variable, true); + if (closureItem != null) { + // We need to convert to object to store the value in the box. + return Expression.Block( + new[] { variable }, + Expression.Assign(variable, Visit(node.Right)), + Expression.Assign(closureItem, Ast.Utils.Convert(variable, typeof(object))), + variable + ); + } + } + return base.VisitBinary(node); + } + + private Expression GetClosureItem(ParameterExpression variable, bool unbox) { + // Skip variables that are shadowed by a nested scope/lambda + foreach (HashSet<ParameterExpression> hidden in _shadowedVars) { + if (hidden.Contains(variable)) { + return null; + } + } + + LocalVariable loc; + if (!_closureVars.TryGetValue(variable, out loc)) { + throw new InvalidOperationException("unbound variable: " + variable.Name); + } + + var result = loc.LoadFromArray(null, _closureArray); + return (unbox) ? LightCompiler.Unbox(result) : result; + } + + protected override Expression VisitExtension(Expression node) { + // Reduce extensions now so we can find embedded variables + return Visit(node.ReduceExtensions()); + } + + + #region MergedRuntimeVariables + + /// <summary> + /// Provides a list of variables, supporing read/write of the values + /// </summary> + private sealed class MergedRuntimeVariables : IRuntimeVariables { + private readonly IRuntimeVariables _first; + private readonly IRuntimeVariables _second; + + // For reach item, the index into the first or second list + // Positive values mean the first array, negative means the second + private readonly int[] _indexes; + + private MergedRuntimeVariables(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) { + _first = first; + _second = second; + _indexes = indexes; + } + + internal static IRuntimeVariables Create(IRuntimeVariables first, IRuntimeVariables second, int[] indexes) { + return new MergedRuntimeVariables(first, second, indexes); + } + + int IRuntimeVariables.Count { + get { return _indexes.Length; } + } + + object IRuntimeVariables.this[int index] { + get { + index = _indexes[index]; + return (index >= 0) ? _first[index] : _second[-1 - index]; + } + set { + index = _indexes[index]; + if (index >= 0) { + _first[index] = value; + } else { + _second[-1 - index] = value; + } + } + } + } + #endregion + + #endregion + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LocalVariables.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LocalVariables.cs new file mode 100644 index 00000000000..d848a643002 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LocalVariables.cs @@ -0,0 +1,266 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + public sealed class LocalVariable { + private const int IsBoxedFlag = 1; + private const int InClosureFlag = 2; + + public readonly int Index; + private int _flags; + + public bool IsBoxed { + get { return (_flags & IsBoxedFlag) != 0; } + set { + if (value) { + _flags |= IsBoxedFlag; + } else { + _flags &= ~IsBoxedFlag; + } + } + } + + public bool InClosure { + get { return (_flags & InClosureFlag) != 0; } + } + + public bool InClosureOrBoxed { + get { return InClosure | IsBoxed; } + } + + internal LocalVariable(int index, bool closure, bool boxed) { + Index = index; + _flags = (closure ? InClosureFlag : 0) | (boxed ? IsBoxedFlag : 0); + } + + internal Expression LoadFromArray(Expression frameData, Expression closure) { + Expression result = Expression.ArrayAccess(InClosure ? closure : frameData, Expression.Constant(Index)); + return IsBoxed ? Expression.Convert(result, typeof(StrongBox<object>)) : result; + } + + public override string ToString() { + return String.Format("{0}: {1} {2}", Index, IsBoxed ? "boxed" : null, InClosure ? "in closure" : null); + } + } + + public struct LocalDefinition { + private readonly int _index; + private readonly ParameterExpression _parameter; + + internal LocalDefinition(int localIndex, ParameterExpression parameter) { + _index = localIndex; + _parameter = parameter; + } + + public int Index { + get { + return _index; + } + } + + public ParameterExpression Parameter { + get { + return _parameter; + } + } + + public override bool Equals(object obj) { + if (obj is LocalDefinition) { + LocalDefinition other = (LocalDefinition)obj; + return other.Index == Index && other.Parameter == Parameter; + } + + return false; + } + + public override int GetHashCode() { + if (_parameter == null) { + return 0; + } + return _parameter.GetHashCode() ^ _index.GetHashCode(); + } + + public static bool operator ==(LocalDefinition self, LocalDefinition other) { + return self.Index == other.Index && self.Parameter == other.Parameter; + } + + public static bool operator !=(LocalDefinition self, LocalDefinition other) { + return self.Index != other.Index || self.Parameter != other.Parameter; + } + } + + public sealed class LocalVariables { + private readonly HybridReferenceDictionary<ParameterExpression, VariableScope> _variables = new HybridReferenceDictionary<ParameterExpression, VariableScope>(); + private Dictionary<ParameterExpression, LocalVariable> _closureVariables; + + private int _localCount, _maxLocalCount; + + internal LocalVariables() { + } + + public LocalDefinition DefineLocal(ParameterExpression variable, int start) { + ContractUtils.RequiresNotNull(variable, "variable"); + ContractUtils.Requires(start >= 0, "start", "start must be positive"); + + LocalVariable result = new LocalVariable(_localCount++, false, false); + _maxLocalCount = System.Math.Max(_localCount, _maxLocalCount); + + VariableScope existing, newScope; + if (_variables.TryGetValue(variable, out existing)) { + newScope = new VariableScope(result, start, existing); + if (existing.ChildScopes == null) { + existing.ChildScopes = new List<VariableScope>(); + } + existing.ChildScopes.Add(newScope); + } else { + newScope = new VariableScope(result, start, null); + } + + _variables[variable] = newScope; + return new LocalDefinition(result.Index, variable); + } + + public void UndefineLocal(LocalDefinition definition, int end) { + var scope = _variables[definition.Parameter]; + scope.Stop = end; + if (scope.Parent != null) { + _variables[definition.Parameter] = scope.Parent; + } else { + _variables.Remove(definition.Parameter); + } + + _localCount--; + } + + internal void Box(ParameterExpression variable, InstructionList instructions) { + var scope = _variables[variable]; + + LocalVariable local = scope.Variable; + Debug.Assert(!local.IsBoxed && !local.InClosure); + _variables[variable].Variable.IsBoxed = true; + + int curChild = 0; + for (int i = scope.Start; i < scope.Stop && i < instructions.Count; i++) { + if (scope.ChildScopes != null && scope.ChildScopes[curChild].Start == i) { + // skip boxing in the child scope + var child = scope.ChildScopes[curChild]; + i = child.Stop; + + curChild++; + continue; + } + + instructions.SwitchToBoxed(local.Index, i); + } + } + + public int LocalCount { + get { return _maxLocalCount; } + } + + public int GetOrDefineLocal(ParameterExpression var) { + int index = GetLocalIndex(var); + if (index == -1) { + return DefineLocal(var, 0).Index; + } + return index; + } + + public int GetLocalIndex(ParameterExpression var) { + VariableScope loc; + return _variables.TryGetValue(var, out loc) ? loc.Variable.Index : -1; + } + + public bool TryGetLocalOrClosure(ParameterExpression var, out LocalVariable local) { + VariableScope scope; + if (_variables.TryGetValue(var, out scope)) { + local = scope.Variable; + return true; + } + if (_closureVariables != null && _closureVariables.TryGetValue(var, out local)) { + return true; + } + + local = null; + return false; + } + + /// <summary> + /// Gets a copy of the local variables which are defined in the current scope. + /// </summary> + /// <returns></returns> + internal Dictionary<ParameterExpression, LocalVariable> CopyLocals() { + var res = new Dictionary<ParameterExpression, LocalVariable>(_variables.Count); + foreach (var keyValue in _variables) { + res[keyValue.Key] = keyValue.Value.Variable; + } + return res; + } + + /// <summary> + /// Checks to see if the given variable is defined within the current local scope. + /// </summary> + internal bool ContainsVariable(ParameterExpression variable) { + return _variables.ContainsKey(variable); + } + + /// <summary> + /// Gets the variables which are defined in an outer scope and available within the current scope. + /// </summary> + internal Dictionary<ParameterExpression, LocalVariable> ClosureVariables { + get { + return _closureVariables; + } + } + + internal LocalVariable AddClosureVariable(ParameterExpression variable) { + if (_closureVariables == null) { + _closureVariables = new Dictionary<ParameterExpression, LocalVariable>(); + } + LocalVariable result = new LocalVariable(_closureVariables.Count, true, false); + _closureVariables.Add(variable, result); + return result; + } + + /// <summary> + /// Tracks where a variable is defined and what range of instructions it's used in + /// </summary> + private sealed class VariableScope { + public readonly int Start; + public int Stop = Int32.MaxValue; + public readonly LocalVariable Variable; + public readonly VariableScope Parent; + public List<VariableScope> ChildScopes; + + public VariableScope(LocalVariable variable, int start, VariableScope parent) { + Variable = variable; + Start = start; + Parent = parent; + } + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LoopCompiler.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LoopCompiler.cs new file mode 100644 index 00000000000..acc416ea5e5 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/LoopCompiler.cs @@ -0,0 +1,323 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#endif + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Ast; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Interpreter { + using AstUtils = Microsoft.Scripting.Ast.Utils; + using LoopFunc = Func<object[], StrongBox<object>[], InterpretedFrame, int>; + using System.Collections.ObjectModel; + + internal sealed class LoopCompiler : ExpressionVisitor { + private struct LoopVariable { + public ExpressionAccess Access; + + // a variable that holds on the strong box for closure variables: + public ParameterExpression BoxStorage; + + public LoopVariable(ExpressionAccess access, ParameterExpression box) { + Access = access; + BoxStorage = box; + } + + public override string ToString() { + return Access.ToString() + " " + BoxStorage; + } + } + + private readonly ParameterExpression _frameDataVar; + private readonly ParameterExpression _frameClosureVar; + private readonly ParameterExpression _frameVar; + private readonly LabelTarget _returnLabel; + // locals and closure variables defined outside the loop + private readonly Dictionary<ParameterExpression, LocalVariable> _outerVariables, _closureVariables; + private readonly LoopExpression _loop; + private ReadOnlyCollectionBuilder<ParameterExpression> _temps; + // tracks variables that flow in and flow out for initialization and + private readonly Dictionary<ParameterExpression, LoopVariable> _loopVariables; + // variables which are defined and used within the loop + private HashSet<ParameterExpression> _loopLocals; + + private readonly HybridReferenceDictionary<LabelTarget, BranchLabel> _labelMapping; + private readonly int _loopStartInstructionIndex; + private readonly int _loopEndInstructionIndex; + + internal LoopCompiler(LoopExpression loop, HybridReferenceDictionary<LabelTarget, BranchLabel> labelMapping, Dictionary<ParameterExpression, LocalVariable> locals, + Dictionary<ParameterExpression, LocalVariable> closureVariables, int loopStartInstructionIndex, int loopEndInstructionIndex) { + _loop = loop; + _outerVariables = locals; + _closureVariables = closureVariables; + _frameDataVar = Expression.Parameter(typeof(object[])); + _frameClosureVar = Expression.Parameter(typeof(StrongBox<object>[])); + _frameVar = Expression.Parameter(typeof(InterpretedFrame)); + _loopVariables = new Dictionary<ParameterExpression, LoopVariable>(); + _returnLabel = Expression.Label(typeof(int)); + _labelMapping = labelMapping; + _loopStartInstructionIndex = loopStartInstructionIndex; + _loopEndInstructionIndex = loopEndInstructionIndex; + } + + internal LoopFunc CreateDelegate() { + var loop = (LoopExpression)Visit(_loop); + var body = new ReadOnlyCollectionBuilder<Expression>(); + var finallyClause = new ReadOnlyCollectionBuilder<Expression>(); + + foreach (var variable in _loopVariables) { + LocalVariable local; + if (!_outerVariables.TryGetValue(variable.Key, out local)) { + local = _closureVariables[variable.Key]; + } + Expression elemRef = local.LoadFromArray(_frameDataVar, _frameClosureVar); + + if (local.InClosureOrBoxed) { + var box = variable.Value.BoxStorage; + Debug.Assert(box != null); + body.Add(Expression.Assign(box, elemRef)); + AddTemp(box); + } else { + // Always initialize the variable even if it is only written to. + // If a write-only variable is actually not assigned during execution of the loop we will still write some value back. + // This value must be the original value, which we assign at entry. + body.Add(Expression.Assign(variable.Key, AstUtils.Convert(elemRef, variable.Key.Type))); + + if ((variable.Value.Access & ExpressionAccess.Write) != 0) { + finallyClause.Add(Expression.Assign(elemRef, AstUtils.Box(variable.Key))); + } + + AddTemp(variable.Key); + } + } + + if (finallyClause.Count > 0) { + body.Add(Expression.TryFinally(loop, Expression.Block(finallyClause))); + } else { + body.Add(loop); + } + + body.Add(Expression.Label(_returnLabel, Expression.Constant(_loopEndInstructionIndex - _loopStartInstructionIndex))); + + var lambda = Expression.Lambda<LoopFunc>( + _temps != null ? Expression.Block(_temps.ToReadOnlyCollection(), body) : Expression.Block(body), + new[] { _frameDataVar, _frameClosureVar, _frameVar } + ); + return lambda.Compile(); + } + + protected override Expression VisitExtension(Expression node) { + // Reduce extensions before we visit them so that we operate on a plain DLR tree, + // where we know relationships among the nodes (which nodes represent write context etc.). + if (node.CanReduce) { + return Visit(node.Reduce()); + } + + return base.VisitExtension(node); + } + + #region Gotos + + protected override Expression VisitGoto(GotoExpression node) { + BranchLabel label; + + var target = node.Target; + var value = Visit(node.Value); + + // TODO: Is it possible for an inner reducible node of the loop to rely on nodes produced by reducing outer reducible nodes? + + // Unknown label => must be within the loop: + if (!_labelMapping.TryGetValue(target, out label)) { + return node.Update(target, value); + } + + // Known label within the loop: + if (label.TargetIndex >= _loopStartInstructionIndex && label.TargetIndex < _loopEndInstructionIndex) { + return node.Update(target, value); + } + + return Expression.Return(_returnLabel, + (value != null) ? + Expression.Call(_frameVar, InterpretedFrame.GotoMethod, Expression.Constant(label.LabelIndex), AstUtils.Box(value)) : + Expression.Call(_frameVar, InterpretedFrame.VoidGotoMethod, Expression.Constant(label.LabelIndex)), + node.Type + ); + } + + #endregion + + #region Local Variables + + // Gather all outer variables accessed in the loop. + // Determines which ones are read from and written to. + // We will consider a variable as "read" if it is read anywhere in the loop even though + // the first operation might actually always be "write". We could do better if we had CFG. + + protected override Expression VisitBlock(BlockExpression node) { + var variables = ((BlockExpression)node).Variables; + var prevLocals = EnterVariableScope(variables); + + var res = base.VisitBlock(node); + + ExitVariableScope(prevLocals); + return res; + } + + private HashSet<ParameterExpression> EnterVariableScope(ICollection<ParameterExpression> variables) { + if (_loopLocals == null) { + _loopLocals = new HashSet<ParameterExpression>(variables); + return null; + } + + var prevLocals = new HashSet<ParameterExpression>(_loopLocals); + _loopLocals.UnionWith(variables); + return prevLocals; + } + + protected override CatchBlock VisitCatchBlock(CatchBlock node) { + if (node.Variable != null) { + var prevLocals = EnterVariableScope(new[] { node.Variable }); + var res = base.VisitCatchBlock(node); + ExitVariableScope(prevLocals); + return res; + } else { + return base.VisitCatchBlock(node); + } + } + + protected override Expression VisitLambda<T>(Expression<T> node) { + var prevLocals = EnterVariableScope(node.Parameters); + try { + return base.VisitLambda<T>(node); + } finally { + ExitVariableScope(prevLocals); + } + } + + private void ExitVariableScope(HashSet<ParameterExpression> prevLocals) { + _loopLocals = prevLocals; + } + + protected override Expression VisitBinary(BinaryExpression node) { + // reduce compound assignments: + if (node.CanReduce) { + return Visit(node.Reduce()); + } + Debug.Assert(!node.NodeType.IsReadWriteAssignment()); + + var param = node.Left as ParameterExpression; + if (param != null && node.NodeType == ExpressionType.Assign) { + var left = VisitVariable(param, ExpressionAccess.Write); + var right = Visit(node.Right); + + // left parameter is a boxed variable: + if (left.Type != param.Type) { + Debug.Assert(left.Type == typeof(object)); + + Expression rightVar; + if (right.NodeType != ExpressionType.Parameter) { + // { left.Value = (object)(rightVar = right), rightVar } + rightVar = AddTemp(Expression.Parameter(right.Type)); + right = Expression.Assign(rightVar, right); + } else { + // { left.Value = (object)right, right } + rightVar = right; + } + + return Expression.Block( + node.Update(left, Expression.Convert(right, left.Type)), + rightVar + ); + } else { + return node.Update(left, right); + } + + } else { + return base.VisitBinary(node); + } + } + + protected override Expression VisitUnary(UnaryExpression node) { + // reduce inplace increment/decrement: + if (node.CanReduce) { + return Visit(node.Reduce()); + } + Debug.Assert(!node.NodeType.IsReadWriteAssignment()); + return base.VisitUnary(node); + } + + // TODO: if we supported ref/out parameter we would need to override + // MethodCallExpression, VisitDynamic and VisitNew + + protected override Expression VisitParameter(ParameterExpression node) { + return VisitVariable(node, ExpressionAccess.Read); + } + + private Expression VisitVariable(ParameterExpression node, ExpressionAccess access) { + ParameterExpression box; + LoopVariable existing; + LocalVariable loc; + + if (_loopLocals.Contains(node)) { + // local to the loop - not propagated in or out + return node; + } else if (_loopVariables.TryGetValue(node, out existing)) { + // existing outer variable that we are already tracking + box = existing.BoxStorage; + _loopVariables[node] = new LoopVariable(existing.Access | access, box); + } else if (_outerVariables.TryGetValue(node, out loc) || + (_closureVariables != null && _closureVariables.TryGetValue(node, out loc))) { + // not tracking this variable yet, but defined in outer scope and seen for the 1st time + box = loc.InClosureOrBoxed ? Expression.Parameter(typeof(StrongBox<object>), node.Name) : null; + _loopVariables[node] = new LoopVariable(access, box); + } else { + // node is a variable defined in a nested lambda -> skip + return node; + } + + if (box != null) { + if ((access & ExpressionAccess.Write) != 0) { + // compound assignments were reduced: + Debug.Assert((access & ExpressionAccess.Read) == 0); + + // box.Value = (object)rhs + return LightCompiler.Unbox(box); + } else { + // (T)box.Value + return Expression.Convert(LightCompiler.Unbox(box), node.Type); + } + } + + return node; + } + + private ParameterExpression AddTemp(ParameterExpression variable) { + if (_temps == null) { + _temps = new ReadOnlyCollectionBuilder<ParameterExpression>(); + } + + _temps.Add(variable); + return variable; + } + + #endregion + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/RuntimeVariables.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/RuntimeVariables.cs new file mode 100644 index 00000000000..e8b8e98520c --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Interpreter/RuntimeVariables.cs @@ -0,0 +1,46 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Runtime.CompilerServices; + +namespace Microsoft.Scripting.Interpreter { + internal sealed class RuntimeVariables : IRuntimeVariables { + private readonly IStrongBox[] _boxes; + + private RuntimeVariables(IStrongBox[] boxes) { + _boxes = boxes; + } + + int IRuntimeVariables.Count { + get { + return _boxes.Length; + } + } + + object IRuntimeVariables.this[int index] { + get { + return _boxes[index].Value; + } + set { + _boxes[index].Value = value; + } + } + + internal static IRuntimeVariables Create(IStrongBox[] boxes) { + return new RuntimeVariables(boxes); + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Math/BigIntegerV4.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Math/BigIntegerV4.cs new file mode 100644 index 00000000000..303eb7521b6 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Math/BigIntegerV4.cs @@ -0,0 +1,614 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ +#if FEATURE_NUMERICS + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Text; +using Microsoft.Scripting.Utils; +using BigInt = System.Numerics.BigInteger; + +namespace Microsoft.Scripting.Math { + /// <summary> + /// arbitrary precision integers + /// </summary> + [Serializable] + public sealed class BigInteger : IFormattable, IComparable, IEquatable<BigInteger> { + internal readonly BigInt Value; + + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly BigInteger Zero = new BigInteger((BigInt)0); + [SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly BigInteger One = new BigInteger((BigInt)1); + + public BigInteger(BigInt value) { + Value = value; + } + + [CLSCompliant(false)] + public static BigInteger Create(ulong v) { + return new BigInteger(new BigInt(v)); + } + + [CLSCompliant(false)] + public static BigInteger Create(uint v) { + return new BigInteger(new BigInt(v)); + } + + public static BigInteger Create(long v) { + return new BigInteger(new BigInt(v)); + } + + public static BigInteger Create(int v) { + return new BigInteger(new BigInt(v)); + } + + public static BigInteger Create(decimal v) { + return new BigInteger(new BigInt(v)); + } + + public static BigInteger Create(byte[] v) { + return new BigInteger(v); + } + + public static BigInteger Create(double v) { + return new BigInteger(new BigInt(v)); + } + + public static implicit operator BigInteger(byte i) { + return new BigInteger((BigInt)i); + } + + [CLSCompliant(false)] + public static implicit operator BigInteger(sbyte i) { + return new BigInteger((BigInt)i); + } + + public static implicit operator BigInteger(short i) { + return new BigInteger((BigInt)i); + } + + [CLSCompliant(false)] + public static implicit operator BigInteger(ushort i) { + return new BigInteger((BigInt)i); + } + + [CLSCompliant(false)] + public static implicit operator BigInteger(uint i) { + return new BigInteger((BigInt)i); + } + + public static implicit operator BigInteger(int i) { + return new BigInteger((BigInt)i); + } + + [CLSCompliant(false)] + public static implicit operator BigInteger(ulong i) { + return new BigInteger((BigInt)i); + } + + public static implicit operator BigInteger(long i) { + return new BigInteger((BigInt)i); + } + + public static implicit operator BigInteger(decimal self) { + return new BigInteger((BigInt)self); + } + + public static explicit operator BigInteger(double self) { + return new BigInteger((BigInt)self); + } + + public static explicit operator BigInteger(float self) { + return new BigInteger((BigInt)self); + } + + public static explicit operator double(BigInteger self) { + return (double)self.Value; + } + + public static explicit operator float(BigInteger self) { + return (float)self.Value; + } + + public static explicit operator decimal(BigInteger self) { + return (decimal)self.Value; + } + + public static explicit operator byte(BigInteger self) { + return (byte)self.Value; + } + + [CLSCompliant(false)] + public static explicit operator sbyte(BigInteger self) { + return (sbyte)self.Value; + } + + [CLSCompliant(false)] + public static explicit operator UInt16(BigInteger self) { + return (UInt16)self.Value; + } + + public static explicit operator Int16(BigInteger self) { + return (Int16)self.Value; + } + + [CLSCompliant(false)] + public static explicit operator UInt32(BigInteger self) { + return (UInt32)self.Value; + } + + public static explicit operator Int32(BigInteger self) { + return (Int32)self.Value; + } + + public static explicit operator Int64(BigInteger self) { + return (Int64)self.Value; + } + + [CLSCompliant(false)] + public static explicit operator UInt64(BigInteger self) { + return (UInt64)self.Value; + } + + public static implicit operator BigInteger(BigInt value) { + return new BigInteger(value); + } + + public static implicit operator BigInt(BigInteger value) { + return value.Value; + } + + public BigInteger(BigInteger copy) { + if (object.ReferenceEquals(copy, null)) { + throw new ArgumentNullException("copy"); + } + Value = copy.Value; + } + + public BigInteger(byte[] data) { + ContractUtils.RequiresNotNull(data, "data"); + + Value = new BigInt(data); + } + + public BigInteger(int sign, byte[] data) { + ContractUtils.RequiresNotNull(data, "data"); + ContractUtils.Requires(sign >= -1 && sign <= +1, "sign"); + + Value = new BigInt(data); + if (sign < 0) { + Value = -Value; + } + } + + [CLSCompliant(false)] + public BigInteger(int sign, uint[] data) { + ContractUtils.RequiresNotNull(data, "data"); + ContractUtils.Requires(sign >= -1 && sign <= +1, "sign"); + int length = GetLength(data); + ContractUtils.Requires(length == 0 || sign != 0, "sign"); + if (length == 0) { + Value = 0; + return; + } + + bool highest = (data[length - 1] & 0x80000000) != 0; + byte[] bytes = new byte[length * 4 + (highest ? 1 : 0)]; + int j = 0; + for (int i = 0; i < length; i++) { + ulong w = data[i]; + bytes[j++] = (byte)(w & 0xff); + bytes[j++] = (byte)((w >> 8) & 0xff); + bytes[j++] = (byte)((w >> 16) & 0xff); + bytes[j++] = (byte)((w >> 24) & 0xff); + } + + Value = new BigInt(bytes); + if (sign < 0) { + Value = -Value; + } + } + + [CLSCompliant(false)] + public uint[] GetWords() { + return Value.GetWords(); + } + + public int GetBitCount() { + return Value.GetBitCount(); + } + + public int GetWordCount() { + return Value.GetWordCount(); + } + + public int GetByteCount() { + return Value.GetByteCount(); + } + + /// <summary> + /// Return the sign of this BigInteger: -1, 0, or 1. + /// </summary> + public int Sign { + get { + return Value.Sign; + } + } + + public bool AsInt64(out long ret) { + if (Value >= Int64.MinValue && Value <= Int64.MaxValue) { + ret = (long)Value; + return true; + } + ret = 0; + return false; + } + + [CLSCompliant(false)] + public bool AsUInt32(out uint ret) { + if (Value >= UInt32.MinValue && Value <= UInt32.MaxValue) { + ret = (UInt32)Value; + return true; + } + ret = 0; + return false; + } + + [CLSCompliant(false)] + public bool AsUInt64(out ulong ret) { + if (Value >= UInt64.MinValue && Value <= UInt64.MaxValue) { + ret = (UInt64)Value; + return true; + } + ret = 0; + return false; + } + + public bool AsInt32(out int ret) { + if (Value >= Int32.MinValue && Value <= Int32.MaxValue) { + ret = (Int32)Value; + return true; + } + ret = 0; + return false; + } + + [CLSCompliant(false)] + public uint ToUInt32() { + return (uint)Value; + } + + public int ToInt32() { + return (int)Value; + } + + public decimal ToDecimal() { + return (decimal)Value; + } + + [CLSCompliant(false)] + public ulong ToUInt64() { + return (ulong)Value; + } + + public long ToInt64() { + return (long)Value; + } + + private static int GetLength(uint[] data) { + int ret = data.Length - 1; + while (ret >= 0 && data[ret] == 0) ret--; + return ret + 1; + } + + public static int Compare(BigInteger x, BigInteger y) { + return BigInt.Compare(x.Value, y.Value); + } + + public static bool operator ==(BigInteger x, int y) { + return x.Value == y; + } + + public static bool operator !=(BigInteger x, int y) { + return x.Value != y; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] // TODO: fix + public static bool operator ==(BigInteger x, double y) { + if (object.ReferenceEquals(x, null)) { + throw new ArgumentNullException("x"); + } + + // we can hold all double values, but not all double values + // can hold BigInteger values, and we may lose precision. Convert + // the double to a big int, then compare. + + if ((y % 1) != 0) return false; // not a whole number, can't be equal + + return x.Value == (BigInt)y; + } + + public static bool operator ==(double x, BigInteger y) { + return y == x; + } + + public static bool operator !=(BigInteger x, double y) { + return !(x == y); + } + + public static bool operator !=(double x, BigInteger y) { + return !(x == y); + } + + + public static bool operator ==(BigInteger x, BigInteger y) { + return Compare(x, y) == 0; + } + + public static bool operator !=(BigInteger x, BigInteger y) { + return Compare(x, y) != 0; + } + public static bool operator <(BigInteger x, BigInteger y) { + return Compare(x, y) < 0; + } + public static bool operator <=(BigInteger x, BigInteger y) { + return Compare(x, y) <= 0; + } + public static bool operator >(BigInteger x, BigInteger y) { + return Compare(x, y) > 0; + } + public static bool operator >=(BigInteger x, BigInteger y) { + return Compare(x, y) >= 0; + } + + public static BigInteger Add(BigInteger x, BigInteger y) { + return x + y; + } + + public static BigInteger operator +(BigInteger x, BigInteger y) { + return new BigInteger(x.Value + y.Value); + } + + public static BigInteger Subtract(BigInteger x, BigInteger y) { + return x - y; + } + + public static BigInteger operator -(BigInteger x, BigInteger y) { + return new BigInteger(x.Value - y.Value); + } + + public static BigInteger Multiply(BigInteger x, BigInteger y) { + return x * y; + } + + public static BigInteger operator *(BigInteger x, BigInteger y) { + return new BigInteger(x.Value * y.Value); + } + + public static BigInteger Divide(BigInteger x, BigInteger y) { + return x / y; + } + + public static BigInteger operator /(BigInteger x, BigInteger y) { + BigInteger dummy; + return DivRem(x, y, out dummy); + } + + public static BigInteger Mod(BigInteger x, BigInteger y) { + return x % y; + } + + public static BigInteger operator %(BigInteger x, BigInteger y) { + BigInteger ret; + DivRem(x, y, out ret); + return ret; + } + + public static BigInteger DivRem(BigInteger x, BigInteger y, out BigInteger remainder) { + BigInt rem; + BigInt result = BigInt.DivRem(x.Value, y.Value, out rem); + remainder = new BigInteger(rem); + return new BigInteger(result); + } + + public static BigInteger BitwiseAnd(BigInteger x, BigInteger y) { + return x & y; + } + + public static BigInteger operator &(BigInteger x, BigInteger y) { + return new BigInteger(x.Value & y.Value); + } + + public static BigInteger BitwiseOr(BigInteger x, BigInteger y) { + return x | y; + } + + public static BigInteger operator |(BigInteger x, BigInteger y) { + return new BigInteger(x.Value | y.Value); + } + + public static BigInteger Xor(BigInteger x, BigInteger y) { + return x ^ y; + } + + public static BigInteger operator ^(BigInteger x, BigInteger y) { + return new BigInteger(x.Value ^ y.Value); + } + + public static BigInteger LeftShift(BigInteger x, int shift) { + return x << shift; + } + + public static BigInteger operator <<(BigInteger x, int shift) { + return new BigInteger(x.Value << shift); + } + + public static BigInteger RightShift(BigInteger x, int shift) { + return x >> shift; + } + + public static BigInteger operator >>(BigInteger x, int shift) { + return new BigInteger(x.Value >> shift); + } + + public static BigInteger Negate(BigInteger x) { + return -x; + } + + public static BigInteger operator -(BigInteger x) { + return new BigInteger(-x.Value); + } + + public BigInteger OnesComplement() { + return ~this; + } + + public static BigInteger operator ~(BigInteger x) { + return new BigInteger(~x.Value); + } + + public BigInteger Abs() { + return new BigInteger(BigInt.Abs(Value)); + } + + public BigInteger Power(int exp) { + return new BigInteger(BigInt.Pow(Value, exp)); + } + + public BigInteger ModPow(int power, BigInteger mod) { + return new BigInteger(BigInt.ModPow(Value, power, mod.Value)); + } + + public BigInteger ModPow(BigInteger power, BigInteger mod) { + return new BigInteger(BigInt.ModPow(Value, power.Value, mod.Value)); + } + + public BigInteger Square() { + return this * this; + } + +#if !SILVERLIGHT + public static BigInteger Parse(string str) { + return new BigInteger(BigInt.Parse(str)); + } +#endif + + public override string ToString() { + return ToString(10); + } + + public string ToString(int @base) { + return MathUtils.BigIntegerToString(GetWords(), Sign, @base, false); + } + + public string ToString(string format) { + return Value.ToString(format); + } + + public override int GetHashCode() { + return Value.GetHashCode(); + } + + public override bool Equals(object obj) { + return Equals(obj as BigInteger); + } + + public bool Equals(BigInteger other) { + if (object.ReferenceEquals(other, null)) return false; + return this == other; + } + + public bool IsNegative() { + return Value.Sign < 0; + } + + public bool IsZero() { + return Value.Sign == 0; + } + + public bool IsPositive() { + return Value.Sign > 0; + } + + public bool IsEven { + get { return Value.IsEven; } + } + + public bool IsPowerOfTwo { + get { + return Value.IsPowerOfTwo; + } + } + + public double Log(Double newBase) { + return BigInt.Log(Value, newBase); + } + + /// <summary> + /// Calculates the natural logarithm of the BigInteger. + /// </summary> + public double Log() { + return BigInt.Log(Value); + } + + /// <summary> + /// Calculates log base 10 of a BigInteger. + /// </summary> + public double Log10() { + return BigInt.Log10(Value); + } + +#region IComparable Members + + public int CompareTo(object obj) { + if (obj == null) { + return 1; + } + BigInteger o = obj as BigInteger; + if (object.ReferenceEquals(o, null)) { + throw new ArgumentException("expected integer"); + } + return Compare(this, o); + } + + #endregion + + /// <summary> + /// Return the value of this BigInteger as a little-endian twos-complement + /// byte array, using the fewest number of bytes possible. If the value is zero, + /// return an array of one byte whose element is 0x00. + /// </summary> + public byte[] ToByteArray() { + return Value.ToByteArray(); + } + + public string ToString(IFormatProvider provider) { + return Value.ToString(provider); + } + +#region IFormattable Members + + string IFormattable.ToString(string format, IFormatProvider formatProvider) { + return Value.ToString(format, formatProvider); + } + + #endregion + } +} +#endif diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Math/Complex64.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Math/Complex64.cs new file mode 100644 index 00000000000..bb6da752e40 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Math/Complex64.cs @@ -0,0 +1,276 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using Microsoft.Scripting.Utils; + +#if FEATURE_NUMERICS +using BigInt = System.Numerics.BigInteger; +#endif + +namespace Microsoft.Scripting.Math { + /// <summary> + /// Implementation of the complex number data type. + /// </summary> + [Serializable] + public struct Complex64 { + public static readonly Complex64 Zero = new Complex64(0.0, 0.0); + public static readonly Complex64 One = new Complex64(1.0, 0.0); + public static readonly Complex64 ImaginaryOne = new Complex64(0.0, 1.0); + + private readonly double real, imag; + + public static Complex64 MakeImaginary(double imag) { + return new Complex64(0.0, imag); + } + + public static Complex64 MakeReal(double real) { + return new Complex64(real, 0.0); + } + + public static Complex64 Make(double real, double imag) { + return new Complex64(real, imag); + } + + public Complex64(double real) + : this(real, 0.0) { + } + + public Complex64(double real, double imag) { + this.real = real; + this.imag = imag; + } + + public bool IsZero { + get { + return real == 0.0 && imag == 0.0; + } + } + + public double Real { + get { + return real; + } + } + + public double Imag { + get { + return imag; + } + } + + public Complex64 Conjugate() { + return new Complex64(real, -imag); + } + + + public override string ToString() { + if (real == 0.0) return imag.ToString(System.Globalization.CultureInfo.InvariantCulture.NumberFormat) + "j"; + else if (imag < 0.0) return string.Format(System.Globalization.CultureInfo.InvariantCulture.NumberFormat, "({0}{1}j)", real, imag); + else return string.Format(System.Globalization.CultureInfo.InvariantCulture.NumberFormat, "({0}+{1}j)", real, imag); + } + + public static implicit operator Complex64(bool b) { + return b ? One : Zero; + } + + public static implicit operator Complex64(int i) { + return MakeReal(i); + } + + [CLSCompliant(false)] + public static implicit operator Complex64(uint i) { + return MakeReal(i); + } + + public static implicit operator Complex64(short i) { + return MakeReal(i); + } + + [CLSCompliant(false)] + public static implicit operator Complex64(ushort i) { + return MakeReal(i); + } + + public static implicit operator Complex64(long l) { + return MakeReal(l); + } + [CLSCompliant(false)] + public static implicit operator Complex64(ulong i) { + return MakeReal(i); + } + + [CLSCompliant(false)] + public static implicit operator Complex64(sbyte i) { + return MakeReal(i); + } + + public static implicit operator Complex64(byte i) { + return MakeReal(i); + } + + public static implicit operator Complex64(float f) { + return MakeReal(f); + } + + public static implicit operator Complex64(double d) { + return MakeReal(d); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] // TODO: fix + public static implicit operator Complex64(BigInteger i) { + ContractUtils.RequiresNotNull(i, "i"); + + // throws an overflow exception if we can't handle the value. + return MakeReal((double)i); + } + +#if FEATURE_NUMERICS + public static implicit operator Complex64(BigInt i) { + // throws an overflow exception if we can't handle the value. + return MakeReal((double)i); + } +#endif + + public static bool operator ==(Complex64 x, Complex64 y) { + return x.real == y.real && x.imag == y.imag; + } + + public static bool operator !=(Complex64 x, Complex64 y) { + return x.real != y.real || x.imag != y.imag; + } + + public static Complex64 Add(Complex64 x, Complex64 y) { + return x + y; + } + + public static Complex64 operator +(Complex64 x, Complex64 y) { + return new Complex64(x.real + y.real, x.imag + y.imag); + } + + public static Complex64 Subtract(Complex64 x, Complex64 y) { + return x - y; + } + + public static Complex64 operator -(Complex64 x, Complex64 y) { + return new Complex64(x.real - y.real, x.imag - y.imag); + } + + public static Complex64 Multiply(Complex64 x, Complex64 y) { + return x * y; + } + + public static Complex64 operator *(Complex64 x, Complex64 y) { + return new Complex64(x.real * y.real - x.imag * y.imag, x.real * y.imag + x.imag * y.real); + } + + public static Complex64 Divide(Complex64 x, Complex64 y) { + return x / y; + } + + public static Complex64 operator /(Complex64 a, Complex64 b) { + if (b.IsZero) { + throw new DivideByZeroException("complex division by zero"); + } + + double real, imag, den, r; + + if (System.Math.Abs(b.real) >= System.Math.Abs(b.imag)) { + r = b.imag / b.real; + den = b.real + r * b.imag; + real = (a.real + a.imag * r) / den; + imag = (a.imag - a.real * r) / den; + } else { + r = b.real / b.imag; + den = b.imag + r * b.real; + real = (a.real * r + a.imag) / den; + imag = (a.imag * r - a.real) / den; + } + + return new Complex64(real, imag); + } + + public static Complex64 Negate(Complex64 x) { + return -x; + } + + public static Complex64 operator -(Complex64 x) { + return new Complex64(-x.real, -x.imag); + } + + public static Complex64 Plus(Complex64 x) { + return +x; + } + + public static Complex64 operator +(Complex64 x) { + return x; + } + + [Obsolete("Deprecated - consider using MS.Scripting.Utils.MathUtils.Hypot")] + public static double Hypot(double x, double y) { + return MathUtils.Hypot(x, y); + } + + public double Abs() { + return MathUtils.Hypot(real, imag); + } + + public Complex64 Power(Complex64 y) { + double c = y.real; + double d = y.imag; + int power = (int)c; + + if (power == c && power >= 0 && d == .0) { + Complex64 result = One; + if (power == 0) return result; + Complex64 factor = this; + while (power != 0) { + if ((power & 1) != 0) { + result = result * factor; + } + factor = factor * factor; + power >>= 1; + } + return result; + } else if (IsZero) { + return y.IsZero ? One : Zero; + } else { + double a = real; + double b = imag; + double powers = a * a + b * b; + double arg = System.Math.Atan2(b, a); + double mul = System.Math.Pow(powers, c / 2) * System.Math.Exp(-d * arg); + double common = c * arg + .5 * d * System.Math.Log(powers); + return new Complex64(mul * System.Math.Cos(common), mul * System.Math.Sin(common)); + } + } + + public override int GetHashCode() { + // The Object.GetHashCode function needs to be consistent with the Object.Equals function. + // Languages that build on top of this may have a more flexible equality function and + // so may not be able to use this hash function directly. + // For example, Python allows that c=Complex64(1.5, 0), f = 1.5f, c==f. + // so then the hash(f) == hash(c). Since the python (and other languages) can define an arbitrary + // hash(float) function, the language may need to define a matching hash(complex) function for + // the cases where the float and complex numbers overlap. + return (int)real + (int)imag * 1000003; + } + + public override bool Equals(object obj) { + if (!(obj is Complex64)) return false; + return this == ((Complex64)obj); + } + } +}
\ No newline at end of file diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/MultiRuntimeAwareAttribute.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/MultiRuntimeAwareAttribute.cs new file mode 100644 index 00000000000..3b0cc25069a --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/MultiRuntimeAwareAttribute.cs @@ -0,0 +1,34 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Diagnostics; + +namespace Microsoft.Scripting { + /// <summary> + /// marks a field, class, or struct as being safe to have statics which can be accessed + /// from multiple runtimes. + /// + /// Static fields which are not read-only or marked with this attribute will be flagged + /// by a test which looks for state being shared between runtimes. Before applying this + /// attribute you should ensure that it is safe to share the state. This is typically + /// state which is lazy initialized or state which is caching values which are identical + /// in all runtimes and are immutable. + /// </summary> + [Conditional("DEBUG")] + [AttributeUsage(AttributeTargets.Field)] + public sealed class MultiRuntimeAwareAttribute : Attribute { + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/PerfTrack.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/PerfTrack.cs new file mode 100644 index 00000000000..622e41d0927 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/PerfTrack.cs @@ -0,0 +1,185 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.Scripting.Utils; +using System.Dynamic; +using System.IO; + +namespace Microsoft.Scripting { + /// <summary> + /// This class is useful for quickly collecting performance counts for expensive + /// operations. Usually this means operations involving either reflection or + /// code gen. Long-term we need to see if this can be plugged better into the + /// standard performance counter architecture. + /// </summary> + public static class PerfTrack { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1717:OnlyFlagsEnumsShouldHavePluralNames")] // TODO: fix + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")] // TODO: fix + public enum Categories { + /// <summary> + /// temporary categories for quick investigation, use a custom key if you + /// need to track multiple items, and if you want to keep it then create + /// a new Categories entry and rename all your temporary entries. + /// </summary> + Temporary, + ReflectedTypes, + Exceptions, // exceptions thrown + Properties, // properties got or set + Fields, // fields got or set + Methods, // methods called through MethodBase.Invoke()... + Compiler, // Methods compiled via the ReflectOptimizer + DelegateCreate, // we've created a new method for delegates + DictInvoke, // Dictionary accesses + OperatorInvoke, // Invoking an operator against a type + OverAllocate, // a spot where we have an un-ideal algorithm that needs to allocate more than necessary + Rules, // related to rules / actions. + RuleEvaluation, // a rule was evaluated + Binding, // a rule was bound + BindingSlow, + BindingFast, + BindingTarget, // a rule was bound against a target of a specific type + Count + } + + [MultiRuntimeAware] + private static int totalEvents; + private static readonly Dictionary<Categories, Dictionary<string, int>> _events = MakeEventsDictionary(); + private static readonly Dictionary<Categories, int> summaryStats = new Dictionary<Categories, int>(); + + private static Dictionary<Categories, Dictionary<string, int>> MakeEventsDictionary() { + Dictionary<Categories, Dictionary<string, int>> result = new Dictionary<Categories, Dictionary<string, int>>(); + + // We do not use Enum.GetValues here since it is not available in SILVERLIGHT + for (int i = 0; i <= (int)Categories.Count; i++) { + result[(Categories)i] = new Dictionary<string, int>(); + } + + return result; + } + +#if FEATURE_BASIC_CONSOLE + public static void DumpHistogram<TKey>(IDictionary<TKey, int> histogram) { + DumpHistogram(histogram, Console.Out); + } + + public static void DumpStats() { + DumpStats(Console.Out); + } +#endif + + public static void DumpHistogram<TKey>(IDictionary<TKey, int> histogram, TextWriter output) { + var keys = ArrayUtils.MakeArray(histogram.Keys); + var values = ArrayUtils.MakeArray(histogram.Values); + +#if !WIN8 // TODO: + Array.Sort(values, keys); +#endif + for (int i = 0; i < keys.Length; i++) { + output.WriteLine("{0} {1}", keys[i], values[i]); + } + } + + public static void AddHistograms<TKey>(IDictionary<TKey, int> result, IDictionary<TKey, int> addend) { + foreach (var entry in addend) { + int value; + result[entry.Key] = entry.Value + (result.TryGetValue(entry.Key, out value) ? value : 0); + } + } + + public static void IncrementEntry<TKey>(IDictionary<TKey, int> histogram, TKey key) { + int value; + histogram.TryGetValue(key, out value); + histogram[key] = value + 1; + } + + public static void DumpStats(TextWriter output) { + if (totalEvents == 0) return; + + // numbers from AMD Opteron 244 1.8 Ghz, 2.00GB of ram, + // running on IronPython 1.0 Beta 4 against Whidbey RTM. + const double CALL_TIME = 0.0000051442355; + const double THROW_TIME = 0.000025365656; + const double FIELD_TIME = 0.0000018080093; + + output.WriteLine(); + output.WriteLine("---- Performance Details ----"); + output.WriteLine(); + + foreach (KeyValuePair<Categories, Dictionary<string, int>> kvpCategories in _events) { + if (kvpCategories.Value.Count > 0) { + output.WriteLine("Category : " + kvpCategories.Key); + DumpHistogram(kvpCategories.Value, output); + output.WriteLine(); + } + } + + output.WriteLine(); + output.WriteLine("---- Performance Summary ----"); + output.WriteLine(); + double knownTimes = 0; + foreach (KeyValuePair<Categories, int> kvp in summaryStats) { + switch (kvp.Key) { + case Categories.Exceptions: + output.WriteLine("Total Exception ({0}) = {1} (throwtime = ~{2} secs)", kvp.Key, kvp.Value, kvp.Value * THROW_TIME); + knownTimes += kvp.Value * THROW_TIME; + break; + case Categories.Fields: + output.WriteLine("Total field = {0} (time = ~{1} secs)", kvp.Value, kvp.Value * FIELD_TIME); + knownTimes += kvp.Value * FIELD_TIME; + break; + case Categories.Methods: + output.WriteLine("Total calls = {0} (calltime = ~{1} secs)", kvp.Value, kvp.Value * CALL_TIME); + knownTimes += kvp.Value * CALL_TIME; + break; + //case Categories.Properties: + default: + output.WriteLine("Total {1} = {0}", kvp.Value, kvp.Key); + break; + } + } + + output.WriteLine(); + output.WriteLine("Total Known Times: {0}", knownTimes); + } + + [Conditional("DEBUG")] + public static void NoteEvent(Categories category, object key) { + if (!DebugOptions.TrackPerformance) return; + + Dictionary<string, int> categoryEvents = _events[category]; + totalEvents++; + lock (categoryEvents) { + string name = key.ToString(); + Exception ex = key as Exception; + if (ex != null) name = ex.GetType().ToString(); + int v; + if (!categoryEvents.TryGetValue(name, out v)) categoryEvents[name] = 1; + else categoryEvents[name] = v + 1; + + if (!summaryStats.TryGetValue(category, out v)) summaryStats[category] = 1; + else summaryStats[category] = v + 1; + } + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/ArgumentArray.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/ArgumentArray.cs new file mode 100644 index 00000000000..b6484afc31d --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/ArgumentArray.cs @@ -0,0 +1,76 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Dynamic; +using System.Reflection; +using Microsoft.Scripting.Utils; + +namespace Microsoft.Scripting.Runtime { + using AstUtils = Microsoft.Scripting.Ast.Utils; + + /// <summary> + /// Wraps all arguments passed to a dynamic site with more arguments than can be accepted by a Func/Action delegate. + /// The binder generating a rule for such a site should unwrap the arguments first and then perform a binding to them. + /// </summary> + public sealed class ArgumentArray { + private readonly object[] _arguments; + + // the index of the first item _arguments that represents an argument: + private readonly int _first; + + // the number of items in _arguments that represent the arguments: + private readonly int _count; + + internal ArgumentArray(object[] arguments, int first, int count) { + _arguments = arguments; + _first = first; + _count = count; + } + + public int Count { + get { return _count; } + } + + public object GetArgument(int index) { + ContractUtils.RequiresArrayIndex(_arguments, index, "index"); + return _arguments[_first + index]; + } + + public DynamicMetaObject GetMetaObject(Expression parameter, int index) { + return DynamicMetaObject.Create( + GetArgument(index), + Expression.Call( + _GetArgMethod, + AstUtils.Convert(parameter, typeof(ArgumentArray)), + AstUtils.Constant(index) + ) + ); + } + + [CLSCompliant(false)] + public static object GetArg(ArgumentArray array, int index) { + return array._arguments[array._first + index]; + } + + private static readonly MethodInfo _GetArgMethod = new Func<ArgumentArray, int, object>(GetArg).GetMethodInfo(); + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/DynamicNull.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/DynamicNull.cs new file mode 100644 index 00000000000..378bea4d090 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/DynamicNull.cs @@ -0,0 +1,27 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +namespace Microsoft.Scripting.Runtime { + /// <summary> + /// Represents the type of a null value. + /// </summary> + public sealed class DynamicNull { + /// <summary> + /// Private constructor is never called since 'null' is the only valid instance. + /// </summary> + private DynamicNull() { } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/ExceptionHelpers.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/ExceptionHelpers.cs new file mode 100644 index 00000000000..43350e7611e --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/ExceptionHelpers.cs @@ -0,0 +1,79 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Threading; +using Microsoft.Scripting.Actions; +using Microsoft.Scripting.Generation; + +namespace Microsoft.Scripting.Runtime { + public static class ExceptionHelpers { +#if FEATURE_STACK_TRACE + private const string prevStackTraces = "PreviousStackTraces"; + + /// <summary> + /// Updates an exception before it's getting re-thrown so + /// we can present a reasonable stack trace to the user. + /// </summary> + public static Exception UpdateForRethrow(Exception rethrow) { +#if !SILVERLIGHT + List<StackTrace> prev; + + // we don't have any dynamic stack trace data, capture the data we can + // from the raw exception object. + StackTrace st = new StackTrace(rethrow, true); + + if (!TryGetAssociatedStackTraces(rethrow, out prev)) { + prev = new List<StackTrace>(); + AssociateStackTraces(rethrow, prev); + } + + prev.Add(st); + +#endif + return rethrow; + } + + /// <summary> + /// Returns all the stack traces associates with an exception + /// </summary> + public static IList<StackTrace> GetExceptionStackTraces(Exception rethrow) { + List<StackTrace> result; + return TryGetAssociatedStackTraces(rethrow, out result) ? result : null; + } + + private static void AssociateStackTraces(Exception e, List<StackTrace> traces) { + e.Data[prevStackTraces] = traces; + } + + private static bool TryGetAssociatedStackTraces(Exception e, out List<StackTrace> traces) { + traces = e.Data[prevStackTraces] as List<StackTrace>; + return traces != null; + } +#else + public static Exception UpdateForRethrow(Exception rethrow) { + return rethrow; + } +#endif + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/ScriptingRuntimeHelpers.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/ScriptingRuntimeHelpers.cs new file mode 100644 index 00000000000..f7fc8b33eda --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Runtime/ScriptingRuntimeHelpers.cs @@ -0,0 +1,261 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Scripting.Actions; +using Microsoft.Scripting.Generation; +using Microsoft.Scripting.Utils; +using Microsoft.Scripting.Interpreter; + +namespace Microsoft.Scripting.Runtime { + /// <summary> + /// These are some generally useful helper methods. Currently the only methods are those to + /// cached boxed representations of commonly used primitive types so that they can be shared. + /// This is useful to most dynamic languages that use object as a universal type. + /// + /// The methods in RuntimeHelepers are caleld by the generated code. From here the methods may + /// dispatch to other parts of the runtime to get bulk of the work done, but the entry points + /// should be here. + /// </summary> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")] + public static partial class ScriptingRuntimeHelpers { + private const int MIN_CACHE = -100; + private const int MAX_CACHE = 1000; + private static readonly object[] cache = MakeCache(); + + /// <summary> + /// A singleton boxed boolean true. + /// </summary> + public static readonly object True = true; + + /// <summary> + ///A singleton boxed boolean false. + /// </summary> + public static readonly object False = false; + + internal static readonly MethodInfo BooleanToObjectMethod = typeof(ScriptingRuntimeHelpers).GetMethod("BooleanToObject"); + internal static readonly MethodInfo Int32ToObjectMethod = typeof(ScriptingRuntimeHelpers).GetMethod("Int32ToObject"); + + private static object[] MakeCache() { + object[] result = new object[MAX_CACHE - MIN_CACHE]; + + for (int i = 0; i < result.Length; i++) { + result[i] = (object)(i + MIN_CACHE); + } + + return result; + } + +#if DEBUG + public static void NoteException(Exception e) { + PerfTrack.NoteEvent(PerfTrack.Categories.Exceptions, "LightEH Missed: " + e.GetType()); + } +#endif + + /// <summary> + /// Gets a singleton boxed value for the given integer if possible, otherwise boxes the integer. + /// </summary> + /// <param name="value">The value to box.</param> + /// <returns>The boxed value.</returns> + public static object Int32ToObject(Int32 value) { + // caches improves pystone by ~5-10% on MS .Net 1.1, this is a very integer intense app + // TODO: investigate if this still helps perf. There's evidence that it's harmful on + // .NET 3.5 and 4.0 + if (value < MAX_CACHE && value >= MIN_CACHE) { + return cache[value - MIN_CACHE]; + } + return (object)value; + } + + private static readonly string[] chars = MakeSingleCharStrings(); + + private static string[] MakeSingleCharStrings() { + string[] result = new string[255]; + + for (char ch = (char)0; ch < result.Length; ch++) { + result[ch] = new string(ch, 1); + } + + return result; + } + + public static object BooleanToObject(bool value) { + return value ? True : False; + } + + public static string CharToString(char ch) { + if (ch < 255) return chars[ch]; + return new string(ch, 1); + } + + internal static object GetPrimitiveDefaultValue(Type type) { + switch (type.GetTypeCode()) { + case TypeCode.Boolean: return ScriptingRuntimeHelpers.False; + case TypeCode.SByte: return default(SByte); + case TypeCode.Byte: return default(Byte); + case TypeCode.Char: return default(Char); + case TypeCode.Int16: return default(Int16); + case TypeCode.Int32: return ScriptingRuntimeHelpers.Int32ToObject(0); + case TypeCode.Int64: return default(Int64); + case TypeCode.UInt16: return default(UInt16); + case TypeCode.UInt32: return default(UInt32); + case TypeCode.UInt64: return default(UInt64); + case TypeCode.Single: return default(Single); + case TypeCode.Double: return default(Double); +#if FEATURE_DBNULL + case TypeCode.DBNull: return default(DBNull); +#endif + case TypeCode.DateTime: return default(DateTime); + case TypeCode.Decimal: return default(Decimal); + default: return null; + } + } + + public static ArgumentTypeException SimpleTypeError(string message) { + return new ArgumentTypeException(message); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] // TODO: fix + public static Exception CannotConvertError(Type toType, object value) { + return SimpleTypeError(String.Format("Cannot convert {0}({1}) to {2}", CompilerHelpers.GetType(value).Name, value, toType.Name)); + } + + public static Exception SimpleAttributeError(string message) { + //TODO: localize + return new MissingMemberException(message); + } + + public static object ReadOnlyAssignError(bool field, string fieldName) { + if (field) { + throw Error.FieldReadonly(fieldName); + } else { + throw Error.PropertyReadonly(fieldName); + } + } + + /// <summary> + /// Helper method to create an instance. Work around for Silverlight where Activator.CreateInstance + /// is SecuritySafeCritical. + /// + /// TODO: Why can't we just emit the right thing for default(T)? + /// It's always null for reference types and it's well defined for value types + /// </summary> + public static T CreateInstance<T>() { + return default(T); + } + + // TODO: can't we just emit a new array? + public static T[] CreateArray<T>(int args) { + return new T[args]; + } + + /// <summary> + /// EventInfo.EventHandlerType getter is marked SecuritySafeCritical in CoreCLR + /// This method is to get to the property without using Reflection + /// </summary> + /// <param name="eventInfo"></param> + /// <returns></returns> + public static Type GetEventHandlerType(EventInfo eventInfo) { + ContractUtils.RequiresNotNull(eventInfo, "eventInfo"); + return eventInfo.EventHandlerType; + } + + public static IList<string> GetStringMembers(IList<object> members) { + List<string> res = new List<string>(); + foreach (object o in members) { + string str = o as string; + if (str != null) { + res.Add(str); + } + } + return res; + } +#if !MONO_INTERPRETER + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] // TODO: fix + public static void SetEvent(EventTracker eventTracker, object value) { + EventTracker et = value as EventTracker; + if (et != null) { + if (et != eventTracker) { + throw Error.UnexpectedEvent(eventTracker.DeclaringType.Name, + eventTracker.Name, + et.DeclaringType.Name, + et.Name); + } + return; + } + + BoundMemberTracker bmt = value as BoundMemberTracker; + if (bmt == null) { + throw Error.ExpectedBoundEvent(CompilerHelpers.GetType(value).Name); + } + if (bmt.BoundTo.MemberType != TrackerTypes.Event) throw Error.ExpectedBoundEvent(bmt.BoundTo.MemberType.ToString()); + + if (bmt.BoundTo != eventTracker) throw Error.UnexpectedEvent( + eventTracker.DeclaringType.Name, + eventTracker.Name, + bmt.BoundTo.DeclaringType.Name, + bmt.BoundTo.Name); + } +#endif + // TODO: just emit this in the generated code + public static bool CheckDictionaryMembers(IDictionary dict, string[] names) { + if (dict.Count != names.Length) return false; + + foreach (string name in names) { + if (!dict.Contains(name)) { + return false; + } + } + return true; + } + + // TODO: just emit this in the generated code + [Obsolete("use MakeIncorrectBoxTypeError instead")] + public static T IncorrectBoxType<T>(object received) { + throw Error.UnexpectedType("StrongBox<" + typeof(T).Name + ">", CompilerHelpers.GetType(received).Name); + } + + public static Exception MakeIncorrectBoxTypeError(Type type, object received) { + return Error.UnexpectedType("StrongBox<" + type.Name + ">", CompilerHelpers.GetType(received).Name); + } + + /// <summary> + /// Provides the test to see if an interpreted call site should switch over to being compiled. + /// </summary> + public static bool InterpretedCallSiteTest(bool restrictionResult, object bindingInfo) { + if (restrictionResult) { + CachedBindingInfo bindInfo = (CachedBindingInfo)bindingInfo; + if (bindInfo.CompilationThreshold >= 0) { + // still interpreting... + bindInfo.CompilationThreshold--; + return true; + } +#if SILVERLIGHT + if (PlatformAdaptationLayer.IsCompactFramework) { + bindInfo.CompilationThreshold = Int32.MaxValue; + return true; + } +#endif + return bindInfo.CheckCompiled(); + } + return false; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ArrayUtils.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ArrayUtils.cs new file mode 100644 index 00000000000..4262c15b0de --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ArrayUtils.cs @@ -0,0 +1,354 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace Microsoft.Scripting.Utils { + public static class ArrayUtils { + internal sealed class FunctorComparer<T> : IComparer<T> { + private readonly Comparison<T> _comparison; + + public FunctorComparer(Comparison<T> comparison) { + Assert.NotNull(comparison); + _comparison = comparison; + } + + public int Compare(T x, T y) { + return _comparison(x, y); + } + } + + // Emitted: + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] + public static readonly string[] EmptyStrings = new string[0]; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly")] + public static readonly object[] EmptyObjects = new object[0]; + + public static IComparer<T> ToComparer<T>(Comparison<T> comparison) { + return new FunctorComparer<T>(comparison); + } + + public static TOutput[] ConvertAll<TInput, TOutput>(TInput[] input, Func<TInput, TOutput> conv) { + ContractUtils.RequiresNotNull(input, "input"); + ContractUtils.RequiresNotNull(conv, "conv"); + + TOutput[] res = new TOutput[input.Length]; + for (int i = 0; i < input.Length; i++) { + res[i] = conv(input[i]); + } + + return res; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "1#")] // TODO: fix + public static void PrintTable(StringBuilder output, string[,] table) { + ContractUtils.RequiresNotNull(output, "output"); + ContractUtils.RequiresNotNull(table, "table"); + + int max_width = 0; + for (int i = 0; i < table.GetLength(0); i++) { + if (table[i, 0].Length > max_width) { + max_width = table[i, 0].Length; + } + } + + for (int i = 0; i < table.GetLength(0); i++) { + output.Append(" "); + output.Append(table[i, 0]); + + for (int j = table[i, 0].Length; j < max_width + 1; j++) { + output.Append(' '); + } + + output.AppendLine(table[i, 1]); + } + } + + public static T[] Copy<T>(T[] array) { + return (array.Length > 0) ? (T[])array.Clone() : array; + } + + /// <summary> + /// Converts a generic ICollection of T into an array of T. + /// + /// If the collection is already an array of T the original collection is returned. + /// </summary> + public static T[] ToArray<T>(ICollection<T> list) { + return (list as T[]) ?? MakeArray(list); + } + + /// <summary> + /// Converts a generic ICollection of T into an array of R using a given conversion. + /// + /// If the collection is already an array of R the original collection is returned. + /// </summary> + public static TResult[] ToArray<TElement, TResult>(ICollection<TElement> list, Func<TElement, TResult> convertor) { + TResult[] res = list as TResult[]; + if (res == null) { + res = new TResult[list.Count]; + int i = 0; + foreach (TElement obj in list) { + res[i++] = convertor(obj); + } + } + return res; + } + + public static T[] MakeArray<T>(ICollection<T> list) { + if (list.Count == 0) { + return new T[0]; + } + + T[] res = new T[list.Count]; + list.CopyTo(res, 0); + return res; + } + + public static T[] MakeArray<T>(ICollection<T> elements, int reservedSlotsBefore, int reservedSlotsAfter) { + if (reservedSlotsAfter < 0) throw new ArgumentOutOfRangeException("reservedSlotsAfter"); + if (reservedSlotsBefore < 0) throw new ArgumentOutOfRangeException("reservedSlotsBefore"); + + if (elements == null) { + return new T[reservedSlotsBefore + reservedSlotsAfter]; + } + + T[] result = new T[reservedSlotsBefore + elements.Count + reservedSlotsAfter]; + elements.CopyTo(result, reservedSlotsBefore); + return result; + } + + public static T[] RotateRight<T>(T[] array, int count) { + ContractUtils.RequiresNotNull(array, "array"); + if ((count < 0) || (count > array.Length)) throw new ArgumentOutOfRangeException("count"); + + T[] result = new T[array.Length]; + // The head of the array is shifted, and the tail will be rotated to the head of the resulting array + int sizeOfShiftedArray = array.Length - count; + Array.Copy(array, 0, result, count, sizeOfShiftedArray); + Array.Copy(array, sizeOfShiftedArray, result, 0, count); + return result; + } + + public static T[] ShiftRight<T>(T[] array, int count) { + ContractUtils.RequiresNotNull(array, "array"); + if (count < 0) throw new ArgumentOutOfRangeException("count"); + + T[] result = new T[array.Length + count]; + System.Array.Copy(array, 0, result, count, array.Length); + return result; + } + + public static T[] ShiftLeft<T>(T[] array, int count) { + ContractUtils.RequiresNotNull(array, "array"); + if (count < 0) throw new ArgumentOutOfRangeException("count"); + + T[] result = new T[array.Length - count]; + System.Array.Copy(array, count, result, 0, result.Length); + return result; + } + + public static T[] Insert<T>(T item, IList<T> list) { + T[] res = new T[list.Count + 1]; + res[0] = item; + list.CopyTo(res, 1); + return res; + } + + public static T[] Insert<T>(T item1, T item2, IList<T> list) { + T[] res = new T[list.Count + 2]; + res[0] = item1; + res[1] = item2; + list.CopyTo(res, 2); + return res; + } + + public static T[] Insert<T>(T item, T[] array) { + T[] result = ShiftRight(array, 1); + result[0] = item; + return result; + } + + public static T[] Insert<T>(T item1, T item2, T[] array) { + T[] result = ShiftRight(array, 2); + result[0] = item1; + result[1] = item2; + return result; + } + + public static T[] Append<T>(T[] array, T item) { + System.Array.Resize<T>(ref array, (array == null) ? 1 : array.Length + 1); + array[array.Length - 1] = item; + return array; + } + + public static T[] AppendRange<T>(T[] array, IList<T> items) { + return AppendRange<T>(array, items, 0); + } + + public static T[] AppendRange<T>(T[] array, IList<T> items, int additionalItemCount) { + if (additionalItemCount < 0) { + throw new ArgumentOutOfRangeException("additionalItemCount"); + } + + int j = (array == null) ? 0 : array.Length; + System.Array.Resize<T>(ref array, j + items.Count + additionalItemCount); + + for (int i = 0; i < items.Count; i++, j++) { + array[j] = items[i]; + } + + return array; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional")] // TODO: fix + public static T[,] Concatenate<T>(T[,] array1, T[,] array2) { + int columnsCount = array1.GetLength(1); + Debug.Assert(array2.GetLength(1) == columnsCount); + + int row1Count = array1.GetLength(0); + int row2Count = array2.GetLength(0); + int totalRowsCount = row1Count + row2Count; + T[,] result = new T[totalRowsCount, columnsCount]; + + for (int i = 0; i < row1Count; i++) { + for (int j = 0; j < columnsCount; j++) { + result[i, j] = array1[i, j]; + } + } + + for (int i = 0; i < row2Count; i++) { + for (int j = 0; j < columnsCount; j++) { + result[(i + row1Count), j] = array2[i, j]; + } + } + + return result; + } + + public static void SwapLastTwo<T>(T[] array) { + Debug.Assert(array != null && array.Length >= 2); + + T temp = array[array.Length - 1]; + array[array.Length - 1] = array[array.Length - 2]; + array[array.Length - 2] = temp; + } + + public static T[] RemoveFirst<T>(IList<T> list) { + return ShiftLeft(MakeArray(list), 1); + } + + public static T[] RemoveFirst<T>(T[] array) { + return ShiftLeft(array, 1); + } + + public static T[] RemoveLast<T>(T[] array) { + ContractUtils.RequiresNotNull(array, "array"); + + System.Array.Resize(ref array, array.Length - 1); + return array; + } + + public static T[] RemoveAt<T>(IList<T> list, int indexToRemove) { + return RemoveAt(MakeArray(list), indexToRemove); + } + + public static T[] RemoveAt<T>(T[] array, int indexToRemove) { + ContractUtils.RequiresNotNull(array, "array"); + ContractUtils.Requires(indexToRemove >= 0 && indexToRemove < array.Length, "index"); + + T[] result = new T[array.Length - 1]; + if (indexToRemove > 0) { + Array.Copy(array, 0, result, 0, indexToRemove); + } + int remaining = array.Length - indexToRemove - 1; + if (remaining > 0) { + Array.Copy(array, array.Length - remaining, result, result.Length - remaining, remaining); + } + return result; + } + + public static T[] InsertAt<T>(IList<T> list, int index, params T[] items) { + return InsertAt(MakeArray(list), index, items); + } + + public static T[] InsertAt<T>(T[] array, int index, params T[] items) { + ContractUtils.RequiresNotNull(array, "array"); + ContractUtils.RequiresNotNull(items, "items"); + ContractUtils.Requires(index >= 0 && index <= array.Length, "index"); + + if (items.Length == 0) { + return Copy(array); + } + + T[] result = new T[array.Length + items.Length]; + if (index > 0) { + Array.Copy(array, 0, result, 0, index); + } + Array.Copy(items, 0, result, index, items.Length); + + int remaining = array.Length - index; + if (remaining > 0) { + Array.Copy(array, array.Length - remaining, result, result.Length - remaining, remaining); + } + return result; + } + + public static bool ValueEquals<T>(this T[] array, T[] other) { + if (other.Length != array.Length) { + return false; + } + + for (int i = 0; i < array.Length; i++) { + if (!Object.Equals(array[i], other[i])) { + return false; + } + } + + return true; + } + + public static int GetValueHashCode<T>(this T[] array) { + return GetValueHashCode<T>(array, 0, array.Length); + } + + public static int GetValueHashCode<T>(this T[] array, int start, int count) { + ContractUtils.RequiresNotNull(array, "array"); + ContractUtils.RequiresArrayRange(array.Length, start, count, "start", "count"); + + if (count == 0) { + return 0; + } + + int result = array[start].GetHashCode(); + for (int i = 1; i < count; i++) { + result = ((result << 5) | (result >> 27)) ^ array[start + i].GetHashCode(); + } + + return result; + } + + public static T[] Reverse<T>(this T[] array) { + T[] res = new T[array.Length]; + for (int i = 0; i < array.Length; i++) { + res[array.Length - i - 1] = array[i]; + } + return res; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/Assert.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/Assert.cs new file mode 100644 index 00000000000..adae9ddd77a --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/Assert.cs @@ -0,0 +1,78 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#define DEBUG + +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Microsoft.Scripting.Utils { + + public static class Assert { + + public static Exception Unreachable { + get { + Debug.Assert(false, "Unreachable"); + return new InvalidOperationException("Code supposed to be unreachable"); + } + } + + [Conditional("DEBUG")] + public static void NotNull(object var) { + Debug.Assert(var != null); + } + + [Conditional("DEBUG")] + public static void NotNull(object var1, object var2) { + Debug.Assert(var1 != null && var2 != null); + } + + [Conditional("DEBUG")] + public static void NotNull(object var1, object var2, object var3) { + Debug.Assert(var1 != null && var2 != null && var3 != null); + } + + [Conditional("DEBUG")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1025:ReplaceRepetitiveArgumentsWithParamsArray")] + public static void NotNull(object var1, object var2, object var3, object var4) { + Debug.Assert(var1 != null && var2 != null && var3 != null && var4 != null); + } + + [Conditional("DEBUG")] + public static void NotEmpty(string str) { + Debug.Assert(!String.IsNullOrEmpty(str)); + } + + [Conditional("DEBUG")] + public static void NotEmpty<T>(ICollection<T> array) { + Debug.Assert(array != null && array.Count > 0); + } + + [Conditional("DEBUG")] + public static void NotNullItems<T>(IEnumerable<T> items) where T : class { + Debug.Assert(items != null); + foreach (object item in items) { + Debug.Assert(item != null); + } + } + + [Conditional("DEBUG")] + public static void IsTrue(Func<bool> predicate) { + ContractUtils.RequiresNotNull(predicate, "predicate"); + Debug.Assert(predicate()); + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/CacheDict.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/CacheDict.cs new file mode 100644 index 00000000000..57724cc447a --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/CacheDict.cs @@ -0,0 +1,114 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace Microsoft.Scripting.Utils { + /// <summary> + /// Provides a dictionary-like object used for caches which holds onto a maximum + /// number of elements specified at construction time. + /// + /// This class is not thread safe. + /// </summary> + public class CacheDict<TKey, TValue> { + private readonly Dictionary<TKey, KeyInfo> _dict = new Dictionary<TKey, KeyInfo>(); + private readonly LinkedList<TKey> _list = new LinkedList<TKey>(); + private readonly int _maxSize; + + /// <summary> + /// Creates a dictionary-like object used for caches. + /// </summary> + /// <param name="maxSize">The maximum number of elements to store.</param> + public CacheDict(int maxSize) { + _maxSize = maxSize; + } + + /// <summary> + /// Tries to get the value associated with 'key', returning true if it's found and + /// false if it's not present. + /// </summary> + public bool TryGetValue(TKey key, out TValue value) { + KeyInfo storedValue; + if (_dict.TryGetValue(key, out storedValue)) { + LinkedListNode<TKey> node = storedValue.List; + if (node.Previous != null) { + // move us to the head of the list... + _list.Remove(node); + _list.AddFirst(node); + } + + value = storedValue.Value; + return true; + } + + value = default(TValue); + return false; + } + + /// <summary> + /// Adds a new element to the cache, replacing and moving it to the front if the + /// element is already present. + /// </summary> + public void Add(TKey key, TValue value) { + KeyInfo keyInfo; + if (_dict.TryGetValue(key, out keyInfo)) { + // remove original entry from the linked list + _list.Remove(keyInfo.List); + } else if (_list.Count == _maxSize) { + // we've reached capacity, remove the last used element... + LinkedListNode<TKey> node = _list.Last; + _list.RemoveLast(); + bool res = _dict.Remove(node.Value); + Debug.Assert(res); + } + + // add the new entry to the head of the list and into the dictionary + LinkedListNode<TKey> listNode = new LinkedListNode<TKey>(key); + _list.AddFirst(listNode); + _dict[key] = new CacheDict<TKey, TValue>.KeyInfo(value, listNode); + } + + /// <summary> + /// Returns the value associated with the given key, or throws KeyNotFoundException + /// if the key is not present. + /// </summary> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")] + public TValue this[TKey key] { + get { + TValue res; + if (TryGetValue(key, out res)) { + return res; + } + throw new KeyNotFoundException(); + } + set { + Add(key, value); + } + } + + private struct KeyInfo { + internal readonly TValue Value; + internal readonly LinkedListNode<TKey> List; + + internal KeyInfo(TValue value, LinkedListNode<TKey> list) { + Value = value; + List = list; + } + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/CollectionExtensions.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/CollectionExtensions.cs new file mode 100644 index 00000000000..7eaf4000160 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/CollectionExtensions.cs @@ -0,0 +1,156 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; + +namespace Microsoft.Scripting.Utils { + internal static class CollectionExtensions { + /// <summary> + /// Wraps the provided enumerable into a ReadOnlyCollection{T} + /// + /// Copies all of the data into a new array, so the data can't be + /// changed after creation. The exception is if the enumerable is + /// already a ReadOnlyCollection{T}, in which case we just return it. + /// </summary> + internal static ReadOnlyCollection<T> ToReadOnly<T>(this IEnumerable<T> enumerable) { + if (enumerable == null) { + return EmptyReadOnlyCollection<T>.Instance; + } + + var roCollection = enumerable as ReadOnlyCollection<T>; + if (roCollection != null) { + return roCollection; + } + + var collection = enumerable as ICollection<T>; + if (collection != null) { + int count = collection.Count; + if (count == 0) { + return EmptyReadOnlyCollection<T>.Instance; + } + + T[] array = new T[count]; + collection.CopyTo(array, 0); + return new ReadOnlyCollection<T>(array); + } + + // ToArray trims the excess space and speeds up access + return new ReadOnlyCollection<T>(new List<T>(enumerable).ToArray()); + } + + // We could probably improve the hashing here + internal static int ListHashCode<T>(this IEnumerable<T> list) { + var cmp = EqualityComparer<T>.Default; + int h = 6551; + foreach (T t in list) { + h ^= (h << 5) ^ cmp.GetHashCode(t); + } + return h; + } + + internal static bool ListEquals<T>(this ICollection<T> first, ICollection<T> second) { + if (first.Count != second.Count) { + return false; + } + var cmp = EqualityComparer<T>.Default; + var f = first.GetEnumerator(); + var s = second.GetEnumerator(); + while (f.MoveNext()) { + s.MoveNext(); + + if (!cmp.Equals(f.Current, s.Current)) { + return false; + } + } + return true; + } + + // Name needs to be different so it doesn't conflict with Enumerable.Select + internal static U[] Map<T, U>(this ICollection<T> collection, Func<T, U> select) { + int count = collection.Count; + U[] result = new U[count]; + count = 0; + foreach (T t in collection) { + result[count++] = select(t); + } + return result; + } + + internal static T[] RemoveFirst<T>(this T[] array) { + T[] result = new T[array.Length - 1]; + Array.Copy(array, 1, result, 0, result.Length); + return result; + } + + internal static T[] RemoveLast<T>(this T[] array) { + T[] result = new T[array.Length - 1]; + Array.Copy(array, 0, result, 0, result.Length); + return result; + } + + internal static T[] AddFirst<T>(this IList<T> list, T item) { + T[] res = new T[list.Count + 1]; + res[0] = item; + list.CopyTo(res, 1); + return res; + } + + internal static T[] AddLast<T>(this IList<T> list, T item) { + T[] res = new T[list.Count + 1]; + list.CopyTo(res, 0); + res[list.Count] = item; + return res; + } + + internal static T[] RemoveAt<T>(this T[] array, int indexToRemove) { + Debug.Assert(array != null); + Debug.Assert(indexToRemove >= 0 && indexToRemove < array.Length); + + T[] result = new T[array.Length - 1]; + if (indexToRemove > 0) { + Array.Copy(array, 0, result, 0, indexToRemove); + } + int remaining = array.Length - indexToRemove - 1; + if (remaining > 0) { + Array.Copy(array, array.Length - remaining, result, result.Length - remaining, remaining); + } + return result; + } + + internal static T[] RotateRight<T>(this T[] array, int count) { + Debug.Assert(count >= 0 && count <= array.Length); + + T[] result = new T[array.Length]; + // The head of the array is shifted, and the tail will be rotated to the head of the resulting array + int sizeOfShiftedArray = array.Length - count; + Array.Copy(array, 0, result, count, sizeOfShiftedArray); + Array.Copy(array, sizeOfShiftedArray, result, 0, count); + return result; + } + } + + + internal static class EmptyReadOnlyCollection<T> { + internal static ReadOnlyCollection<T> Instance = new ReadOnlyCollection<T>(new T[0]); + } + // TODO: Should we use this everywhere for empty arrays? + // my thought is, probably more hassle than its worth + internal static class EmptyArray<T> { + internal static T[] Instance = new T[0]; + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/CollectionUtils.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/CollectionUtils.cs new file mode 100644 index 00000000000..dec3b4e5992 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/CollectionUtils.cs @@ -0,0 +1,322 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Microsoft.Scripting.Utils { + /// <summary> + /// Allows wrapping of proxy types (like COM RCWs) to expose their IEnumerable functionality + /// which is supported after casting to IEnumerable, even though Reflection will not indicate + /// IEnumerable as a supported interface + /// </summary> + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1010:CollectionsShouldImplementGenericInterface")] // TODO + public class EnumerableWrapper : IEnumerable { + private IEnumerable _wrappedObject; + public EnumerableWrapper(IEnumerable o) { + _wrappedObject = o; + } + + public IEnumerator GetEnumerator() { + return _wrappedObject.GetEnumerator(); + } + } + + public static class CollectionUtils { +#if !FEATURE_VARIANCE + public static IEnumerable<T> Cast<S, T>(this IEnumerable<S> sequence) where S : T { + foreach (var item in sequence) { + yield return (T)item; + } + } +#else + public static IEnumerable<T> Cast<S, T>(this IEnumerable<S> sequence) where S : T { + return (IEnumerable<T>)sequence; + } +#endif + + public static IEnumerable<TSuper> ToCovariant<T, TSuper>(IEnumerable<T> enumerable) + where T : TSuper { +#if FEATURE_VARIANCE + return (IEnumerable<TSuper>)enumerable; +#else + return new CovariantConvertor<T, TSuper>(enumerable); +#endif + } + + public static void AddRange<T>(ICollection<T> collection, IEnumerable<T> items) { + ContractUtils.RequiresNotNull(collection, "collection"); + ContractUtils.RequiresNotNull(items, "items"); + + List<T> list = collection as List<T>; + if (list != null) { + list.AddRange(items); + } else { + foreach (T item in items) { + collection.Add(item); + } + } + } + + public static void AddRange<T>(this IList<T> list, IEnumerable<T> items) { + foreach (var item in items) { + list.Add(item); + } + } + + public static IEnumerable<T> ToEnumerable<T>(IEnumerable enumerable) { + foreach (T item in enumerable) { + yield return item; + } + } + + public static IEnumerator<TSuper> ToCovariant<T, TSuper>(IEnumerator<T> enumerator) + where T : TSuper { + + ContractUtils.RequiresNotNull(enumerator, "enumerator"); + + while (enumerator.MoveNext()) { + yield return enumerator.Current; + } + } + + private class CovariantConvertor<T, TSuper> : IEnumerable<TSuper> where T : TSuper { + private IEnumerable<T> _enumerable; + + public CovariantConvertor(IEnumerable<T> enumerable) { + ContractUtils.RequiresNotNull(enumerable, "enumerable"); + _enumerable = enumerable; + } + + public IEnumerator<TSuper> GetEnumerator() { + return CollectionUtils.ToCovariant<T, TSuper>(_enumerable.GetEnumerator()); + } + + IEnumerator IEnumerable.GetEnumerator() { + return GetEnumerator(); + } + } + + public static IDictionaryEnumerator ToDictionaryEnumerator(IEnumerator<KeyValuePair<object, object>> enumerator) { + return new DictionaryEnumerator(enumerator); + } + + private sealed class DictionaryEnumerator : IDictionaryEnumerator { + private readonly IEnumerator<KeyValuePair<object, object>> _enumerator; + + public DictionaryEnumerator(IEnumerator<KeyValuePair<object, object>> enumerator) { + _enumerator = enumerator; + } + + public DictionaryEntry Entry { + get { return new DictionaryEntry(_enumerator.Current.Key, _enumerator.Current.Value); } + } + + public object Key { + get { return _enumerator.Current.Key; } + } + + public object Value { + get { return _enumerator.Current.Value; } + } + + public object Current { + get { return Entry; } + } + + public bool MoveNext() { + return _enumerator.MoveNext(); + } + + public void Reset() { + _enumerator.Reset(); + } + } + + public static List<T> MakeList<T>(T item) { + List<T> result = new List<T>(); + result.Add(item); + return result; + } + + public static int CountOf<T>(IList<T> list, T item) where T : IEquatable<T> { + if (list == null) return 0; + + int result = 0; + for (int i = 0; i < list.Count; i++) { + if (list[i].Equals(item)) { + result++; + } + } + return result; + } + + public static int Max(this IEnumerable<int> values) { + ContractUtils.RequiresNotNull(values, "values"); + + int result = Int32.MinValue; + foreach (var value in values) { + if (value > result) { + result = value; + } + } + return result; + } + + public static bool TrueForAll<T>(IEnumerable<T> collection, Predicate<T> predicate) { + ContractUtils.RequiresNotNull(collection, "collection"); + ContractUtils.RequiresNotNull(predicate, "predicate"); + + foreach (T item in collection) { + if (!predicate(item)) return false; + } + + return true; + } + + public static IList<TRet> ConvertAll<T, TRet>(IList<T> collection, Func<T, TRet> predicate) { + ContractUtils.RequiresNotNull(collection, "collection"); + ContractUtils.RequiresNotNull(predicate, "predicate"); + + List<TRet> res = new List<TRet>(collection.Count); + foreach (T item in collection) { + res.Add(predicate(item)); + } + + return res; + } + + public static List<T> GetRange<T>(IList<T> list, int index, int count) { + ContractUtils.RequiresNotNull(list, "list"); + ContractUtils.RequiresArrayRange(list, index, count, "index", "count"); + + List<T> result = new List<T>(count); + int stop = index + count; + for (int i = index; i < stop; i++) { + result.Add(list[i]); + } + return result; + } + + public static void InsertRange<T>(IList<T> collection, int index, IEnumerable<T> items) { + ContractUtils.RequiresNotNull(collection, "collection"); + ContractUtils.RequiresNotNull(items, "items"); + ContractUtils.RequiresArrayInsertIndex(collection, index, "index"); + + List<T> list = collection as List<T>; + if (list != null) { + list.InsertRange(index, items); + } else { + int i = index; + foreach (T obj in items) { + collection.Insert(i++, obj); + } + } + } + + public static void RemoveRange<T>(IList<T> collection, int index, int count) { + ContractUtils.RequiresNotNull(collection, "collection"); + ContractUtils.RequiresArrayRange(collection, index, count, "index", "count"); + + List<T> list = collection as List<T>; + if (list != null) { + list.RemoveRange(index, count); + } else { + for (int i = index + count - 1; i >= index; i--) { + collection.RemoveAt(i); + } + } + } + + public static int FindIndex<T>(this IList<T> collection, Predicate<T> predicate) { + ContractUtils.RequiresNotNull(collection, "collection"); + ContractUtils.RequiresNotNull(predicate, "predicate"); + + for (int i = 0; i < collection.Count; i++) { + if (predicate(collection[i])) { + return i; + } + } + return -1; + } + + public static IList<T> ToSortedList<T>(this ICollection<T> collection, Comparison<T> comparison) { + ContractUtils.RequiresNotNull(collection, "collection"); + ContractUtils.RequiresNotNull(comparison, "comparison"); + + var array = new T[collection.Count]; + collection.CopyTo(array, 0); + Array.Sort(array, comparison); + return array; + } + + public static T[] ToReverseArray<T>(this IList<T> list) { + ContractUtils.RequiresNotNull(list, "list"); + T[] result = new T[list.Count]; + for (int i = 0; i < result.Length; i++) { + result[i] = list[result.Length - 1 - i]; + } + return result; + } + + +#if SILVERLIGHT || WIN8 || WP75 + // HashSet.CreateSetComparer not available on Silverlight + public static IEqualityComparer<HashSet<T>> CreateSetComparer<T>() { + return new HashSetEqualityComparer<T>(); + } + + class HashSetEqualityComparer<T> : IEqualityComparer<HashSet<T>> { + private IEqualityComparer<T> _comparer; + + public HashSetEqualityComparer() { + _comparer = EqualityComparer<T>.Default; + } + + public bool Equals(HashSet<T> x, HashSet<T> y) { + if (x == y) { + return true; + } else if (x == null || y == null || x.Count != y.Count) { + return false; + } + + foreach (T value in x) { + if (!y.Contains(value)) { + return false; + } + } + + return true; + } + + public int GetHashCode(HashSet<T> obj) { + int res = 6551; + if (obj != null) { + foreach (T t in obj) { + res = res ^ _comparer.GetHashCode(t); + } + } + + return res; + } + } +#else + public static IEqualityComparer<HashSet<T>> CreateSetComparer<T>() { + return HashSet<T>.CreateSetComparer(); + } +#endif + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ContractUtils.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ContractUtils.cs new file mode 100644 index 00000000000..53a9ea256fd --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ContractUtils.cs @@ -0,0 +1,233 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Microsoft.Scripting.Utils { + public static class ContractUtils { + [Conditional("DEBUG")] + public static void Assert(bool precondition) { + Debug.Assert(precondition); + } + + public static void Requires(bool precondition) { + if (!precondition) { + throw new ArgumentException(Strings.MethodPreconditionViolated); + } + } + + public static void Requires(bool precondition, string paramName) { + Utils.Assert.NotEmpty(paramName); + + if (!precondition) { + throw new ArgumentException(Strings.InvalidArgumentValue, paramName); + } + } + + public static void Requires(bool precondition, string paramName, string message) { + Utils.Assert.NotEmpty(paramName); + + if (!precondition) { + throw new ArgumentException(message, paramName); + } + } + + public static void RequiresNotNull(object value, string paramName) { + Utils.Assert.NotEmpty(paramName); + + if (value == null) { + throw new ArgumentNullException(paramName); + } + } + + public static void RequiresNotEmpty(string str, string paramName) { + RequiresNotNull(str, paramName); + if (str.Length == 0) { + throw new ArgumentException(Strings.NonEmptyStringRequired, paramName); + } + } + + public static void RequiresNotEmpty<T>(ICollection<T> collection, string paramName) { + RequiresNotNull(collection, paramName); + if (collection.Count == 0) { + throw new ArgumentException(Strings.NonEmptyCollectionRequired, paramName); + } + } + + /// <summary> + /// Requires the specified index to point inside the array. + /// </summary> + /// <exception cref="ArgumentNullException">Array is <c>null</c>.</exception> + /// <exception cref="ArgumentOutOfRangeException">Index is outside the array.</exception> + public static void RequiresArrayIndex<T>(IList<T> array, int index, string indexName) { + RequiresArrayIndex(array.Count, index, indexName); + } + + /// <summary> + /// Requires the specified index to point inside the array. + /// </summary> + /// <exception cref="ArgumentOutOfRangeException">Index is outside the array.</exception> + public static void RequiresArrayIndex(int arraySize, int index, string indexName) { + Utils.Assert.NotEmpty(indexName); + Debug.Assert(arraySize >= 0); + + if (index < 0 || index >= arraySize) throw new ArgumentOutOfRangeException(indexName); + } + + /// <summary> + /// Requires the specified index to point inside the array or at the end + /// </summary> + /// <exception cref="ArgumentNullException">Array is <c>null</c>.</exception> + /// <exception cref="ArgumentOutOfRangeException">Index is outside the array.</exception> + public static void RequiresArrayInsertIndex<T>(IList<T> array, int index, string indexName) { + RequiresArrayInsertIndex(array.Count, index, indexName); + } + + /// <summary> + /// Requires the specified index to point inside the array or at the end + /// </summary> + /// <exception cref="ArgumentNullException">Array is <c>null</c>.</exception> + /// <exception cref="ArgumentOutOfRangeException">Index is outside the array.</exception> + public static void RequiresArrayInsertIndex(int arraySize, int index, string indexName) { + Utils.Assert.NotEmpty(indexName); + Debug.Assert(arraySize >= 0); + + if (index < 0 || index > arraySize) throw new ArgumentOutOfRangeException(indexName); + } + + /// <summary> + /// Requires the range [offset, offset + count] to be a subset of [0, array.Count]. + /// </summary> + /// <exception cref="ArgumentOutOfRangeException">Offset or count are out of range.</exception> + public static void RequiresArrayRange<T>(IList<T> array, int offset, int count, string offsetName, string countName) { + Utils.Assert.NotNull(array); + RequiresArrayRange(array.Count, offset, count, offsetName, countName); + } + + /// <summary> + /// Requires the range [offset, offset + count] to be a subset of [0, array.Count]. + /// </summary> + /// <exception cref="ArgumentOutOfRangeException">Offset or count are out of range.</exception> + public static void RequiresArrayRange(int arraySize, int offset, int count, string offsetName, string countName) { + Utils.Assert.NotEmpty(offsetName); + Utils.Assert.NotEmpty(countName); + Debug.Assert(arraySize >= 0); + + if (count < 0) throw new ArgumentOutOfRangeException(countName); + if (offset < 0 || arraySize - offset < count) throw new ArgumentOutOfRangeException(offsetName); + } + + + /// <summary> + /// Requires the range [offset, offset + count] to be a subset of [0, array.Count]. + /// </summary> + /// <exception cref="ArgumentNullException">Array is <c>null</c>.</exception> + /// <exception cref="ArgumentOutOfRangeException">Offset or count are out of range.</exception> + public static void RequiresListRange(IList array, int offset, int count, string offsetName, string countName) { + Utils.Assert.NotEmpty(offsetName); + Utils.Assert.NotEmpty(countName); + Utils.Assert.NotNull(array); + + if (count < 0) throw new ArgumentOutOfRangeException(countName); + if (offset < 0 || array.Count - offset < count) throw new ArgumentOutOfRangeException(offsetName); + } + + /// <summary> + /// Requires the range [offset, offset + count] to be a subset of [0, array.Count]. + /// </summary> + /// <exception cref="ArgumentNullException">String is <c>null</c>.</exception> + /// <exception cref="ArgumentOutOfRangeException">Offset or count are out of range.</exception> + public static void RequiresArrayRange(string str, int offset, int count, string offsetName, string countName) { + Utils.Assert.NotEmpty(offsetName); + Utils.Assert.NotEmpty(countName); + Utils.Assert.NotNull(str); + + if (count < 0) throw new ArgumentOutOfRangeException(countName); + if (offset < 0 || str.Length - offset < count) throw new ArgumentOutOfRangeException(offsetName); + } + + /// <summary> + /// Requires the array and all its items to be non-null. + /// </summary> + public static void RequiresNotNullItems<T>(IList<T> array, string arrayName) { + Utils.Assert.NotNull(arrayName); + RequiresNotNull(array, arrayName); + + for (int i = 0; i < array.Count; i++) { + if (array[i] == null) { + throw ExceptionUtils.MakeArgumentItemNullException(i, arrayName); + } + } + } + + /// <summary> + /// Requires the enumerable collection and all its items to be non-null. + /// </summary> + public static void RequiresNotNullItems<T>(IEnumerable<T> collection, string collectionName) { + Utils.Assert.NotNull(collectionName); + RequiresNotNull(collection, collectionName); + + int i = 0; + foreach (var item in collection) { + if (item == null) { + throw ExceptionUtils.MakeArgumentItemNullException(i, collectionName); + } + i++; + } + } + + [Conditional("FALSE")] + public static void Invariant(bool condition) { + Debug.Assert(condition); + } + + [Conditional("FALSE")] + public static void Invariant(bool condition, string message) { + Debug.Assert(condition, message); + } + + [Conditional("FALSE")] + public static void Ensures(bool condition) { + // nop + } + + [Conditional("FALSE")] + public static void Ensures(bool condition, string message) { + // nop + } + + public static T Result<T>() { + return default(T); + } + + public static T Parameter<T>(out T value) { + value = default(T); + return value; + } + + public static T Old<T>(T value) { + return value; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/DynamicUtils.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/DynamicUtils.cs new file mode 100644 index 00000000000..3c8e955c587 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/DynamicUtils.cs @@ -0,0 +1,297 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_TASKS +using System.Threading.Tasks; +#endif + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Dynamic; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Threading; +using Microsoft.Scripting.Generation; +using Microsoft.Scripting.Interpreter; +using Microsoft.Scripting.Runtime; + +#if !FEATURE_DYNAMIC_EXPRESSION_VISITOR +#if FEATURE_CORE_DLR +namespace System.Linq.Expressions { +#else +namespace Microsoft.Scripting.Ast { +#endif + public abstract class DynamicExpressionVisitor : ExpressionVisitor { + } +} +#endif + +namespace Microsoft.Scripting.Utils { + using AstUtils = Microsoft.Scripting.Ast.Utils; + + public static class DynamicUtils { + /// <summary> + /// Returns the list of expressions represented by the <see cref="DynamicMetaObject"/> instances. + /// </summary> + /// <param name="objects">An array of <see cref="DynamicMetaObject"/> instances to extract expressions from.</param> + /// <returns>The array of expressions.</returns> + public static Expression[] GetExpressions(DynamicMetaObject[] objects) { + ContractUtils.RequiresNotNull(objects, "objects"); + + Expression[] res = new Expression[objects.Length]; + for (int i = 0; i < objects.Length; i++) { + DynamicMetaObject mo = objects[i]; + res[i] = mo != null ? mo.Expression : null; + } + + return res; + } + + /// <summary> + /// Creates an instance of <see cref="DynamicMetaObject"/> for a runtime value and the expression that represents it during the binding process. + /// </summary> + /// <param name="argValue">The runtime value to be represented by the <see cref="DynamicMetaObject"/>.</param> + /// <param name="parameterExpression">An expression to represent this <see cref="DynamicMetaObject"/> during the binding process.</param> + /// <returns>The new instance of <see cref="DynamicMetaObject"/>.</returns> + public static DynamicMetaObject ObjectToMetaObject(object argValue, Expression parameterExpression) { + IDynamicMetaObjectProvider ido = argValue as IDynamicMetaObjectProvider; + if (ido != null) { + return ido.GetMetaObject(parameterExpression); + } else { + return new DynamicMetaObject(parameterExpression, BindingRestrictions.Empty, argValue); + } + } + + /// <summary> + /// Produces an interpreted binding using the given binder which falls over to a compiled + /// binding after hitCount tries. + /// + /// This method should be called whenever an interpreted binding is required. Sometimes it will + /// return a compiled binding if a previous binding was produced and it's hit count was exhausted. + /// In this case the binder will not be called back for a new binding - the previous one will + /// be used. + /// </summary> + /// <typeparam name="T">The delegate type being used for the call site</typeparam> + /// <param name="binder">The binder used for the call site</param> + /// <param name="compilationThreshold">The number of calls before the binder should switch to a compiled mode.</param> + /// <param name="args">The arguments that are passed for the binding (as received in a BindDelegate call)</param> + /// <returns>A delegate which represents the interpreted binding.</returns> + public static T/*!*/ LightBind<T>(this DynamicMetaObjectBinder/*!*/ binder, object[]/*!*/ args, int compilationThreshold) where T : class { + ContractUtils.RequiresNotNull(binder, "binder"); + ContractUtils.RequiresNotNull(args, "args"); + + return GenericInterpretedBinder<T>.Instance.Bind(binder, compilationThreshold < 0 ? LightCompiler.DefaultCompilationThreshold : compilationThreshold, args); + } + + private class GenericInterpretedBinder<T> where T : class { + public static GenericInterpretedBinder<T>/*!*/ Instance = new GenericInterpretedBinder<T>(); + private readonly ReadOnlyCollection<ParameterExpression>/*!*/ _parameters; + private readonly Expression/*!*/ _updateExpression; + + private GenericInterpretedBinder() { + var invokeMethod = typeof(T).GetMethod("Invoke"); + var methodParams = invokeMethod.GetParameters(); + + ReadOnlyCollectionBuilder<ParameterExpression> prms = new ReadOnlyCollectionBuilder<ParameterExpression>(methodParams.Length); + ReadOnlyCollectionBuilder<Expression> invokePrms = new ReadOnlyCollectionBuilder<Expression>(methodParams.Length); + for (int i = 0; i < methodParams.Length; i++) { + var param = Expression.Parameter(methodParams[i].ParameterType); + if (i == 0) { + invokePrms.Add(Expression.Convert(param, typeof(CallSite<T>))); + } else { + invokePrms.Add(param); + } + prms.Add(param); + } + + _parameters = prms.ToReadOnlyCollection(); + + _updateExpression = Expression.Block( + Expression.Label(CallSiteBinder.UpdateLabel), + Expression.Invoke( + Expression.Property( + invokePrms[0], + typeof(CallSite<T>).GetDeclaredProperty("Update") + ), + invokePrms.ToReadOnlyCollection() + ) + ); + } + + public T/*!*/ Bind(DynamicMetaObjectBinder/*!*/ binder, int compilationThreshold, object[] args) { + if (CachedBindingInfo<T>.LastInterpretedFailure != null && CachedBindingInfo<T>.LastInterpretedFailure.Binder == binder) { + // we failed the rule because we have a compiled target available, return the compiled target + Debug.Assert(CachedBindingInfo<T>.LastInterpretedFailure.CompiledTarget != null); + var res = CachedBindingInfo<T>.LastInterpretedFailure.CompiledTarget; + CachedBindingInfo<T>.LastInterpretedFailure = null; + return res; + } + + // we haven't produced a rule yet.... + var bindingInfo = new CachedBindingInfo<T>(binder, compilationThreshold); + + var targetMO = DynamicMetaObject.Create(args[0], _parameters[1]); // 1 is skipping CallSite + DynamicMetaObject[] argsMO = new DynamicMetaObject[args.Length - 1]; + for (int i = 0; i < argsMO.Length; i++) { + argsMO[i] = DynamicMetaObject.Create(args[i + 1], _parameters[i + 2]); + } + var binding = binder.Bind(targetMO, argsMO); + + return CreateDelegate(binding, bindingInfo); + } + + private T/*!*/ CreateDelegate(DynamicMetaObject/*!*/ binding, CachedBindingInfo<T>/*!*/ bindingInfo) { + return Compile(binding, bindingInfo).LightCompile(Int32.MaxValue); + } + + private Expression<T>/*!*/ Compile(DynamicMetaObject/*!*/ obj, CachedBindingInfo<T>/*!*/ bindingInfo) { + var restrictions = obj.Restrictions.ToExpression(); + + var body = Expression.Condition( + new InterpretedRuleHitCheckExpression(restrictions, bindingInfo), + AstUtils.Convert(obj.Expression, _updateExpression.Type), + _updateExpression + ); + + var res = Expression.Lambda<T>( + body, + "CallSite.Target", + true, // always compile the rules with tail call optimization + _parameters + ); + + bindingInfo.Target = res; + return res; + } + + /// <summary> + /// Expression which reduces to the normal test but under the interpreter adds a count down + /// check which enables compiling when the count down is reached. + /// </summary> + class InterpretedRuleHitCheckExpression : Expression, IInstructionProvider { + private readonly Expression/*!*/ _test; + private readonly CachedBindingInfo/*!*/ _bindingInfo; + + private static readonly MethodInfo InterpretedCallSiteTest = typeof(ScriptingRuntimeHelpers).GetMethod("InterpretedCallSiteTest"); + public InterpretedRuleHitCheckExpression(Expression/*!*/ test, CachedBindingInfo/*!*/ bindingInfo) { + Assert.NotNull(test, bindingInfo); + + _test = test; + _bindingInfo = bindingInfo; + } + + public override Expression Reduce() { + return _test; + } + + protected override Expression VisitChildren(ExpressionVisitor visitor) { + var test = visitor.Visit(_test); + if (test != _test) { + return new InterpretedRuleHitCheckExpression(test, _bindingInfo); + } + return this; + } + + public override bool CanReduce { + get { return true; } + } + + public override ExpressionType NodeType { + get { return ExpressionType.Extension; } + } + + public override Type Type { + get { return typeof(bool); } + } + + #region IInstructionProvider Members + + public void AddInstructions(LightCompiler compiler) { + compiler.Compile(_test); + compiler.Instructions.EmitLoad(_bindingInfo); + compiler.EmitCall(InterpretedCallSiteTest); + } + + #endregion + } + } + } + + + /// <summary> + /// Base class for storing information about the binding that a specific rule is applicable for. + /// + /// We have a derived generic class but this class enables us to refer to it w/o having the + /// generic type information around. + /// + /// This class tracks both the count down to when we should compile. When we compile we + /// take the Expression[T] that was used before and compile it. While this is happening + /// we continue to allow the interpreted code to run. When the compilation is complete we + /// store a thread static which tells us what binding failed and the current rule is no + /// longer functional. Finally the language binder will call us again and we'll retrieve + /// and return the compiled overload. + /// </summary> + abstract class CachedBindingInfo { + public readonly DynamicMetaObjectBinder/*!*/ Binder; + public int CompilationThreshold; + + public CachedBindingInfo(DynamicMetaObjectBinder binder, int compilationThreshold) { + Binder = binder; + CompilationThreshold = compilationThreshold; + } + + public abstract bool CheckCompiled(); + } + + class CachedBindingInfo<T> : CachedBindingInfo where T : class { + public T CompiledTarget; + public Expression<T> Target; + + [ThreadStatic] + public static CachedBindingInfo<T> LastInterpretedFailure; + + public CachedBindingInfo(DynamicMetaObjectBinder binder, int compilationThreshold) + : base(binder, compilationThreshold) { + } + + public override bool CheckCompiled() { + if (Target != null) { + // start compiling the target if no one else has + var lambda = Interlocked.Exchange(ref Target, null); + if (lambda != null) { +#if FEATURE_TASKS + new Task(() => { CompiledTarget = lambda.Compile(); }).Start(); +#else + ThreadPool.QueueUserWorkItem(x => { CompiledTarget = lambda.Compile(); }); +#endif + } + } + + if (CompiledTarget != null) { + LastInterpretedFailure = this; + return false; + } + + return true; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ExceptionFactory.Generated.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ExceptionFactory.Generated.cs new file mode 100644 index 00000000000..1214351549a --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ExceptionFactory.Generated.cs @@ -0,0 +1,1050 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; + +namespace Microsoft.Scripting { + + internal static partial class Strings { + private static string FormatString(string format, params object[] args) { + return string.Format(System.Globalization.CultureInfo.CurrentCulture, format, args); + } + } + + #region Generated Microsoft.Scripting Exception Factory + + // *** BEGIN GENERATED CODE *** + // generated by function: gen_expr_factory_scripting from: generate_exception_factory.py + + /// <summary> + /// Strongly-typed and parameterized string factory. + /// </summary> + + internal static partial class Strings { + /// <summary> + /// A string like "Cannot access member {1} declared on type {0} because the type contains generic parameters." + /// </summary> + internal static string InvalidOperation_ContainsGenericParameters(object p0, object p1) { + return FormatString("Cannot access member {1} declared on type {0} because the type contains generic parameters.", p0, p1); + } + + /// <summary> + /// A string like "Type '{0}' is missing or cannot be loaded." + /// </summary> + internal static string MissingType(object p0) { + return FormatString("Type '{0}' is missing or cannot be loaded.", p0); + } + + /// <summary> + /// A string like "static property "{0}" of "{1}" can only be read through a type, not an instance" + /// </summary> + internal static string StaticAccessFromInstanceError(object p0, object p1) { + return FormatString("static property \"{0}\" of \"{1}\" can only be read through a type, not an instance", p0, p1); + } + + /// <summary> + /// A string like "static property "{0}" of "{1}" can only be assigned to through a type, not an instance" + /// </summary> + internal static string StaticAssignmentFromInstanceError(object p0, object p1) { + return FormatString("static property \"{0}\" of \"{1}\" can only be assigned to through a type, not an instance", p0, p1); + } + + /// <summary> + /// A string like "Method precondition violated" + /// </summary> + internal static string MethodPreconditionViolated { + get { + return "Method precondition violated"; + } + } + + /// <summary> + /// A string like "Invalid argument value" + /// </summary> + internal static string InvalidArgumentValue { + get { + return "Invalid argument value"; + } + } + + /// <summary> + /// A string like "Non-empty string required" + /// </summary> + internal static string NonEmptyStringRequired { + get { + return "Non-empty string required"; + } + } + + /// <summary> + /// A string like "Non-empty collection required" + /// </summary> + internal static string NonEmptyCollectionRequired { + get { + return "Non-empty collection required"; + } + } + + /// <summary> + /// A string like "must by an Exception instance" + /// </summary> + internal static string MustBeExceptionInstance { + get { + return "must by an Exception instance"; + } + } + + /// <summary> + /// A string like "Type of test must be bool" + /// </summary> + internal static string TypeOfTestMustBeBool { + get { + return "Type of test must be bool"; + } + } + + /// <summary> + /// A string like "Type of the expression must be bool" + /// </summary> + internal static string TypeOfExpressionMustBeBool { + get { + return "Type of the expression must be bool"; + } + } + + /// <summary> + /// A string like "Empty string is not a valid path." + /// </summary> + internal static string EmptyStringIsInvalidPath { + get { + return "Empty string is not a valid path."; + } + } + + /// <summary> + /// A string like "Invalid delegate type (Invoke method not found)." + /// </summary> + internal static string InvalidDelegate { + get { + return "Invalid delegate type (Invoke method not found)."; + } + } + + /// <summary> + /// A string like "expected only static property" + /// </summary> + internal static string ExpectedStaticProperty { + get { + return "expected only static property"; + } + } + + /// <summary> + /// A string like "Property doesn't exist on the provided type" + /// </summary> + internal static string PropertyDoesNotExist { + get { + return "Property doesn't exist on the provided type"; + } + } + + /// <summary> + /// A string like "Field doesn't exist on provided type" + /// </summary> + internal static string FieldDoesNotExist { + get { + return "Field doesn't exist on provided type"; + } + } + + /// <summary> + /// A string like "Type doesn't have constructor with a given signature" + /// </summary> + internal static string TypeDoesNotHaveConstructorForTheSignature { + get { + return "Type doesn't have constructor with a given signature"; + } + } + + /// <summary> + /// A string like "Type doesn't have a method with a given name." + /// </summary> + internal static string TypeDoesNotHaveMethodForName { + get { + return "Type doesn't have a method with a given name."; + } + } + + /// <summary> + /// A string like "Type doesn't have a method with a given name and signature." + /// </summary> + internal static string TypeDoesNotHaveMethodForNameSignature { + get { + return "Type doesn't have a method with a given name and signature."; + } + } + + /// <summary> + /// A string like "Count must be non-negative." + /// </summary> + internal static string CountCannotBeNegative { + get { + return "Count must be non-negative."; + } + } + + /// <summary> + /// A string like "arrayType must be an array type" + /// </summary> + internal static string ArrayTypeMustBeArray { + get { + return "arrayType must be an array type"; + } + } + + /// <summary> + /// A string like "Either code or target must be specified." + /// </summary> + internal static string MustHaveCodeOrTarget { + get { + return "Either code or target must be specified."; + } + } + + /// <summary> + /// A string like "Type parameter is {0}. Expected a delegate." + /// </summary> + internal static string TypeParameterIsNotDelegate(object p0) { + return FormatString("Type parameter is {0}. Expected a delegate.", p0); + } + + /// <summary> + /// A string like "Cannot cast from type '{0}' to type '{1}" + /// </summary> + internal static string InvalidCast(object p0, object p1) { + return FormatString("Cannot cast from type '{0}' to type '{1}", p0, p1); + } + + /// <summary> + /// A string like "unknown member type: '{0}'. " + /// </summary> + internal static string UnknownMemberType(object p0) { + return FormatString("unknown member type: '{0}'. ", p0); + } + + /// <summary> + /// A string like "RuleBuilder can only be used with delegates whose first argument is CallSite." + /// </summary> + internal static string FirstArgumentMustBeCallSite { + get { + return "RuleBuilder can only be used with delegates whose first argument is CallSite."; + } + } + + /// <summary> + /// A string like "no instance for call." + /// </summary> + internal static string NoInstanceForCall { + get { + return "no instance for call."; + } + } + + /// <summary> + /// A string like "Missing Test." + /// </summary> + internal static string MissingTest { + get { + return "Missing Test."; + } + } + + /// <summary> + /// A string like "Missing Target." + /// </summary> + internal static string MissingTarget { + get { + return "Missing Target."; + } + } + + /// <summary> + /// A string like "The operation requires a non-generic type for {0}, but this represents generic types only" + /// </summary> + internal static string NonGenericWithGenericGroup(object p0) { + return FormatString("The operation requires a non-generic type for {0}, but this represents generic types only", p0); + } + + /// <summary> + /// A string like "Invalid operation: '{0}'" + /// </summary> + internal static string InvalidOperation(object p0) { + return FormatString("Invalid operation: '{0}'", p0); + } + + /// <summary> + /// A string like "Finally already defined." + /// </summary> + internal static string FinallyAlreadyDefined { + get { + return "Finally already defined."; + } + } + + /// <summary> + /// A string like "Can not have fault and finally." + /// </summary> + internal static string CannotHaveFaultAndFinally { + get { + return "Can not have fault and finally."; + } + } + + /// <summary> + /// A string like "Fault already defined." + /// </summary> + internal static string FaultAlreadyDefined { + get { + return "Fault already defined."; + } + } + + /// <summary> + /// A string like "Cannot create default value for type {0}." + /// </summary> + internal static string CantCreateDefaultTypeFor(object p0) { + return FormatString("Cannot create default value for type {0}.", p0); + } + + /// <summary> + /// A string like "Unhandled convert: {0}" + /// </summary> + internal static string UnhandledConvert(object p0) { + return FormatString("Unhandled convert: {0}", p0); + } + + /// <summary> + /// A string like "{0}.{1} has no publiclly visible method." + /// </summary> + internal static string NoCallableMethods(object p0, object p1) { + return FormatString("{0}.{1} has no publiclly visible method.", p0, p1); + } + + /// <summary> + /// A string like "Global/top-level local variable names must be unique." + /// </summary> + internal static string GlobalsMustBeUnique { + get { + return "Global/top-level local variable names must be unique."; + } + } + + /// <summary> + /// A string like "Generating code from non-serializable CallSiteBinder." + /// </summary> + internal static string GenNonSerializableBinder { + get { + return "Generating code from non-serializable CallSiteBinder."; + } + } + + /// <summary> + /// A string like "pecified path is invalid." + /// </summary> + internal static string InvalidPath { + get { + return "pecified path is invalid."; + } + } + + /// <summary> + /// A string like "Dictionaries are not hashable." + /// </summary> + internal static string DictionaryNotHashable { + get { + return "Dictionaries are not hashable."; + } + } + + /// <summary> + /// A string like "language already registered." + /// </summary> + internal static string LanguageRegistered { + get { + return "language already registered."; + } + } + + /// <summary> + /// A string like "The method or operation is not implemented." + /// </summary> + internal static string MethodOrOperatorNotImplemented { + get { + return "The method or operation is not implemented."; + } + } + + /// <summary> + /// A string like "No exception." + /// </summary> + internal static string NoException { + get { + return "No exception."; + } + } + + /// <summary> + /// A string like "Extension type {0} must be public." + /// </summary> + internal static string ExtensionMustBePublic(object p0) { + return FormatString("Extension type {0} must be public.", p0); + } + + /// <summary> + /// A string like "Already initialized." + /// </summary> + internal static string AlreadyInitialized { + get { + return "Already initialized."; + } + } + + /// <summary> + /// A string like "CreateScopeExtension must return a scope extension." + /// </summary> + internal static string MustReturnScopeExtension { + get { + return "CreateScopeExtension must return a scope extension."; + } + } + + /// <summary> + /// A string like "Invalid number of parameters for the service." + /// </summary> + internal static string InvalidParamNumForService { + get { + return "Invalid number of parameters for the service."; + } + } + + /// <summary> + /// A string like "Invalid type of argument {0}; expecting {1}." + /// </summary> + internal static string InvalidArgumentType(object p0, object p1) { + return FormatString("Invalid type of argument {0}; expecting {1}.", p0, p1); + } + + /// <summary> + /// A string like "Cannot change non-caching value." + /// </summary> + internal static string CannotChangeNonCachingValue { + get { + return "Cannot change non-caching value."; + } + } + + /// <summary> + /// A string like "Field {0} is read-only" + /// </summary> + internal static string FieldReadonly(object p0) { + return FormatString("Field {0} is read-only", p0); + } + + /// <summary> + /// A string like "Property {0} is read-only" + /// </summary> + internal static string PropertyReadonly(object p0) { + return FormatString("Property {0} is read-only", p0); + } + + /// <summary> + /// A string like "Expected event from {0}.{1}, got event from {2}.{3}." + /// </summary> + internal static string UnexpectedEvent(object p0, object p1, object p2, object p3) { + return FormatString("Expected event from {0}.{1}, got event from {2}.{3}.", p0, p1, p2, p3); + } + + /// <summary> + /// A string like "expected bound event, got {0}." + /// </summary> + internal static string ExpectedBoundEvent(object p0) { + return FormatString("expected bound event, got {0}.", p0); + } + + /// <summary> + /// A string like "Expected type {0}, got {1}." + /// </summary> + internal static string UnexpectedType(object p0, object p1) { + return FormatString("Expected type {0}, got {1}.", p0, p1); + } + + /// <summary> + /// A string like "can only write to member {0}." + /// </summary> + internal static string MemberWriteOnly(object p0) { + return FormatString("can only write to member {0}.", p0); + } + + /// <summary> + /// A string like "No code to compile." + /// </summary> + internal static string NoCodeToCompile { + get { + return "No code to compile."; + } + } + + /// <summary> + /// A string like "Invalid stream type: {0}." + /// </summary> + internal static string InvalidStreamType(object p0) { + return FormatString("Invalid stream type: {0}.", p0); + } + + /// <summary> + /// A string like "Queue empty." + /// </summary> + internal static string QueueEmpty { + get { + return "Queue empty."; + } + } + + /// <summary> + /// A string like "Enumeration has not started. Call MoveNext." + /// </summary> + internal static string EnumerationNotStarted { + get { + return "Enumeration has not started. Call MoveNext."; + } + } + + /// <summary> + /// A string like "Enumeration already finished." + /// </summary> + internal static string EnumerationFinished { + get { + return "Enumeration already finished."; + } + } + + /// <summary> + /// A string like "can't add another casing for identifier {0}" + /// </summary> + internal static string CantAddCasing(object p0) { + return FormatString("can't add another casing for identifier {0}", p0); + } + + /// <summary> + /// A string like "can't add new identifier {0}" + /// </summary> + internal static string CantAddIdentifier(object p0) { + return FormatString("can't add new identifier {0}", p0); + } + + /// <summary> + /// A string like "Type '{0}' doesn't provide a suitable public constructor or its implementation is faulty: {1}" + /// </summary> + internal static string InvalidCtorImplementation(object p0, object p1) { + return FormatString("Type '{0}' doesn't provide a suitable public constructor or its implementation is faulty: {1}", p0, p1); + } + + /// <summary> + /// A string like "Invalid output directory." + /// </summary> + internal static string InvalidOutputDir { + get { + return "Invalid output directory."; + } + } + + /// <summary> + /// A string like "Invalid assembly name or file extension." + /// </summary> + internal static string InvalidAsmNameOrExtension { + get { + return "Invalid assembly name or file extension."; + } + } + + /// <summary> + /// A string like "Cannot emit constant {0} ({1})" + /// </summary> + internal static string CanotEmitConstant(object p0, object p1) { + return FormatString("Cannot emit constant {0} ({1})", p0, p1); + } + + /// <summary> + /// A string like "No implicit cast from {0} to {1}" + /// </summary> + internal static string NoImplicitCast(object p0, object p1) { + return FormatString("No implicit cast from {0} to {1}", p0, p1); + } + + /// <summary> + /// A string like "No explicit cast from {0} to {1}" + /// </summary> + internal static string NoExplicitCast(object p0, object p1) { + return FormatString("No explicit cast from {0} to {1}", p0, p1); + } + + /// <summary> + /// A string like "name '{0}' not defined" + /// </summary> + internal static string NameNotDefined(object p0) { + return FormatString("name '{0}' not defined", p0); + } + + /// <summary> + /// A string like "No default value for a given type." + /// </summary> + internal static string NoDefaultValue { + get { + return "No default value for a given type."; + } + } + + /// <summary> + /// A string like "Specified language provider type is not registered." + /// </summary> + internal static string UnknownLanguageProviderType { + get { + return "Specified language provider type is not registered."; + } + } + + /// <summary> + /// A string like "can't read from property" + /// </summary> + internal static string CantReadProperty { + get { + return "can't read from property"; + } + } + + /// <summary> + /// A string like "can't write to property" + /// </summary> + internal static string CantWriteProperty { + get { + return "can't write to property"; + } + } + + /// <summary> + /// A string like "Cannot create instance of {0} because it contains generic parameters" + /// </summary> + internal static string IllegalNew_GenericParams(object p0) { + return FormatString("Cannot create instance of {0} because it contains generic parameters", p0); + } + + /// <summary> + /// A string like "Non-verifiable assembly generated: {0}:\nAssembly preserved as {1}\nError text:\n{2}\n" + /// </summary> + internal static string VerificationException(object p0, object p1, object p2) { + return FormatString("Non-verifiable assembly generated: {0}:\nAssembly preserved as {1}\nError text:\n{2}\n", p0, p1, p2); + } + + } + /// <summary> + /// Strongly-typed and parameterized exception factory. + /// </summary> + + internal static partial class Error { + /// <summary> + /// ArgumentException with message like "Either code or target must be specified." + /// </summary> + internal static Exception MustHaveCodeOrTarget() { + return new ArgumentException(Strings.MustHaveCodeOrTarget); + } + + /// <summary> + /// InvalidOperationException with message like "Type parameter is {0}. Expected a delegate." + /// </summary> + internal static Exception TypeParameterIsNotDelegate(object p0) { + return new InvalidOperationException(Strings.TypeParameterIsNotDelegate(p0)); + } + + /// <summary> + /// InvalidOperationException with message like "Cannot cast from type '{0}' to type '{1}" + /// </summary> + internal static Exception InvalidCast(object p0, object p1) { + return new InvalidOperationException(Strings.InvalidCast(p0, p1)); + } + + /// <summary> + /// InvalidOperationException with message like "unknown member type: '{0}'. " + /// </summary> + internal static Exception UnknownMemberType(object p0) { + return new InvalidOperationException(Strings.UnknownMemberType(p0)); + } + + /// <summary> + /// InvalidOperationException with message like "RuleBuilder can only be used with delegates whose first argument is CallSite." + /// </summary> + internal static Exception FirstArgumentMustBeCallSite() { + return new InvalidOperationException(Strings.FirstArgumentMustBeCallSite); + } + + /// <summary> + /// InvalidOperationException with message like "no instance for call." + /// </summary> + internal static Exception NoInstanceForCall() { + return new InvalidOperationException(Strings.NoInstanceForCall); + } + + /// <summary> + /// InvalidOperationException with message like "Missing Test." + /// </summary> + internal static Exception MissingTest() { + return new InvalidOperationException(Strings.MissingTest); + } + + /// <summary> + /// InvalidOperationException with message like "Missing Target." + /// </summary> + internal static Exception MissingTarget() { + return new InvalidOperationException(Strings.MissingTarget); + } + + /// <summary> + /// TypeLoadException with message like "The operation requires a non-generic type for {0}, but this represents generic types only" + /// </summary> + internal static Exception NonGenericWithGenericGroup(object p0) { + return new TypeLoadException(Strings.NonGenericWithGenericGroup(p0)); + } + + /// <summary> + /// ArgumentException with message like "Invalid operation: '{0}'" + /// </summary> + internal static Exception InvalidOperation(object p0) { + return new ArgumentException(Strings.InvalidOperation(p0)); + } + + /// <summary> + /// InvalidOperationException with message like "Finally already defined." + /// </summary> + internal static Exception FinallyAlreadyDefined() { + return new InvalidOperationException(Strings.FinallyAlreadyDefined); + } + + /// <summary> + /// InvalidOperationException with message like "Can not have fault and finally." + /// </summary> + internal static Exception CannotHaveFaultAndFinally() { + return new InvalidOperationException(Strings.CannotHaveFaultAndFinally); + } + + /// <summary> + /// InvalidOperationException with message like "Fault already defined." + /// </summary> + internal static Exception FaultAlreadyDefined() { + return new InvalidOperationException(Strings.FaultAlreadyDefined); + } + + /// <summary> + /// ArgumentException with message like "Cannot create default value for type {0}." + /// </summary> + internal static Exception CantCreateDefaultTypeFor(object p0) { + return new ArgumentException(Strings.CantCreateDefaultTypeFor(p0)); + } + + /// <summary> + /// ArgumentException with message like "Unhandled convert: {0}" + /// </summary> + internal static Exception UnhandledConvert(object p0) { + return new ArgumentException(Strings.UnhandledConvert(p0)); + } + + /// <summary> + /// InvalidOperationException with message like "{0}.{1} has no publiclly visible method." + /// </summary> + internal static Exception NoCallableMethods(object p0, object p1) { + return new InvalidOperationException(Strings.NoCallableMethods(p0, p1)); + } + + /// <summary> + /// ArgumentException with message like "Global/top-level local variable names must be unique." + /// </summary> + internal static Exception GlobalsMustBeUnique() { + return new ArgumentException(Strings.GlobalsMustBeUnique); + } + + /// <summary> + /// ArgumentException with message like "Generating code from non-serializable CallSiteBinder." + /// </summary> + internal static Exception GenNonSerializableBinder() { + return new ArgumentException(Strings.GenNonSerializableBinder); + } + + /// <summary> + /// ArgumentException with message like "pecified path is invalid." + /// </summary> + internal static Exception InvalidPath() { + return new ArgumentException(Strings.InvalidPath); + } + + /// <summary> + /// ArgumentTypeException with message like "Dictionaries are not hashable." + /// </summary> + internal static Exception DictionaryNotHashable() { + return new ArgumentTypeException(Strings.DictionaryNotHashable); + } + + /// <summary> + /// InvalidOperationException with message like "language already registered." + /// </summary> + internal static Exception LanguageRegistered() { + return new InvalidOperationException(Strings.LanguageRegistered); + } + + /// <summary> + /// NotImplementedException with message like "The method or operation is not implemented." + /// </summary> + internal static Exception MethodOrOperatorNotImplemented() { + return new NotImplementedException(Strings.MethodOrOperatorNotImplemented); + } + + /// <summary> + /// InvalidOperationException with message like "No exception." + /// </summary> + internal static Exception NoException() { + return new InvalidOperationException(Strings.NoException); + } + + /// <summary> + /// ArgumentException with message like "Extension type {0} must be public." + /// </summary> + internal static Exception ExtensionMustBePublic(object p0) { + return new ArgumentException(Strings.ExtensionMustBePublic(p0)); + } + + /// <summary> + /// InvalidOperationException with message like "Already initialized." + /// </summary> + internal static Exception AlreadyInitialized() { + return new InvalidOperationException(Strings.AlreadyInitialized); + } + + /// <summary> + /// InvalidImplementationException with message like "CreateScopeExtension must return a scope extension." + /// </summary> + internal static Exception MustReturnScopeExtension() { + return new InvalidImplementationException(Strings.MustReturnScopeExtension); + } + + /// <summary> + /// ArgumentException with message like "Invalid number of parameters for the service." + /// </summary> + internal static Exception InvalidParamNumForService() { + return new ArgumentException(Strings.InvalidParamNumForService); + } + + /// <summary> + /// ArgumentException with message like "Invalid type of argument {0}; expecting {1}." + /// </summary> + internal static Exception InvalidArgumentType(object p0, object p1) { + return new ArgumentException(Strings.InvalidArgumentType(p0, p1)); + } + + /// <summary> + /// ArgumentException with message like "Cannot change non-caching value." + /// </summary> + internal static Exception CannotChangeNonCachingValue() { + return new ArgumentException(Strings.CannotChangeNonCachingValue); + } + + /// <summary> + /// MissingMemberException with message like "Field {0} is read-only" + /// </summary> + internal static Exception FieldReadonly(object p0) { + return new MissingMemberException(Strings.FieldReadonly(p0)); + } + + /// <summary> + /// MissingMemberException with message like "Property {0} is read-only" + /// </summary> + internal static Exception PropertyReadonly(object p0) { + return new MissingMemberException(Strings.PropertyReadonly(p0)); + } + + /// <summary> + /// ArgumentException with message like "Expected event from {0}.{1}, got event from {2}.{3}." + /// </summary> + internal static Exception UnexpectedEvent(object p0, object p1, object p2, object p3) { + return new ArgumentException(Strings.UnexpectedEvent(p0, p1, p2, p3)); + } + + /// <summary> + /// ArgumentTypeException with message like "expected bound event, got {0}." + /// </summary> + internal static Exception ExpectedBoundEvent(object p0) { + return new ArgumentTypeException(Strings.ExpectedBoundEvent(p0)); + } + + /// <summary> + /// ArgumentTypeException with message like "Expected type {0}, got {1}." + /// </summary> + internal static Exception UnexpectedType(object p0, object p1) { + return new ArgumentTypeException(Strings.UnexpectedType(p0, p1)); + } + + /// <summary> + /// MemberAccessException with message like "can only write to member {0}." + /// </summary> + internal static Exception MemberWriteOnly(object p0) { + return new MemberAccessException(Strings.MemberWriteOnly(p0)); + } + + /// <summary> + /// InvalidOperationException with message like "No code to compile." + /// </summary> + internal static Exception NoCodeToCompile() { + return new InvalidOperationException(Strings.NoCodeToCompile); + } + + /// <summary> + /// ArgumentException with message like "Invalid stream type: {0}." + /// </summary> + internal static Exception InvalidStreamType(object p0) { + return new ArgumentException(Strings.InvalidStreamType(p0)); + } + + /// <summary> + /// InvalidOperationException with message like "Queue empty." + /// </summary> + internal static Exception QueueEmpty() { + return new InvalidOperationException(Strings.QueueEmpty); + } + + /// <summary> + /// InvalidOperationException with message like "Enumeration has not started. Call MoveNext." + /// </summary> + internal static Exception EnumerationNotStarted() { + return new InvalidOperationException(Strings.EnumerationNotStarted); + } + + /// <summary> + /// InvalidOperationException with message like "Enumeration already finished." + /// </summary> + internal static Exception EnumerationFinished() { + return new InvalidOperationException(Strings.EnumerationFinished); + } + + /// <summary> + /// InvalidOperationException with message like "can't add another casing for identifier {0}" + /// </summary> + internal static Exception CantAddCasing(object p0) { + return new InvalidOperationException(Strings.CantAddCasing(p0)); + } + + /// <summary> + /// InvalidOperationException with message like "can't add new identifier {0}" + /// </summary> + internal static Exception CantAddIdentifier(object p0) { + return new InvalidOperationException(Strings.CantAddIdentifier(p0)); + } + + /// <summary> + /// ArgumentException with message like "Invalid output directory." + /// </summary> + internal static Exception InvalidOutputDir() { + return new ArgumentException(Strings.InvalidOutputDir); + } + + /// <summary> + /// ArgumentException with message like "Invalid assembly name or file extension." + /// </summary> + internal static Exception InvalidAsmNameOrExtension() { + return new ArgumentException(Strings.InvalidAsmNameOrExtension); + } + + /// <summary> + /// ArgumentException with message like "Cannot emit constant {0} ({1})" + /// </summary> + internal static Exception CanotEmitConstant(object p0, object p1) { + return new ArgumentException(Strings.CanotEmitConstant(p0, p1)); + } + + /// <summary> + /// ArgumentException with message like "No implicit cast from {0} to {1}" + /// </summary> + internal static Exception NoImplicitCast(object p0, object p1) { + return new ArgumentException(Strings.NoImplicitCast(p0, p1)); + } + + /// <summary> + /// ArgumentException with message like "No explicit cast from {0} to {1}" + /// </summary> + internal static Exception NoExplicitCast(object p0, object p1) { + return new ArgumentException(Strings.NoExplicitCast(p0, p1)); + } + + /// <summary> + /// MissingMemberException with message like "name '{0}' not defined" + /// </summary> + internal static Exception NameNotDefined(object p0) { + return new MissingMemberException(Strings.NameNotDefined(p0)); + } + + /// <summary> + /// ArgumentException with message like "No default value for a given type." + /// </summary> + internal static Exception NoDefaultValue() { + return new ArgumentException(Strings.NoDefaultValue); + } + + /// <summary> + /// ArgumentException with message like "Specified language provider type is not registered." + /// </summary> + internal static Exception UnknownLanguageProviderType() { + return new ArgumentException(Strings.UnknownLanguageProviderType); + } + + /// <summary> + /// InvalidOperationException with message like "can't read from property" + /// </summary> + internal static Exception CantReadProperty() { + return new InvalidOperationException(Strings.CantReadProperty); + } + + /// <summary> + /// InvalidOperationException with message like "can't write to property" + /// </summary> + internal static Exception CantWriteProperty() { + return new InvalidOperationException(Strings.CantWriteProperty); + } + + /// <summary> + /// ArgumentException with message like "Cannot create instance of {0} because it contains generic parameters" + /// </summary> + internal static Exception IllegalNew_GenericParams(object p0) { + return new ArgumentException(Strings.IllegalNew_GenericParams(p0)); + } + + /// <summary> + /// System.Security.VerificationException with message like "Non-verifiable assembly generated: {0}:\nAssembly preserved as {1}\nError text:\n{2}\n" + /// </summary> + internal static Exception VerificationException(object p0, object p1, object p2) { + return new System.Security.VerificationException(Strings.VerificationException(p0, p1, p2)); + } + + } + + // *** END GENERATED CODE *** + + #endregion + +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ExceptionUtils.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ExceptionUtils.cs new file mode 100644 index 00000000000..89449659612 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ExceptionUtils.cs @@ -0,0 +1,111 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Collections.Generic; +using System.Threading; + +namespace Microsoft.Scripting.Utils { + public static class ExceptionUtils { + public static ArgumentOutOfRangeException MakeArgumentOutOfRangeException(string paramName, object actualValue, string message) { +#if SILVERLIGHT || WP75 // ArgumentOutOfRangeException ctor overload + throw new ArgumentOutOfRangeException(paramName, string.Format("{0} (actual value is '{1}')", message, actualValue)); +#else + throw new ArgumentOutOfRangeException(paramName, actualValue, message); +#endif + } + + public static ArgumentNullException MakeArgumentItemNullException(int index, string arrayName) { + return new ArgumentNullException(String.Format("{0}[{1}]", arrayName, index)); + } + +#if FEATURE_REMOTING + public static object GetData(this Exception e, object key) { + return e.Data[key]; + } + + public static void SetData(this Exception e, object key, object data) { + e.Data[key] = data; + } + + public static void RemoveData(this Exception e, object key) { + e.Data.Remove(key); + } +#else + +#if WP75 + private static WeakDictionary<Exception, List<KeyValuePair<object, object>>> _exceptionData; +#else + private static ConditionalWeakTable<Exception, List<KeyValuePair<object, object>>> _exceptionData; +#endif + + public static void SetData(this Exception e, object key, object value) { + if (_exceptionData == null) { +#if WP75 + Interlocked.CompareExchange(ref _exceptionData, new WeakDictionary<Exception, List<KeyValuePair<object, object>>>(), null); +#else + Interlocked.CompareExchange(ref _exceptionData, new ConditionalWeakTable<Exception, List<KeyValuePair<object, object>>>(), null); +#endif + } + + lock (_exceptionData) { + var data = _exceptionData.GetOrCreateValue(e); + + int index = data.FindIndex(entry => entry.Key == key); + if (index >= 0) { + data[index] = new KeyValuePair<object, object>(key, value); + } else { + data.Add(new KeyValuePair<object, object>(key, value)); + } + } + } + + public static object GetData(this Exception e, object key) { + if (_exceptionData == null) { + return null; + } + + lock (_exceptionData) { + List<KeyValuePair<object, object>> data; + if (!_exceptionData.TryGetValue(e, out data)) { + return null; + } + + return data.FirstOrDefault(entry => entry.Key == key).Value; + } + } + + public static void RemoveData(this Exception e, object key) { + if (_exceptionData == null) { + return; + } + + lock (_exceptionData) { + List<KeyValuePair<object, object>> data; + if (!_exceptionData.TryGetValue(e, out data)) { + return; + } + + int index = data.FindIndex(entry => entry.Key == key); + if (index >= 0) { + data.RemoveAt(index); + } + } + } +#endif + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/HybridReferenceDictionary.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/HybridReferenceDictionary.cs new file mode 100644 index 00000000000..13b62d45f07 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/HybridReferenceDictionary.cs @@ -0,0 +1,170 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; + +namespace Microsoft.Scripting.Utils { + /// <summary> + /// A hybrid dictionary which compares based upon object identity. + /// </summary> + class HybridReferenceDictionary<TKey, TValue> where TKey : class { + private KeyValuePair<TKey, TValue>[] _keysAndValues; + private Dictionary<TKey, TValue> _dict; + private int _count; + private const int _arraySize = 10; + + public HybridReferenceDictionary() { + } + + public HybridReferenceDictionary(int initialCapicity) { + if (initialCapicity > _arraySize) { + _dict = new Dictionary<TKey, TValue>(initialCapicity); + } else { + _keysAndValues = new KeyValuePair<TKey, TValue>[initialCapicity]; + } + } + + public bool TryGetValue(TKey key, out TValue value) { + Debug.Assert(key != null); + + if (_dict != null) { + return _dict.TryGetValue(key, out value); + } else if (_keysAndValues != null) { + for (int i = 0; i < _keysAndValues.Length; i++) { + if (_keysAndValues[i].Key == key) { + value = _keysAndValues[i].Value; + return true; + } + } + } + value = default(TValue); + return false; + } + + public bool Remove(TKey key) { + Debug.Assert(key != null); + + if (_dict != null) { + return _dict.Remove(key); + } else if (_keysAndValues != null) { + for (int i = 0; i < _keysAndValues.Length; i++) { + if (_keysAndValues[i].Key == key) { + _keysAndValues[i] = new KeyValuePair<TKey, TValue>(); + _count--; + return true; + } + } + } + + return false; + } + + public bool ContainsKey(TKey key) { + Debug.Assert(key != null); + + if (_dict != null) { + return _dict.ContainsKey(key); + } else if (_keysAndValues != null) { + for (int i = 0; i < _keysAndValues.Length; i++) { + if (_keysAndValues[i].Key == key) { + return true; + } + } + } + + return false; + } + + public int Count { + get { + if (_dict != null) { + return _dict.Count; + } + return _count; + } + + } + + public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { + if (_dict != null) { + return _dict.GetEnumerator(); + } + + return GetEnumeratorWorker(); + } + + private IEnumerator<KeyValuePair<TKey, TValue>> GetEnumeratorWorker() { + if (_keysAndValues != null) { + for (int i = 0; i < _keysAndValues.Length; i++) { + if (_keysAndValues[i].Key != null) { + yield return _keysAndValues[i]; + } + } + } + } + + public TValue this[TKey key] { + get { + Debug.Assert(key != null); + + TValue res; + if (TryGetValue(key, out res)) { + return res; + } + + throw new KeyNotFoundException(); + } + set { + Debug.Assert(key != null); + + if (_dict != null) { + _dict[key] = value; + } else { + int index; + if (_keysAndValues != null) { + index = -1; + for (int i = 0; i < _keysAndValues.Length; i++) { + if (_keysAndValues[i].Key == key) { + _keysAndValues[i] = new KeyValuePair<TKey, TValue>(key, value); + return; + } else if (_keysAndValues[i].Key == null) { + index = i; + } + } + } else { + _keysAndValues = new KeyValuePair<TKey, TValue>[_arraySize]; + index = 0; + } + + if (index != -1) { + _count++; + _keysAndValues[index] = new KeyValuePair<TKey, TValue>(key, value); + } else { + _dict = new Dictionary<TKey, TValue>(); + for (int i = 0; i < _keysAndValues.Length; i++) { + _dict[_keysAndValues[i].Key] = _keysAndValues[i].Value; + } + _keysAndValues = null; + + _dict[key] = value; + } + } + } + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ListEqualityComparer.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ListEqualityComparer.cs new file mode 100644 index 00000000000..3d04b8f27f3 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ListEqualityComparer.cs @@ -0,0 +1,34 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System.Collections.Generic; + +namespace Microsoft.Scripting.Utils { + // Compares two ICollection<T>'s using element equality + internal sealed class ListEqualityComparer<T> : EqualityComparer<ICollection<T>> { + internal static readonly ListEqualityComparer<T> Instance = new ListEqualityComparer<T>(); + + private ListEqualityComparer() { } + + // EqualityComparer<T> handles null and object identity for us + public override bool Equals(ICollection<T> x, ICollection<T> y) { + return x.ListEquals(y); + } + + public override int GetHashCode(ICollection<T> obj) { + return obj.ListHashCode(); + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/MathUtils.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/MathUtils.cs new file mode 100644 index 00000000000..3b164273526 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/MathUtils.cs @@ -0,0 +1,1229 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_NUMERICS +using BigInt = System.Numerics.BigInteger; +using Complex = System.Numerics.Complex; +#endif + +using System; +using System.Text; +using System.Collections.Generic; +using Microsoft.Scripting.Math; +using Microsoft.Scripting.Runtime; + +namespace Microsoft.Scripting.Utils { + using Math = System.Math; + + public static class MathUtils { + /// <summary> + /// Calculates the quotient of two 32-bit signed integers rounded towards negative infinity. + /// </summary> + /// <param name="x">Dividend.</param> + /// <param name="y">Divisor.</param> + /// <returns>The quotient of the specified numbers rounded towards negative infinity, or <code>(int)Floor((double)x/(double)y)</code>.</returns> + /// <exception cref="DivideByZeroException"><paramref name="y"/> is 0.</exception> + /// <remarks>The caller must check for overflow (x = Int32.MinValue, y = -1)</remarks> + public static int FloorDivideUnchecked(int x, int y) { + int q = x / y; + + if (x >= 0) { + if (y > 0) { + return q; + } else if (x % y == 0) { + return q; + } else { + return q - 1; + } + } else { + if (y > 0) { + if (x % y == 0) { + return q; + } else { + return q - 1; + } + } else { + return q; + } + } + } + + /// <summary> + /// Calculates the quotient of two 32-bit signed integers rounded towards negative infinity. + /// </summary> + /// <param name="x">Dividend.</param> + /// <param name="y">Divisor.</param> + /// <returns>The quotient of the specified numbers rounded towards negative infinity, or <code>(int)Floor((double)x/(double)y)</code>.</returns> + /// <exception cref="DivideByZeroException"><paramref name="y"/> is 0.</exception> + /// <remarks>The caller must check for overflow (x = Int64.MinValue, y = -1)</remarks> + public static long FloorDivideUnchecked(long x, long y) { + long q = x / y; + + if (x >= 0) { + if (y > 0) { + return q; + } else if (x % y == 0) { + return q; + } else { + return q - 1; + } + } else { + if (y > 0) { + if (x % y == 0) { + return q; + } else { + return q - 1; + } + } else { + return q; + } + } + } + + /// <summary> + /// Calculates the remainder of floor division of two 32-bit signed integers. + /// </summary> + /// <param name="x">Dividend.</param> + /// <param name="y">Divisor.</param> + /// <returns>The remainder of of floor division of the specified numbers, or <code>x - (int)Floor((double)x/(double)y) * y</code>.</returns> + /// <exception cref="DivideByZeroException"><paramref name="y"/> is 0.</exception> + public static int FloorRemainder(int x, int y) { + if (y == -1) return 0; + int r = x % y; + + if (x >= 0) { + if (y > 0) { + return r; + } else if (r == 0) { + return 0; + } else { + return r + y; + } + } else { + if (y > 0) { + if (r == 0) { + return 0; + } else { + return r + y; + } + } else { + return r; + } + } + } + + /// <summary> + /// Calculates the remainder of floor division of two 32-bit signed integers. + /// </summary> + /// <param name="x">Dividend.</param> + /// <param name="y">Divisor.</param> + /// <returns>The remainder of of floor division of the specified numbers, or <code>x - (int)Floor((double)x/(double)y) * y</code>.</returns> + /// <exception cref="DivideByZeroException"><paramref name="y"/> is 0.</exception> + public static long FloorRemainder(long x, long y) { + if (y == -1) return 0; + long r = x % y; + + if (x >= 0) { + if (y > 0) { + return r; + } else if (r == 0) { + return 0; + } else { + return r + y; + } + } else { + if (y > 0) { + if (r == 0) { + return 0; + } else { + return r + y; + } + } else { + return r; + } + } + } + + /// <summary> + /// Behaves like Math.Round(value, MidpointRounding.AwayFromZero) + /// Needed because CoreCLR doesn't support this particular overload of Math.Round + /// </summary> + public static double RoundAwayFromZero(double value) { +#if !SILVERLIGHT && !WP75 + return Math.Round(value, MidpointRounding.AwayFromZero); +#else + if (value < 0) { + return -RoundAwayFromZero(-value); + } + + // we can assume positive value + double result = Math.Floor(value); + if (value - result >= 0.5) { + result += 1.0; + } + return result; +#endif + } + + private static readonly double[] _RoundPowersOfTens = new double[] { 1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9, 1E10, 1E11, 1E12, 1E13, 1E14, 1E15 }; + + private static double GetPowerOf10(int precision) { + return (precision < 16) ? _RoundPowersOfTens[precision] : Math.Pow(10, precision); + } + + /// <summary> + /// Behaves like Math.Round(value, precision, MidpointRounding.AwayFromZero) + /// However, it works correctly on negative precisions and cases where precision is + /// outside of the [-15, 15] range. + /// + /// (This function is also needed because CoreCLR lacks this overload.) + /// </summary> + public static double RoundAwayFromZero(double value, int precision) { + if (double.IsInfinity(value) || double.IsNaN(value)) { + return value; + } + + if (precision >= 0) { + if (precision > 308) { + return value; + } + + double num = GetPowerOf10(precision); + return RoundAwayFromZero(value * num) / num; + } else if (precision >= -308) { + // Note: this code path could be merged with the precision >= 0 path, + // (by extending the cache to negative powers of 10) + // but the results seem to be more precise if we do it this way + double num = GetPowerOf10(-precision); + return RoundAwayFromZero(value / num) * num; + } else { + // Preserve the sign of the input, including +/-0.0 + return value < 0.0 || 1.0 / value < 0.0 ? -0.0 : 0.0; + } + } + + public static bool IsNegativeZero(double self) { +#if SILVERLIGHT // BitConverter.DoubleToInt64Bits + if ( self != 0.0 ) { + return false; + } + byte[] bits = BitConverter.GetBytes(self); + return (bits[7] == 0x80 && bits[6] == 0x00 && bits[5] == 0x00 && bits[4] == 0x00 + && bits[3] == 0x00 && bits[2] == 0x00 && bits[1] == 0x00 && bits[0] == 0x00); +#else + return (self == 0.0 && 1.0 / self < 0); +#endif + } + + #region Special Functions + + public static double Erf(double v0) { + // Calculate the error function using the approximation method outlined in + // W. J. Cody's "Rational Chebyshev Approximations for the Error Function" + + if (v0 >= 10.0) { + return 1.0; + } else if (v0 <= -10.0) { + return -1.0; + } + + if (v0 > 0.47 || v0 < -0.47) { + return 1.0 - ErfComplement(v0); + } + + double sq = v0 * v0; + double numer = EvalPolynomial(sq, ErfNumerCoeffs); + double denom = EvalPolynomial(sq, ErfDenomCoeffs); + + return v0 * numer / denom; + } + + public static double ErfComplement(double v0) { + if (v0 >= 30.0) { + return 0.0; + } else if (v0 <= -10.0) { + return 2.0; + } + + double a = Math.Abs(v0); + if (a < 0.47) { + return 1.0 - Erf(v0); + } + + // Different approximations are required for different ranges of v0 + double res; + if (a <= 4.0) { + // Use the approximation method outlined in W. J. Cody's "Rational Chebyshev + // Approximations for the Error Function" + double numer = EvalPolynomial(a, ErfcNumerCoeffs); + double denom = EvalPolynomial(a, ErfcDenomCoeffs); + + res = Math.Exp(-a * a) * numer / denom; + } else { + // Use the approximation method introduced by C. Tellambura and A. Annamalai + // in "Efficient Computation of erfc(x) for Large Arguments" + const double h = 0.5; + const double hSquared = 0.25; + const int nTerms = 10; + double sq = a * a; + res = 0.0; + for (int i = nTerms; i > 0; i--) { + double term = i * i * hSquared; + res += Math.Exp(-term) / (term + sq); + } + + res = h * a * Math.Exp(-sq) / Math.PI * (res * 2 + 1.0 / sq); + } + + if (v0 < 0.0) { + res = 2.0 - res; + } + return res; + } + + public static double Gamma(double v0) { + // Calculate the Gamma function using the Lanczos approximation + + if (double.IsNegativeInfinity(v0)) { + return double.NaN; + } + double a = Math.Abs(v0); + + // Special-case integers + if (a % 1.0 == 0.0) { + // Gamma is undefined on non-positive integers + if (v0 <= 0.0) { + return double.NaN; + } + + // factorial(v0 - 1) + if (a <= 25.0) { + if (a <= 2.0) { + return 1.0; + } + a -= 1.0; + v0 -= 1.0; + while (--v0 > 1.0) { + a *= v0; + } + return a; + } + } + + // lim(Gamma(v0)) = 1.0 / v0 as v0 approaches 0.0 + if (a < 1e-50) { + return 1.0 / v0; + } + + double res; + if (v0 < -150.0) { + // If Gamma(1 - v0) could overflow for large v0, use the duplication formula to + // compute Gamma(1 - v0): + // Gamma(x) * Gamma(x + 0,5) = sqrt(pi) * 2**(1 - 2x) * Gamma(2x) + // ==> Gamma(1 - x) = Gamma((1-x)/2) * Gamma((2-x)/2) / (2**x * sqrt(pi)) + // Then apply the reflection formula: + // Gamma(x) = pi / sin(pi * x) / Gamma(1 - x) + double halfV0 = v0 / 2.0; + res = Math.Pow(Math.PI, 1.5) / SinPi(v0); + res *= Math.Pow(2.0, v0); + res /= PositiveGamma(0.5 - halfV0); + res /= PositiveGamma(1.0 - halfV0); + } else if (v0 < 0.001) { + // For values less than or close to zero, just use the reflection formula + res = Math.PI / SinPi(v0); + double v1 = 1.0 - v0; + if (v0 == 1.0 - v1) { + res /= PositiveGamma(v1); + } else { + // Computing v1 has resulted in a loss of precision. To avoid this, use the + // recurrence relation Gamma(x + 1) = x * Gamma(x). + res /= -v0 * PositiveGamma(-v0); + } + } else { + res = PositiveGamma(v0); + } + + return res; + } + + public static double LogGamma(double v0) { + // Calculate the log of the Gamma function using the Lanczos approximation + + if (double.IsInfinity(v0)) { + return double.PositiveInfinity; + } + double a = Math.Abs(v0); + + // Gamma is undefined on non-positive integers + if (v0 <= 0.0 && a % 1.0 == 0.0) { + return double.NaN; + } + + // lim(LGamma(v0)) = -log|v0| as v0 approaches 0.0 + if (a < 1e-50) { + return -Math.Log(a); + } + + double res; + if (v0 < 0.0) { + // For negative values, use the reflection formula: + // Gamma(x) = pi / sin(pi * x) / Gamma(1 - x) + // ==> LGamma(x) = log(pi / |sin(pi * x)|) - LGamma(1 - x) + res = Math.Log(Math.PI / AbsSinPi(v0)); + res -= PositiveLGamma(1.0 - v0); + } else { + res = PositiveLGamma(v0); + } + + return res; + } + + public static double Hypot(double x, double y) { + // + // sqrt(x*x + y*y) == sqrt(x*x * (1 + (y*y)/(x*x))) == + // sqrt(x*x) * sqrt(1 + (y/x)*(y/x)) == + // abs(x) * sqrt(1 + (y/x)*(y/x)) + // + + // Handle infinities + if (double.IsInfinity(x) || double.IsInfinity(y)) { + return double.PositiveInfinity; + } + + // First, get abs + if (x < 0.0) x = -x; + if (y < 0.0) y = -y; + + // Obvious cases + if (x == 0.0) return y; + if (y == 0.0) return x; + + // Divide smaller number by bigger number to safeguard the (y/x)*(y/x) + if (x < y) { + double temp = y; y = x; x = temp; + } + + y /= x; + + // calculate abs(x) * sqrt(1 + (y/x)*(y/x)) + return x * System.Math.Sqrt(1 + y * y); + } + + /// <summary> + /// Evaluates a polynomial in v0 where the coefficients are ordered in increasing degree + /// </summary> + private static double EvalPolynomial(double v0, double[] coeffs) { + double res = 0.0; + for (int i = coeffs.Length - 1; i >= 0; i--) { + res = checked(res * v0 + coeffs[i]); + } + + return res; + } + + /// <summary> + /// Evaluates a polynomial in v0 where the coefficients are ordered in increasing degree + /// if reverse is false, and increasing degree if reverse is true. + /// </summary> + private static double EvalPolynomial(double v0, double[] coeffs, bool reverse) { + if (!reverse) { + return EvalPolynomial(v0, coeffs); + } + + double res = 0.0; + for (int i = 0; i < coeffs.Length; i++) { + res = checked(res * v0 + coeffs[i]); + } + + return res; + } + + /// <summary> + /// A numerically precise version of sin(v0 * pi) + /// </summary> + private static double SinPi(double v0) { + double res = Math.Abs(v0) % 2.0; + + if (res < 0.25) { + res = Math.Sin(res * Math.PI); + } else if (res < 0.75) { + res = Math.Cos((res - 0.5) * Math.PI); + } else if (res < 1.25) { + res = -Math.Sin((res - 1.0) * Math.PI); + } else if (res < 1.75) { + res = -Math.Cos((res - 1.5) * Math.PI); + } else { + res = Math.Sin((res - 2.0) * Math.PI); + } + + return v0 < 0 ? -res : res; + } + + /// <summary> + /// A numerically precise version of |sin(v0 * pi)| + /// </summary> + private static double AbsSinPi(double v0) { + double res = Math.Abs(v0) % 1.0; + + if (res < 0.25) { + res = Math.Sin(res * Math.PI); + } else if (res < 0.75) { + res = Math.Cos((res - 0.5) * Math.PI); + } else { + res = Math.Sin((res - 1.0) * Math.PI); + } + + return Math.Abs(res); + } + + // polynomial coefficients ordered by increasing degree + private static double[] ErfNumerCoeffs = { + 2.4266795523053175e02, 2.1979261618294152e01, + 6.9963834886191355, -3.5609843701815385e-02 + }; + private static double[] ErfDenomCoeffs = { + 2.1505887586986120e02, 9.1164905404514901e01, + 1.5082797630407787e01, 1.0 + }; + private static double[] ErfcNumerCoeffs = { + 3.004592610201616005e02, 4.519189537118729422e02, + 3.393208167343436870e02, 1.529892850469404039e02, + 4.316222722205673530e01, 7.211758250883093659, + 5.641955174789739711e-01, -1.368648573827167067e-07 + }; + private static double[] ErfcDenomCoeffs = { + 3.004592609569832933e02, 7.909509253278980272e02, + 9.313540948506096211e02, 6.389802644656311665e02, + 2.775854447439876434e02, 7.700015293522947295e01, + 1.278272731962942351e01, 1.0 + }; + private static double[] GammaNumerCoeffs = { + 4.401213842800460895436e13, 4.159045335859320051581e13, + 1.801384278711799677796e13, 4.728736263475388896889e12, + 8.379100836284046470415e11, 1.055837072734299344907e11, + 9.701363618494999493386e09, 6.549143975482052641016e08, + 3.223832294213356530668e07, 1.128514219497091438040e06, + 2.666579378459858944762e04, 3.818801248632926870394e02, + 2.506628274631000502415 + }; + private static double[] GammaDenomCoeffs = { + 0.0, 39916800.0, 120543840.0, 150917976.0, + 105258076.0, 45995730.0, 13339535.0, 2637558.0, + 357423.0, 32670.0, 1925.0, 66.0, 1.0 + }; + + /// <summary> + /// Take the quotient of the 2 polynomials forming the Lanczos approximation + /// with N=13 and G=13.144565 + /// </summary> + private static double GammaRationalFunc(double v0) { + double numer = 0.0; + double denom = 0.0; + + if (v0 < 1e15) { + numer = EvalPolynomial(v0, GammaNumerCoeffs); + denom = EvalPolynomial(v0, GammaDenomCoeffs); + } else { + double vRecip = 1.0 / v0; + numer = EvalPolynomial(vRecip, GammaNumerCoeffs, true); + denom = EvalPolynomial(vRecip, GammaDenomCoeffs, true); + } + + return numer / denom; + } + + /// <summary> + /// Computes the Gamma function on positive values, using the Lanczos approximation. + /// Lanczos parameters are N=13 and G=13.144565. + /// </summary> + private static double PositiveGamma(double v0) { + if (v0 > 200.0) { + return Double.PositiveInfinity; + } + + double vg = v0 + 12.644565; // v0 + g - 0.5 + double res = GammaRationalFunc(v0); + res /= Math.Exp(vg); + if (v0 < 120.0) { + res *= Math.Pow(vg, v0 - 0.5); + } else { + // Use a smaller exponent if we're in danger of overflowing Math.Pow + double sqrt = Math.Pow(vg, v0 / 2.0 - 0.25); + res *= sqrt; + res *= sqrt; + } + + return res; + } + + /// <summary> + /// Computes the Log-Gamma function on positive values, using the Lanczos approximation. + /// Lanczos parameters are N=13 and G=13.144565. + /// </summary> + private static double PositiveLGamma(double v0) { + double vg = v0 + 12.644565; // v0 + g - 0.5 + double res = Math.Log(GammaRationalFunc(v0)) - vg; + res += (v0 - 0.5) * Math.Log(vg); + + return res; + } + + #endregion + + #region BigInteger + + // generated by scripts/radix_generator.py + private static readonly uint[] maxCharsPerDigit = { 0, 0, 31, 20, 15, 13, 12, 11, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 }; + private static readonly uint[] groupRadixValues = { 0, 0, 2147483648, 3486784401, 1073741824, 1220703125, 2176782336, 1977326743, 1073741824, 3486784401, 1000000000, 2357947691, 429981696, 815730721, 1475789056, 2562890625, 268435456, 410338673, 612220032, 893871739, 1280000000, 1801088541, 2494357888, 3404825447, 191102976, 244140625, 308915776, 387420489, 481890304, 594823321, 729000000, 887503681, 1073741824, 1291467969, 1544804416, 1838265625, 2176782336 }; + + internal static string BigIntegerToString(uint[] d, int sign, int radix, bool lowerCase) { + if (radix < 2) { + throw ExceptionUtils.MakeArgumentOutOfRangeException("radix", radix, "radix must be >= 2"); + } + if (radix > 36) { + throw ExceptionUtils.MakeArgumentOutOfRangeException("radix", radix, "radix must be <= 36"); + } + + int dl = d.Length; + if (dl == 0) { + return "0"; + } + + List<uint> digitGroups = new List<uint>(); + + uint groupRadix = groupRadixValues[radix]; + while (dl > 0) { + uint rem = div(d, ref dl, groupRadix); + digitGroups.Add(rem); + } + + StringBuilder ret = new StringBuilder(); + if (sign == -1) { + ret.Append("-"); + } + + int digitIndex = digitGroups.Count - 1; + + char[] tmpDigits = new char[maxCharsPerDigit[radix]]; + + AppendRadix((uint)digitGroups[digitIndex--], (uint)radix, tmpDigits, ret, false, lowerCase); + while (digitIndex >= 0) { + AppendRadix((uint)digitGroups[digitIndex--], (uint)radix, tmpDigits, ret, true, lowerCase); + } + return ret.Length == 0 ? "0" : ret.ToString(); + } + + private const int BitsPerDigit = 32; + + private static uint div(uint[] n, ref int nl, uint d) { + ulong rem = 0; + int i = nl; + bool seenNonZero = false; + while (--i >= 0) { + rem <<= BitsPerDigit; + rem |= n[i]; + uint v = (uint)(rem / d); + n[i] = v; + if (v == 0) { + if (!seenNonZero) nl--; + } else { + seenNonZero = true; + } + rem %= d; + } + return (uint)rem; + } + + private static void AppendRadix(uint rem, uint radix, char[] tmp, StringBuilder buf, bool leadingZeros, bool lowerCase) { + string symbols = lowerCase ? "0123456789abcdefghijklmnopqrstuvwxyz" : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + int digits = tmp.Length; + int i = digits; + while (i > 0 && (leadingZeros || rem != 0)) { + uint digit = rem % radix; + rem /= radix; + tmp[--i] = symbols[(int)digit]; + } + if (leadingZeros) buf.Append(tmp); + else buf.Append(tmp, i, digits - i); + } + + // Helper for GetRandBits + private static uint GetWord(byte[] bytes, int start, int end) { + uint four = 0; + int bits = end - start; + int shift = 0; + if (bits > 32) { + bits = 32; + } + start /= 8; + while (bits > 0) { + uint value = bytes[start]; + if (bits < 8) { + value &= (1u << bits) - 1u; + } + value <<= shift; + four |= value; + bits -= 8; + shift += 8; + start++; + } + + return four; + } + +#if !FEATURE_NUMERICS + public static BigInteger GetRandBits(this Random generator, int bits) { + ContractUtils.Requires(bits > 0); + + // equivalent to (bits + 7) / 8 without possibility of overflow + int count = bits % 8 == 0 ? bits / 8 : bits / 8 + 1; + + // Pad the end (most significant) with zeros if we align to the byte + // to ensure that we end up with a positive value + byte[] bytes = new byte[bits % 8 == 0 ? count + 1 : count]; + generator.NextBytes(bytes); + if (bits % 8 == 0) { + bytes[bytes.Length - 1] = 0; + } else { + bytes[bytes.Length - 1] = (byte)(bytes[bytes.Length - 1] & ((1 << (bits % 8)) - 1)); + } + + if (bits <= 32) { + return (BigInteger)GetWord(bytes, 0, bits); + } else if (bits <= 64) { + ulong a = GetWord(bytes, 0, bits); + ulong b = GetWord(bytes, 32, bits); + return (BigInteger)(a | (b << 32)); + } else { + count = (count + 3) / 4; + uint[] data = new uint[count]; + for (int i = 0; i < count; i++) { + data[i] = GetWord(bytes, i * 32, bits); + } + return new BigInteger(1, data); + } + } + + public static BigInteger Random(this Random generator, BigInteger limit) { + ContractUtils.Requires(limit.Sign > 0, "limit"); + ContractUtils.RequiresNotNull(generator, "generator"); + + // TODO: this doesn't yield a uniform distribution (small numbers will be picked more frequently): + uint[] result = new uint[limit.GetWordCount() + 1]; + for (int i = 0; i < result.Length; i++) { + result[i] = unchecked((uint)generator.Next()); + } + return new BigInteger(1, result) % limit; + } +#else + public static BigInt GetRandBits(this Random generator, int bits) { + ContractUtils.Requires(bits > 0); + + // equivalent to (bits + 7) / 8 without possibility of overflow + int count = bits % 8 == 0 ? bits / 8 : bits / 8 + 1; + + // Pad the end (most significant) with zeros if we align to the byte + // to ensure that we end up with a positive value + byte[] bytes = new byte[bits % 8 == 0 ? count + 1 : count]; + generator.NextBytes(bytes); + if (bits % 8 == 0) { + bytes[bytes.Length - 1] = 0; + } else { + bytes[bytes.Length - 1] = (byte)(bytes[bytes.Length - 1] & ((1 << (bits % 8)) - 1)); + } + + if (bits <= 32) { + return (BigInt)GetWord(bytes, 0, bits); + } else if (bits <= 64) { + ulong a = GetWord(bytes, 0, bits); + ulong b = GetWord(bytes, 32, bits); + return (BigInt)(a | (b << 32)); + } + + return new BigInt(bytes); + } + + public static BigInteger Random(this Random generator, BigInteger limit) { + return new BigInteger(generator.Random(limit.Value)); + } + + public static BigInt Random(this Random generator, BigInt limit) { + ContractUtils.Requires(limit.Sign > 0, "limit"); + ContractUtils.RequiresNotNull(generator, "generator"); + + BigInt res = BigInt.Zero; + + while (true) { + // if we've run out of significant digits, we can return the total + if (limit == BigInt.Zero) { + return res; + } + + // if we're small enough to fit in an int, do so + int iLimit; + if (limit.AsInt32(out iLimit)) { + return res + generator.Next(iLimit); + } + + // get the 3 or 4 uppermost bytes that fit into an int + int hiData; + byte[] data = limit.ToByteArray(); + int index = data.Length; + while (data[--index] == 0) ; + if (data[index] < 0x80) { + hiData = data[index] << 24; + data[index--] = (byte)0; + } else { + hiData = 0; + } + hiData |= data[index] << 16; + data[index--] = (byte)0; + hiData |= data[index] << 8; + data[index--] = (byte)0; + hiData |= data[index]; + data[index--] = (byte)0; + + // get a uniform random number for the uppermost portion of the bigint + byte[] randomData = new byte[index + 2]; + generator.NextBytes(randomData); + randomData[index + 1] = (byte)0; + res += new BigInt(randomData); + res += (BigInt)generator.Next(hiData) << ((index + 1) * 8); + + // sum it with a uniform random number for the remainder of the bigint + limit = new BigInt(data); + } + } + + public static bool TryToFloat64(this BigInt self, out double result) { + return StringUtils.TryParseDouble( + self.ToString(), + System.Globalization.NumberStyles.Number, + System.Globalization.CultureInfo.InvariantCulture.NumberFormat, + out result + ); + } + + public static double ToFloat64(this BigInt self) { + return double.Parse( + self.ToString(), + System.Globalization.NumberStyles.Number, + System.Globalization.CultureInfo.InvariantCulture.NumberFormat + ); + } +#endif + + public static bool TryToFloat64(this BigInteger self, out double result) { + return StringUtils.TryParseDouble( + self.ToString(10), + System.Globalization.NumberStyles.Number, + System.Globalization.CultureInfo.InvariantCulture.NumberFormat, + out result + ); + } + + public static double ToFloat64(this BigInteger self) { + return double.Parse( + self.ToString(10), + System.Globalization.NumberStyles.Number, + System.Globalization.CultureInfo.InvariantCulture.NumberFormat + ); + } + + // Like GetBitCount(Abs(x)), except 0 maps to 0 + public static int BitLength(BigInteger x) { + if (x.IsZero()) { + return 0; + } + + return x.Abs().GetBitCount(); + } + +#if FEATURE_NUMERICS + public static int BitLength(BigInt x) { + if (x.IsZero) { + return 0; + } + + byte[] bytes = BigInt.Abs(x).ToByteArray(); + int index = bytes.Length; + while (bytes[--index] == 0) ; + + return index * 8 + BitLength((int)bytes[index]); + } +#endif + + // Like GetBitCount(Abs(x)), except 0 maps to 0 + public static int BitLength(long x) { + if (x == 0) { + return 0; + } + if (x == Int64.MinValue) { + return 64; + } + + x = Math.Abs(x); + int res = 1; + if (x >= 1L << 32) { + x >>= 32; + res += 32; + } + if (x >= 1L << 16) { + x >>= 16; + res += 16; + } + if (x >= 1L << 8) { + x >>= 8; + res += 8; + } + if (x >= 1L << 4) { + x >>= 4; + res += 4; + } + if (x >= 1L << 2) { + x >>= 2; + res += 2; + } + if (x >= 1L << 1) { + res += 1; + } + + return res; + } + + // Like GetBitCount(Abs(x)), except 0 maps to 0 + [CLSCompliant(false)] + public static int BitLengthUnsigned(ulong x) { + if (x >= 1uL << 63) { + return 64; + } + return BitLength((long)x); + } + + // Like GetBitCount(Abs(x)), except 0 maps to 0 + public static int BitLength(int x) { + if (x == 0) { + return 0; + } + if (x == Int32.MinValue) { + return 32; + } + + x = Math.Abs(x); + int res = 1; + if (x >= 1 << 16) { + x >>= 16; + res += 16; + } + if (x >= 1 << 8) { + x >>= 8; + res += 8; + } + if (x >= 1 << 4) { + x >>= 4; + res += 4; + } + if (x >= 1 << 2) { + x >>= 2; + res += 2; + } + if (x >= 1 << 1) { + res += 1; + } + + return res; + } + + // Like GetBitCount(Abs(x)), except 0 maps to 0 + [CLSCompliant(false)] + public static int BitLengthUnsigned(uint x) { + if (x >= 1u << 31) { + return 32; + } + return BitLength((int)x); + } + + #region Extending BigInt with BigInteger API +#if FEATURE_NUMERICS + + public static bool AsInt32(this BigInt self, out int ret) { + if (self >= Int32.MinValue && self <= Int32.MaxValue) { + ret = (Int32)self; + return true; + } + ret = 0; + return false; + } + + public static bool AsInt64(this BigInt self, out long ret) { + if (self >= Int64.MinValue && self <= Int64.MaxValue) { + ret = (long)self; + return true; + } + ret = 0; + return false; + } + + [CLSCompliant(false)] + public static bool AsUInt32(this BigInt self, out uint ret) { + if (self >= UInt32.MinValue && self <= UInt32.MaxValue) { + ret = (UInt32)self; + return true; + } + ret = 0; + return false; + } + + [CLSCompliant(false)] + public static bool AsUInt64(this BigInt self, out ulong ret) { + if (self >= UInt64.MinValue && self <= UInt64.MaxValue) { + ret = (UInt64)self; + return true; + } + ret = 0; + return false; + } + + public static BigInt Abs(this BigInt self) { + return BigInt.Abs(self); + } + + public static bool IsZero(this BigInt self) { + return self.IsZero; + } + + public static bool IsPositive(this BigInt self) { + return self.Sign > 0; + } + + public static bool IsNegative(this BigInt self) { + return self.Sign < 0; + } + + public static double Log(this BigInt self) { + return BigInt.Log(self); + } + + public static double Log(this BigInt self, double baseValue) { + return BigInt.Log(self, baseValue); + } + + public static double Log10(this BigInt self) { + return BigInt.Log10(self); + } + + public static BigInt Power(this BigInt self, int exp) { + return BigInt.Pow(self, exp); + } + + public static BigInt ModPow(this BigInt self, int power, BigInt mod) { + return BigInt.ModPow(self, power, mod); + } + + public static BigInt ModPow(this BigInt self, BigInt power, BigInt mod) { + return BigInt.ModPow(self, power, mod); + } + + public static string ToString(this BigInt self, int radix) { + const string symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + if (radix < 2) { + throw ExceptionUtils.MakeArgumentOutOfRangeException("radix", radix, "radix must be >= 2"); + } + if (radix > 36) { + throw ExceptionUtils.MakeArgumentOutOfRangeException("radix", radix, "radix must be <= 36"); + } + + bool isNegative = false; + if (self < BigInt.Zero) { + self = -self; + isNegative = true; + } else if (self == BigInt.Zero) { + return "0"; + } + + List<char> digits = new List<char>(); + while (self > 0) { + digits.Add(symbols[(int)(self % radix)]); + self /= radix; + } + + StringBuilder ret = new StringBuilder(); + if (isNegative) { + ret.Append('-'); + } + for (int digitIndex = digits.Count - 1; digitIndex >= 0; digitIndex--) { + ret.Append(digits[digitIndex]); + } + return ret.ToString(); + } +#endif + #endregion + + #region Exposing underlying data +#if FEATURE_NUMERICS + + [CLSCompliant(false)] + public static uint[] GetWords(this BigInt self) { + if (self.IsZero) { + return new uint[] { 0 }; + } + + int hi; + byte[] bytes; + GetHighestByte(self, out hi, out bytes); + + uint[] result = new uint[(hi + 1 + 3) / 4]; + int i = 0; + int j = 0; + uint u = 0; + int shift = 0; + while (i < bytes.Length) { + u |= (uint)bytes[i++] << shift; + if (i % 4 == 0) { + result[j++] = u; + u = 0; + } + shift += 8; + } + if (u != 0) { + result[j] = u; + } + return result; + } + + [CLSCompliant(false)] + public static uint GetWord(this BigInt self, int index) { + return GetWords(self)[index]; + } + + public static int GetWordCount(this BigInt self) { + int index; + byte[] bytes; + GetHighestByte(self, out index, out bytes); + return index / 4 + 1; // return (index + 1 + 3) / 4; + } + + public static int GetByteCount(this BigInt self) { + int index; + byte[] bytes; + GetHighestByte(self, out index, out bytes); + return index + 1; + } + + public static int GetBitCount(this BigInt self) { + if (self.IsZero) { + return 1; + } + byte[] bytes = BigInt.Abs(self).ToByteArray(); + + int index = bytes.Length; + while (bytes[--index] == 0) ; + + int count = index * 8; + for (int hiByte = bytes[index]; hiByte > 0; hiByte >>= 1) { + count++; + } + return count; + } + + private static byte GetHighestByte(BigInt self, out int index, out byte[] byteArray) { + byte[] bytes = BigInt.Abs(self).ToByteArray(); + if (self.IsZero) { + byteArray = bytes; + index = 0; + return 1; + } + + int hi = bytes.Length; + byte b; + do { + b = bytes[--hi]; + } while (b == 0); + index = hi; + byteArray = bytes; + return b; + } + +#endif + #endregion + + #endregion + + #region Complex + +#if !FEATURE_NUMERICS + public static Complex64 MakeReal(double real) { + return new Complex64(real, 0.0); + } + + public static Complex64 MakeImaginary(double imag) { + return new Complex64(0.0, imag); + } + + public static Complex64 MakeComplex(double real, double imag) { + return new Complex64(real, imag); + } + + public static double Imaginary(this Complex64 self) { + return self.Imag; + } + + public static bool IsZero(this Complex64 self) { + return self.IsZero; + } + + public static Complex64 Pow(this Complex64 self, Complex64 power) { + return self.Power(power); + } +#else + public static Complex MakeReal(double real) { + return new Complex(real, 0.0); + } + + public static Complex MakeImaginary(double imag) { + return new Complex(0.0, imag); + } + + public static Complex MakeComplex(double real, double imag) { + return new Complex(real, imag); + } + + public static double Imaginary(this Complex self) { + return self.Imaginary; + } + + public static bool IsZero(this Complex self) { + return self.Equals(Complex.Zero); + } + + public static Complex Conjugate(this Complex self) { + return new Complex(self.Real, -self.Imaginary); + } + + public static double Abs(this Complex self) { + return Complex.Abs(self); + } + + public static Complex Pow(this Complex self, Complex power) { + return Complex.Pow(self, power); + } +#endif + + #endregion + } + +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ReferenceEqualityComparer.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ReferenceEqualityComparer.cs new file mode 100644 index 00000000000..291a23eec16 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ReferenceEqualityComparer.cs @@ -0,0 +1,48 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Linq.Expressions; +using System.Dynamic; + +namespace Microsoft.Scripting.Utils { + public sealed class ReferenceEqualityComparer<T> : IEqualityComparer<T> where T : class { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly ReferenceEqualityComparer<T> Instance = new ReferenceEqualityComparer<T>(); + + private ReferenceEqualityComparer() { } + + public bool Equals(T x, T y) { + return object.ReferenceEquals(x, y); + } + +#if WIN8 + private static Expression NullConst = Expression.Constant(null); + private static int H = 536870912 ^ NullConst.GetHashCode(); +#endif + + public int GetHashCode(T obj) { +#if WP75 // CF RH.GetHashCode throws NullReferenceException if the argument is null + return obj != null ? RuntimeHelpers.GetHashCode(obj) : 0; +#elif WIN8 + // TODO: HACK! + return BindingRestrictions.GetInstanceRestriction(NullConst, obj).GetHashCode() ^ H; +#else + return RuntimeHelpers.GetHashCode(obj); +#endif + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ReflectionUtils.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ReflectionUtils.cs new file mode 100644 index 00000000000..95e23e634a8 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/ReflectionUtils.cs @@ -0,0 +1,1951 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_METADATA_READER +using Microsoft.Scripting.Metadata; +#endif + +#if !WIN8 +using TypeInfo = System.Type; +#endif + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +#if FEATURE_REFEMIT +using System.Reflection.Emit; +#endif +using System.Runtime.CompilerServices; +using System.Security; +using System.Text; +using System.Runtime.InteropServices; +using System.Dynamic; +using System.Linq.Expressions; + +using Microsoft.Scripting.Generation; +using Microsoft.Scripting.Runtime; +using Microsoft.Scripting.Utils; + +#if WIN8 || WP75 +namespace System.Runtime.CompilerServices { + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event)] + public sealed class SpecialNameAttribute : Attribute { + public SpecialNameAttribute() { + } + } +} +#endif + +#if WIN8 +namespace System { + public enum TypeCode { + Empty, + Object, + DBNull, + Boolean, + Char, + SByte, + Byte, + Int16, + UInt16, + Int32, + UInt32, + Int64, + UInt64, + Single, + Double, + Decimal, + DateTime, + String = 18 + } +} + +namespace System.Reflection { + [Flags] + public enum BindingFlags { + /// <summary>Specifies that instance members are to be included in the search.</summary> + Instance = 4, + /// <summary>Specifies that static members are to be included in the search.</summary> + Static = 8, + /// <summary>Specifies that public members are to be included in the search.</summary> + Public = 16, + /// <summary>Specifies that non-public members are to be included in the search.</summary> + NonPublic = 32 + } +} +#elif !CLR45 +namespace System.Reflection { + public static class RuntimeReflectionExtensions { + public static MethodInfo GetRuntimeBaseDefinition(this MethodInfo method) { + return method.GetBaseDefinition(); + } + + public static IEnumerable<MethodInfo> GetRuntimeMethods(this Type type) { + return type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + } + } +} +#endif + +namespace Microsoft.Scripting.Utils { + // CF doesn't support DefaultParameterValue attribute. Define our own, but not in System.Runtime.InteropServices namespace as that would + // make C# compiler emit the parameter's default value metadata not the attribute itself. The default value metadata are not accessible on CF. +#if !FEATURE_DEFAULT_PARAMETER_VALUE + /// <summary> + /// The Default Parameter Value Attribute. + /// </summary> + public sealed class DefaultParameterValueAttribute : Attribute + { + private readonly object _value; + + public object Value + { + get { return _value; } + } + + /// <summary> + /// The constructor + /// </summary> + /// <param name="value">The value.</param> + public DefaultParameterValueAttribute(object value) + { + _value = value; + } + } + +#if !ANDROID + [AttributeUsage(AttributeTargets.Parameter, Inherited = false), ComVisible(true)] + public sealed class OptionalAttribute : Attribute { + } +#endif +#endif + + public static class ReflectionUtils { + #region Accessibility + + public static BindingFlags AllMembers = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + + public static bool IsPublic(this PropertyInfo property) { + return property.GetGetMethod(nonPublic: false) != null + || property.GetSetMethod(nonPublic: false) != null; + } + + public static bool IsStatic(this PropertyInfo property) { + var getter = property.GetGetMethod(nonPublic: true); + var setter = property.GetSetMethod(nonPublic: true); + + return getter != null && getter.IsStatic + || setter != null && setter.IsStatic; + } + + public static bool IsStatic(this EventInfo evnt) { + var add = evnt.GetAddMethod(nonPublic: true); + var remove = evnt.GetRemoveMethod(nonPublic: true); + + return add != null && add.IsStatic + || remove != null && remove.IsStatic; + } + + public static bool IsPrivate(this PropertyInfo property) { + var getter = property.GetGetMethod(nonPublic: true); + var setter = property.GetSetMethod(nonPublic: true); + + return (getter == null || getter.IsPrivate) + && (setter == null || setter.IsPrivate); + } + + public static bool IsPrivate(this EventInfo evnt) { + var add = evnt.GetAddMethod(nonPublic: true); + var remove = evnt.GetRemoveMethod(nonPublic: true); + + return (add == null || add.IsPrivate) + && (remove == null || remove.IsPrivate); + } + + private static bool MatchesFlags(ConstructorInfo member, BindingFlags flags) { + return + ((member.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic) & flags) != 0 && + ((member.IsStatic ? BindingFlags.Static : BindingFlags.Instance) & flags) != 0; + } + + private static bool MatchesFlags(MethodInfo member, BindingFlags flags) { + return + ((member.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic) & flags) != 0 && + ((member.IsStatic ? BindingFlags.Static : BindingFlags.Instance) & flags) != 0; + } + + private static bool MatchesFlags(FieldInfo member, BindingFlags flags) { + return + ((member.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic) & flags) != 0 && + ((member.IsStatic ? BindingFlags.Static : BindingFlags.Instance) & flags) != 0; + } + + private static bool MatchesFlags(PropertyInfo member, BindingFlags flags) { + return + ((member.IsPublic() ? BindingFlags.Public : BindingFlags.NonPublic) & flags) != 0 && + ((member.IsStatic() ? BindingFlags.Static : BindingFlags.Instance) & flags) != 0; + } + + private static bool MatchesFlags(EventInfo member, BindingFlags flags) { + var add = member.GetAddMethod(); + var remove = member.GetRemoveMethod(); + var raise = member.GetRaiseMethod(); + + bool isPublic = add != null && add.IsPublic || remove != null && remove.IsPublic || raise != null && raise.IsPublic; + bool isStatic = add != null && add.IsStatic || remove != null && remove.IsStatic || raise != null && raise.IsStatic; + + return + ((isPublic ? BindingFlags.Public : BindingFlags.NonPublic) & flags) != 0 && + ((isStatic ? BindingFlags.Static : BindingFlags.Instance) & flags) != 0; + } + + private static bool MatchesFlags(TypeInfo member, BindingFlags flags) { + // Static/Instance are ignored + return (((member.IsPublic || member.IsNestedPublic) ? BindingFlags.Public : BindingFlags.NonPublic) & flags) != 0; + } + + private static bool MatchesFlags(MemberInfo member, BindingFlags flags) { + ConstructorInfo ctor; + MethodInfo method; + FieldInfo field; + EventInfo evnt; + PropertyInfo property; + + if ((method = member as MethodInfo) != null) { + return MatchesFlags(method, flags); + } + + if ((field = member as FieldInfo) != null) { + return MatchesFlags(field, flags); + } + + if ((ctor = member as ConstructorInfo) != null) { + return MatchesFlags(ctor, flags); + } + + if ((evnt = member as EventInfo) != null) { + return MatchesFlags(evnt, flags); + } + + if ((property = member as PropertyInfo) != null) { + return MatchesFlags(property, flags); + } + + return MatchesFlags((TypeInfo)member, flags); + } + + private static IEnumerable<T> WithBindingFlags<T>(this IEnumerable<T> members, Func<T, BindingFlags, bool> matchFlags, BindingFlags flags) + where T : MemberInfo { + return members.Where(member => matchFlags(member, flags)); + } + + public static IEnumerable<MemberInfo> WithBindingFlags(this IEnumerable<MemberInfo> members, BindingFlags flags) { + return members.WithBindingFlags(MatchesFlags, flags); + } + + public static IEnumerable<MethodInfo> WithBindingFlags(this IEnumerable<MethodInfo> members, BindingFlags flags) { + return members.WithBindingFlags(MatchesFlags, flags); + } + + public static IEnumerable<ConstructorInfo> WithBindingFlags(this IEnumerable<ConstructorInfo> members, BindingFlags flags) { + return members.WithBindingFlags(MatchesFlags, flags); + } + + public static IEnumerable<FieldInfo> WithBindingFlags(this IEnumerable<FieldInfo> members, BindingFlags flags) { + return members.WithBindingFlags(MatchesFlags, flags); + } + + public static IEnumerable<PropertyInfo> WithBindingFlags(this IEnumerable<PropertyInfo> members, BindingFlags flags) { + return members.WithBindingFlags(MatchesFlags, flags); + } + + public static IEnumerable<EventInfo> WithBindingFlags(this IEnumerable<EventInfo> members, BindingFlags flags) { + return members.WithBindingFlags(MatchesFlags, flags); + } + + public static IEnumerable<TypeInfo> WithBindingFlags(this IEnumerable<TypeInfo> members, BindingFlags flags) { + return members.WithBindingFlags(MatchesFlags, flags); + } + + public static MemberInfo WithBindingFlags(this MemberInfo member, BindingFlags flags) { + return member != null && MatchesFlags(member, flags) ? member : null; + } + + public static MethodInfo WithBindingFlags(this MethodInfo member, BindingFlags flags) { + return member != null && MatchesFlags(member, flags) ? member : null; + } + + public static ConstructorInfo WithBindingFlags(this ConstructorInfo member, BindingFlags flags) { + return member != null && MatchesFlags(member, flags) ? member : null; + } + + public static FieldInfo WithBindingFlags(this FieldInfo member, BindingFlags flags) { + return member != null && MatchesFlags(member, flags) ? member : null; + } + + public static PropertyInfo WithBindingFlags(this PropertyInfo member, BindingFlags flags) { + return member != null && MatchesFlags(member, flags) ? member : null; + } + + public static EventInfo WithBindingFlags(this EventInfo member, BindingFlags flags) { + return member != null && MatchesFlags(member, flags) ? member : null; + } + + public static TypeInfo WithBindingFlags(this TypeInfo member, BindingFlags flags) { + return member != null && MatchesFlags(member, flags) ? member : null; + } + + #endregion + + #region Signatures + + public static IEnumerable<MethodInfo> WithSignature(this IEnumerable<MethodInfo> members, Type[] parameterTypes) { + return members.Where(c => { + var ps = c.GetParameters(); + if (ps.Length != parameterTypes.Length) { + return false; + } + + for (int i = 0; i < ps.Length; i++) { + if (parameterTypes[i] != ps[i].ParameterType) { + return false; + } + } + + return true; + }); + } + + public static IEnumerable<ConstructorInfo> WithSignature(this IEnumerable<ConstructorInfo> members, Type[] parameterTypes) { + return members.Where(c => { + var ps = c.GetParameters(); + if (ps.Length != parameterTypes.Length) { + return false; + } + + for (int i = 0; i < ps.Length; i++) { + if (parameterTypes[i] != ps[i].ParameterType) { + return false; + } + } + + return true; + }); + } + + #endregion + + #region Member Inheritance + + // CLI specification, partition I, 8.10.4: Hiding, overriding, and layout + // ---------------------------------------------------------------------- + // While hiding applies to all members of a type, overriding deals with object layout and is applicable only to instance fields + // and virtual methods. The CTS provides two forms of member overriding, new slot and expect existing slot. A member of a derived + // type that is marked as a new slot will always get a new slot in the object’s layout, guaranteeing that the base field or method + // is available in the object by using a qualified reference that combines the name of the base type with the name of the member + // and its type or signature. A member of a derived type that is marked as expect existing slot will re-use (i.e., share or override) + // a slot that corresponds to a member of the same kind (field or method), name, and type if one already exists from the base type; + // if no such slot exists, a new slot is allocated and used. + // + // The general algorithm that is used for determining the names in a type and the layout of objects of the type is roughly as follows: + // - Flatten the inherited names (using the hide by name or hide by name-and-signature rule) ignoring accessibility rules. + // - For each new member that is marked “expect existing slot”, look to see if an exact match on kind (i.e., field or method), + // name, and signature exists and use that slot if it is found, otherwise allocate a new slot. + // - After doing this for all new members, add these new member-kind/name/signatures to the list of members of this type + // - Finally, remove any inherited names that match the new members based on the hide by name or hide by name-and-signature rules. + + // NOTE: Following GetXxx only implement overriding, not hiding specified by hide-by-name or hide-by-name-and-signature flags. + + public static IEnumerable<MethodInfo> GetInheritedMethods(this Type type, string name = null, bool flattenHierarchy = false) { + while (type.IsGenericParameter) { + type = type.GetBaseType(); + } + + var baseDefinitions = new HashSet<MethodInfo>(ReferenceEqualityComparer<MethodInfo>.Instance); + foreach (var ancestor in type.Ancestors()) { + foreach (var declaredMethod in ancestor.GetDeclaredMethods(name)) { + if (declaredMethod != null && IncludeMethod(declaredMethod, type, baseDefinitions, flattenHierarchy)) { + yield return declaredMethod; + } + } + } + } + + private static bool IncludeMethod(MethodInfo member, Type reflectedType, HashSet<MethodInfo> baseDefinitions, bool flattenHierarchy) { + if (member.IsVirtual) { + if (baseDefinitions.Add(RuntimeReflectionExtensions.GetRuntimeBaseDefinition(member))) { + return true; + } + } else if (member.DeclaringType == reflectedType) { + return true; + } else if (!member.IsPrivate && (!member.IsStatic || flattenHierarchy)) { + return true; + } + + return false; + } + + public static IEnumerable<PropertyInfo> GetInheritedProperties(this Type type, string name = null, bool flattenHierarchy = false) { + while (type.IsGenericParameter) { + type = type.GetBaseType(); + } + + var baseDefinitions = new HashSet<MethodInfo>(ReferenceEqualityComparer<MethodInfo>.Instance); + foreach (var ancestor in type.Ancestors()) { + if (name != null) { + var declaredProperty = ancestor.GetDeclaredProperty(name); + if (declaredProperty != null && IncludeProperty(declaredProperty, type, baseDefinitions, flattenHierarchy)) { + yield return declaredProperty; + } + } else { + foreach (var declaredProperty in ancestor.GetDeclaredProperties()) { + if (IncludeProperty(declaredProperty, type, baseDefinitions, flattenHierarchy)) { + yield return declaredProperty; + } + } + } + } + } + + // CLI spec 22.34 Properties + // ------------------------- + // [Note: The CLS (see Partition I) refers to instance, virtual, and static properties. + // The signature of a property (from the Type column) can be used to distinguish a static property, + // since instance and virtual properties will have the “HASTHIS” bit set in the signature (§23.2.1) + // while a static property will not. The distinction between an instance and a virtual property + // depends on the signature of the getter and setter methods, which the CLS requires to be either + // both virtual or both instance. end note] + private static bool IncludeProperty(PropertyInfo member, Type reflectedType, HashSet<MethodInfo> baseDefinitions, bool flattenHierarchy) { + var getter = member.GetGetMethod(nonPublic: true); + var setter = member.GetSetMethod(nonPublic: true); + + MethodInfo virtualAccessor; + if (getter != null && getter.IsVirtual) { + virtualAccessor = getter; + } else if (setter != null && setter.IsVirtual) { + virtualAccessor = setter; + } else { + virtualAccessor = null; + } + + if (virtualAccessor != null) { + if (baseDefinitions.Add(RuntimeReflectionExtensions.GetRuntimeBaseDefinition(virtualAccessor))) { + return true; + } + } else if (member.DeclaringType == reflectedType) { + return true; + } else if (!member.IsPrivate() && (!member.IsStatic() || flattenHierarchy)) { + return true; + } + + return false; + } + + public static IEnumerable<EventInfo> GetInheritedEvents(this Type type, string name = null, bool flattenHierarchy = false) { + while (type.IsGenericParameter) { + type = type.GetBaseType(); + } + + var baseDefinitions = new HashSet<MethodInfo>(ReferenceEqualityComparer<MethodInfo>.Instance); + foreach (var ancestor in type.Ancestors()) { + if (name != null) { + var declaredEvent = ancestor.GetDeclaredEvent(name); + if (declaredEvent != null && IncludeEvent(declaredEvent, type, baseDefinitions, flattenHierarchy)) { + yield return declaredEvent; + } + } else { + foreach (var declaredEvent in ancestor.GetDeclaredEvents()) { + if (IncludeEvent(declaredEvent, type, baseDefinitions, flattenHierarchy)) { + yield return declaredEvent; + } + } + } + } + } + + private static bool IncludeEvent(EventInfo member, Type reflectedType, HashSet<MethodInfo> baseDefinitions, bool flattenHierarchy) { + var add = member.GetAddMethod(nonPublic: true); + var remove = member.GetRemoveMethod(nonPublic: true); + + // TOOD: fire method? + + MethodInfo virtualAccessor; + if (add != null && add.IsVirtual) { + virtualAccessor = add; + } else if (remove != null && remove.IsVirtual) { + virtualAccessor = remove; + } else { + virtualAccessor = null; + } + + if (virtualAccessor != null) { + if (baseDefinitions.Add(RuntimeReflectionExtensions.GetRuntimeBaseDefinition(virtualAccessor))) { + return true; + } + } else if (member.DeclaringType == reflectedType) { + return true; + } else if (!member.IsPrivate() && (!member.IsStatic() || flattenHierarchy)) { + return true; + } + + return false; + } + + public static IEnumerable<FieldInfo> GetInheritedFields(this Type type, string name = null, bool flattenHierarchy = false) { + while (type.IsGenericParameter) { + type = type.GetBaseType(); + } + + foreach (var ancestor in type.Ancestors()) { + if (name != null) { + var declaredField = ancestor.GetDeclaredField(name); + if (declaredField != null && IncludeField(declaredField, type, flattenHierarchy)) { + yield return declaredField; + } + } else { + foreach (var declaredField in ancestor.GetDeclaredFields()) { + if (IncludeField(declaredField, type, flattenHierarchy)) { + yield return declaredField; + } + } + } + } + } + + private static bool IncludeField(FieldInfo member, Type reflectedType, bool flattenHierarchy) { + if (member.DeclaringType == reflectedType) { + return true; + } else if (!member.IsPrivate && (!member.IsStatic || flattenHierarchy)) { + return true; + } + + return false; + } + + public static IEnumerable<MemberInfo> GetInheritedMembers(this Type type, string name = null, bool flattenHierarchy = false) { + var result = + type.GetInheritedMethods(name, flattenHierarchy).Cast<MethodInfo, MemberInfo>().Concat( + type.GetInheritedProperties(name, flattenHierarchy).Cast<PropertyInfo, MemberInfo>().Concat( + type.GetInheritedEvents(name, flattenHierarchy).Cast<EventInfo, MemberInfo>().Concat( + type.GetInheritedFields(name, flattenHierarchy).Cast<FieldInfo, MemberInfo>()))); + + if (name == null) { + return result.Concat<MemberInfo>( + type.GetDeclaredConstructors().Cast<ConstructorInfo, MemberInfo>().Concat( + type.GetDeclaredNestedTypes().Cast<TypeInfo, MemberInfo>())); + } + + var nestedType = type.GetDeclaredNestedType(name); + return (nestedType != null) ? result.Concat(new[] { nestedType }) : result; + } + + #endregion + + #region Declared Members + + public static IEnumerable<ConstructorInfo> GetDeclaredConstructors(this Type type) { +#if WIN8 + return type.GetTypeInfo().DeclaredConstructors; +#else + return type.GetConstructors(BindingFlags.DeclaredOnly | AllMembers); +#endif + } + +#if WIN8 + public static ConstructorInfo GetConstructor(this Type type, Type[] parameterTypes) { + return type.GetDeclaredConstructors().Where(ci => !ci.IsStatic && ci.IsPublic).WithSignature(parameterTypes).SingleOrDefault(); + } +#endif + + public static IEnumerable<MethodInfo> GetDeclaredMethods(this Type type, string name = null) { +#if WIN8 + if (name == null) { + return type.GetTypeInfo().DeclaredMethods; + } else { + return type.GetTypeInfo().GetDeclaredMethods(name); + } +#else + if (name == null) { + return type.GetMethods(BindingFlags.DeclaredOnly | AllMembers); + } else { + return type.GetMember(name, MemberTypes.Method, BindingFlags.DeclaredOnly | AllMembers).OfType<MethodInfo>(); + } +#endif + } + + public static IEnumerable<PropertyInfo> GetDeclaredProperties(this Type type) { +#if WIN8 + return type.GetTypeInfo().DeclaredProperties; +#else + return type.GetProperties(BindingFlags.DeclaredOnly | AllMembers); +#endif + } + + public static PropertyInfo GetDeclaredProperty(this Type type, string name) { + Debug.Assert(name != null); +#if WIN8 + return type.GetTypeInfo().GetDeclaredProperty(name); +#else + return type.GetProperty(name, BindingFlags.DeclaredOnly | AllMembers); +#endif + } + + public static IEnumerable<EventInfo> GetDeclaredEvents(this Type type) { +#if WIN8 + return type.GetTypeInfo().DeclaredEvents; +#else + return type.GetEvents(BindingFlags.DeclaredOnly | AllMembers); +#endif + } + + public static EventInfo GetDeclaredEvent(this Type type, string name) { + Debug.Assert(name != null); +#if WIN8 + return type.GetTypeInfo().GetDeclaredEvent(name); +#else + return type.GetEvent(name, BindingFlags.DeclaredOnly | AllMembers); +#endif + } + + public static IEnumerable<FieldInfo> GetDeclaredFields(this Type type) { +#if WIN8 + return type.GetTypeInfo().DeclaredFields; +#else + return type.GetFields(BindingFlags.DeclaredOnly | AllMembers); +#endif + } + + public static FieldInfo GetDeclaredField(this Type type, string name) { + Debug.Assert(name != null); +#if WIN8 + return type.GetTypeInfo().GetDeclaredField(name); +#else + return type.GetField(name, BindingFlags.DeclaredOnly | AllMembers); +#endif + } + + public static IEnumerable<TypeInfo> GetDeclaredNestedTypes(this Type type) { +#if WIN8 + return type.GetTypeInfo().DeclaredNestedTypes; +#else + return type.GetNestedTypes(BindingFlags.DeclaredOnly | AllMembers); +#endif + } + + public static TypeInfo GetDeclaredNestedType(this Type type, string name) { + Debug.Assert(name != null); +#if WIN8 + return type.GetTypeInfo().GetDeclaredNestedType(name); +#else + return type.GetNestedType(name, BindingFlags.DeclaredOnly | AllMembers); +#endif + } + + public static IEnumerable<MemberInfo> GetDeclaredMembers(this Type type, string name = null) { +#if WIN8 + var info = type.GetTypeInfo(); + if (name == null) { + return info.DeclaredMembers; + } else { + return GetDeclaredMembersWithName(info, name); + } +#else + if (name == null) { + return type.GetMembers(BindingFlags.DeclaredOnly | AllMembers); + } else { + return type.GetMember(name, BindingFlags.DeclaredOnly | AllMembers); + } +#endif + } + +#if WIN8 + private static IEnumerable<MemberInfo> GetDeclaredMembersWithName(TypeInfo info, string name) { + MemberInfo member; + + if ((member = info.GetDeclaredMethod(name)) != null) { + yield return member; + } + + if ((member = info.GetDeclaredField(name)) != null) { + yield return member; + } + + if ((member = info.GetDeclaredProperty(name)) != null) { + yield return member; + } + + if ((member = info.GetDeclaredEvent(name)) != null) { + yield return member; + } + + if ((member = info.GetDeclaredNestedType(name)) != null) { + yield return member; + } + } +#endif + + #endregion + + #region Win8 +#if WIN8 || CLR45 + public static TypeCode GetTypeCode(this Enum e) { + return GetTypeCode(Enum.GetUnderlyingType(e.GetType())); + } + + // TODO: reduce to numeric types? + public static TypeCode GetTypeCode(this Type type) { + if (type == typeof(int)) { + return TypeCode.Int32; + } + if (type == typeof(sbyte)) { + return TypeCode.SByte; + } + if (type == typeof(short)) { + return TypeCode.Int16; + } + if (type == typeof(long)) { + return TypeCode.Int64; + } + if (type == typeof(uint)) { + return TypeCode.UInt32; + } + if (type == typeof(byte)) { + return TypeCode.Byte; + } + if (type == typeof(ushort)) { + return TypeCode.UInt16; + } + if (type == typeof(ulong)) { + return TypeCode.UInt64; + } + if (type == typeof(bool)) { + return TypeCode.Boolean; + } + if (type == typeof(char)) { + return TypeCode.Char; + } + + // TODO: do we need this? + if (type == typeof(string)) { + return TypeCode.String; + } + if (type == typeof(bool)) { + return TypeCode.Boolean; + } + if (type == typeof(double)) { + return TypeCode.Double; + } + if (type == typeof(float)) { + return TypeCode.Single; + } + if (type == typeof(decimal)) { + return TypeCode.Decimal; + } + if (type == typeof(DateTime)) { + return TypeCode.DateTime; + } + return TypeCode.Object; + } + + public static IEnumerable<Type> GetImplementedInterfaces(this Type type) { + return type.GetTypeInfo().ImplementedInterfaces; + } + + public static MethodInfo GetGetMethod(this PropertyInfo propertyInfo, bool nonPublic = false) { + var accessor = propertyInfo.GetMethod; + return nonPublic || accessor == null || accessor.IsPublic ? accessor : null; + } + + public static MethodInfo GetSetMethod(this PropertyInfo propertyInfo, bool nonPublic = false) { + var accessor = propertyInfo.SetMethod; + return nonPublic || accessor == null || accessor.IsPublic ? accessor : null; + } + + public static MethodInfo GetAddMethod(this EventInfo eventInfo, bool nonPublic = false) { + var accessor = eventInfo.AddMethod; + return nonPublic || accessor == null || accessor.IsPublic ? accessor : null; + } + + public static MethodInfo GetRemoveMethod(this EventInfo eventInfo, bool nonPublic = false) { + var accessor = eventInfo.RemoveMethod; + return nonPublic || accessor == null || accessor.IsPublic ? accessor : null; + } + + public static MethodInfo GetRaiseMethod(this EventInfo eventInfo, bool nonPublic = false) { + var accessor = eventInfo.RaiseMethod; + return nonPublic || accessor == null || accessor.IsPublic ? accessor : null; + } + + public static MethodInfo GetMethod(this Type type, string name) { + return type.GetTypeInfo().GetDeclaredMethod(name); + } + + // TODO: FlattenHierarchy + // TODO: inherited! + public static MethodInfo GetMethod(this Type type, string name, Type[] parameterTypes) { + return type.GetTypeInfo().GetDeclaredMethods(name).WithSignature(parameterTypes).Single(); + } + + public static MethodInfo GetMethod(this Type type, string name, BindingFlags bindingFlags) { + return type.GetMethods(name, bindingFlags).Single(); + } + + private static IEnumerable<MethodInfo> GetMethods(this Type type, string name, BindingFlags bindingFlags) { + return type.GetTypeInfo().GetDeclaredMethods(name).WithBindingFlags(bindingFlags); + } + + public static MethodInfo GetMethod(this Delegate d) { + return d.GetMethodInfo(); + } + + // TODO: Callers should distinguish parameters from arguments. Stop using this method. + public static Type[] GetGenericArguments(this Type type) { + var info = type.GetTypeInfo(); + return info.IsGenericTypeDefinition ? info.GenericTypeParameters : info.GenericTypeArguments; + } + + public static Type[] GetGenericTypeArguments(this Type type) { + return type.GetTypeInfo().GenericTypeArguments; + } + + public static Type[] GetGenericTypeParameters(this Type type) { + return type.GetTypeInfo().GenericTypeParameters; + } + + public static bool IsAssignableFrom(this Type type, Type other) { + return type.GetTypeInfo().IsAssignableFrom(other.GetTypeInfo()); + } + + public static Type[] GetGenericParameterConstraints(this Type type) { + return type.GetTypeInfo().GetGenericParameterConstraints(); + } + + public static bool IsSubclassOf(this Type type, Type other) { + return type.GetTypeInfo().IsSubclassOf(other); + } + + public static IEnumerable<Type> GetInterfaces(this Type type) { + return type.GetTypeInfo().ImplementedInterfaces; + } + + public static Type[] GetRequiredCustomModifiers(this ParameterInfo parameter) { + return EmptyTypes; + } + + public static Type[] GetOptionalCustomModifiers(this ParameterInfo parameter) { + return EmptyTypes; + } + + public static IEnumerable<Module> GetModules(this Assembly assembly) { + return assembly.Modules; + } + + private static string GetDefaultMemberName(this Type type) { + foreach (var ancestor in type.Ancestors()) { + var attr = ancestor.GetTypeInfo().GetCustomAttributes<DefaultMemberAttribute>().SingleOrDefault(); + if (attr != null) { + return attr.MemberName; + } + } + + return null; + } + + public static IEnumerable<MemberInfo> GetDefaultMembers(this Type type) { + string defaultMemberName = type.GetDefaultMemberName(); + if (defaultMemberName != null) { + return type.GetInheritedMembers(defaultMemberName).WithBindingFlags(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public); + } + + return Enumerable.Empty<MemberInfo>(); + } +#else + public static Type[] GetGenericTypeArguments(this Type type) { + return type.IsGenericType && !type.IsGenericTypeDefinition ? type.GetTypeInfo().GetGenericArguments() : null; + } + + public static Type[] GetGenericTypeParameters(this Type type) { + return type.IsGenericTypeDefinition ? type.GetTypeInfo().GetGenericArguments() : null; + } + + public static IEnumerable<Module> GetModules(this Assembly assembly) { + return assembly.GetModules(); + } + + public static IEnumerable<Type> GetImplementedInterfaces(this Type type) { + return type.GetInterfaces(); + } + + public static TypeCode GetTypeCode(this Type type) { + return Type.GetTypeCode(type); + } + + public static MethodInfo GetMethodInfo(this Delegate d) { + return d.Method; + } + + public static bool IsDefined(this Assembly assembly, Type attributeType) { + return assembly.IsDefined(attributeType, false); + } + + public static T GetCustomAttribute<T>(this Assembly assembly, bool inherit = false) where T : Attribute { + return (T)Attribute.GetCustomAttribute(assembly, typeof(T), inherit); + } + + public static T GetCustomAttribute<T>(this MemberInfo member, bool inherit = false) where T : Attribute { + return (T)Attribute.GetCustomAttribute(member, typeof(T), inherit); + } + + public static IEnumerable<T> GetCustomAttributes<T>(this Assembly assembly, bool inherit = false) where T : Attribute { + return Attribute.GetCustomAttributes(assembly, typeof(T), inherit).Cast<T>(); + } + + public static IEnumerable<T> GetCustomAttributes<T>(this MemberInfo member, bool inherit = false) where T : Attribute { + return Attribute.GetCustomAttributes(member, typeof(T), inherit).Cast<T>(); + } +#endif + + public static bool ContainsGenericParameters(this Type type) { + return type.GetTypeInfo().ContainsGenericParameters; + } + + public static bool IsInterface(this Type type) { + return type.GetTypeInfo().IsInterface; + } + + public static bool IsClass(this Type type) { + return type.GetTypeInfo().IsClass; + } + + public static bool IsGenericType(this Type type) { + return type.GetTypeInfo().IsGenericType; + } + + public static bool IsGenericTypeDefinition(this Type type) { + return type.GetTypeInfo().IsGenericTypeDefinition; + } + + public static bool IsSealed(this Type type) { + return type.GetTypeInfo().IsSealed; + } + + public static bool IsAbstract(this Type type) { + return type.GetTypeInfo().IsAbstract; + } + + public static bool IsPublic(this Type type) { + return type.GetTypeInfo().IsPublic; + } + + public static bool IsVisible(this Type type) { + return type.GetTypeInfo().IsVisible; + } + + public static Type GetBaseType(this Type type) { + return type.GetTypeInfo().BaseType; + } + + public static bool IsValueType(this Type type) { + return type.GetTypeInfo().IsValueType; + } + + public static bool IsEnum(this Type type) { + return type.GetTypeInfo().IsEnum; + } + + public static bool IsPrimitive(this Type type) { + return type.GetTypeInfo().IsPrimitive; + } + + public static GenericParameterAttributes GetGenericParameterAttributes(this Type type) { + return type.GetTypeInfo().GenericParameterAttributes; + } + + public static Type[] EmptyTypes = new Type[0]; + + public static object GetRawConstantValue(this FieldInfo field) { + if (!field.IsLiteral) { + throw new ArgumentException(field + " not a literal."); + } + + object value = field.GetValue(null); + return field.FieldType.IsEnum() ? UnwrapEnumValue(value) : value; + } + + /// <summary> + /// Converts a boxed enum value to the underlying integer value. + /// </summary> + public static object UnwrapEnumValue(object value) { + if (value == null) { + throw new ArgumentNullException("value"); + } + + switch (value.GetType().GetTypeCode()) { + case TypeCode.Byte: + return System.Convert.ToByte(value); + + case TypeCode.Int16: + return System.Convert.ToInt16(value); + + case TypeCode.Int32: + return System.Convert.ToInt32(value); + + case TypeCode.Int64: + return System.Convert.ToInt64(value); + + case TypeCode.SByte: + return System.Convert.ToSByte(value); + + case TypeCode.UInt16: + return System.Convert.ToUInt16(value); + + case TypeCode.UInt32: + return System.Convert.ToUInt32(value); + + case TypeCode.UInt64: + return System.Convert.ToUInt64(value); + + default: + throw new ArgumentException("Value must be a boxed enum.", "value"); + } + } + + #endregion + +#if FEATURE_REFEMIT +#if FEATURE_ASSEMBLYBUILDER_DEFINEDYNAMICASSEMBLY + public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access) { + return AssemblyBuilder.DefineDynamicAssembly(name, access); + } +#else + public static AssemblyBuilder DefineDynamicAssembly(AssemblyName name, AssemblyBuilderAccess access) { + return AppDomain.CurrentDomain.DefineDynamicAssembly(name, access); + } +#endif +#if !FEATURE_PDBEMIT + public static ModuleBuilder DefineDynamicModule(this AssemblyBuilder assembly, string name, bool emitDebugInfo) { + // ignore the flag + return assembly.DefineDynamicModule(name); + } +#endif +#endif + + #region Signature and Type Formatting + + // Generic type names have the arity (number of generic type paramters) appended at the end. + // For eg. the mangled name of System.List<T> is "List`1". This mangling is done to enable multiple + // generic types to exist as long as they have different arities. + public const char GenericArityDelimiter = '`'; + +#if !WIN8 + public static StringBuilder FormatSignature(StringBuilder result, MethodBase method) { + return FormatSignature(result, method, (t) => t.FullName); + } + + public static StringBuilder FormatSignature(StringBuilder result, MethodBase method, Func<Type, string> nameDispenser) { + ContractUtils.RequiresNotNull(result, "result"); + ContractUtils.RequiresNotNull(method, "method"); + ContractUtils.RequiresNotNull(nameDispenser, "nameDispenser"); + + MethodInfo methodInfo = method as MethodInfo; + if (methodInfo != null) { + FormatTypeName(result, methodInfo.ReturnType, nameDispenser); + result.Append(' '); + } + +#if FEATURE_REFEMIT + MethodBuilder builder = method as MethodBuilder; + if (builder != null) { + result.Append(builder.Signature); + return result; + } + + ConstructorBuilder cb = method as ConstructorBuilder; + if (cb != null) { + result.Append(cb.Signature); + return result; + } +#endif + FormatTypeName(result, method.DeclaringType, nameDispenser); + result.Append("::"); + result.Append(method.Name); + + if (!method.IsConstructor) { + FormatTypeArgs(result, method.GetGenericArguments(), nameDispenser); + } + + result.Append("("); + + if (!method.ContainsGenericParameters) { + ParameterInfo[] ps = method.GetParameters(); + for (int i = 0; i < ps.Length; i++) { + if (i > 0) result.Append(", "); + FormatTypeName(result, ps[i].ParameterType, nameDispenser); + if (!System.String.IsNullOrEmpty(ps[i].Name)) { + result.Append(" "); + result.Append(ps[i].Name); + } + } + } else { + result.Append("?"); + } + + result.Append(")"); + return result; + } +#endif + + public static StringBuilder FormatTypeName(StringBuilder result, Type type) { + return FormatTypeName(result, type, (t) => t.FullName); + } + + public static StringBuilder FormatTypeName(StringBuilder result, Type type, Func<Type, string> nameDispenser) { + ContractUtils.RequiresNotNull(result, "result"); + ContractUtils.RequiresNotNull(type, "type"); + ContractUtils.RequiresNotNull(nameDispenser, "nameDispenser"); + + if (type.IsGenericType()) { + Type genType = type.GetGenericTypeDefinition(); + string genericName = nameDispenser(genType).Replace('+', '.'); + int tickIndex = genericName.IndexOf('`'); + result.Append(tickIndex != -1 ? genericName.Substring(0, tickIndex) : genericName); + + Type[] typeArgs = type.GetGenericArguments(); + if (type.IsGenericTypeDefinition()) { + result.Append('<'); + result.Append(',', typeArgs.Length - 1); + result.Append('>'); + } else { + FormatTypeArgs(result, typeArgs, nameDispenser); + } + } else if (type.IsGenericParameter) { + result.Append(type.Name); + } else { + // cut namespace off: + result.Append(nameDispenser(type).Replace('+', '.')); + } + return result; + } + + public static StringBuilder FormatTypeArgs(StringBuilder result, Type[] types) { + return FormatTypeArgs(result, types, (t) => t.FullName); + } + + public static StringBuilder FormatTypeArgs(StringBuilder result, Type[] types, Func<Type, string> nameDispenser) { + ContractUtils.RequiresNotNull(result, "result"); + ContractUtils.RequiresNotNullItems(types, "types"); + ContractUtils.RequiresNotNull(nameDispenser, "nameDispenser"); + + if (types.Length > 0) { + result.Append("<"); + + for (int i = 0; i < types.Length; i++) { + if (i > 0) result.Append(", "); + FormatTypeName(result, types[i], nameDispenser); + } + + result.Append(">"); + } + return result; + } + + internal static string ToValidTypeName(string str) { + if (String.IsNullOrEmpty(str)) { + return "_"; + } + + StringBuilder sb = new StringBuilder(str); + for (int i = 0; i < str.Length; i++) { + if (str[i] == '\0' || str[i] == '.' || str[i] == '*' || str[i] == '+' || str[i] == '[' || str[i] == ']' || str[i] == '\\') { + sb[i] = '_'; + } + } + return sb.ToString(); + } + + public static string GetNormalizedTypeName(Type type) { + string name = type.Name; + if (type.IsGenericType()) { + return GetNormalizedTypeName(name); + } + return name; + } + + public static string GetNormalizedTypeName(string typeName) { + Debug.Assert(typeName.IndexOf('.') == -1); // This is the simple name, not the full name + int backtick = typeName.IndexOf(ReflectionUtils.GenericArityDelimiter); + if (backtick != -1) return typeName.Substring(0, backtick); + return typeName; + } + + #endregion + + #region Delegates and Dynamic Methods + +#if WP75 + /// <summary> + /// Creates an open delegate for the given (dynamic)method. + /// </summary> + public static Delegate CreateDelegate(this MethodInfo methodInfo, Type delegateType) { + return CreateDelegate(methodInfo, delegateType, null); + } + + /// <summary> + /// Creates a closed delegate for the given (dynamic)method. + /// </summary> + public static Delegate CreateDelegate(this MethodInfo methodInfo, Type delegateType, object target) { + return Delegate.CreateDelegate(delegateType, target, methodInfo); + } +#elif !WIN8 + /// <summary> + /// Creates an open delegate for the given (dynamic)method. + /// </summary> + public static Delegate CreateDelegate(this MethodInfo methodInfo, Type delegateType) { + return CreateDelegate(methodInfo, delegateType, null); + } + + /// <summary> + /// Creates a closed delegate for the given (dynamic)method. + /// </summary> + public static Delegate CreateDelegate(this MethodInfo methodInfo, Type delegateType, object target) { +#if FEATURE_REFEMIT + DynamicMethod dm = methodInfo as DynamicMethod; + if (dm != null) { + return dm.CreateDelegate(delegateType, target); +#endif + return Delegate.CreateDelegate(delegateType, target, methodInfo); + } +#endif + +#if FEATURE_LCG + public static bool IsDynamicMethod(MethodBase method) { + return !PlatformAdaptationLayer.IsCompactFramework && IsDynamicMethodInternal(method); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static bool IsDynamicMethodInternal(MethodBase method) { + return method is DynamicMethod; + } +#else + public static bool IsDynamicMethod(MethodBase method) { + return false; + } +#endif + + public static void GetDelegateSignature(Type delegateType, out ParameterInfo[] parameterInfos, out ParameterInfo returnInfo) { + ContractUtils.RequiresNotNull(delegateType, "delegateType"); + + MethodInfo invokeMethod = delegateType.GetMethod("Invoke"); + ContractUtils.Requires(invokeMethod != null, "delegateType", Strings.InvalidDelegate); + + parameterInfos = invokeMethod.GetParameters(); + returnInfo = invokeMethod.ReturnParameter; + } + + /// <summary> + /// Gets a Func of CallSite, object * paramCnt, object delegate type + /// that's suitable for use in a non-strongly typed call site. + /// </summary> + public static Type GetObjectCallSiteDelegateType(int paramCnt) { + switch (paramCnt) { + case 0: return typeof(Func<CallSite, object, object>); + case 1: return typeof(Func<CallSite, object, object, object>); + case 2: return typeof(Func<CallSite, object, object, object, object>); + case 3: return typeof(Func<CallSite, object, object, object, object, object>); + case 4: return typeof(Func<CallSite, object, object, object, object, object, object>); + case 5: return typeof(Func<CallSite, object, object, object, object, object, object, object>); + case 6: return typeof(Func<CallSite, object, object, object, object, object, object, object, object>); + case 7: return typeof(Func<CallSite, object, object, object, object, object, object, object, object, object>); + case 8: return typeof(Func<CallSite, object, object, object, object, object, object, object, object, object, object>); + case 9: return typeof(Func<CallSite, object, object, object, object, object, object, object, object, object, object, object>); + case 10: return typeof(Func<CallSite, object, object, object, object, object, object, object, object, object, object, object, object>); + case 11: return typeof(Func<CallSite, object, object, object, object, object, object, object, object, object, object, object, object, object>); + case 12: return typeof(Func<CallSite, object, object, object, object, object, object, object, object, object, object, object, object, object, object>); + case 13: return typeof(Func<CallSite, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>); + case 14: return typeof(Func<CallSite, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>); + default: +#if FEATURE_REFEMIT + Type[] paramTypes = new Type[paramCnt + 2]; + paramTypes[0] = typeof(CallSite); + paramTypes[1] = typeof(object); + for (int i = 0; i < paramCnt; i++) { + paramTypes[i + 2] = typeof(object); + } + return Snippets.Shared.DefineDelegate("InvokeDelegate" + paramCnt, typeof(object), paramTypes); +#else + throw new NotSupportedException("Signature not supported on this platform."); +#endif + } + } + +#if FEATURE_LCG + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Portability", "CA1903:UseOnlyApiFromTargetedFramework")] + internal static DynamicMethod RawCreateDynamicMethod(string name, Type returnType, Type[] parameterTypes) { +#if SILVERLIGHT // Module-hosted DynamicMethod is not available in SILVERLIGHT + return new DynamicMethod(name, returnType, parameterTypes); +#else + // + // WARNING: we set restrictedSkipVisibility == true (last parameter) + // setting this bit will allow accessing nonpublic members + // for more information see http://msdn.microsoft.com/en-us/library/bb348332.aspx + // + return new DynamicMethod(name, returnType, parameterTypes, true); +#endif + } +#endif + + #endregion + + #region Methods and Parameters + + public static MethodBase[] GetMethodInfos(MemberInfo[] members) { + return ArrayUtils.ConvertAll<MemberInfo, MethodBase>( + members, + delegate(MemberInfo inp) { return (MethodBase)inp; }); + } + + public static Type[] GetParameterTypes(ParameterInfo[] parameterInfos) { + return GetParameterTypes((IList<ParameterInfo>)parameterInfos); + } + + public static Type[] GetParameterTypes(IList<ParameterInfo> parameterInfos) { + Type[] result = new Type[parameterInfos.Count]; + for (int i = 0; i < result.Length; i++) { + result[i] = parameterInfos[i].ParameterType; + } + return result; + } + + public static Type GetReturnType(this MethodBase mi) { + return (mi.IsConstructor) ? mi.DeclaringType : ((MethodInfo)mi).ReturnType; + } + + public static bool SignatureEquals(MethodInfo method, params Type[] requiredSignature) { + ContractUtils.RequiresNotNull(method, "method"); + + Type[] actualTypes = ReflectionUtils.GetParameterTypes(method.GetParameters()); + Debug.Assert(actualTypes.Length == requiredSignature.Length - 1); + int i = 0; + while (i < actualTypes.Length) { + if (actualTypes[i] != requiredSignature[i]) return false; + i++; + } + + return method.ReturnType == requiredSignature[i]; + } + +#if CLR2 && !SILVERLIGHT + private static Type _ExtensionAttributeType; +#endif + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + public static bool IsExtension(this MemberInfo member) { + var dlrExtension = typeof(ExtensionAttribute); + if (member.IsDefined(dlrExtension, false)) { + return true; + } + +#if CLR2 && !SILVERLIGHT + if (_ExtensionAttributeType == null) { + try { + _ExtensionAttributeType = Assembly.Load("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089") + .GetType("System.Runtime.CompilerServices.ExtensionAttribute"); + } catch { + _ExtensionAttributeType = dlrExtension; + } + } + + if (_ExtensionAttributeType != dlrExtension) { + return member.IsDefined(_ExtensionAttributeType, false); + } +#endif + return false; + } + + public static bool IsOutParameter(this ParameterInfo pi) { + // not using IsIn/IsOut properties as they are not available in Silverlight: + return pi.ParameterType.IsByRef && (pi.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out; + } + + /// <summary> + /// Returns <c>true</c> if the specified parameter is mandatory, i.e. is not optional and doesn't have a default value. + /// </summary> + public static bool IsMandatory(this ParameterInfo pi) { + return (pi.Attributes & ParameterAttributes.Optional) == 0 && !pi.HasDefaultValue(); + } + + public static bool HasDefaultValue(this ParameterInfo pi) { +#if !FEATURE_DEFAULT_PARAMETER_VALUE + return pi.IsDefined(typeof(DefaultParameterValueAttribute), false); +#else + return (pi.Attributes & ParameterAttributes.HasDefault) != 0; +#endif + } + + public static bool ProhibitsNull(this ParameterInfo parameter) { + return parameter.IsDefined(typeof(NotNullAttribute), false); + } + + public static bool ProhibitsNullItems(this ParameterInfo parameter) { + return parameter.IsDefined(typeof(NotNullItemsAttribute), false); + } + + public static bool IsParamArray(this ParameterInfo parameter) { + return parameter.IsDefined(typeof(ParamArrayAttribute), false); + } + + public static bool IsParamDictionary(this ParameterInfo parameter) { + return parameter.IsDefined(typeof(ParamDictionaryAttribute), false); + } + + public static bool IsParamsMethod(MethodBase method) { + return IsParamsMethod(method.GetParameters()); + } + + public static bool IsParamsMethod(ParameterInfo[] pis) { + foreach (ParameterInfo pi in pis) { + if (pi.IsParamArray() || pi.IsParamDictionary()) return true; + } + return false; + } + + public static object GetDefaultValue(this ParameterInfo info) { +#if !FEATURE_DEFAULT_PARAMETER_VALUE + if (info.IsOptional) { + return info.ParameterType == typeof(object) ? Missing.Value : ScriptingRuntimeHelpers.GetPrimitiveDefaultValue(info.ParameterType); + } + + var defaultValueAttribute = info.GetCustomAttributes(typeof(DefaultParameterValueAttribute), false); + if (defaultValueAttribute.Length > 0) { + return ((DefaultParameterValueAttribute)defaultValueAttribute[0]).Value; + } + + return null; +#else + return info.DefaultValue; +#endif + } + + #endregion + + #region Types + + /// <summary> + /// Yields all ancestors of the given type including the type itself. + /// Does not include implemented interfaces. + /// </summary> + public static IEnumerable<Type> Ancestors(this Type type) { + do { + yield return type; + type = type.GetTypeInfo().BaseType; + } while (type != null); + } + + /// <summary> + /// Like Type.GetInterfaces, but only returns the interfaces implemented by this type + /// and not its parents. + /// </summary> + public static List<Type> GetDeclaredInterfaces(Type type) { + IEnumerable<Type> baseInterfaces = (type.GetBaseType() != null) ? type.GetBaseType().GetInterfaces() : EmptyTypes; + List<Type> interfaces = new List<Type>(); + foreach (Type iface in type.GetInterfaces()) { + if (!baseInterfaces.Contains(iface)) { + interfaces.Add(iface); + } + } + return interfaces; + } + + internal static IEnumerable<TypeInfo> GetAllTypesFromAssembly(Assembly asm) { + // TODO: WP7, SL5 +#if SILVERLIGHT // ReflectionTypeLoadException + try { + return asm.GetTypes(); + } catch (Exception) { + return ReflectionUtils.EmptyTypes; + } +#elif WIN8 + return asm.DefinedTypes; +#else + foreach (Module module in asm.GetModules()) { + Type[] moduleTypes; + try { + moduleTypes = module.GetTypes(); + } catch (ReflectionTypeLoadException e) { + moduleTypes = e.Types; + } + + foreach (var type in moduleTypes) { + if (type != null) { + yield return type; + } + } + } +#endif + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + internal static IEnumerable<TypeInfo> GetAllTypesFromAssembly(Assembly assembly, bool includePrivateTypes) { + ContractUtils.RequiresNotNull(assembly, "assembly"); + + if (includePrivateTypes) { + return GetAllTypesFromAssembly(assembly); + } + + try { +#if WIN8 + return assembly.ExportedTypes.Select(t => t.GetTypeInfo()); +#else + return assembly.GetExportedTypes(); +#endif + } catch (NotSupportedException) { + // GetExportedTypes does not work with dynamic assemblies + } catch (Exception) { + // Some type loads may cause exceptions. Unfortunately, there is no way to ask GetExportedTypes + // for just the list of types that we successfully loaded. + } + + return GetAllTypesFromAssembly(assembly).Where(type => type.IsPublic); + } + + #endregion + + #region Type Builder +#if FEATURE_REFEMIT + +#if WIN8 // TODO: what is ReservedMask? + private const MethodAttributes MethodAttributesToEraseInOveride = MethodAttributes.Abstract | (MethodAttributes)0xD000; +#else + private const MethodAttributes MethodAttributesToEraseInOveride = MethodAttributes.Abstract | MethodAttributes.ReservedMask; +#endif + + public static MethodBuilder DefineMethodOverride(TypeBuilder tb, MethodAttributes extra, MethodInfo decl) { + MethodAttributes finalAttrs = (decl.Attributes & ~MethodAttributesToEraseInOveride) | extra; + if (!decl.DeclaringType.GetTypeInfo().IsInterface) { + finalAttrs &= ~MethodAttributes.NewSlot; + } + + if ((extra & MethodAttributes.MemberAccessMask) != 0) { + // remove existing member access, add new member access + finalAttrs &= ~MethodAttributes.MemberAccessMask; + finalAttrs |= extra; + } + + MethodBuilder impl = tb.DefineMethod(decl.Name, finalAttrs, decl.CallingConvention); + CopyMethodSignature(decl, impl, false); + return impl; + } + + public static void CopyMethodSignature(MethodInfo from, MethodBuilder to, bool substituteDeclaringType) { + ParameterInfo[] paramInfos = from.GetParameters(); + Type[] parameterTypes = new Type[paramInfos.Length]; + Type[][] parameterRequiredModifiers = null, parameterOptionalModifiers = null; + Type[] returnRequiredModifiers = null, returnOptionalModifiers = null; + +#if FEATURE_CUSTOM_MODIFIERS + returnRequiredModifiers = from.ReturnParameter.GetRequiredCustomModifiers(); + returnOptionalModifiers = from.ReturnParameter.GetOptionalCustomModifiers(); +#endif + for (int i = 0; i < paramInfos.Length; i++) { + if (substituteDeclaringType && paramInfos[i].ParameterType == from.DeclaringType) { + parameterTypes[i] = to.DeclaringType; + } else { + parameterTypes[i] = paramInfos[i].ParameterType; + } + +#if FEATURE_CUSTOM_MODIFIERS + var mods = paramInfos[i].GetRequiredCustomModifiers(); + if (mods.Length > 0) { + if (parameterRequiredModifiers == null) { + parameterRequiredModifiers = new Type[paramInfos.Length][]; + } + + parameterRequiredModifiers[i] = mods; + } + + mods = paramInfos[i].GetOptionalCustomModifiers(); + if (mods.Length > 0) { + if (parameterOptionalModifiers == null) { + parameterOptionalModifiers = new Type[paramInfos.Length][]; + } + + parameterOptionalModifiers[i] = mods; + } +#endif + } + + to.SetSignature( + from.ReturnType, returnRequiredModifiers, returnOptionalModifiers, + parameterTypes, parameterRequiredModifiers, parameterOptionalModifiers + ); + + CopyGenericMethodAttributes(from, to); + + for (int i = 0; i < paramInfos.Length; i++) { + to.DefineParameter(i + 1, paramInfos[i].Attributes, paramInfos[i].Name); + } + } + + private static void CopyGenericMethodAttributes(MethodInfo from, MethodBuilder to) { + if (from.IsGenericMethodDefinition) { + Type[] args = from.GetGenericArguments(); + string[] names = new string[args.Length]; + for (int i = 0; i < args.Length; i++) { + names[i] = args[i].Name; + } + var builders = to.DefineGenericParameters(names); + for (int i = 0; i < args.Length; i++) { + // Copy template parameter attributes + builders[i].SetGenericParameterAttributes(args[i].GetGenericParameterAttributes()); + + // Copy template parameter constraints + Type[] constraints = args[i].GetGenericParameterConstraints(); + List<Type> interfaces = new List<Type>(constraints.Length); + foreach (Type constraint in constraints) { + if (constraint.IsInterface()) { + interfaces.Add(constraint); + } else { + builders[i].SetBaseTypeConstraint(constraint); + } + } + if (interfaces.Count > 0) { + builders[i].SetInterfaceConstraints(interfaces.ToArray()); + } + } + } + } +#endif + #endregion + + #region Extension Methods + + public static IEnumerable<MethodInfo> GetVisibleExtensionMethods(Assembly assembly) { +#if FEATURE_METADATA_READER + if (!assembly.IsDynamic && AppDomain.CurrentDomain.IsFullyTrusted) { + try { + return GetVisibleExtensionMethodsFast(assembly); + } catch (SecurityException) { + // full-demand can still fail if there is a partial trust domain on the stack + } + } +#endif + return GetVisibleExtensionMethodsSlow(assembly); + } + +#if FEATURE_METADATA_READER + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2116:AptcaMethodsShouldOnlyCallAptcaMethods")] + [MethodImpl(MethodImplOptions.NoInlining)] + private static IEnumerable<MethodInfo> GetVisibleExtensionMethodsFast(Assembly assembly) { + // Security: link demand + return MetadataServices.GetVisibleExtensionMethodInfos(assembly); + } +#endif + + // TODO: make internal + // TODO: handle type load exceptions + public static IEnumerable<MethodInfo> GetVisibleExtensionMethodsSlow(Assembly assembly) { + var ea = typeof(ExtensionAttribute); + if (assembly.IsDefined(ea)) { + foreach (TypeInfo type in ReflectionUtils.GetAllTypesFromAssembly(assembly)) { + if ((type.IsPublic || type.IsNestedPublic) && + type.IsAbstract && + type.IsSealed && + type.IsDefined(ea, false)) { + + foreach (MethodInfo method in type.AsType().GetDeclaredMethods()) { + if (method.IsPublic && method.IsStatic && method.IsDefined(ea, false)) { + yield return method; + } + } + } + } + } + } + + // Value is null if there are no extension methods in the assembly. + private static Dictionary<Assembly, Dictionary<string, List<ExtensionMethodInfo>>> _extensionMethodsCache; + + /// <summary> + /// Enumerates extension methods in given assembly. Groups the methods by declaring namespace. + /// Uses a global cache if <paramref name="useCache"/> is true. + /// </summary> + public static IEnumerable<KeyValuePair<string, IEnumerable<ExtensionMethodInfo>>> GetVisibleExtensionMethodGroups(Assembly/*!*/ assembly, bool useCache) { +#if !CLR2 && FEATURE_REFEMIT + useCache &= !assembly.IsDynamic; +#endif + if (useCache) { + if (_extensionMethodsCache == null) { + _extensionMethodsCache = new Dictionary<Assembly, Dictionary<string, List<ExtensionMethodInfo>>>(); + } + + lock (_extensionMethodsCache) { + Dictionary<string, List<ExtensionMethodInfo>> existing; + if (_extensionMethodsCache.TryGetValue(assembly, out existing)) { + return EnumerateExtensionMethods(existing); + } + } + } + + Dictionary<string, List<ExtensionMethodInfo>> result = null; + foreach (MethodInfo method in ReflectionUtils.GetVisibleExtensionMethodsSlow(assembly)) { + if (method.DeclaringType == null || method.DeclaringType.IsGenericTypeDefinition()) { + continue; + } + + var parameters = method.GetParameters(); + if (parameters.Length == 0) { + continue; + } + + Type type = parameters[0].ParameterType; + if (type.IsByRef || type.IsPointer) { + continue; + } + + string ns = method.DeclaringType.Namespace ?? String.Empty; + List<ExtensionMethodInfo> extensions = null; + + if (result == null) { + result = new Dictionary<string, List<ExtensionMethodInfo>>(); + } + + if (!result.TryGetValue(ns, out extensions)) { + result.Add(ns, extensions = new List<ExtensionMethodInfo>()); + } + + extensions.Add(new ExtensionMethodInfo(type, method)); + } + + if (useCache) { + lock (_extensionMethodsCache) { + _extensionMethodsCache[assembly] = result; + } + } + + return EnumerateExtensionMethods(result); + } + + // TODO: GetVisibleExtensionMethods(Hashset<string> namespaces, Type type, string methodName) : IEnumerable<MethodInfo> {} + + private static IEnumerable<KeyValuePair<string, IEnumerable<ExtensionMethodInfo>>> EnumerateExtensionMethods(Dictionary<string, List<ExtensionMethodInfo>> dict) { + if (dict != null) { + foreach (var entry in dict) { + yield return new KeyValuePair<string, IEnumerable<ExtensionMethodInfo>>(entry.Key, new ReadOnlyCollection<ExtensionMethodInfo>(entry.Value)); + } + } + } + + #endregion + + #region Generic Types + + internal static Dictionary<Type, Type> BindGenericParameters(Type/*!*/ openType, Type/*!*/ closedType, bool ignoreUnboundParameters) { + var binding = new Dictionary<Type, Type>(); + BindGenericParameters(openType, closedType, (parameter, type) => { + Type existing; + if (binding.TryGetValue(parameter, out existing)) { + return type == existing; + } + + binding[parameter] = type; + + return true; + }); + + return ConstraintsViolated(binding, ignoreUnboundParameters) ? null : binding; + } + + /// <summary> + /// Binds occurances of generic parameters in <paramref name="openType"/> against corresponding types in <paramref name="closedType"/>. + /// Invokes <paramref name="binder"/>(parameter, type) for each such binding. + /// Returns false if the <paramref name="openType"/> is structurally different from <paramref name="closedType"/> or if the binder returns false. + /// </summary> + internal static bool BindGenericParameters(Type/*!*/ openType, Type/*!*/ closedType, Func<Type, Type, bool>/*!*/ binder) { + if (openType.IsGenericParameter) { + return binder(openType, closedType); + } + + if (openType.IsArray) { + if (!closedType.IsArray) { + return false; + } + return BindGenericParameters(openType.GetElementType(), closedType.GetElementType(), binder); + } + + if (!openType.IsGenericType() || !closedType.IsGenericType()) { + return openType == closedType; + } + + if (openType.GetGenericTypeDefinition() != closedType.GetGenericTypeDefinition()) { + return false; + } + + Type[] closedArgs = closedType.GetGenericArguments(); + Type[] openArgs = openType.GetGenericArguments(); + + for (int i = 0; i < openArgs.Length; i++) { + if (!BindGenericParameters(openArgs[i], closedArgs[i], binder)) { + return false; + } + } + + return true; + } + + internal static bool ConstraintsViolated(Dictionary<Type, Type>/*!*/ binding, bool ignoreUnboundParameters) { + foreach (var entry in binding) { + if (ConstraintsViolated(entry.Key, entry.Value, binding, ignoreUnboundParameters)) { + return true; + } + } + + return false; + } + + internal static bool ConstraintsViolated(Type/*!*/ genericParameter, Type/*!*/ closedType, Dictionary<Type, Type>/*!*/ binding, bool ignoreUnboundParameters) { + if ((genericParameter.GetGenericParameterAttributes() & GenericParameterAttributes.ReferenceTypeConstraint) != 0 && closedType.IsValueType()) { + // value type to parameter type constrained as class + return true; + } + + if ((genericParameter.GetGenericParameterAttributes() & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0 && + (!closedType.IsValueType() || (closedType.IsGenericType() && closedType.GetGenericTypeDefinition() == typeof(Nullable<>)))) { + // nullable<T> or class/interface to parameter type constrained as struct + return true; + } + + if ((genericParameter.GetGenericParameterAttributes() & GenericParameterAttributes.DefaultConstructorConstraint) != 0 && + (!closedType.IsValueType() && closedType.GetConstructor(ReflectionUtils.EmptyTypes) == null)) { + // reference type w/o a default constructor to type constrianed as new() + return true; + } + + Type[] constraints = genericParameter.GetGenericParameterConstraints(); + for (int i = 0; i < constraints.Length; i++) { + Type instantiation = InstantiateConstraint(constraints[i], binding); + + if (instantiation == null) { + if (ignoreUnboundParameters) { + continue; + } else { + return true; + } + } + + if (!instantiation.IsAssignableFrom(closedType)) { + return true; + } + } + + return false; + } + + internal static Type InstantiateConstraint(Type/*!*/ constraint, Dictionary<Type, Type>/*!*/ binding) { + Debug.Assert(!constraint.IsArray && !constraint.IsByRef && !constraint.IsGenericTypeDefinition()); + if (!constraint.ContainsGenericParameters()) { + return constraint; + } + + Type closedType; + if (constraint.IsGenericParameter) { + return binding.TryGetValue(constraint, out closedType) ? closedType : null; + } + + Type[] args = constraint.GetGenericArguments(); + for (int i = 0; i < args.Length; i++) { + if ((args[i] = InstantiateConstraint(args[i], binding)) == null) { + return null; + } + } + + return constraint.GetGenericTypeDefinition().MakeGenericType(args); + } + + #endregion + } + + public struct ExtensionMethodInfo : IEquatable<ExtensionMethodInfo> { + private readonly Type/*!*/ _extendedType; // cached type of the first parameter + private readonly MethodInfo/*!*/ _method; + + internal ExtensionMethodInfo(Type/*!*/ extendedType, MethodInfo/*!*/ method) { + Assert.NotNull(extendedType, method); + _extendedType = extendedType; + _method = method; + } + + public Type/*!*/ ExtendedType { + get { return _extendedType; } + } + + public MethodInfo/*!*/ Method { + get { return _method; } + } + + public override bool Equals(object obj) { + return obj is ExtensionMethodInfo && Equals((ExtensionMethodInfo)obj); + } + + public bool Equals(ExtensionMethodInfo other) { + return _method.Equals(other._method); + } + + public static bool operator ==(ExtensionMethodInfo self, ExtensionMethodInfo other) { + return self.Equals(other); + } + + public static bool operator !=(ExtensionMethodInfo self, ExtensionMethodInfo other) { + return !self.Equals(other); + } + + public override int GetHashCode() { + return _method.GetHashCode(); + } + + /// <summary> + /// Determines if a given type matches the type that the method extends. + /// The match might be non-trivial if the extended type is an open generic type with constraints. + /// </summary> + public bool IsExtensionOf(Type/*!*/ type) { + ContractUtils.RequiresNotNull(type, "type"); +#if FEATURE_TYPE_EQUIVALENCE + if (type.IsEquivalentTo(ExtendedType)) { + return true; + } +#else + if (type == _extendedType) { + return true; + } +#endif + if (!_extendedType.GetTypeInfo().ContainsGenericParameters) { + return false; + } + + // + // Ignores constraints that can't be instantiated given the information we have (type of the first parameter). + // + // For example, + // void Foo<S, T>(this S x, T y) where S : T; + // + // We make such methods available on all types. + // If they are not called with arguments that satisfy the constraint the overload resolver might fail. + // + return ReflectionUtils.BindGenericParameters(_extendedType, type, true) != null; + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/StringUtils.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/StringUtils.cs new file mode 100644 index 00000000000..934021ff69b --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/StringUtils.cs @@ -0,0 +1,269 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace Microsoft.Scripting.Utils { + public static class StringUtils { + + public static Encoding DefaultEncoding { + get { +#if FEATURE_ENCODING + return Encoding.Default; +#else + return Encoding.UTF8; +#endif + } + } + + public static string GetSuffix(string str, char separator, bool includeSeparator) { + ContractUtils.RequiresNotNull(str, "str"); + int last = str.LastIndexOf(separator); + return (last != -1) ? str.Substring(includeSeparator ? last : last + 1) : null; + } + + public static string GetLongestPrefix(string str, char separator, bool includeSeparator) { + ContractUtils.RequiresNotNull(str, "str"); + int last = str.LastIndexOf(separator); + return (last != -1) ? str.Substring(0, (includeSeparator || last == 0) ? last : last - 1) : null; + } + + public static int CountOf(string str, char c) { + if (System.String.IsNullOrEmpty(str)) return 0; + + int result = 0; + for (int i = 0; i < str.Length; i++) { + if (c == str[i]) { + result++; + } + } + return result; + } + + public static string[] Split(string str, string separator, int maxComponents, StringSplitOptions options) { + ContractUtils.RequiresNotNull(str, "str"); +#if SILVERLIGHT || WP75 + if (string.IsNullOrEmpty(separator)) throw new ArgumentNullException("separator"); + + bool keep_empty = (options & StringSplitOptions.RemoveEmptyEntries) != StringSplitOptions.RemoveEmptyEntries; + + List<string> result = new List<string>(maxComponents == Int32.MaxValue ? 1 : maxComponents + 1); + + int i = 0; + int next; + while (maxComponents > 1 && i < str.Length && (next = str.IndexOf(separator, i)) != -1) { + + if (next > i || keep_empty) { + result.Add(str.Substring(i, next - i)); + maxComponents--; + } + + i = next + separator.Length; + } + + if (i < str.Length || keep_empty) { + result.Add(str.Substring(i)); + } + + return result.ToArray(); +#else + return str.Split(new string[] { separator }, maxComponents, options); +#endif + } + + public static string[] Split(string str, char[] separators, int maxComponents, StringSplitOptions options) { + ContractUtils.RequiresNotNull(str, "str"); +#if SILVERLIGHT || WP75 + if (separators == null) return SplitOnWhiteSpace(str, maxComponents, options); + + bool keep_empty = (options & StringSplitOptions.RemoveEmptyEntries) != StringSplitOptions.RemoveEmptyEntries; + + List<string> result = new List<string>(maxComponents == Int32.MaxValue ? 1 : maxComponents + 1); + + int i = 0; + int next; + while (maxComponents > 1 && i < str.Length && (next = str.IndexOfAny(separators, i)) != -1) { + + if (next > i || keep_empty) { + result.Add(str.Substring(i, next - i)); + maxComponents--; + } + + i = next + 1; + } + + if (i < str.Length || keep_empty) { + result.Add(str.Substring(i)); + } + + return result.ToArray(); +#else + return str.Split(separators, maxComponents, options); +#endif + } + +#if SILVERLIGHT|| WP75 + public static string[] SplitOnWhiteSpace(string str, int maxComponents, StringSplitOptions options) { + ContractUtils.RequiresNotNull(str, "str"); + + bool keep_empty = (options & StringSplitOptions.RemoveEmptyEntries) != StringSplitOptions.RemoveEmptyEntries; + + List<string> result = new List<string>(maxComponents == Int32.MaxValue ? 1 : maxComponents + 1); + + int i = 0; + int next; + while (maxComponents > 1 && i < str.Length && (next = IndexOfWhiteSpace(str, i)) != -1) { + + if (next > i || keep_empty) { + result.Add(str.Substring(i, next - i)); + maxComponents--; + } + + i = next + 1; + } + + if (i < str.Length || keep_empty) { + result.Add(str.Substring(i)); + } + + return result.ToArray(); + } + + public static int IndexOfWhiteSpace(string str, int start) { + ContractUtils.RequiresNotNull(str, "str"); + if (start < 0 || start > str.Length) throw new ArgumentOutOfRangeException("start"); + + while (start < str.Length && !Char.IsWhiteSpace(str[start])) start++; + + return (start == str.Length) ? -1 : start; + } +#endif + + /// <summary> + /// Splits text and optionally indents first lines - breaks along words, not characters. + /// </summary> + public static string SplitWords(string text, bool indentFirst, int lineWidth) { + ContractUtils.RequiresNotNull(text, "text"); + + const string indent = " "; + + if (text.Length <= lineWidth || lineWidth <= 0) { + if (indentFirst) return indent + text; + return text; + } + + StringBuilder res = new StringBuilder(); + int start = 0, len = lineWidth; + while (start != text.Length) { + if (len >= lineWidth) { + // find last space to break on + while (len != 0 && !Char.IsWhiteSpace(text[start + len - 1])) + len--; + } + + if (res.Length != 0) res.Append(' '); + if (indentFirst || res.Length != 0) res.Append(indent); + + if (len == 0) { + int copying = System.Math.Min(lineWidth, text.Length - start); + res.Append(text, start, copying); + start += copying; + } else { + res.Append(text, start, len); + start += len; + } + res.AppendLine(); + len = System.Math.Min(lineWidth, text.Length - start); + } + return res.ToString(); + } + + public static string AddSlashes(string str) { + ContractUtils.RequiresNotNull(str, "str"); + + // TODO: optimize + StringBuilder result = new StringBuilder(str.Length); + for (int i = 0; i < str.Length; i++) { + switch (str[i]) { + case '\a': result.Append("\\a"); break; + case '\b': result.Append("\\b"); break; + case '\f': result.Append("\\f"); break; + case '\n': result.Append("\\n"); break; + case '\r': result.Append("\\r"); break; + case '\t': result.Append("\\t"); break; + case '\v': result.Append("\\v"); break; + default: result.Append(str[i]); break; + } + } + + return result.ToString(); + } + + public static bool TryParseDouble(string s, NumberStyles style, IFormatProvider provider, out double result) { + return Double.TryParse(s, style, provider, out result); + } + + public static bool TryParseInt32(string s, out int result) { + return Int32.TryParse(s, out result); + } + + public static bool TryParseDateTimeExact(string s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result) { + return DateTime.TryParseExact(s, format, provider, style, out result); + } + + public static bool TryParseDateTimeExact(string s, string[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result) { + return DateTime.TryParseExact(s, formats, provider, style, out result); + } + + public static bool TryParseDate(string s, IFormatProvider provider, DateTimeStyles style, out DateTime result) { + return DateTime.TryParse(s, provider, style, out result); + } + +#if !WIN8 +#if SILVERLIGHT || WP75 + private static Dictionary<string, CultureInfo> _cultureInfoCache = new Dictionary<string, CultureInfo>(); +#endif + + // Aims to be equivalent to Culture.GetCultureInfo for Silverlight + public static CultureInfo GetCultureInfo(string name) { +#if SILVERLIGHT || WP75 + lock (_cultureInfoCache) { + CultureInfo result; + if (_cultureInfoCache.TryGetValue(name, out result)) { + return result; + } + _cultureInfoCache[name] = result = new CultureInfo(name); + return result; + } +#else + return CultureInfo.GetCultureInfo(name); +#endif + } +#endif + // Like string.Split, but enumerates + public static IEnumerable<string> Split(string str, string sep) { + int start = 0, end; + while ((end = str.IndexOf(sep, start)) != -1) { + yield return str.Substring(start, end - start); + + start = end + sep.Length; + } + yield return str.Substring(start); + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/TypeUtils.cs b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/TypeUtils.cs new file mode 100644 index 00000000000..c20371d0f0e --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Dynamic/Utils/TypeUtils.cs @@ -0,0 +1,375 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Reflection; +using System.Dynamic; +using Microsoft.Scripting.Generation; +using Microsoft.Scripting.Runtime; + +namespace Microsoft.Scripting.Utils { + public static class TypeUtils { + public static bool IsNested(this Type t) { + return t.DeclaringType != null; + } + + // keep in sync with System.Core version + internal static Type GetNonNullableType(Type type) { + if (IsNullableType(type)) { + return type.GetGenericArguments()[0]; + } + return type; + } + + // keep in sync with System.Core version + internal static bool IsNullableType(Type type) { + return type.IsGenericType() && type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + // keep in sync with System.Core version + internal static bool IsBool(Type type) { + return GetNonNullableType(type) == typeof(bool); + } + + // keep in sync with System.Core version + internal static bool IsNumeric(Type type) { + type = GetNonNullableType(type); + if (!type.IsEnum()) { + return IsNumeric(type.GetTypeCode()); + } + return false; + } + + internal static bool IsNumeric(TypeCode typeCode) { + switch (typeCode) { + case TypeCode.Char: + case TypeCode.SByte: + case TypeCode.Byte: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Double: + case TypeCode.Single: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + return true; + } + return false; + } + + // keep in sync with System.Core version + internal static bool IsArithmetic(Type type) { + type = GetNonNullableType(type); + if (!type.IsEnum()) { + switch (type.GetTypeCode()) { + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Double: + case TypeCode.Single: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + return true; + } + } + return false; + } + + // keep in sync with System.Core version + internal static bool IsUnsignedInt(Type type) { + type = GetNonNullableType(type); + if (!type.IsEnum()) { + switch (type.GetTypeCode()) { + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + return true; + } + } + return false; + } + + // keep in sync with System.Core version + internal static bool IsIntegerOrBool(Type type) { + type = GetNonNullableType(type); + if (!type.IsEnum()) { + switch (type.GetTypeCode()) { + case TypeCode.Int64: + case TypeCode.Int32: + case TypeCode.Int16: + case TypeCode.UInt64: + case TypeCode.UInt32: + case TypeCode.UInt16: + case TypeCode.Boolean: + case TypeCode.SByte: + case TypeCode.Byte: + return true; + } + } + return false; + } + + internal static bool CanAssign(Type to, Expression from) { + if (CanAssign(to, from.Type)) return true; + + if (to.IsValueType() && + to.IsGenericType() && + to.GetGenericTypeDefinition() == typeof(Nullable<>) && + ConstantCheck.Check(from, null)) { + return true; + } + + return false; + } + + internal static bool CanAssign(Type to, Type from) { + if (to == from) { + return true; + } + // Reference types + if (!to.IsValueType() && !from.IsValueType()) { + if (to.IsAssignableFrom(from)) { + return true; + } + // Arrays can be assigned if they have same rank and assignable element types. + if (to.IsArray && from.IsArray && + to.GetArrayRank() == from.GetArrayRank() && + CanAssign(to.GetElementType(), from.GetElementType())) { + return true; + } + } + + return false; + } + + internal static bool IsGeneric(Type type) { + return type.ContainsGenericParameters() || type.IsGenericTypeDefinition(); + } + + internal static bool CanCompareToNull(Type type) { + // This is a bit too conservative. + return !type.IsValueType(); + } + + /// <summary> + /// Returns a numerical code of the size of a type. All types get both a horizontal + /// and vertical code. Types that are lower in both dimensions have implicit conversions + /// to types that are higher in both dimensions. + /// </summary> + internal static bool GetNumericConversionOrder(TypeCode code, out int x, out int y) { + // implicit conversions: + // 0 1 2 3 4 + // 0: U1 -> U2 -> U4 -> U8 + // | | | + // v v v + // 1: I1 -> I2 -> I4 -> I8 + // | | + // v v + // 2: R4 -> R8 + + switch (code) { + case TypeCode.Byte: x = 0; y = 0; break; + case TypeCode.UInt16: x = 1; y = 0; break; + case TypeCode.UInt32: x = 2; y = 0; break; + case TypeCode.UInt64: x = 3; y = 0; break; + + case TypeCode.SByte: x = 0; y = 1; break; + case TypeCode.Int16: x = 1; y = 1; break; + case TypeCode.Int32: x = 2; y = 1; break; + case TypeCode.Int64: x = 3; y = 1; break; + + case TypeCode.Single: x = 1; y = 2; break; + case TypeCode.Double: x = 2; y = 2; break; + + default: + x = y = 0; + return false; + } + return true; + } + + internal static bool IsImplicitlyConvertible(int fromX, int fromY, int toX, int toY) { + return fromX <= toX && fromY <= toY; + } + + internal static bool HasBuiltinEquality(Type left, Type right) { + // Reference type can be compared to interfaces + if (left.IsInterface() && !right.IsValueType() || + right.IsInterface() && !left.IsValueType()) { + return true; + } + + // Reference types compare if they are assignable + if (!left.IsValueType() && !right.IsValueType()) { + if (CanAssign(left, right) || CanAssign(right, left)) { + return true; + } + } + + // Nullable<T> vs null + if (NullVsNullable(left, right) || NullVsNullable(right, left)) { + return true; + } + + if (left != right) { + return false; + } + + if (left == typeof(bool) || IsNumeric(left) || left.IsEnum()) { + return true; + } + + return false; + } + + private static bool NullVsNullable(Type left, Type right) { + return IsNullableType(left) && right == typeof(DynamicNull); + } + + // keep in sync with System.Core version + internal static bool AreEquivalent(Type t1, Type t2) { +#if FEATURE_TYPE_EQUIVALENCE + return t1 == t2 || t1.IsEquivalentTo(t2); +#else + return t1 == t2; +#endif + } + + // keep in sync with System.Core version + internal static bool AreReferenceAssignable(Type dest, Type src) { + // WARNING: This actually implements "Is this identity assignable and/or reference assignable?" + if (dest == src) { + return true; + } + if (!dest.IsValueType() && !src.IsValueType() && AreAssignable(dest, src)) { + return true; + } + return false; + } + + // keep in sync with System.Core version + internal static bool AreAssignable(Type dest, Type src) { + if (dest == src) { + return true; + } + if (dest.IsAssignableFrom(src)) { + return true; + } + if (dest.IsArray && src.IsArray && dest.GetArrayRank() == src.GetArrayRank() && AreReferenceAssignable(dest.GetElementType(), src.GetElementType())) { + return true; + } + if (src.IsArray && dest.IsGenericType() && + (dest.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IEnumerable<>) + || dest.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IList<>) + || dest.GetGenericTypeDefinition() == typeof(System.Collections.Generic.ICollection<>)) + && dest.GetGenericArguments()[0] == src.GetElementType()) { + return true; + } + return false; + } + + // keep in sync with System.Core version + internal static Type GetConstantType(Type type) { + // If it's a visible type, we're done + if (type.IsVisible()) { + return type; + } + + // Get the visible base type + Type bt = type; + do { + bt = bt.GetBaseType(); + } while (!bt.IsVisible()); + + // If it's one of the known reflection types, + // return the known type. + if (bt == typeof(Type) || + bt == typeof(ConstructorInfo) || + bt == typeof(EventInfo) || + bt == typeof(FieldInfo) || + bt == typeof(MethodInfo) || + bt == typeof(PropertyInfo)) { + return bt; + } + + // else return the original type + return type; + } + + internal static bool IsConvertible(Type type) { + type = GetNonNullableType(type); + if (type.IsEnum()) { + return true; + } + switch (type.GetTypeCode()) { + case TypeCode.Boolean: + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Char: + return true; + default: + return false; + } + } + + internal static bool IsFloatingPoint(Type type) { + type = GetNonNullableType(type); + switch (type.GetTypeCode()) { + case TypeCode.Single: + case TypeCode.Double: + return true; + default: + return false; + } + } + +#if FEATURE_COM + public static readonly Type ComObjectType = typeof(object).Assembly.GetType("System.__ComObject"); + + public static bool IsComObjectType(Type/*!*/ type) { + return ComObjectType.IsAssignableFrom(type); + } + + // we can't use System.Runtime.InteropServices.Marshal.IsComObject(obj) since it doesn't work in partial trust + public static bool IsComObject(object obj) { + return obj != null && IsComObjectType(obj.GetType()); + } +#else + public static bool IsComObjectType(Type/*!*/ type) { + return false; + } + + public static bool IsComObject(object obj) { + return false; + } +#endif + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting/ArgumentTypeException.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting/ArgumentTypeException.cs new file mode 100644 index 00000000000..5d1e9e2d726 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Scripting/ArgumentTypeException.cs @@ -0,0 +1,38 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Runtime.Serialization; + +namespace Microsoft.Scripting { + [Serializable] + public class ArgumentTypeException : Exception { + public ArgumentTypeException() + : base() { + } + + public ArgumentTypeException(string message) + : base(message) { + } + + public ArgumentTypeException(string message, Exception innerException) + : base(message, innerException) { + } + +#if FEATURE_SERIALIZATION + protected ArgumentTypeException(SerializationInfo info, StreamingContext context) : base(info, context) { } +#endif + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting/InvalidImplementationException.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting/InvalidImplementationException.cs new file mode 100644 index 00000000000..dff8c291a41 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Scripting/InvalidImplementationException.cs @@ -0,0 +1,38 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; +using System.Runtime.Serialization; + +namespace Microsoft.Scripting { + [Serializable] + public class InvalidImplementationException : Exception { + public InvalidImplementationException() + : base() { + } + + public InvalidImplementationException(string message) + : base(message) { + } + + public InvalidImplementationException(string message, Exception e) + : base(message, e) { + } + +#if FEATURE_SERIALIZATION + protected InvalidImplementationException(SerializationInfo info, StreamingContext context) : base(info, context) { } +#endif + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting/PlatformAdaptationLayer.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting/PlatformAdaptationLayer.cs new file mode 100644 index 00000000000..d197e8ee4be --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Scripting/PlatformAdaptationLayer.cs @@ -0,0 +1,471 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if FEATURE_CORE_DLR +using System.Linq.Expressions; +#else +using Microsoft.Scripting.Ast; +#endif + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; +using Microsoft.Scripting.Utils; +using System.Runtime.CompilerServices; +using System.Collections; + +namespace Microsoft.Scripting { + +#if !FEATURE_PROCESS + public class ExitProcessException : Exception { + + public int ExitCode { get { return exitCode; } } + int exitCode; + + public ExitProcessException(int exitCode) { + this.exitCode = exitCode; + } + } +#endif + + /// <summary> + /// Abstracts system operations that are used by DLR and could potentially be platform specific. + /// The host can implement its PAL to adapt DLR to the platform it is running on. + /// For example, the Silverlight host adapts some file operations to work against files on the server. + /// </summary> + [Serializable] + public class PlatformAdaptationLayer { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly PlatformAdaptationLayer Default = new PlatformAdaptationLayer(); + + public static readonly bool IsCompactFramework = +#if WIN8 + false; +#else + Environment.OSVersion.Platform == PlatformID.WinCE || + Environment.OSVersion.Platform == PlatformID.Xbox; +#endif + +#if SILVERLIGHT + + // this dictionary is readonly after initialization: + private Dictionary<string, string> _assemblyFullNames = new Dictionary<string, string>(); + + public PlatformAdaptationLayer() { + LoadSilverlightAssemblyNameMapping(); + } + + // TODO: remove the need for this + private void LoadSilverlightAssemblyNameMapping() { + // non-trasparent assemblies + AssemblyName platformKeyVer = new AssemblyName(typeof(object).Assembly.FullName); + AddAssemblyMappings(platformKeyVer, + "mscorlib", + "System", + "System.Core", + "System.Net", + "System.Runtime.Serialization", + "System.ServiceModel.Web", + "System.Windows", + "System.Windows.Browser", + "System.Xml", + "Microsoft.VisualBasic" + ); + + // DLR + language assemblies + AssemblyName languageKeyVer = new AssemblyName(typeof(PlatformAdaptationLayer).Assembly.FullName); + AddAssemblyMappings(languageKeyVer, + "Microsoft.Scripting", + "Microsoft.Dynamic", + "Microsoft.Scripting.Core", + "Microsoft.Scripting.Silverlight", + "IronPython", + "IronPython.Modules", + "IronRuby", + "IronRuby.Libraries" + ); + + // transparent assemblies => same version as mscorlib but uses transparent key (same as languages) + AssemblyName transparentKeyVer = new AssemblyName(typeof(object).Assembly.FullName); + transparentKeyVer.SetPublicKeyToken(languageKeyVer.GetPublicKeyToken()); + AddAssemblyMappings(transparentKeyVer, + "System.ServiceModel", + "System.ServiceModel.Syndication", + "System.Windows.Controls", + "System.Windows.Controls.Data", + "System.Windows.Controls.Data.Design", + "System.Windows.Controls.Design", + "System.Windows.Controls.Extended", + "System.Windows.Controls.Extended.Design", + "System.Xml.Linq", + "System.Xml.Serialization" + ); + } + + private void AddAssemblyMappings(AssemblyName keyVersion, params string[] names) { + foreach (string asm in names) { + keyVersion.Name = asm; + _assemblyFullNames.Add(asm.ToLower(), keyVersion.FullName); + } + } + + protected string LookupFullName(string name) { + AssemblyName asm = new AssemblyName(name); + if (asm.Version != null || asm.GetPublicKeyToken() != null || asm.GetPublicKey() != null) { + return name; + } + return _assemblyFullNames.ContainsKey(name.ToLower()) ? _assemblyFullNames[name.ToLower()] : name; + } +#endif + #region Assembly Loading + + public virtual Assembly LoadAssembly(string name) { +#if WIN8 + throw new NotImplementedException(); +#elif !SILVERLIGHT + return Assembly.Load(name); +#else + return Assembly.Load(LookupFullName(name)); +#endif + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Reflection.Assembly.LoadFile")] + public virtual Assembly LoadAssemblyFromPath(string path) { +#if FEATURE_FILESYSTEM + return Assembly.LoadFile(path); +#else + throw new NotImplementedException(); +#endif + } + + public virtual void TerminateScriptExecution(int exitCode) { +#if FEATURE_PROCESS + System.Environment.Exit(exitCode); +#else + throw new ExitProcessException(exitCode); +#endif + } + + #endregion + + #region Virtual File System + + public virtual bool IsSingleRootFileSystem { + get { +#if FEATURE_FILESYSTEM + return Environment.OSVersion.Platform == PlatformID.Unix + || Environment.OSVersion.Platform == PlatformID.MacOSX; +#elif WIN8 + return false; +#else + return true; +#endif + } + } + + public virtual StringComparer PathComparer { + get { +#if FEATURE_FILESYSTEM + return Environment.OSVersion.Platform == PlatformID.Unix ? StringComparer.Ordinal : StringComparer.OrdinalIgnoreCase; +#else + return StringComparer.OrdinalIgnoreCase; +#endif + } + } + + public virtual bool FileExists(string path) { +#if FEATURE_FILESYSTEM + return File.Exists(path); +#else + throw new NotImplementedException(); +#endif + } + + public virtual bool DirectoryExists(string path) { +#if FEATURE_FILESYSTEM + return Directory.Exists(path); +#else + throw new NotImplementedException(); +#endif + } + +#if !CLR2 + // TODO: better APIs + public virtual Stream OpenFileStream(string path, FileMode mode = FileMode.OpenOrCreate, FileAccess access = FileAccess.ReadWrite, FileShare share = FileShare.Read, int bufferSize = 8192) { +#if FEATURE_FILESYSTEM + if (string.Equals("nul", path, StringComparison.InvariantCultureIgnoreCase)) { + return Stream.Null; + } + return new FileStream(path, mode, access, share, bufferSize); +#else + throw new NotImplementedException(); +#endif + } + + // TODO: better APIs + public virtual Stream OpenInputFileStream(string path, FileMode mode = FileMode.Open, FileAccess access = FileAccess.Read, FileShare share = FileShare.Read, int bufferSize = 8192) { + return OpenFileStream(path, mode, access, share, bufferSize); + } + + // TODO: better APIs + public virtual Stream OpenOutputFileStream(string path) { + return OpenFileStream(path, FileMode.Create, FileAccess.Write); + } +#else + public virtual Stream OpenFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize) { +#if FEATURE_FILESYSTEM + if (string.Equals("nul", path, StringComparison.InvariantCultureIgnoreCase)) { + return Stream.Null; + } + return new FileStream(path, mode, access, share, bufferSize); +#else + throw new NotImplementedException(); +#endif + } + + // TODO: better APIs + public virtual Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share) { + return OpenFileStream(path, mode, access, share, 8912); + } + + // TODO: better APIs + public virtual Stream OpenInputFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize) { + return OpenFileStream(path, mode, access, share, bufferSize); + } + + // TODO: better APIs + public virtual Stream OpenInputFileStream(string path) { + return OpenFileStream(path, FileMode.Open, FileAccess.Read, FileShare.None, 8912); + } + + // TODO: better APIs + public virtual Stream OpenOutputFileStream(string path) { + return OpenFileStream(path, FileMode.Create, FileAccess.Write, FileShare.None, 8912); + } +#endif + + public virtual void DeleteFile(string path, bool deleteReadOnly) { +#if FEATURE_FILESYSTEM + FileInfo info = new FileInfo(path); +#if !ANDROID + if (deleteReadOnly && info.IsReadOnly) { + info.IsReadOnly = false; + } +#endif + info.Delete(); +#else + throw new NotImplementedException(); +#endif + } + + public string[] GetFiles(string path, string searchPattern) { + return GetFileSystemEntries(path, searchPattern, true, false); + } + + public string[] GetDirectories(string path, string searchPattern) { + return GetFileSystemEntries(path, searchPattern, false, true); + } + + public string[] GetFileSystemEntries(string path, string searchPattern) { + return GetFileSystemEntries(path, searchPattern, true, true); + } + + public virtual string[] GetFileSystemEntries(string path, string searchPattern, bool includeFiles, bool includeDirectories) { +#if FEATURE_FILESYSTEM + if (includeFiles && includeDirectories) { + return Directory.GetFileSystemEntries(path, searchPattern); + } + if (includeFiles) { + return Directory.GetFiles(path, searchPattern); + } + if (includeDirectories) { + return Directory.GetDirectories(path, searchPattern); + } + return ArrayUtils.EmptyStrings; +#else + throw new NotImplementedException(); +#endif + } + + /// <exception cref="ArgumentException">Invalid path.</exception> + public virtual string GetFullPath(string path) { +#if FEATURE_FILESYSTEM + try { + return Path.GetFullPath(path); + } catch (Exception) { + throw Error.InvalidPath(); + } +#else + throw new NotImplementedException(); +#endif + } + + public virtual string CombinePaths(string path1, string path2) { + return Path.Combine(path1, path2); + } + + public virtual string GetFileName(string path) { + return Path.GetFileName(path); + } + + public virtual string GetDirectoryName(string path) { + return Path.GetDirectoryName(path); + } + + public virtual string GetExtension(string path) { + return Path.GetExtension(path); + } + + public virtual string GetFileNameWithoutExtension(string path) { + return Path.GetFileNameWithoutExtension(path); + } + + /// <exception cref="ArgumentException">Invalid path.</exception> + public virtual bool IsAbsolutePath(string path) { + if (String.IsNullOrEmpty(path)) { + return false; + } + + // no drives, no UNC: + if (IsSingleRootFileSystem) { + return IsDirectorySeparator(path[0]); + } + + if (IsDirectorySeparator(path[0])) { + // UNC path + return path.Length > 1 && IsDirectorySeparator(path[1]); + } + + if (path.Length > 2 && path[1] == ':' && IsDirectorySeparator(path[2])) { + return true; + } + + return false; + } + +#if FEATURE_FILESYSTEM + private bool IsDirectorySeparator(char c) { + return c == Path.DirectorySeparatorChar || c == Path.AltDirectorySeparatorChar; + } +#else + private bool IsDirectorySeparator(char c) { + return c == '\\' || c == '/'; + } +#endif + + public virtual string CurrentDirectory { + get { +#if FEATURE_FILESYSTEM + return Directory.GetCurrentDirectory(); +#else + throw new NotImplementedException(); +#endif + } + set { +#if FEATURE_FILESYSTEM + Directory.SetCurrentDirectory(value); +#else + throw new NotImplementedException(); +#endif + } + } + + public virtual void CreateDirectory(string path) { +#if FEATURE_FILESYSTEM + Directory.CreateDirectory(path); +#else + throw new NotImplementedException(); +#endif + } + + public virtual void DeleteDirectory(string path, bool recursive) { +#if FEATURE_FILESYSTEM + Directory.Delete(path, recursive); +#else + throw new NotImplementedException(); +#endif + } + + public virtual void MoveFileSystemEntry(string sourcePath, string destinationPath) { +#if FEATURE_FILESYSTEM + Directory.Move(sourcePath, destinationPath); +#else + throw new NotImplementedException(); +#endif + } + + #endregion + + #region Environmental Variables + + public virtual string GetEnvironmentVariable(string key) { +#if FEATURE_PROCESS + return Environment.GetEnvironmentVariable(key); +#else + throw new NotImplementedException(); +#endif + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")] + public virtual void SetEnvironmentVariable(string key, string value) { +#if FEATURE_PROCESS + if (value != null && value.Length == 0) { + SetEmptyEnvironmentVariable(key); + } else { + Environment.SetEnvironmentVariable(key, value); + } +#else + throw new NotImplementedException(); +#endif + } + +#if FEATURE_PROCESS + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2149:TransparentMethodsMustNotCallNativeCodeFxCopRule")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2140:TransparentMethodsMustNotReferenceCriticalCodeFxCopRule")] + [MethodImpl(MethodImplOptions.NoInlining)] + private static void SetEmptyEnvironmentVariable(string key) { + // System.Environment.SetEnvironmentVariable interprets an empty value string as + // deleting the environment variable. So we use the native SetEnvironmentVariable + // function here which allows setting of the value to an empty string. + // This will require high trust and will fail in sandboxed environments + if (!NativeMethods.SetEnvironmentVariable(key, String.Empty)) { + throw new ExternalException("SetEnvironmentVariable failed", Marshal.GetLastWin32Error()); + } + } +#endif + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public virtual Dictionary<string, string> GetEnvironmentVariables() { +#if FEATURE_PROCESS + var result = new Dictionary<string, string>(); + + foreach (DictionaryEntry entry in Environment.GetEnvironmentVariables()) + { + result.Add((string)entry.Key, (string)entry.Value); + } + + return result; +#else + throw new NotImplementedException(); +#endif + } + + #endregion + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting/Runtime/NotNullAttribute.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting/Runtime/NotNullAttribute.cs new file mode 100644 index 00000000000..43cc1af4653 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Scripting/Runtime/NotNullAttribute.cs @@ -0,0 +1,40 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; + +namespace Microsoft.Scripting.Runtime { + /// <summary> + /// This attribute marks a parameter that is not allowed to be null. + /// It is used by the method binding infrastructure to generate better error + /// messages and method selection. + /// </summary> + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + public sealed class NotNullAttribute : Attribute { + public NotNullAttribute() { + } + } + + /// <summary> + /// This attribute marks a parameter whose type is an array that is not allowed to have null items. + /// It is used by the method binding infrastructure to generate better error + /// messages and method selection. + /// </summary> + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + public sealed class NotNullItemsAttribute : Attribute { + public NotNullItemsAttribute() { + } + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting/Runtime/ParamDictionaryAttribute.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting/Runtime/ParamDictionaryAttribute.cs new file mode 100644 index 00000000000..3f0a081ea1c --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Scripting/Runtime/ParamDictionaryAttribute.cs @@ -0,0 +1,55 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +using System; + +namespace Microsoft.Scripting { + /// <summary> + /// This attribute is used to mark a parameter that can accept any keyword parameters that + /// are not bound to normal arguments. The extra keyword parameters will be + /// passed in a dictionary which is created for the call. + /// + /// Most languages which support params dictionaries will support the following types: + /// IDictionary<string, anything> + /// IDictionary<object, anything> + /// Dictionary<string, anything> + /// Dictionary<object, anything> + /// IDictionary + /// IAttributesCollection (deprecated) + /// + /// For languages which don't have language level support the user will be required to + /// create and populate the dictionary by hand. + /// + /// This attribute is the dictionary equivalent of the System.ParamArrayAttribute. + /// </summary> + /// <example> + /// public static void KeywordArgFunction([ParamsDictionary]IDictionary<string, object> dict) { + /// foreach (var v in dict) { + /// Console.WriteLine("Key: {0} Value: {1}", v.Key, v.Value); + /// } + /// } + /// + /// Called from Python: + /// + /// KeywordArgFunction(a = 2, b = "abc") + /// + /// will print: + /// Key: a Value = 2 + /// Key: b Value = abc + /// </example> + [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] + public sealed class ParamDictionaryAttribute : Attribute { + } +} diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting/Stubs.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting/Stubs.cs new file mode 100644 index 00000000000..5719fd93043 --- /dev/null +++ b/mcs/class/dlr/Runtime/Microsoft.Scripting/Stubs.cs @@ -0,0 +1,116 @@ +/* **************************************************************************** + * + * Copyright (c) Microsoft Corporation. + * + * This source code is subject to terms and conditions of the Apache License, Version 2.0. A + * copy of the license can be found in the License.html file at the root of this distribution. If + * you cannot locate the Apache License, Version 2.0, please send an email to + * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound + * by the terms of the Apache License, Version 2.0. + * + * You must not remove this notice, or any other, from this software. + * + * + * ***************************************************************************/ + +#if WIN8 + +// When compiled with Dev10 VS CSC reports errors if this is not defined +// error CS0656: Missing compiler required member 'System.Threading.Thread.get_ManagedThreadId' +// error CS0656: Missing compiler required member 'System.Threading.Thread.get_CurrentThread' +namespace System.Threading { + internal class Thread { + public int ManagedThreadId { get { throw new NotImplementedException(); } } + public static Thread CurrentThread { get { throw new NotImplementedException(); } } + } +} + +namespace System.IO { + [Serializable] + public enum FileMode { + CreateNew = 1, + Create, + Open, + OpenOrCreate, + Truncate, + Append + } + + [Serializable] + public enum FileAccess { + Read = 1, + Write = 2, + ReadWrite = 3 + } + + [Serializable] + public enum FileShare { + None = 0, + Read = 1, + Write = 2, + ReadWrite = 3, + Delete = 4, + Inheritable = 16 + } +} +#else +namespace System { + public static class TypeExtensions { +#if !FEATURE_GET_TYPE_INFO + public static Type GetTypeInfo(this Type type) { + return type; + } +#endif + + public static Type AsType(this Type type) { + return type; + } + } +} +#endif + +#if !FEATURE_SERIALIZATION + +namespace System { + using System.Diagnostics; + + [Conditional("STUB")] + public class SerializableAttribute : Attribute { + } + + [Conditional("STUB")] + public class NonSerializedAttribute : Attribute { + } + + namespace Runtime.Serialization { + public interface ISerializable { + } + + public interface IDeserializationCallback { + } + } + + public class SerializationException : Exception { + } +} + +#endif + +#if SILVERLIGHT && !CLR2 + +namespace System { + namespace Runtime.InteropServices { + /// <summary> + /// The Default Parameter Value Attribute. + /// </summary> + public sealed class DefaultParameterValueAttribute : Attribute { + /// <summary> + /// The constructor + /// </summary> + /// <param name="value">The value.</param> + public DefaultParameterValueAttribute(object value) { } + } + } +} + +#endif
\ No newline at end of file |