internal void AddArgumentRestrictions(MetaObjectBuilder /*!*/ metaBuilder, BindingTarget /*!*/ bindingTarget) { var args = GetActualArguments(); var restrictedArgs = bindingTarget.Success ? bindingTarget.RestrictedArguments.GetObjects() : args.Arguments; for (int i = _firstRestrictedArg; i < restrictedArgs.Count; i++) { var arg = (bindingTarget.Success ? restrictedArgs[i] : restrictedArgs[i].Restrict(restrictedArgs[i].GetLimitType())); if (i >= args.FirstSplattedArg && i <= _lastSplattedArg) { metaBuilder.AddCondition(arg.Restrictions.ToExpression()); } else { metaBuilder.AddRestriction(arg.Restrictions); } } // Adds condition for collapsed arguments - it is the same whether we succeed or not: var splatCondition = GetCollapsedArgsCondition(); if (splatCondition != null) { metaBuilder.AddCondition(splatCondition); } }
protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { RubyModule currentDeclaringModule; string currentMethodName; var scope = args.Scope; object target; scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out target); var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self"); metaBuilder.AddCondition( Methods.IsSuperCallTarget.OpCall( AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)), AstUtils.Constant(currentDeclaringModule), AstUtils.Constant(currentMethodName), targetExpression ) ); args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); RubyMemberInfo method; RubyMemberInfo methodMissing = null; // we need to lock the hierarchy of the target class: var targetClass = scope.RubyContext.GetImmediateClassOf(target); using (targetClass.Context.ClassHierarchyLocker()) { // initialize all methods in ancestors: targetClass.InitializeMethodsNoLock(); // target is stored in a local, therefore it cannot be part of the restrictions: metaBuilder.TreatRestrictionsAsConditions = true; metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext, new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton ); metaBuilder.TreatRestrictionsAsConditions = false; method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info; if (method == null) { // MRI: method_missing is called for the targetClass, not for the super: methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None); } } if (method != null) { method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } else { return RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback); } return true; }
internal static MethodResolutionResult Resolve(MetaObjectBuilder /*!*/ metaBuilder, string /*!*/ methodName, CallArguments /*!*/ args, out RubyMemberInfo methodMissing) { MethodResolutionResult method; var targetClass = args.TargetClass; var visibilityContext = GetVisibilityContext(args.Signature, args.Scope); using (targetClass.Context.ClassHierarchyLocker()) { metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext, new[] { methodName, Symbols.MethodMissing } ); if (args.Signature.IsSuperCall) { Debug.Assert(!args.Signature.IsVirtualCall && args.Signature.HasImplicitSelf); method = targetClass.ResolveSuperMethodNoLock(methodName, targetClass).InvalidateSitesOnOverride(); } else { var options = args.Signature.IsVirtualCall ? MethodLookup.Virtual : MethodLookup.Default; method = targetClass.ResolveMethodForSiteNoLock(methodName, visibilityContext, options); } if (!method.Found) { methodMissing = targetClass.ResolveMethodMissingForSite(methodName, method.IncompatibleVisibility); } else { methodMissing = null; } } // Whenever the current self's class changes we need to invalidate the rule, if a protected method is being called. if (method.Info != null && method.Info.IsProtected && visibilityContext.Class != null) { // We don't need to compare versions, just the class objects (super-class relationship cannot be changed). // Since we don't want to hold on a class object (to make it collectible) we compare references to the version handlers. metaBuilder.AddCondition(Ast.Equal( Methods.GetSelfClassVersionHandle.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))), Ast.Constant(visibilityContext.Class.Version) )); } return(method); }
internal void SetRule(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args) { RubyModule currentDeclaringModule; string currentMethodName; var scope = args.Scope; object target; scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out target); var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self"); metaBuilder.AddCondition( Methods.IsSuperCallTarget.OpCall( AstUtils.Convert(args.ScopeExpression, typeof(RubyScope)), Ast.Constant(currentDeclaringModule), AstUtils.Constant(currentMethodName), targetExpression ) ); args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); // target is stored in a local, therefore it cannot be part of the restrictions: metaBuilder.TreatRestrictionsAsConditions = true; metaBuilder.AddTargetTypeTest(target, targetExpression, scope.RubyContext, args.ContextExpression); metaBuilder.TreatRestrictionsAsConditions = false; RubyMemberInfo method = scope.RubyContext.ResolveSuperMethod(target, currentMethodName, currentDeclaringModule); // super calls don't go to method_missing if (method == null) { metaBuilder.SetError(Methods.MakeMissingSuperException.OpCall(Ast.Constant(currentMethodName))); } else { method.InvalidateSitesOnOverride = true; method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } }
internal static MethodResolutionResult Resolve(MetaObjectBuilder/*!*/ metaBuilder, string/*!*/ methodName, CallArguments/*!*/ args, out RubyMemberInfo methodMissing) { MethodResolutionResult method; var targetClass = args.TargetClass; var visibilityContext = GetVisibilityContext(args.Signature, args.Scope); using (targetClass.Context.ClassHierarchyLocker()) { metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext, new[] { methodName, Symbols.MethodMissing } ); if (args.Signature.IsSuperCall) { Debug.Assert(!args.Signature.IsVirtualCall && args.Signature.HasImplicitSelf); method = targetClass.ResolveSuperMethodNoLock(methodName, targetClass).InvalidateSitesOnOverride(); } else { var options = args.Signature.IsVirtualCall ? MethodLookup.Virtual : MethodLookup.Default; method = targetClass.ResolveMethodForSiteNoLock(methodName, visibilityContext, options); } if (!method.Found) { methodMissing = targetClass.ResolveMethodMissingForSite(methodName, method.IncompatibleVisibility); } else { methodMissing = null; } } // Whenever the current self's class changes we need to invalidate the rule, if a protected method is being called. if (method.Info != null && method.Info.IsProtected && visibilityContext.Class != null) { // We don't need to compare versions, just the class objects (super-class relationship cannot be changed). // Since we don't want to hold on a class object (to make it collectible) we compare references to the version handlers. metaBuilder.AddCondition(Ast.Equal( Methods.GetSelfClassVersionHandle.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))), Ast.Constant(visibilityContext.Class.Version) )); } return method; }
internal void AddArgumentRestrictions(MetaObjectBuilder/*!*/ metaBuilder, BindingTarget/*!*/ bindingTarget) { var args = GetActualArguments(); var restrictedArgs = bindingTarget.Success ? bindingTarget.RestrictedArguments.GetObjects() : args.Arguments; for (int i = _firstRestrictedArg; i < restrictedArgs.Count; i++) { var arg = (bindingTarget.Success ? restrictedArgs[i] : restrictedArgs[i].Restrict(restrictedArgs[i].GetLimitType())); if (i >= args.FirstSplattedArg && i <= _lastSplattedArg) { metaBuilder.AddCondition(arg.Restrictions.ToExpression()); } else { metaBuilder.AddRestriction(arg.Restrictions); } } // Adds condition for collapsed arguments - it is the same whether we succeed or not: var splatCondition = GetCollapsedArgsCondition(); if (splatCondition != null) { metaBuilder.AddCondition(splatCondition); } }
protected override bool Build(MetaObjectBuilder/*!*/ metaBuilder, CallArguments/*!*/ args, bool defaultFallback) { RubyModule currentDeclaringModule; string currentMethodName; var scope = args.Scope; var scopeExpr = AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)); RubyScope targetScope; int scopeNesting = scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out targetScope); if (scopeNesting == -1) { metaBuilder.AddCondition(Methods.IsSuperOutOfMethodScope.OpCall(scopeExpr)); metaBuilder.SetError(Methods.MakeTopLevelSuperException.OpCall()); return true; } object target = targetScope.SelfObject; var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self"); var assignTarget = Ast.Assign( targetExpression, Methods.GetSuperCallTarget.OpCall(scopeExpr, AstUtils.Constant(scopeNesting)) ); if (_signature.HasImplicitArguments && targetScope.Kind == ScopeKind.BlockMethod) { metaBuilder.AddCondition(Ast.NotEqual(assignTarget, Ast.Field(null, Fields.NeedsUpdate))); metaBuilder.SetError(Methods.MakeImplicitSuperInBlockMethodError.OpCall()); return true; } // If we need to update we return RubyOps.NeedsUpdate instance that will cause the subsequent conditions to fail: metaBuilder.AddInitialization(assignTarget); args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); RubyMemberInfo method; RubyMemberInfo methodMissing = null; // MRI bug: Uses currentDeclaringModule for method look-up so we can end up with an instance method of class C // called on a target of another class. See http://redmine.ruby-lang.org/issues/show/2419. // we need to lock the hierarchy of the target class: var targetClass = scope.RubyContext.GetImmediateClassOf(target); using (targetClass.Context.ClassHierarchyLocker()) { // initialize all methods in ancestors: targetClass.InitializeMethodsNoLock(); // target is stored in a local, therefore it cannot be part of the restrictions: metaBuilder.TreatRestrictionsAsConditions = true; metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext, new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton ); metaBuilder.TreatRestrictionsAsConditions = false; method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info; if (_signature.ResolveOnly) { metaBuilder.Result = AstUtils.Constant(method != null); return true; } if (method == null) { // MRI: method_missing is called for the targetClass, not for the super: methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None); } } if (method != null) { method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } else { return RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback); } return true; }
protected override bool Build(MetaObjectBuilder /*!*/ metaBuilder, CallArguments /*!*/ args, bool defaultFallback) { RubyModule currentDeclaringModule; string currentMethodName; var scope = args.Scope; var scopeExpr = AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope)); RubyScope targetScope; int scopeNesting = scope.GetSuperCallTarget(out currentDeclaringModule, out currentMethodName, out targetScope); if (scopeNesting == -1) { metaBuilder.AddCondition(Methods.IsSuperOutOfMethodScope.OpCall(scopeExpr)); metaBuilder.SetError(Methods.MakeTopLevelSuperException.OpCall()); return(true); } object target = targetScope.SelfObject; var targetExpression = metaBuilder.GetTemporary(typeof(object), "#super-self"); var assignTarget = Ast.Assign( targetExpression, Methods.GetSuperCallTarget.OpCall(scopeExpr, AstUtils.Constant(scopeNesting)) ); if (_signature.HasImplicitArguments && targetScope.Kind == ScopeKind.BlockMethod) { metaBuilder.AddCondition(Ast.NotEqual(assignTarget, Ast.Field(null, Fields.NeedsUpdate))); metaBuilder.SetError(Methods.MakeImplicitSuperInBlockMethodError.OpCall()); return(true); } // If we need to update we return RubyOps.NeedsUpdate instance that will cause the subsequent conditions to fail: metaBuilder.AddInitialization(assignTarget); args.SetTarget(targetExpression, target); Debug.Assert(currentDeclaringModule != null); RubyMemberInfo method; RubyMemberInfo methodMissing = null; // MRI bug: Uses currentDeclaringModule for method look-up so we can end up with an instance method of class C // called on a target of another class. See http://redmine.ruby-lang.org/issues/show/2419. // we need to lock the hierarchy of the target class: var targetClass = scope.RubyContext.GetImmediateClassOf(target); using (targetClass.Context.ClassHierarchyLocker()) { // initialize all methods in ancestors: targetClass.InitializeMethodsNoLock(); // target is stored in a local, therefore it cannot be part of the restrictions: metaBuilder.TreatRestrictionsAsConditions = true; metaBuilder.AddTargetTypeTest(target, targetClass, targetExpression, args.MetaContext, new[] { Symbols.MethodMissing } // currentMethodName is resolved for super, which cannot be an instance singleton ); metaBuilder.TreatRestrictionsAsConditions = false; method = targetClass.ResolveSuperMethodNoLock(currentMethodName, currentDeclaringModule).InvalidateSitesOnOverride().Info; if (_signature.ResolveOnly) { metaBuilder.Result = AstUtils.Constant(method != null); return(true); } if (method == null) { // MRI: method_missing is called for the targetClass, not for the super: methodMissing = targetClass.ResolveMethodMissingForSite(currentMethodName, RubyMethodVisibility.None); } } if (method != null) { method.BuildSuperCall(metaBuilder, args, currentMethodName, currentDeclaringModule); } else { return(RubyCallAction.BuildMethodMissingCall(metaBuilder, args, currentMethodName, methodMissing, RubyMethodVisibility.None, true, defaultFallback)); } return(true); }
internal static MethodResolutionResult Resolve(MetaObjectBuilder/*!*/ metaBuilder, string/*!*/ methodName, CallArguments/*!*/ args, out RubyMemberInfo methodMissing) { MethodResolutionResult method; RubyClass targetClass = args.RubyContext.GetImmediateClassOf(args.Target); using (targetClass.Context.ClassHierarchyLocker()) { metaBuilder.AddTargetTypeTest(args.Target, targetClass, args.TargetExpression, args.MetaContext); // TODO: All sites should have either implicit-self or has-scope flag set? var visibilityContext = args.Signature.HasImplicitSelf || !args.Signature.HasScope ? RubyClass.IgnoreVisibility : args.Scope.SelfImmediateClass; method = targetClass.ResolveMethodForSiteNoLock(methodName, visibilityContext); if (!method.Found) { if (args.Signature.IsTryCall) { // TODO: this shouldn't throw. We need to fix caching of non-existing methods. throw new MissingMethodException(); // metaBuilder.Result = AstUtils.Constant(Fields.RubyOps_MethodNotFound); } else { methodMissing = targetClass.ResolveMethodMissingForSite(methodName, method.IncompatibleVisibility); } } else { methodMissing = null; } } // Whenever the current self's class changes we need to invalidate the rule, if a protected method is being called. if (method.Info != null && method.Info.IsProtected && !args.Signature.HasImplicitSelf) { // We don't need to compare versions, just the class objects (super-class relationship cannot be changed). // Since we don't want to hold on a class object (to make it collectible) we compare references to the version boxes. metaBuilder.AddCondition(Ast.Equal( Methods.GetSelfClassVersionHandle.OpCall(AstUtils.Convert(args.MetaScope.Expression, typeof(RubyScope))), Ast.Constant(args.Scope.SelfImmediateClass.Version) )); } return method; }
internal void AddFullVersionTest(MetaObjectBuilder/*!*/ metaBuilder, MSA.Expression/*!*/ contextExpression) { Assert.NotNull(metaBuilder); EnsureInitialized(); // Initialization changes the version number, so ensure that the module is initialized // check for runtime: metaBuilder.AddRestriction(Ast.Equal(contextExpression, Ast.Constant(_context))); // check for version: metaBuilder.AddCondition(Ast.Equal(Ast.Property(Ast.Constant(this), VersionProperty), Ast.Constant(_version))); }