/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation.Runspaces;
using System.Reflection;
using System.Reflection.Emit;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Management.Automation.Language;
using System.Threading;
// These APIs are not part of the public contract.
// They are implementation details and intendent to be called from generated assemlbies for PS classes.
//
// Because they are called from other assemblies, we have to make them public.
// We put them in Internal namespace to emphasise that despite the fact that they are public, it's not part of API contract.
namespace System.Management.Automation.Internal
{
///
/// Every Runspace in one process contains SessionStateInternal per module (module SessionState).
/// Every RuntimeType is associated to only one SessionState in the Runspace, which creates it:
/// it's ever global state or a module state.
/// In the former case, module can be imported from the different runspaces in the same process.
/// And so runspaces will share RuntimeType. But in every runspace, Type is associated with just one SessionState.
/// We want type methods to be able access $script: variables and module-specific methods.
/// To achive it, we preserve reference to SessionState that creates type in the private field 'SessionStateFieldName'.
/// Later, we use it to call scriptBlocks captured in ScriptBlockMemberMethodWrapper with the right sessionState.
///
public class SessionStateKeeper
{
// We use ConditionalWeakTable, because if GC already collect Runspace,
// then there is no way to call a ctor on the type in this Runspace.
private readonly ConditionalWeakTable _stateMap;
internal SessionStateKeeper()
{
_stateMap = new ConditionalWeakTable();
}
internal void RegisterRunspace()
{
// it's not get, but really 'Add' value.
// ConditionalWeakTable.Add throw exception, when you are trying to add a value with the same key.
_stateMap.GetValue(Runspace.DefaultRunspace, runspace => runspace.ExecutionContext.EngineSessionState);
}
///
/// This method should be called only from generated ctors for PowerShell classes.
/// It's not intended to be a public API, but because we generate type in a different assembly it has to be public.
/// Return type should be SessionStateInternal, but it violates accessibility consistency, so we use object.
///
/// SessionStateInternal
public object GetSessionState()
{
SessionStateInternal ss = null;
bool found = _stateMap.TryGetValue(Runspace.DefaultRunspace, out ss);
Diagnostics.Assert(found, "We always should be able to find corresponding SessionState");
return ss;
}
}
///
public class ScriptBlockMemberMethodWrapper
{
/// Used in codegen
public static readonly object[] _emptyArgumentArray = Utils.EmptyArray