public ScopeDictionaryStorage(TotemContext/*!*/ context, Scope/*!*/ scope) { Assert.NotNull(context, scope); _scope = scope; _context = context; }
public ModuleContext(TotemModule module, TotemContext creatingContext) { ContractUtils.RequiresNotNull(module, "module"); ContractUtils.RequiresNotNull(creatingContext, "creatingContext"); _globals = module.Dictionary; }
public TotemArgs(TotemContext context, string[] names, IList<object> args, Dictionary<string, object> kwargs) : base(context.GetType<Types.Arguments>()) { _names = new ReadOnlyCollectionBuilder<string>(names).ToReadOnlyCollection(); var vb = new ReadOnlyCollectionBuilder<object>(); var nvb = new Dictionary<string, object>(); var snb = new ReadOnlyCollectionBuilder<string>(); for (var i = 0; i < args.Count; i++) { vb.Add(args[i]); if (i < names.Length) nvb.Add(names[i], args[i]); } foreach (var arg in kwargs) { nvb.Add(arg.Key, arg.Value); snb.Add(arg.Key); } _values = vb.ToReadOnlyCollection(); _namedValues = new ReadOnlyDictionary<string, object>(nvb); _named = snb.ToReadOnlyCollection(); }
public TotemScopeExtension(TotemContext context, Scope scope) : base(scope) { _codeContext = new CodeContext(new TotemDictionary( new ScopeDictionaryStorage(context, scope) ), null, context); }
/// <summary> /// Creates a new CodeContext which is backed by the specified Python dictionary. /// </summary> public CodeContext(TotemDictionary/*!*/ dict, CodeContext globalContext, TotemContext/*!*/ context) { ContractUtils.RequiresNotNull(dict, "dict"); ContractUtils.RequiresNotNull(context, "context"); _context = context; _dict = dict; _globalContext = globalContext; }
public TotemMethod(TotemContext/*!*/ context, string name, ITotemCallable wrapped, object instance) : base(context.GetType<Types.Method>()) { ContractUtils.RequiresNotNull(wrapped, "wrapped"); ContractUtils.RequiresNotNull(instance, "instance"); _wrapped = wrapped; _name = name; _instance = instance; }
public ModuleContext(TotemDictionary globals, TotemContext creatingContext) { ContractUtils.RequiresNotNull(globals, "globals"); ContractUtils.RequiresNotNull(creatingContext, "creatingContext"); _globals = globals; _totemContext = creatingContext; _globalContext = new CodeContext(globals, this); _module = new TotemModule(globals); _module.Scope.SetExtension(_totemContext.ContextId, new TotemScopeExtension(_totemContext, _module, this)); }
internal static TotemNull Get(TotemContext context) { lock (nullValues) { TotemNull val; if (!nullValues.TryGetValue(context, out val)) { val = new TotemNull(context); nullValues.Add(context, val); } return val; } }
private LambdaExpression _tracingLambda; // the transformed lambda used for tracing/debugging #endregion Fields #region Constructors /// <summary> /// Constructor used to create a FunctionCode for code that's been serialized to disk. /// /// Code constructed this way cannot be interpreted or debugged using sys.settrace/sys.setprofile. /// /// Function codes created this way do support recursion enforcement and are therefore registered in the global function code registry. /// </summary> internal FunctionCode(TotemContext context, Delegate code, Parsing.Ast.ScopeStatement scope, int localCount) { _normalDelegate = code; _lambda = scope; _argCount = CalculateArgumentCount(); // need to take this lock to ensure sys.settrace/sys.setprofile is not actively changing lock (_CodeCreateAndUpdateDelegateLock) { SetTarget(AddRecursionCheck(context, code)); } RegisterFunctionCode(context); }
/// <summary> /// Constructor to create a FunctionCode at runtime. /// /// Code constructed this way supports both being interpreted and debugged. When necessary the code will /// be re-compiled or re-interpreted for that specific purpose. /// /// Function codes created this way do support recursion enforcement and are therefore registered in the global function code registry. /// /// the initial delegate provided here should NOT be the actual code. It should always be a delegate which updates our Target lazily. /// </summary> internal FunctionCode(TotemContext context, Delegate initialDelegate, CompilableStmt code, bool? tracing, bool register) { _lambda = code; Target = LightThrowTarget = initialDelegate; _localCount = code._scopeVars == null ? 0 : code._scopeVars.Count; _argCount = CalculateArgumentCount(); if (tracing.HasValue) { if (tracing.Value) { _tracingDelegate = initialDelegate; } else { _normalDelegate = initialDelegate; } } if (register) { RegisterFunctionCode(context); } }
private static CodeList GetRootCodeNoUpdating(TotemContext context) { CodeList cur = context._allCodes; if (cur == _CodeCreateAndUpdateDelegateLock) { lock (_CodeCreateAndUpdateDelegateLock) { // wait until enumerating thread is done, but it's alright // if we got cur and then an enumeration started (because we'll // just clear entries out) cur = context._allCodes; Debug.Assert(cur != _CodeCreateAndUpdateDelegateLock); } } return cur; }
/// <summary> /// Enumerates all function codes for updating the current type of targets we generate. /// /// While enumerating we hold a lock so that users cannot change sys.settrace/sys.setprofile /// until the lock is released. /// </summary> private static IEnumerable<FunctionCode> GetAllCode(TotemContext context) { // only a single thread can enumerate the current FunctionCodes at a time. lock (_CodeCreateAndUpdateDelegateLock) { CodeList curCodeList = Interlocked.Exchange(ref context._allCodes, _CodeCreateAndUpdateDelegateLock); Debug.Assert(curCodeList != _CodeCreateAndUpdateDelegateLock); CodeList initialCode = curCodeList; try { while (curCodeList != null) { WeakReference codeRef = curCodeList.Code; FunctionCode target = (FunctionCode)codeRef.Target; if (target != null) { yield return target; } curCodeList = curCodeList.Next; } } finally { Interlocked.Exchange(ref context._allCodes, initialCode); } } }
/// <summary> /// Updates the delegate based upon current Totem context settings for recursion enforcement /// and for tracing. /// </summary> internal void UpdateDelegate(TotemContext context, bool forceCreation) { Delegate finalTarget; if (context.EnableTracing && _lambda != null) { if (_tracingLambda == null) { if (!forceCreation) { // the user just called sys.settrace(), don't force re-compilation of every method in the system. Instead // we'll just re-compile them as they're invoked. Target = (Func<TotemFunction, TotemArgs, object>)IronTotem.Parsing.Ast.FunctionDefinition.FunctionDelegate; LightThrowTarget = Target; return; } throw new NotImplementedException(); //_tracingLambda = GetGeneratorOrNormalLambdaTracing(context); } if (_tracingDelegate == null) { throw new NotImplementedException(); //_tracingDelegate = CompileLambda(_tracingLambda, new TargetUpdaterForCompilation(context, this).SetCompiledTargetTracing); } finalTarget = _tracingDelegate; } else { if (_normalDelegate == null) { if (!forceCreation) { // we cannot create the delegate when forceCreation is false because we hold the // _CodeCreateAndUpdateDelegateLock and compiling the delegate may create a FunctionCode // object which requires the lock. Target = (Func<TotemFunction, TotemArgs, object>)IronTotem.Parsing.Ast.FunctionDefinition.FunctionDelegate; LightThrowTarget = Target; return; } _normalDelegate = CompileLambda(GetGeneratorOrNormalLambda(), new TargetUpdaterForCompilation(context, this).SetCompiledTarget); } finalTarget = _normalDelegate; } finalTarget = AddRecursionCheck(context, finalTarget); SetTarget(finalTarget); }
/// <summary> /// Called to set the initial target delegate when the user has passed -X:Debug to enable /// .NET style debugging. /// </summary> internal void SetDebugTarget(TotemContext context, Delegate target) { _normalDelegate = target; SetTarget(AddRecursionCheck(context, target)); }
internal Delegate AddRecursionCheck(TotemContext context, Delegate finalTarget) { //if (context.RecursionLimit != Int32.MaxValue) //{ // if (finalTarget is Func<CodeContext, CodeContext> || // finalTarget is Func<CodeContext, object> || // finalTarget is LookupComiplationDelegate) // { // return finalTarget; // } // switch (_lambda.ParameterNames.Length) // { // default: // finalTarget = new Func<TotemFunction, object[], object>(new TotemFunctionRecursionCheckN((Func<TotemFunction, object[], object>)finalTarget).CallTarget); // break; // } //} return finalTarget; }
public TotemScopeExtension(TotemContext context, TotemModule module, ModuleContext moduleContext) : base(module.Scope) { _module = module; _moduleContext = moduleContext; }
public TargetUpdaterForCompilation(TotemContext context, FunctionCode code) { _code = code; _context = context; }
public static void FunctionPushFrame(TotemContext context) { if (TotemFunction.AddRecursionDepth(1) > context.RecursionLimit) { throw TotemOps.RuntimeError("maximum recursion depth exceeded"); } }
private bool ShouldInterpret(TotemContext tc) { return tc.ShouldInterpret((TotemCompilerOptions)Ast.CompilerContext.Options, Ast.CompilerContext.SourceUnit); }
private TotemNull(TotemContext context) : base(context.GetType<Null>()) { }
public TotemScopeExtension(TotemContext context, Scope scope) : base(scope) { _module = new TotemModule(context, scope); _moduleContext = new ModuleContext(_module, context); }
internal TotemOverload(TotemContext context, TotemType type, string name, Tuple<MethodInfo, TotemType.DynamicFlags>/*!*/[]/*!*/ methodInfos) : base(context.GetType<Overloaded>()) { ContractUtils.RequiresNotNull(methodInfos, "methodInfos"); ContractUtils.RequiresNotNull(name, "name"); ContractUtils.RequiresNotNull(type, "type"); _methodInfos = methodInfos; _name = name; _typeDefinition = type; }
internal static TotemMethod Create(TotemContext/*!*/ context, string name, ITotemCallable wrapped, object/*!*/ instance) { return new TotemMethod(context, name, wrapped, instance); }
/// <summary> /// Registers the current function code in our global weak list of all function codes. /// /// The weak list can be enumerated with GetAllCode(). /// /// Ultimately there are 3 types of threads we care about races with: /// 1. Other threads which are registering function codes /// 2. Threads calling sys.settrace which require the world to stop and get updated /// 3. Threads running cleanup (thread pool thread, or call to gc.collect). /// /// The 1st two must have perfect synchronization. We cannot have a thread registering /// a new function which another thread is trying to update all of the functions in the world. Doing /// so would mean we could miss adding tracing to a thread. /// /// But the cleanup thread can run in parallel to either registrying or sys.settrace. The only /// thing it needs to take a lock for is updating our accounting information about the /// number of code objects are alive. /// </summary> private void RegisterFunctionCode(TotemContext context) { if (_lambda == null) { return; } WeakReference codeRef = new WeakReference(this); CodeList prevCode; lock (_CodeCreateAndUpdateDelegateLock) { Debug.Assert(context._allCodes != _CodeCreateAndUpdateDelegateLock); // we do an interlocked operation here because this can run in parallel w/ the CodeCleanup thread. The // lock only prevents us from running in parallel w/ an update to all of the functions in the world which // needs to be synchronized. do { prevCode = context._allCodes; } while (Interlocked.CompareExchange(ref context._allCodes, new CodeList(codeRef, prevCode), prevCode) != prevCode); if (context._codeCount++ == context._nextCodeCleanup) { // run cleanup of codes on another thread CleanFunctionCodes(context, false); } } }
internal static void CleanFunctionCodes(TotemContext context, bool synchronous) { if (synchronous) { CodeCleanup(context); } else { ThreadPool.QueueUserWorkItem(CodeCleanup, context); } }
internal static void UpdateAllCode(TotemContext context) { foreach (FunctionCode fc in GetAllCode(context)) { fc.UpdateDelegate(context, false); } }
/// <summary> /// Constructor to create a FunctionCode at runtime. /// /// Code constructed this way supports both being interpreted and debugged. When necessary the code will /// be re-compiled or re-interpreted for that specific purpose. /// /// Function codes created this way do support recursion enforcement and are therefore registered in the global function code registry. /// /// the initial delegate provided here should NOT be the actual code. It should always be a delegate which updates our Target lazily. /// </summary> internal FunctionCode(TotemContext context, Delegate initialDelegate, Parsing.Ast.ScopeStatement scope, bool? tracing, bool register) { _lambda = scope; Target = LightThrowTarget = initialDelegate; _localCount = scope.Variables == null ? 0 : scope.Variables.Count; _argCount = CalculateArgumentCount(); if (tracing.HasValue) { if (tracing.Value) { _tracingDelegate = initialDelegate; } else { _normalDelegate = initialDelegate; } } if (register) { RegisterFunctionCode(context); } }
internal static TotemOverload Create(TotemContext/*!*/ context, TotemType/*!*/ type, string name, Tuple<MethodInfo, TotemType.DynamicFlags>/*!*/[]/*!*/ methodInfos) { return new TotemOverload(context, type, name, methodInfos); }
internal TotemModule(TotemContext context, Scope scope) { _dict = new TotemDictionary(new ScopeDictionaryStorage(context, scope)); _scope = scope; }
private Delegate AddRecursionCheck(TotemContext context, Delegate finalTarget) { if (context.RecursionLimit != Int32.MaxValue) { if (finalTarget is Func<CodeContext, CodeContext> || finalTarget is Func<FunctionCode, object> || finalTarget is LookupCompilationDelegate) { // no recursion enforcement on classes or modules return finalTarget; } finalTarget = TotemCallTargets.AddRecursionCheck(_lambda.ParameterNames.Length > TotemCallTargets.MAX_ARGS, _lambda.ParameterNames.Length, finalTarget); } return finalTarget; }