public override UncollectableCompilationMode.ConstantInfo GetContext() { lock (StorageData.Contexts) { int index = StorageData.ContextCount++; int arrIndex = index - StorageData.ContextTypes * StorageData.StaticFields; Type storageType = StorageData.ContextStorageType(index); MSAst.Expression expr; FieldInfo fieldInfo; if (arrIndex < 0) { fieldInfo = storageType.GetField(string.Format("Context{0:000}", index % StorageData.StaticFields)); expr = Ast.Field(null, fieldInfo); } else { fieldInfo = typeof(StorageData).GetField(nameof(StorageData.Contexts)); expr = Ast.ArrayIndex( Ast.Field(null, fieldInfo), Ast.Constant(arrIndex, typeof(int)) ); } return(new ConstantInfo(new CodeContextExpression(expr), fieldInfo, index)); } }
internal void AddVersionTest(RubyClass /*!*/ cls) { cls.Context.RequiresClassHierarchyLock(); // check for module version (do not burn a module reference to the rule): AddCondition(Ast.Equal(Ast.Field(AstUtils.Constant(cls.Version), Fields.VersionHandle_Method), AstUtils.Constant(cls.Version.Method))); }
public override MSAst.Expression Reduce() { if (_expandable) { return(Ast.NewArrayInit( typeof(object), ToObjectArray(Items) )); } if (Items.Count == 0) { return(Ast.Field( null, typeof(PythonOps).GetField(nameof(PythonOps.EmptyTuple)) )); } return(Ast.Call( AstMethods.MakeTuple, Ast.NewArrayInit( typeof(object), ToObjectArray(Items) ) )); }
// public for accessibility via GetMethod("NextSite") public static SiteInfo /*!*/ NextSite <T>(DynamicMetaObjectBinder /*!*/ binder) where T : class { lock (StorageData.SiteLockObj) { int index = SiteStorage <T> .SiteCount++; int arrIndex = index - StorageData.SiteTypes * StorageData.StaticFields; Type storageType = SiteStorage <T> .SiteStorageType(index); MSAst.Expression expr; FieldInfo fieldInfo; if (arrIndex < 0) { fieldInfo = storageType.GetField(string.Format("Site{0:000}", index % StorageData.StaticFields)); expr = Ast.Field(null, fieldInfo); } else { fieldInfo = typeof(SiteStorage <T>).GetField("Sites"); expr = Ast.ArrayIndex( Ast.Field(null, fieldInfo), Ast.Constant(arrIndex, typeof(int)) ); } return(PublishSite(new SiteInfo <T>(binder, expr, fieldInfo, index))); } }
// Note: This should stay non-public to avoid name conflicts when accessing the // generic overload via GetMethod("NextSite") private static SiteInfo /*!*/ NextSite(DynamicMetaObjectBinder /*!*/ binder, Type /*!*/ delegateType) { Type siteType = typeof(SiteStorage <>).MakeGenericType(delegateType); lock (StorageData.SiteLockObj) { int index = (int)siteType.GetField("SiteCount").GetValue(null); siteType.GetField("SiteCount").SetValue(null, index + 1); int arrIndex = index - StorageData.SiteTypes * StorageData.StaticFields; Type storageType = (Type)siteType.GetMethod("SiteStorageType").Invoke(null, new object[] { index }); MSAst.Expression expr; FieldInfo fieldInfo; if (arrIndex < 0) { fieldInfo = storageType.GetField(string.Format("Site{0:000}", index % StorageData.StaticFields)); expr = Ast.Field(null, fieldInfo); } else { fieldInfo = siteType.GetField("Sites"); expr = Ast.ArrayIndex( Ast.Field(null, fieldInfo), Ast.Constant(arrIndex, typeof(int)) ); } return(PublishSite(new SiteInfoLarge(binder, expr, fieldInfo, index, delegateType))); } }
public override Expression GetValue(Expression context, ActionBinder binder, Type type) { if (Field.IsLiteral) { return(Ast.Constant(Field.GetValue(null))); } if (!IsStatic) { // return the field tracker... return(binder.ReturnMemberTracker(type, this)); } if (Field.DeclaringType.ContainsGenericParameters) { return(null); } if (IsPublic && DeclaringType.IsPublic) { return(Ast.Field(null, Field)); } return(Ast.Call( AstUtils.Convert(Ast.Constant(Field), typeof(FieldInfo)), typeof(FieldInfo).GetMethod("GetValue"), Ast.Constant(null) )); }
private MemberExpression /*!*/ ReadStrongBoxValue(Expression instance) { return(Ast.Field( AstUtils.Convert(instance, Value.BindingSelf.GetType()), Value.BindingSelf.GetType().GetField("Value") )); }
/// <summary> if a member-injector is defined-on or registered-for this type call it </summary> private void MakeOperatorGetMemberBody(GetMemberInfo getMemInfo, Expression instance, Type type, string name) { MethodInfo getMem = GetMethod(type, name); if (getMem != null && getMem.IsSpecialName) { ParameterExpression tmp = Ast.Variable(typeof(object), "getVal"); getMemInfo.Body.AddVariable(tmp); getMemInfo.Body.AddCondition( Ast.NotEqual( Ast.Assign( tmp, MakeCallExpression( getMemInfo.CodeContext, getMem, AstUtils.Convert(instance, type), Ast.Constant(getMemInfo.Name) ) ), Ast.Field(null, typeof(OperationFailed).GetField("Value")) ), tmp ); } }
internal MSA.Expression /*!*/ TransformOptionalsInitialization(AstGenerator /*!*/ gen) { Assert.NotNull(gen); if (_optional.Length == 0) { return(AstUtils.Empty()); } MSA.Expression singleton = gen.CurrentScope.DefineHiddenVariable("#default", typeof(object)); MSA.Expression result = AstUtils.Empty(); for (int i = 0; i < _optional.Length; i++) { result = AstUtils.IfThen( Ast.Equal(_optional[i].Left.TransformRead(gen), singleton), Ast.Block( result, _optional[i].TransformRead(gen) // assignment ) ); } return(Ast.Block( Ast.Assign(singleton, Ast.Field(null, Fields.DefaultArgument)), result, AstUtils.Empty() )); }
/// <summary> if a member-injector is defined-on or registered-for this type call it </summary> private void MakeOperatorGetMemberBody(GetMemberInfo getMemInfo, DynamicMetaObject instance, Type instanceType, string name) { MethodInfo getMem = GetMethod(instanceType, name); if (getMem != null) { ParameterExpression tmp = Ast.Variable(typeof(object), "getVal"); getMemInfo.Body.AddVariable(tmp); getMemInfo.Body.AddCondition( Ast.NotEqual( Ast.Assign( tmp, MakeCallExpression( getMemInfo.ResolutionFactory, getMem, new DynamicMetaObject( Expression.Convert(instance.Expression, instanceType), instance.Restrictions, instance.Value ), new DynamicMetaObject( Expression.Constant(getMemInfo.Name), BindingRestrictions.Empty, getMemInfo.Name ) ).Expression ), Ast.Field(null, typeof(OperationFailed).GetDeclaredField("Value")) ), tmp ); } }
/// <summary> /// Takes current result and wraps it into try-filter(MethodUnwinder)-finally block that ensures correct "break" behavior for /// Ruby method calls with a block given in arguments. /// /// Sets up a RFC frame similarly to MethodDeclaration. /// </summary> public static void RuleControlFlowBuilder(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { Debug.Assert(args.Signature.HasBlock); if (metaBuilder.Error) { return; } // TODO (improvement): // We don't special case null block here, although we could (we would need a test for that then). // We could also statically know (via call-site flag) that the current method is not a proc-converter (passed by ref), // which would make such calls faster. var rfcVariable = metaBuilder.GetTemporary(typeof(RuntimeFlowControl), "#rfc"); var resultVariable = metaBuilder.GetTemporary(typeof(object), "#result"); MSA.ParameterExpression unwinder; metaBuilder.Result = Ast.Block( // initialize frame (RFC): Ast.Assign(rfcVariable, Methods.CreateRfcForMethod.OpCall(AstUtils.Convert(args.GetBlockExpression(), typeof(Proc)))), AstUtils.Try( Ast.Assign(resultVariable, metaBuilder.Result) ).Filter(unwinder = Ast.Parameter(typeof(MethodUnwinder), "#unwinder"), Ast.Equal(Ast.Field(unwinder, MethodUnwinder.TargetFrameField), rfcVariable), // return unwinder.ReturnValue; Ast.Assign(resultVariable, Ast.Field(unwinder, MethodUnwinder.ReturnValueField)) ).Finally( // we need to mark the RFC dead snce the block might escape and break later: Methods.LeaveMethodFrame.OpCall(rfcVariable) ), resultVariable ); }
public override MSAst.Expression Reduce() { UnicodeWrapper wrapper; if (_value == Ellipsis.Value) { return(Ast.Property( null, typeof(PythonOps).GetProperty("Ellipsis") )); } else if (_value is bool) { if ((bool)_value) { return(Ast.Field(null, typeof(ScriptingRuntimeHelpers).GetField("True"))); } else { return(Ast.Field(null, typeof(ScriptingRuntimeHelpers).GetField("False"))); } } else if ((wrapper = _value as UnicodeWrapper) != null) { return(GlobalParent.Constant(wrapper.Value)); } return(GlobalParent.Constant(_value)); }
private Expression FallbackGet(DynamicMetaObjectBinder member, DynamicMetaObject[] args) { if (member is GetMemberBinder sa) { return(sa.FallbackGetMember(args[0]).Expression); } PythonGetMemberBinder pyGetMem = member as PythonGetMemberBinder; if (pyGetMem.IsNoThrow) { return(Ast.Field( null, typeof(OperationFailed).GetDeclaredField("Value") )); } else { return(member.Throw( Ast.Call( typeof(PythonOps).GetMethod(nameof(PythonOps.AttributeError)), AstUtils.Constant("{0} instance has no attribute '{1}'"), Ast.NewArrayInit( typeof(object), AstUtils.Constant(((OldInstance)Value)._class._name), AstUtils.Constant(pyGetMem.Name) ) ) )); } }
internal static MethodCallExpression /*!*/ CheckTypeVersion(Expression /*!*/ tested, int version) { #if FEATURE_REFEMIT FieldInfo fi = tested.Type.GetField(NewTypeMaker.ClassFieldName); #else FieldInfo fi = null; #endif if (fi == null) { return(Ast.Call( typeof(PythonOps).GetMethod("CheckTypeVersion"), AstUtils.Convert(tested, typeof(object)), AstUtils.Constant(version) )); } Debug.Assert(tested.Type != typeof(object)); return(Ast.Call( typeof(PythonOps).GetMethod("CheckSpecificTypeVersion"), Ast.Field( tested, fi ), AstUtils.Constant(version) )); }
/// <summary> /// Fills missing arguments with the missing argument placeholder (RubyOps.DefaultArgument singleton). /// </summary> public void FillMissingArguments() { for (int i = _explicitArgCount; i < _mandatoryParamCount + _optionalParamCount; i++) { // TODO: optimize field read? _arguments[_nextArgIndex++] = Ast.Field(null, Fields.DefaultArgument); } }
internal static MSAst.Expression /*!*/ Delete(MSAst.Expression /*!*/ expression) { if (expression is IPythonVariableExpression pyGlobal) { return(pyGlobal.Delete()); } return(Ast.Assign(expression, Ast.Field(null, typeof(Uninitialized).GetField(nameof(Uninitialized.Instance))))); }
private static MSAst.Expression GetSliceValue(Expression expr) { if (expr != null) { return(expr); } return(Ast.Field(null, typeof(MissingParameter).GetField(nameof(MissingParameter.Value)))); }
internal static MSAst.Expression /*!*/ Delete(MSAst.Expression /*!*/ expression) { IPythonVariableExpression pyGlobal = expression as IPythonVariableExpression; if (pyGlobal != null) { return(pyGlobal.Delete()); } return(Ast.Assign(expression, Ast.Field(null, typeof(Uninitialized).GetField("Instance")))); }
private void MakeMissingMemberRuleForGet(Type type) { if (!Action.IsNoThrow) { MakeMissingMemberError(type); } else { AddToBody(Rule.MakeReturn(Binder, Ast.Field(null, typeof(OperationFailed).GetField("Value")))); Rule.IsError = true; } }
protected internal override Expression GetBoundValue(Expression context, ActionBinder binder, Type type, Expression instance) { if (IsPublic && DeclaringType.IsVisible) { return(Ast.Field( Ast.Convert(instance, Field.DeclaringType), Field )); } return(DefaultBinder.MakeError(((DefaultBinder)binder).MakeNonPublicMemberGetError(context, this, type, instance))); }
internal override void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name) { Expression expr = null; Expression instance = _fieldInfo.IsStatic ? null : Ast.Convert(args.TargetExpression, _fieldInfo.DeclaringType); if (_isSetter) { // parameters should be: instance/type, value if (args.SimpleArgumentCount == 0 && args.Signature.HasRhsArgument) { expr = Ast.Assign( Ast.Field(instance, _fieldInfo), // TODO: remove args.RubyContext.Binder.ConvertExpression( args.GetRhsArgumentExpression(), _fieldInfo.FieldType, ConversionResultKind.ExplicitCast, args.ScopeExpression ) ); } } else { // parameter should be: instance/type if (args.SimpleArgumentCount == 0) { if (_fieldInfo.IsLiteral) { // TODO: seems like Compiler should correctly handle the literal field case // (if you emit a read to a literal field, you get a NotSupportedExpception from // FieldHandle when we try to emit) expr = Ast.Constant(_fieldInfo.GetValue(null)); } else { expr = Ast.Field(instance, _fieldInfo); } } } if (expr != null) { metaBuilder.Result = expr; } else { metaBuilder.SetError( Methods.MakeInvalidArgumentTypesError.OpCall(Ast.Constant(_isSetter ? name + "=" : name)) ); } }
private static Expression /*!*/ GetFailureExpression(Type /*!*/ limitType, DynamicMetaObject self, string name, bool isNoThrow, DynamicMetaObjectBinder action) { return(isNoThrow ? Ast.Field(null, typeof(OperationFailed).GetField("Value")) : DefaultBinder.MakeError( PythonContext.GetPythonContext(action).Binder.MakeMissingMemberError( limitType, self, name ), typeof(object) ).Expression); }
internal static MSA.Expression /*!*/ MakeUserMethodBody(AstGenerator gen, int lastLine, MSA.Expression /*!*/ blockParameter, MSA.Expression /*!*/ rfcVariable, MSA.ParameterExpression /*!*/ methodUnwinder, MSA.Expression /*!*/ bodyStatement, ResultOperation resultOperation, int profileTickIndex, MSA.ParameterExpression stampVariable, MSA.LabelTarget returnLabel) { Assert.NotNull(blockParameter, rfcVariable, bodyStatement, methodUnwinder); Debug.Assert(!resultOperation.IsIgnore, "return value should not be ignored"); Debug.Assert(returnLabel != null || resultOperation.Variable != null, "return label needed"); MSA.Expression resultExpression = Ast.Field(methodUnwinder, MethodUnwinder.ReturnValueField); if (resultOperation.Variable != null) { resultExpression = Ast.Assign(resultOperation.Variable, resultExpression); } else { resultExpression = Ast.Return(returnLabel, resultExpression); } // TODO: move this to the caller: MSA.Expression profileStart, profileEnd; if (stampVariable != null) { profileStart = Ast.Assign(stampVariable, Methods.Stopwatch_GetTimestamp.OpCall()); profileEnd = Methods.UpdateProfileTicks.OpCall(Ast.Constant(profileTickIndex), stampVariable); } else { profileStart = profileEnd = Ast.Empty(); } return(AstUtils.Try( // initialize frame (RFC): profileStart, Ast.Assign(rfcVariable, Methods.CreateRfcForMethod.OpCall(AstUtils.Convert(blockParameter, typeof(Proc)))), bodyStatement ).Filter(methodUnwinder, Ast.Equal(Ast.Field(methodUnwinder, MethodUnwinder.TargetFrameField), rfcVariable), // return unwinder.ReturnValue; resultExpression ).Finally( Ast.Assign(Ast.Field(rfcVariable, RuntimeFlowControl.IsActiveMethodField), Ast.Constant(false)), profileEnd, gen != null && gen.TraceEnabled ? Methods.TraceMethodReturn.OpCall( gen.CurrentScopeVariable, Ast.Convert(Ast.Constant(gen.SourceUnit.Path), typeof(string)), Ast.Constant(lastLine) ) : Ast.Empty() )); }
private void MakeMissingMemberRuleForGet(GetMemberInfo getMemInfo, Type type) { if (getMemInfo.IsNoThrow) { getMemInfo.Body.FinishCondition( Ast.Field(null, typeof(OperationFailed).GetField("Value")) ); } else { getMemInfo.Body.FinishCondition( MakeError(MakeMissingMemberError(type, getMemInfo.Name)) ); } }
internal static MSA.Expression /*!*/ MakeCallWithBlockRetryable(AstGenerator /*!*/ gen, MSA.Expression /*!*/ invoke, MSA.Expression blockArgVariable, MSA.Expression transformedBlock, bool isBlockDefinition) { Assert.NotNull(invoke); Debug.Assert((blockArgVariable == null) == (transformedBlock == null)); // see Ruby Language.doc/Control Flow Implementation/Method Call With a Block MSA.Expression resultVariable = gen.CurrentScope.DefineHiddenVariable("#method-result", typeof(object)); MSA.ParameterExpression evalUnwinder; MSA.LabelTarget retryLabel = Ast.Label("retry"); var result = new AstBlock { Ast.Assign(blockArgVariable, Ast.Convert(transformedBlock, blockArgVariable.Type)), Ast.Label(retryLabel), (isBlockDefinition) ? Methods.InitializeBlock.OpCall(blockArgVariable) : null, AstUtils.Try( Ast.Assign(resultVariable, invoke) ).Catch(evalUnwinder = Ast.Parameter(typeof(EvalUnwinder), "#u"), Ast.Assign( resultVariable, Ast.Field(evalUnwinder, EvalUnwinder.ReturnValueField) ) ), Ast.IfThen(Ast.TypeEqual(resultVariable, typeof(BlockReturnResult)), Ast.IfThenElse(Methods.IsRetrySingleton.OpCall(resultVariable), // retry: AstUtils.IfThenElse(Ast.Equal(gen.MakeMethodBlockParameterRead(), blockArgVariable), RetryStatement.TransformRetry(gen), Ast.Goto(retryLabel) ), // return: gen.Return(ReturnStatement.Propagate(gen, resultVariable)) ) ), resultVariable }; return(result); }
protected internal override DynamicMetaObject GetBoundValue(OverloadResolverFactory resolverFactory, ActionBinder binder, Type type, DynamicMetaObject instance) { if (IsPublic && DeclaringType.IsVisible) { return(new DynamicMetaObject( AstUtils.Convert( Ast.Field( AstUtils.Convert(instance.Expression, Field.DeclaringType), Field ), typeof(object) ), BindingRestrictions.Empty )); } return(DefaultBinder.MakeError(((DefaultBinder)binder).MakeNonPublicMemberGetError(resolverFactory, this, type, instance), BindingRestrictions.Empty, typeof(object))); }
/// <summary> /// Takes current result and wraps it into try-filter(MethodUnwinder)-finally block that ensures correct "break" behavior for /// library method calls with block given in bfcVariable (BlockParam). /// </summary> public static void RuleControlFlowBuilder(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { if (metaBuilder.Error) { return; } var metaBlock = args.GetMetaBlock(); Debug.Assert(metaBlock != null, "RuleControlFlowBuilder should only be used if the signature has a block"); // We construct CF only for non-nil blocks thus we need a test for it: if (metaBlock.Value == null) { metaBuilder.AddRestriction(Ast.Equal(metaBlock.Expression, AstUtils.Constant(null))); return; } // don't need to test the exact type of the Proc since the code is subclass agnostic: metaBuilder.AddRestriction(Ast.NotEqual(metaBlock.Expression, AstUtils.Constant(null))); Expression bfcVariable = metaBuilder.BfcVariable; Debug.Assert(bfcVariable != null); // Method call with proc can invoke control flow that returns an arbitrary value from the call, so we need to type result to Object. // Otherwise, the result could only be result of targetExpression unless its return type is void. Expression resultVariable = metaBuilder.GetTemporary(typeof(object), "#result"); ParameterExpression unwinder; metaBuilder.Result = Ast.Block( Ast.Assign(bfcVariable, Methods.CreateBfcForLibraryMethod.OpCall(AstUtils.Convert(args.GetBlockExpression(), typeof(Proc)))), AstUtils.Try( Ast.Assign(resultVariable, AstUtils.Convert(metaBuilder.Result, typeof(object))) ).Filter(unwinder = Ast.Parameter(typeof(MethodUnwinder), "#unwinder"), Methods.IsProcConverterTarget.OpCall(bfcVariable, unwinder), Ast.Assign(resultVariable, Ast.Field(unwinder, MethodUnwinder.ReturnValueField)), AstUtils.Default(typeof(object)) ).Finally( Methods.LeaveProcConverter.OpCall(bfcVariable) ), resultVariable ); }
/// <summary> /// Resolves an library method overload and builds call expression. /// The resulting expression on meta-builder doesn't handle block control flow yet. /// </summary> internal static void BuildCallNoFlow(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, string /*!*/ name, IList <OverloadInfo> /*!*/ overloads, SelfCallConvention callConvention, bool implicitProtocolConversions) { RubyOverloadResolver resolver; var bindingTarget = ResolveOverload(metaBuilder, args, name, overloads, callConvention, implicitProtocolConversions, out resolver); if (bindingTarget.Success) { // TODO: create a custom overload info: if (ReferenceEquals(bindingTarget.Overload.ReflectionInfo, Methods.CreateDefaultInstance)) { Debug.Assert(args.TargetClass.TypeTracker.Type.IsValueType); metaBuilder.Result = Ast.New(args.TargetClass.TypeTracker.Type); } else if (args.Signature.IsVirtualCall && bindingTarget.Overload.IsVirtual) { // Virtual methods that have been detached from the CLR type and // defined on the corresponding Ruby class or its subclass are not // directly invoked from a dynamic virtual call to prevent recursion. // Instead the base call is performed. // // Example: // class C < ArrayList // define_method(:Add, instance_method(:Add)) // end // // C.new.Add(1) // // C.new.Add dispatches to the virtual ArrayList::Add, which in turn dispatches to the auto-generated override C$1::Add. // That gets here since the defined method is a Ruby method (a detached CLR method group). If we called it directly // it would invoke the C$1::Add override again leading to a stack overflow. So we need to use a base call instead. metaBuilder.Result = Ast.Field(null, Fields.ForwardToBase); } else { metaBuilder.Result = bindingTarget.MakeExpression(); } } else { metaBuilder.SetError(resolver.MakeInvalidParametersError(bindingTarget).Expression); } }
public override MSAst.Expression /*!*/ Reduce() { Debug.Assert(_start >= 0); Assert.NotNull(_fieldInfo); int index = _offset + _start; int arrIndex = index - FieldCount; if (arrIndex < 0) { return(Ast.Field(null, _fieldInfo)); } else { return(Ast.ArrayIndex( Ast.Field(null, _fieldInfo), Ast.Constant(arrIndex, typeof(int)) )); } }
/// <summary> if a member-injector is defined-on or registered-for this type call it </summary> protected void MakeOperatorGetMemberBody(Type type, string name) { MethodInfo getMem = GetMethod(type, name); if (getMem != null && getMem.IsSpecialName) { ParameterExpression tmp = Rule.GetTemporary(typeof(object), "getVal"); AddToBody( AstUtils.If( Ast.NotEqual( Ast.Assign( tmp, Binder.MakeCallExpression(Rule.Context, getMem, Instance, Ast.Constant(StringName)) ), Ast.Field(null, typeof(OperationFailed).GetField("Value")) ), Rule.MakeReturn(Binder, tmp) ) ); } }