PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/IronPython_Main/Languages/Ruby/Ruby/Runtime/Calls/CallArguments.cs

#
C# | 353 lines | 252 code | 64 blank | 37 comment | 36 complexity | 63d5fdcc4a3801ae9864390a80a31374 MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) Microsoft Corporation.
  4. *
  5. * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. * copy of the license can be found in the License.html file at the root of this distribution. If
  7. * you cannot locate the Apache License, Version 2.0, please send an email to
  8. * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. * by the terms of the Apache License, Version 2.0.
  10. *
  11. * You must not remove this notice, or any other, from this software.
  12. *
  13. *
  14. * ***************************************************************************/
  15. #if !CLR2
  16. using System.Linq.Expressions;
  17. #else
  18. using Microsoft.Scripting.Ast;
  19. #endif
  20. using System.Collections;
  21. using System.Diagnostics;
  22. using System.Dynamic;
  23. using System.Runtime.CompilerServices;
  24. using Microsoft.Scripting;
  25. using Microsoft.Scripting.Runtime;
  26. using Microsoft.Scripting.Utils;
  27. using IronRuby.Builtins;
  28. using IronRuby.Compiler;
  29. using AstUtils = Microsoft.Scripting.Ast.Utils;
  30. namespace IronRuby.Runtime.Calls {
  31. using Ast = Expression;
  32. using AstExpressions = ReadOnlyCollectionBuilder<Expression>;
  33. using System.Collections.ObjectModel;
  34. /// <summary>
  35. /// Wraps the arguments of a dynamic call site
  36. /// Includes the actual arguments, the expressions that produced those arguments,
  37. /// and the call signature.
  38. ///
  39. /// These three things are grouped together to ensure that they are all in sync
  40. /// when we want to shift the arguments around during the method binding process.
  41. /// </summary>
  42. public sealed class CallArguments {
  43. private readonly bool _hasScopeOrContextArg;
  44. private readonly DynamicMetaObject/*!*/ _context;
  45. private DynamicMetaObject _scope;
  46. // _args[0] might be target, if so _target is null:
  47. private DynamicMetaObject _target;
  48. private RubyClass _targetClass;
  49. // Arguments must be readonly if _copyOnWrite is true.
  50. private DynamicMetaObject[]/*!*/ _args;
  51. private bool _copyArgsOnWrite;
  52. private RubyCallSignature _signature;
  53. public RubyCallSignature/*!*/ Signature {
  54. get { return _signature; }
  55. }
  56. public int CallSiteArgumentCount {
  57. get {
  58. // (scope|context)?, target, arguments:
  59. return (_hasScopeOrContextArg ? 1 : 0) + ExplicitArgumentCount;
  60. }
  61. }
  62. public int ExplicitArgumentCount {
  63. get {
  64. // target, arguments:
  65. return (_target != null ? 1 : 0) + _args.Length;
  66. }
  67. }
  68. // Index of the first argument in _args array.
  69. private int FirstArgumentIndex {
  70. get { return (_target == null) ? 1 : 0; }
  71. }
  72. public int SimpleArgumentCount {
  73. get {
  74. return _args.Length - FirstArgumentIndex - (_signature.HasBlock ? 1 : 0) -
  75. (_signature.HasSplattedArgument ? 1 : 0) - (_signature.HasRhsArgument ? 1 : 0);
  76. }
  77. }
  78. public DynamicMetaObject/*!*/ MetaScope {
  79. get {
  80. if (_scope == null) {
  81. Debug.Assert(!_signature.HasScope);
  82. // we can burn the scope as a constant since we'll restrict the context arg to the current context:
  83. var emptyScope = ((RubyContext)_context.Value).EmptyScope;
  84. _scope = new DynamicMetaObject(Ast.Constant(emptyScope, typeof(RubyScope)), BindingRestrictions.Empty, emptyScope);
  85. }
  86. return _scope;
  87. }
  88. }
  89. public DynamicMetaObject/*!*/ MetaContext {
  90. get { return _context; }
  91. }
  92. public RubyScope/*!*/ Scope {
  93. get { return (RubyScope)MetaScope.Value; }
  94. }
  95. public RubyContext/*!*/ RubyContext {
  96. get { return (RubyContext)MetaContext.Value; }
  97. }
  98. public DynamicMetaObject/*!*/ MetaTarget {
  99. get { return _target ?? _args[0]; }
  100. }
  101. public Expression/*!*/ TargetExpression {
  102. get { return MetaTarget.Expression; }
  103. }
  104. public RubyClass/*!*/ TargetClass {
  105. get {
  106. if (_targetClass == null) {
  107. _targetClass = RubyContext.GetImmediateClassOf(Target);
  108. }
  109. return _targetClass;
  110. }
  111. }
  112. public object Target {
  113. get { return MetaTarget.Value; }
  114. }
  115. public Proc GetBlock() {
  116. return (Proc)_args[GetBlockIndex()].Value;
  117. }
  118. public IList/*!*/ GetSplattedArgument() {
  119. return (IList)_args[GetSplattedArgumentIndex()].Value;
  120. }
  121. public object GetRhsArgument() {
  122. return _args[GetRhsArgumentIndex()].Value;
  123. }
  124. public Expression GetBlockExpression() {
  125. return _signature.HasBlock ? _args[GetBlockIndex()].Expression : null;
  126. }
  127. public DynamicMetaObject GetMetaBlock() {
  128. return _signature.HasBlock ? _args[GetBlockIndex()] : null;
  129. }
  130. public DynamicMetaObject GetSplattedMetaArgument() {
  131. return _signature.HasSplattedArgument ? _args[GetSplattedArgumentIndex()] : null;
  132. }
  133. public Expression GetSplattedArgumentExpression() {
  134. return _signature.HasSplattedArgument ? _args[GetSplattedArgumentIndex()].Expression : null;
  135. }
  136. public DynamicMetaObject GetRhsMetaArgument() {
  137. return _signature.HasRhsArgument ? _args[GetRhsArgumentIndex()] : null;
  138. }
  139. public Expression GetRhsArgumentExpression() {
  140. return _signature.HasRhsArgument ? _args[GetRhsArgumentIndex()].Expression : null;
  141. }
  142. public AstExpressions/*!*/ GetSimpleArgumentExpressions() {
  143. int count = SimpleArgumentCount;
  144. var result = new AstExpressions(count);
  145. for (int i = 0, j = GetSimpleArgumentIndex(0); i < count; j++, i++) {
  146. result.Add(_args[j].Expression);
  147. }
  148. return result;
  149. }
  150. internal ReadOnlyCollection<Expression>/*!*/ GetCallSiteArguments(Expression/*!*/ targetExpression) {
  151. // context, target, arguments:
  152. var result = new AstExpressions(CallSiteArgumentCount);
  153. if (_hasScopeOrContextArg) {
  154. result.Add(_signature.HasScope ? MetaScope.Expression : MetaContext.Expression);
  155. }
  156. result.Add(targetExpression);
  157. for (int j = FirstArgumentIndex; j < _args.Length; j++) {
  158. result.Add(_args[j].Expression);
  159. }
  160. return result.ToReadOnlyCollection();
  161. }
  162. private int GetSimpleArgumentIndex(int i) {
  163. return FirstArgumentIndex + (_signature.HasBlock ? 1 : 0) + i;
  164. }
  165. internal object GetSimpleArgument(int i) {
  166. return GetSimpleMetaArgument(i).Value;
  167. }
  168. internal Expression/*!*/ GetSimpleArgumentExpression(int i) {
  169. return GetSimpleMetaArgument(i).Expression;
  170. }
  171. internal DynamicMetaObject/*!*/ GetSimpleMetaArgument(int i) {
  172. return _args[GetSimpleArgumentIndex(i)];
  173. }
  174. internal int GetBlockIndex() {
  175. Debug.Assert(_signature.HasBlock);
  176. return FirstArgumentIndex;
  177. }
  178. internal int GetSplattedArgumentIndex() {
  179. Debug.Assert(_signature.HasSplattedArgument);
  180. return _args.Length - (_signature.HasRhsArgument ? 2 : 1);
  181. }
  182. internal int GetRhsArgumentIndex() {
  183. Debug.Assert(_signature.HasRhsArgument);
  184. return _args.Length - 1;
  185. }
  186. // Ruby binders:
  187. internal CallArguments(RubyContext context, DynamicMetaObject/*!*/ scopeOrContextOrTargetOrArgArray, DynamicMetaObject/*!*/[]/*!*/ args, RubyCallSignature signature) {
  188. Assert.NotNull(scopeOrContextOrTargetOrArgArray);
  189. Assert.NotNullItems(args);
  190. ArgumentArray argArray = scopeOrContextOrTargetOrArgArray.Value as ArgumentArray;
  191. if (argArray != null) {
  192. Debug.Assert(args.Length == 0 && argArray.Count >= 1);
  193. // build meta-objects for arguments wrapped in the array:
  194. args = new DynamicMetaObject[argArray.Count - 1];
  195. for (int i = 0; i < args.Length; i++) {
  196. args[i] = argArray.GetMetaObject(scopeOrContextOrTargetOrArgArray.Expression, 1 + i);
  197. }
  198. scopeOrContextOrTargetOrArgArray = argArray.GetMetaObject(scopeOrContextOrTargetOrArgArray.Expression, 0);
  199. }
  200. Debug.Assert(signature.HasScope == scopeOrContextOrTargetOrArgArray.Value is RubyScope);
  201. Debug.Assert((context == null && !signature.HasScope) == scopeOrContextOrTargetOrArgArray.Value is RubyContext);
  202. if (context != null) {
  203. // bound site:
  204. _context = new DynamicMetaObject(AstUtils.Constant(context), BindingRestrictions.Empty, context);
  205. if (signature.HasScope) {
  206. _scope = scopeOrContextOrTargetOrArgArray;
  207. _hasScopeOrContextArg = true;
  208. } else {
  209. _target = scopeOrContextOrTargetOrArgArray;
  210. }
  211. } else if (signature.HasScope) {
  212. // unbound site with scope:
  213. _context = new DynamicMetaObject(
  214. Methods.GetContextFromScope.OpCall(scopeOrContextOrTargetOrArgArray.Expression), BindingRestrictions.Empty,
  215. ((RubyScope)scopeOrContextOrTargetOrArgArray.Value).RubyContext
  216. );
  217. _scope = scopeOrContextOrTargetOrArgArray;
  218. _hasScopeOrContextArg = true;
  219. _target = null;
  220. } else {
  221. // unbound site with context:
  222. _context = scopeOrContextOrTargetOrArgArray;
  223. _hasScopeOrContextArg = true;
  224. _target = null;
  225. }
  226. Debug.Assert(_target != null || args.Length > 0);
  227. _args = args;
  228. _copyArgsOnWrite = true;
  229. _signature = signature;
  230. Debug.Assert(!signature.HasSplattedArgument || GetSplattedArgument() != null);
  231. }
  232. // interop binders: the target is a Ruby meta-object closed over the context
  233. internal CallArguments(DynamicMetaObject/*!*/ context, DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, RubyCallSignature signature) {
  234. Assert.NotNull(target, context);
  235. Assert.NotNullItems(args);
  236. Debug.Assert(!signature.HasScope && !signature.HasSplattedArgument);
  237. _target = target;
  238. _context = context;
  239. _args = args;
  240. _copyArgsOnWrite = true;
  241. _signature = signature;
  242. }
  243. // interop binders: the target is a foreign meta-object, the binder is context-bound:
  244. internal CallArguments(RubyContext/*!*/ context, DynamicMetaObject/*!*/ target, DynamicMetaObject/*!*/[]/*!*/ args, CallInfo/*!*/ callInfo)
  245. : this (
  246. new DynamicMetaObject(AstUtils.Constant(context), BindingRestrictions.Empty, context),
  247. target,
  248. args,
  249. RubyCallSignature.Interop(callInfo.ArgumentCount)
  250. ) {
  251. }
  252. public void InsertSimple(int index, DynamicMetaObject/*!*/ arg) {
  253. index = GetSimpleArgumentIndex(index);
  254. _args = ArrayUtils.InsertAt(_args, index, arg);
  255. _signature = new RubyCallSignature(_signature.ArgumentCount + 1, _signature.Flags);
  256. }
  257. internal void InsertMethodName(string/*!*/ methodName) {
  258. // insert the method name argument into the args
  259. object symbol = RubyContext.EncodeIdentifier(methodName);
  260. InsertSimple(0, new DynamicMetaObject(AstUtils.Constant(symbol), BindingRestrictions.Empty, symbol));
  261. }
  262. public void SetSimpleArgument(int index, DynamicMetaObject/*!*/ arg) {
  263. SetArgument(GetSimpleArgumentIndex(index), arg);
  264. }
  265. private void SetArgument(int index, DynamicMetaObject/*!*/ arg) {
  266. if (_copyArgsOnWrite) {
  267. _args = ArrayUtils.Copy(_args);
  268. _copyArgsOnWrite = false;
  269. }
  270. _args[index] = arg;
  271. }
  272. public void SetTarget(Expression/*!*/ expression, object value) {
  273. Assert.NotNull(expression);
  274. var metaTarget = new DynamicMetaObject(expression, BindingRestrictions.Empty, value);
  275. if (_target == null) {
  276. if (_copyArgsOnWrite) {
  277. _args = ArrayUtils.RemoveFirst(_args);
  278. _copyArgsOnWrite = false;
  279. _target = metaTarget;
  280. } else {
  281. _args[0] = metaTarget;
  282. }
  283. } else {
  284. _target = metaTarget;
  285. }
  286. _targetClass = null;
  287. }
  288. }
  289. }