PageRenderTime 158ms CodeModel.GetById 27ms app.highlight 112ms RepoModel.GetById 1ms app.codeStats 1ms

/IronPython_Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs

#
C# | 2570 lines | 1954 code | 449 blank | 167 comment | 303 complexity | 59b560ffd38a41d8fd908eeb89bd675a MD5 | raw file
   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
  16#if !CLR2
  17using MSA = System.Linq.Expressions;
  18#else
  19using MSA = Microsoft.Scripting.Ast;
  20#endif
  21
  22using System;
  23using System.Collections;
  24using System.Collections.Generic;
  25using System.Diagnostics;
  26using System.Dynamic;
  27using System.Globalization;
  28using System.IO;
  29using System.Reflection;
  30using System.Runtime.CompilerServices;
  31using System.Runtime.Serialization;
  32using System.Threading;
  33using IronRuby.Builtins;
  34using IronRuby.Compiler;
  35using IronRuby.Compiler.Generation;
  36using IronRuby.Runtime.Calls;
  37using Microsoft.Scripting;
  38using Microsoft.Scripting.Interpreter;
  39using Microsoft.Scripting.Math;
  40using Microsoft.Scripting.Runtime;
  41using Microsoft.Scripting.Utils;
  42using IronRuby.Compiler.Ast;
  43using IronRuby.Runtime.Conversions;
  44
  45namespace IronRuby.Runtime {
  46    [ReflectionCached, CLSCompliant(false)]
  47    public static partial class RubyOps {
  48        [Emitted]
  49        public static readonly object DefaultArgument = new object();
  50        
  51        // Returned by a virtual site if a base call should be performed.
  52        [Emitted]
  53        public static readonly object ForwardToBase = new object();
  54
  55        // an instance of a dummy type that causes any rule based on instance type check to fail
  56        private sealed class _NeedsUpdate {
  57        }
  58
  59        [Emitted]
  60        public static readonly object NeedsUpdate = new _NeedsUpdate();
  61
  62        #region Scopes
  63
  64        [Emitted]
  65        public static MutableTuple GetLocals(RubyScope/*!*/ scope) {
  66            return scope.Locals;
  67        }
  68
  69        [Emitted]
  70        public static MutableTuple GetParentLocals(RubyScope/*!*/ scope) {
  71            return scope.Parent.Locals;
  72        }
  73
  74        [Emitted]
  75        public static RubyScope/*!*/ GetParentScope(RubyScope/*!*/ scope) {
  76            return scope.Parent;
  77        }
  78
  79        [Emitted]
  80        public static Proc GetMethodBlockParameter(RubyScope/*!*/ scope) {
  81            var methodScope = scope.GetInnerMostMethodScope();
  82            return methodScope != null ? methodScope.BlockParameter : null;
  83        }
  84
  85        [Emitted]
  86        public static object GetMethodBlockParameterSelf(RubyScope/*!*/ scope) {
  87            Proc proc = scope.GetInnerMostMethodScope().BlockParameter;
  88            Debug.Assert(proc != null, "CreateBfcForYield is called before this method and it checks non-nullity");
  89            return proc.Self;
  90        }
  91
  92        [Emitted]
  93        public static object GetProcSelf(Proc/*!*/ proc) {
  94            return proc.Self;
  95        }
  96
  97        [Emitted]
  98        public static int GetProcArity(Proc/*!*/ proc) {
  99            return proc.Dispatcher.Arity;
 100        }
 101
 102        [Emitted]
 103        public static void InitializeScope(RubyScope/*!*/ scope, MutableTuple locals, string[] variableNames, 
 104            InterpretedFrame interpretedFrame) {
 105
 106            if (!scope.LocalsInitialized) {
 107                scope.SetLocals(locals, variableNames ?? ArrayUtils.EmptyStrings);
 108            }
 109            scope.InterpretedFrame = interpretedFrame;
 110        }
 111        
 112        [Emitted]
 113        public static void InitializeScopeNoLocals(RubyScope/*!*/ scope, InterpretedFrame interpretedFrame) {
 114            scope.InterpretedFrame = interpretedFrame;
 115        }
 116
 117        [Emitted]
 118        public static void SetDataConstant(RubyScope/*!*/ scope, string/*!*/ dataPath, int dataOffset) {
 119            Debug.Assert(dataOffset >= 0);
 120            RubyFile dataFile;
 121            RubyContext context = scope.RubyContext;
 122            if (context.DomainManager.Platform.FileExists(dataPath)) {
 123                dataFile = new RubyFile(context, dataPath, IOMode.ReadOnly);
 124                dataFile.Seek(dataOffset, SeekOrigin.Begin);
 125            } else {
 126                dataFile = null;
 127            }
 128
 129            context.ObjectClass.SetConstant("DATA", dataFile);
 130        }
 131
 132        [Emitted]
 133        public static RubyModuleScope/*!*/ CreateModuleScope(MutableTuple locals, string[] variableNames, 
 134            RubyScope/*!*/ parent, RubyModule/*!*/ module) {
 135
 136            if (parent.RubyContext != module.Context) {
 137                throw RubyExceptions.CreateTypeError("Cannot open a module `{0}' defined in a foreign runtime #{1}", module.Name, module.Context.RuntimeId);
 138            }
 139
 140            RubyModuleScope scope = new RubyModuleScope(parent, module);
 141            scope.SetDebugName((module.IsClass ? "class" : "module") + " " + module.Name);
 142            scope.SetLocals(locals, variableNames ?? ArrayUtils.EmptyStrings);
 143            return scope;
 144        }
 145
 146        [Emitted]
 147        public static RubyMethodScope/*!*/ CreateMethodScope(MutableTuple locals, string[] variableNames, int visibleParameterCount,
 148            RubyScope/*!*/ parentScope, RubyModule/*!*/ declaringModule, string/*!*/ definitionName, 
 149            object selfObject, Proc blockParameter, InterpretedFrame interpretedFrame) {
 150
 151            return new RubyMethodScope(
 152                locals, variableNames ?? ArrayUtils.EmptyStrings, visibleParameterCount,
 153                parentScope, declaringModule, definitionName, selfObject, blockParameter,
 154                interpretedFrame
 155            );            
 156        }
 157
 158        [Emitted]
 159        public static RubyScope/*!*/ CreateFileInitializerScope(MutableTuple locals, string[] variableNames, RubyScope/*!*/ parent) {
 160            return new RubyFileInitializerScope(locals, variableNames ?? ArrayUtils.EmptyStrings, parent);
 161        }
 162
 163        [Emitted]
 164        public static RubyBlockScope/*!*/ CreateBlockScope(MutableTuple locals, string[] variableNames, 
 165            BlockParam/*!*/ blockParam, object selfObject, InterpretedFrame interpretedFrame) {
 166
 167            return new RubyBlockScope(locals, variableNames ?? ArrayUtils.EmptyStrings, blockParam, selfObject, interpretedFrame);
 168        }
 169
 170        [Emitted]
 171        public static void TraceMethodCall(RubyMethodScope/*!*/ scope, string fileName, int lineNumber) {
 172            // MRI: 
 173            // Reports DeclaringModule even though an aliased method in a sub-module is called.
 174            // Also works for singleton module-function, which shares DeclaringModule with instance module-function.
 175            RubyModule module = scope.DeclaringModule;
 176            scope.RubyContext.ReportTraceEvent("call", scope, module, scope.DefinitionName, fileName, lineNumber);
 177        }
 178
 179        [Emitted]
 180        public static void TraceMethodReturn(RubyMethodScope/*!*/ scope, string fileName, int lineNumber) {
 181            RubyModule module = scope.DeclaringModule;
 182            scope.RubyContext.ReportTraceEvent("return", scope, module, scope.DefinitionName, fileName, lineNumber);
 183        }
 184
 185        [Emitted]
 186        public static void TraceBlockCall(RubyBlockScope/*!*/ scope, BlockParam/*!*/ block, string fileName, int lineNumber) {
 187            var method = block.Proc.Method;
 188            if (method != null) {
 189                scope.RubyContext.ReportTraceEvent("call", scope, method.DeclaringModule, method.DefinitionName, fileName, lineNumber);
 190            }
 191        }
 192
 193        [Emitted]
 194        public static void TraceBlockReturn(RubyBlockScope/*!*/ scope, BlockParam/*!*/ block, string fileName, int lineNumber) {
 195            var method = block.Proc.Method;
 196            if (method != null) {
 197                scope.RubyContext.ReportTraceEvent("return", scope, method.DeclaringModule, method.DefinitionName, fileName, lineNumber);
 198            }
 199        }
 200
 201        [Emitted]
 202        public static void PrintInteractiveResult(RubyScope/*!*/ scope, MutableString/*!*/ value) {
 203            var writer = scope.RubyContext.DomainManager.SharedIO.OutputStream;
 204            writer.WriteByte((byte)'=');
 205            writer.WriteByte((byte)'>');
 206            writer.WriteByte((byte)' ');
 207            var bytes = value.ToByteArray();
 208            writer.Write(bytes, 0, bytes.Length);
 209            writer.WriteByte((byte)'\r');
 210            writer.WriteByte((byte)'\n');
 211        }
 212
 213        [Emitted]
 214        public static object GetLocalVariable(RubyScope/*!*/ scope, string/*!*/ name) {
 215            return scope.ResolveLocalVariable(name);
 216        }
 217
 218        [Emitted]
 219        public static object SetLocalVariable(object value, RubyScope/*!*/ scope, string/*!*/ name) {
 220            return scope.ResolveAndSetLocalVariable(name, value);
 221        }
 222
 223        [Emitted]
 224        public static VersionHandle/*!*/ GetSelfClassVersionHandle(RubyScope/*!*/ scope) {
 225            return scope.SelfImmediateClass.Version;
 226        }
 227
 228        #endregion
 229
 230        #region Context
 231
 232        [Emitted]
 233        public static RubyContext/*!*/ GetContextFromModule(RubyModule/*!*/ module) {
 234            return module.Context;
 235        }
 236        
 237        [Emitted]
 238        public static RubyContext/*!*/ GetContextFromIRubyObject(IRubyObject/*!*/ obj) {
 239            return obj.ImmediateClass.Context;
 240        }
 241        
 242        [Emitted]
 243        public static RubyContext/*!*/ GetContextFromScope(RubyScope/*!*/ scope) {
 244            return scope.RubyContext;
 245        }
 246
 247        [Emitted]
 248        public static RubyContext/*!*/ GetContextFromMethod(RubyMethod/*!*/ method) {
 249            return method.Info.Context;
 250        }
 251
 252        [Emitted]
 253        public static RubyContext/*!*/ GetContextFromBlockParam(BlockParam/*!*/ block) {
 254            return block.RubyContext;
 255        }
 256
 257        [Emitted]
 258        public static RubyContext/*!*/ GetContextFromProc(Proc/*!*/ proc) {
 259            return proc.LocalScope.RubyContext;
 260        }
 261
 262        [Emitted]
 263        public static RubyScope/*!*/ GetEmptyScope(RubyContext/*!*/ context) {
 264            return context.EmptyScope;
 265        }
 266
 267        [Emitted]
 268        public static Scope/*!*/ GetGlobalScopeFromScope(RubyScope/*!*/ scope) {
 269            return scope.GlobalScope.Scope;
 270        }
 271
 272        #endregion
 273
 274        #region Blocks
 275
 276        [Emitted]
 277        public static Proc InstantiateBlock(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher) {
 278            return (dispatcher.Method != null) ? new Proc(ProcKind.Block, self, scope, dispatcher) : null;
 279        }
 280        [Emitted]
 281        public static Proc InstantiateLambda(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher) {
 282            return (dispatcher.Method != null) ? new Proc(ProcKind.Lambda, self, scope, dispatcher) : null;
 283        }
 284
 285        [Emitted]
 286        public static Proc/*!*/ DefineBlock(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher, object/*!*/ clrMethod) {
 287            // DLR closures should not be used:
 288            Debug.Assert(!(((Delegate)clrMethod).Target is Closure) || ((Closure)((Delegate)clrMethod).Target).Locals == null);
 289            return new Proc(ProcKind.Block, self, scope, dispatcher.SetMethod(clrMethod));
 290        }
 291
 292        [Emitted]
 293        public static Proc/*!*/ DefineLambda(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher, object/*!*/ clrMethod) {
 294            // DLR closures should not be used:
 295            Debug.Assert(!(((Delegate)clrMethod).Target is Closure) || ((Closure)((Delegate)clrMethod).Target).Locals == null);
 296            return new Proc(ProcKind.Lambda, self, scope, dispatcher.SetMethod(clrMethod));
 297        }
 298
 299        /// <summary>
 300        /// Used in a method call with a block to reset proc-kind when the call is retried
 301        /// </summary>
 302        [Emitted]
 303        public static void InitializeBlock(Proc/*!*/ proc) {
 304            Assert.NotNull(proc);
 305            proc.Kind = ProcKind.Block;
 306        }
 307
 308        /// <summary>
 309        /// Implements END block - like if it was a call to at_exit { ... } library method.
 310        /// </summary>
 311        [Emitted]
 312        public static void RegisterShutdownHandler(Proc/*!*/ proc) {
 313            proc.LocalScope.RubyContext.RegisterShutdownHandler(proc);
 314        }
 315
 316        #endregion
 317
 318        #region Yield: TODO: generate
 319
 320        [Emitted] 
 321        public static object Yield0(Proc procArg, object self, BlockParam/*!*/ blockParam) {
 322            object result;
 323            var proc = blockParam.Proc;
 324            try {
 325                result = proc.Dispatcher.Invoke(blockParam, self, procArg);
 326            } catch(EvalUnwinder evalUnwinder) {
 327                result = blockParam.GetUnwinderResult(evalUnwinder);
 328            }
 329
 330            return result;
 331        }
 332
 333        [Emitted]
 334        public static object Yield1(object arg1, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 335            object result;
 336            var proc = blockParam.Proc;
 337            try {
 338                result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1);
 339            } catch (EvalUnwinder evalUnwinder) {
 340                result = blockParam.GetUnwinderResult(evalUnwinder);
 341            }
 342
 343            return result;
 344        }
 345
 346        // YieldNoAutoSplat1 uses InvokeNoAutoSplat instead of Invoke (used by Call1)
 347        internal static object YieldNoAutoSplat1(object arg1, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 348            object result;
 349            var proc = blockParam.Proc;
 350            try {
 351                result = proc.Dispatcher.InvokeNoAutoSplat(blockParam, self, procArg, arg1);
 352            } catch (EvalUnwinder evalUnwinder) {
 353                result = blockParam.GetUnwinderResult(evalUnwinder);
 354            }
 355
 356            return result;
 357        }
 358
 359        [Emitted]
 360        public static object Yield2(object arg1, object arg2, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 361            object result;
 362            var proc = blockParam.Proc;
 363            try {
 364                result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2);
 365            } catch (EvalUnwinder evalUnwinder) {
 366                result = blockParam.GetUnwinderResult(evalUnwinder);
 367            }
 368
 369            return result;
 370        }
 371
 372        [Emitted]
 373        public static object Yield3(object arg1, object arg2, object arg3, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 374            object result;
 375            var proc = blockParam.Proc;
 376            try {
 377                result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2, arg3);
 378            } catch (EvalUnwinder evalUnwinder) {
 379                result = blockParam.GetUnwinderResult(evalUnwinder);
 380            }
 381
 382            return result;
 383        }
 384
 385        [Emitted]
 386        public static object Yield4(object arg1, object arg2, object arg3, object arg4, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 387            object result;
 388            var proc = blockParam.Proc;
 389            try {
 390                result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2, arg3, arg4);
 391            } catch (EvalUnwinder evalUnwinder) {
 392                result = blockParam.GetUnwinderResult(evalUnwinder);
 393            }
 394
 395            return result;
 396        }
 397
 398        [Emitted]
 399        public static object YieldN(object[]/*!*/ args, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 400            Debug.Assert(args.Length > BlockDispatcher.MaxBlockArity);
 401
 402            object result;
 403            var proc = blockParam.Proc;
 404            try {
 405                result = proc.Dispatcher.Invoke(blockParam, self, procArg, args);
 406            } catch (EvalUnwinder evalUnwinder) {
 407                result = blockParam.GetUnwinderResult(evalUnwinder);
 408            }
 409
 410            return result;
 411        }
 412
 413        internal static object Yield(object[]/*!*/ args, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 414            switch (args.Length) {
 415                case 0: return RubyOps.Yield0(procArg, self, blockParam);
 416                case 1: return RubyOps.Yield1(args[0], procArg, self, blockParam);
 417                case 2: return RubyOps.Yield2(args[0], args[1], procArg, self, blockParam);
 418                case 3: return RubyOps.Yield3(args[0], args[1], args[2], procArg, self, blockParam);
 419                case 4: return RubyOps.Yield4(args[0], args[1], args[2], args[3], procArg, self, blockParam);
 420                default: return RubyOps.YieldN(args, procArg, self, blockParam); 
 421            }
 422        }
 423
 424        [Emitted]
 425        public static object YieldSplat0(IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 426            object result;
 427            var proc = blockParam.Proc;
 428            try {
 429                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, splattee);
 430            } catch (EvalUnwinder evalUnwinder) {
 431                result = blockParam.GetUnwinderResult(evalUnwinder);
 432            }
 433
 434            return result;
 435        }
 436
 437        [Emitted]
 438        public static object YieldSplat1(object arg1, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 439            object result;
 440            var proc = blockParam.Proc;
 441            try {
 442                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, splattee);
 443            } catch (EvalUnwinder evalUnwinder) {
 444                result = blockParam.GetUnwinderResult(evalUnwinder);
 445            }
 446
 447            return result;
 448        }
 449
 450        [Emitted]
 451        public static object YieldSplat2(object arg1, object arg2, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 452            object result;
 453            var proc = blockParam.Proc;
 454            try {
 455                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, splattee);
 456            } catch (EvalUnwinder evalUnwinder) {
 457                result = blockParam.GetUnwinderResult(evalUnwinder);
 458            }
 459
 460            return result;
 461        }
 462
 463        [Emitted]
 464        public static object YieldSplat3(object arg1, object arg2, object arg3, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 465            object result;
 466            var proc = blockParam.Proc;
 467            try {
 468                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, arg3, splattee);
 469            } catch (EvalUnwinder evalUnwinder) {
 470                result = blockParam.GetUnwinderResult(evalUnwinder);
 471            }
 472
 473            return result;
 474        }
 475
 476        [Emitted]
 477        public static object YieldSplat4(object arg1, object arg2, object arg3, object arg4, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 478            object result;
 479            var proc = blockParam.Proc;
 480            try {
 481                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, arg3, arg4, splattee);
 482            } catch (EvalUnwinder evalUnwinder) {
 483                result = blockParam.GetUnwinderResult(evalUnwinder);
 484            }
 485
 486            return result;
 487        }
 488
 489        [Emitted]
 490        public static object YieldSplatN(object[]/*!*/ args, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 491            object result;
 492            var proc = blockParam.Proc;
 493            try {
 494                result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, args, splattee);
 495            } catch (EvalUnwinder evalUnwinder) {
 496                result = blockParam.GetUnwinderResult(evalUnwinder);
 497            }
 498
 499            return result;
 500        }
 501
 502        [Emitted]
 503        public static object YieldSplatNRhs(object[]/*!*/ args, IList/*!*/ splattee, object rhs, Proc procArg, object self, BlockParam/*!*/ blockParam) {
 504            object result;
 505            var proc = blockParam.Proc;
 506            try {
 507                result = proc.Dispatcher.InvokeSplatRhs(blockParam, self, procArg, args, splattee, rhs);
 508            } catch (EvalUnwinder evalUnwinder) {
 509                result = blockParam.GetUnwinderResult(evalUnwinder);
 510            }
 511
 512            return result;
 513        }
 514
 515        #endregion
 516
 517        #region Methods
 518
 519        [Emitted] // MethodDeclaration:
 520        public static object DefineMethod(object target, RubyScope/*!*/ scope, RubyMethodBody/*!*/ body) {
 521            Assert.NotNull(body, scope);
 522
 523            RubyModule instanceOwner, singletonOwner;
 524            RubyMemberFlags instanceFlags, singletonFlags;
 525            bool moduleFunction = false;
 526
 527            if (body.HasTarget) {
 528                if (!RubyUtils.CanDefineSingletonMethod(target)) {
 529                    throw RubyExceptions.CreateTypeError("can't define singleton method for literals");
 530                }
 531
 532                instanceOwner = null;
 533                instanceFlags = RubyMemberFlags.Invalid;
 534                singletonOwner = scope.RubyContext.GetOrCreateSingletonClass(target);
 535                singletonFlags = RubyMemberFlags.Public;
 536            } else {
 537                var attributesScope = scope.GetMethodAttributesDefinitionScope();
 538                if ((attributesScope.MethodAttributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction) {
 539                    // Singleton module-function's scope points to the instance method's RubyMemberInfo.
 540                    // This affects:
 541                    // 1) super call
 542                    //    Super call is looking for Method.DeclaringModule while searching MRO, which would fail if the singleton module-function
 543                    //    was in MRO. Since module-function can only be used on module the singleton method could only be on module's singleton.
 544                    //    Module's singleton is never part of MRO so we are safe.
 545                    // 2) trace
 546                    //    Method call trace reports non-singleton module.
 547
 548                    // MRI 1.8: instance method owner is self -> it is possible (via define_method) to define m.f. on a class (bug)
 549                    // MRI 1.9: instance method owner GetMethodDefinitionOwner
 550                    // MRI allows to define m.f. on classes but then doesn't work correctly with it.
 551                    instanceOwner = scope.GetMethodDefinitionOwner();
 552                    if (instanceOwner.IsClass) {
 553                        throw RubyExceptions.CreateTypeError("A module function cannot be defined on a class.");
 554                    }
 555
 556                    instanceFlags = RubyMemberFlags.Private;
 557                    singletonOwner = instanceOwner.GetOrCreateSingletonClass();
 558                    singletonFlags = RubyMemberFlags.Public;
 559                    moduleFunction = true;
 560                } else {
 561                    instanceOwner = scope.GetMethodDefinitionOwner();
 562                    instanceFlags = (RubyMemberFlags)RubyUtils.GetSpecialMethodVisibility(attributesScope.Visibility, body.Name);
 563                    singletonOwner = null;
 564                    singletonFlags = RubyMemberFlags.Invalid;
 565                }
 566            }
 567            
 568            RubyMethodInfo instanceMethod = null, singletonMethod = null;
 569
 570            if (instanceOwner != null) {
 571                SetMethod(scope.RubyContext, instanceMethod =
 572                    new RubyMethodInfo(body, scope, instanceOwner, instanceFlags)
 573                );
 574            }
 575
 576            if (singletonOwner != null) {
 577                SetMethod(scope.RubyContext, singletonMethod =
 578                    new RubyMethodInfo(body, scope, singletonOwner, singletonFlags)
 579                );
 580            }
 581
 582            // the method's scope saves the result => singleton module-function uses instance-method
 583            var method = instanceMethod ?? singletonMethod;
 584
 585            method.DeclaringModule.MethodAdded(body.Name);
 586
 587            if (moduleFunction) {
 588                Debug.Assert(!method.DeclaringModule.IsClass);
 589                method.DeclaringModule.GetOrCreateSingletonClass().MethodAdded(body.Name);
 590            }
 591
 592            return null;
 593        }
 594
 595        private static void SetMethod(RubyContext/*!*/ callerContext, RubyMethodInfo/*!*/ method) {
 596            var owner = method.DeclaringModule;
 597
 598            // Do not trigger the add-method event just yet, we need to assign the result into closure before executing any user code.
 599            // If the method being defined is "method_added" itself, we would call that method before the info gets assigned to the closure.
 600            owner.SetMethodNoEvent(callerContext, method.DefinitionName, method);
 601
 602            // expose RubyMethod in the scope (the method is bound to the main singleton instance):
 603            if (owner.GlobalScope != null) {
 604                RubyOps.ScopeSetMember(
 605                    owner.GlobalScope.Scope,
 606                    method.DefinitionName,
 607                    new RubyMethod(owner.GlobalScope.MainObject, method, method.DefinitionName)
 608                );
 609            }
 610        }
 611
 612        [Emitted] // AliasStatement:
 613        public static void AliasMethod(RubyScope/*!*/ scope, string/*!*/ newName, string/*!*/ oldName) {
 614            scope.GetMethodDefinitionOwner().AddMethodAlias(newName, oldName);
 615        }
 616
 617        [Emitted] // UndefineMethod:
 618        public static void UndefineMethod(RubyScope/*!*/ scope, string/*!*/ name) {
 619            RubyModule owner = scope.GetMethodDefinitionOwner();
 620
 621            if (!owner.ResolveMethod(name, VisibilityContext.AllVisible).Found) {
 622                throw RubyExceptions.CreateUndefinedMethodError(owner, name);
 623            }
 624            owner.UndefineMethod(name);
 625        }
 626
 627        #endregion
 628
 629        #region Modules
 630
 631        [Emitted]
 632        public static RubyModule/*!*/ DefineGlobalModule(RubyScope/*!*/ scope, string/*!*/ name) {
 633            return DefineModule(scope, scope.Top.TopModuleOrObject, name);
 634        }
 635
 636        [Emitted]
 637        public static RubyModule/*!*/ DefineNestedModule(RubyScope/*!*/ scope, string/*!*/ name) {
 638            return DefineModule(scope, scope.GetInnerMostModuleForConstantLookup(), name);
 639        }
 640
 641        [Emitted]
 642        public static RubyModule/*!*/ DefineModule(RubyScope/*!*/ scope, object target, string/*!*/ name) {
 643            return DefineModule(scope, RubyUtils.GetModuleFromObject(scope, target), name);
 644        }
 645
 646        // thread-safe:
 647        private static RubyModule/*!*/ DefineModule(RubyScope/*!*/ scope, RubyModule/*!*/ owner, string/*!*/ name) {
 648            Assert.NotNull(scope, owner);
 649
 650            ConstantStorage existing;
 651            if (owner.TryGetConstant(scope.GlobalScope, name, out existing)) {
 652                RubyModule module = existing.Value as RubyModule;
 653                if (module == null || module.IsClass) {
 654                    throw RubyExceptions.CreateTypeError(String.Format("{0} is not a module", name));
 655                }
 656                return module;
 657            } else {
 658                // create class/module object:
 659                return owner.Context.DefineModule(owner, name);
 660            }
 661        }
 662
 663        #endregion
 664
 665        #region Classes
 666
 667        [Emitted]
 668        public static RubyClass/*!*/ DefineSingletonClass(RubyScope/*!*/ scope, object obj) {
 669            if (!RubyUtils.HasSingletonClass(obj)) {
 670                throw RubyExceptions.CreateTypeError(String.Format("no virtual class for {0}", scope.RubyContext.GetClassOf(obj).Name));
 671            }
 672            return scope.RubyContext.GetOrCreateSingletonClass(obj);
 673        }
 674
 675        [Emitted] 
 676        public static RubyModule/*!*/ DefineGlobalClass(RubyScope/*!*/ scope, string/*!*/ name, object superClassObject) {
 677            return DefineClass(scope, scope.Top.TopModuleOrObject, name, superClassObject);
 678        }
 679
 680        [Emitted]
 681        public static RubyModule/*!*/ DefineNestedClass(RubyScope/*!*/ scope, string/*!*/ name, object superClassObject) {
 682            return DefineClass(scope, scope.GetInnerMostModuleForConstantLookup(), name, superClassObject);
 683        }
 684
 685        [Emitted]
 686        public static RubyModule/*!*/ DefineClass(RubyScope/*!*/ scope, object target, string/*!*/ name, object superClassObject) {
 687            return DefineClass(scope, RubyUtils.GetModuleFromObject(scope, target), name, superClassObject);
 688        }
 689
 690        // thread-safe:
 691        private static RubyClass/*!*/ DefineClass(RubyScope/*!*/ scope, RubyModule/*!*/ owner, string/*!*/ name, object superClassObject) {
 692            Assert.NotNull(owner);
 693            RubyClass superClass = ToSuperClass(owner.Context, superClassObject);
 694
 695            ConstantStorage existing;
 696            if (owner.IsObjectClass
 697                ? owner.TryResolveConstant(scope.GlobalScope, name, out existing)
 698                : owner.TryGetConstant(scope.GlobalScope, name, out existing)) {
 699
 700                RubyClass cls = existing.Value as RubyClass;
 701                if (cls == null || !cls.IsClass) {
 702                    throw RubyExceptions.CreateTypeError("{0} is not a class", name);
 703                }
 704
 705                if (superClassObject != null && !ReferenceEquals(cls.SuperClass, superClass)) {
 706                    throw RubyExceptions.CreateTypeError("superclass mismatch for class {0}", name);
 707                }
 708                return cls;
 709            } else {
 710                return owner.Context.DefineClass(owner, name, superClass, null);
 711            }
 712        }
 713
 714        private static RubyClass/*!*/ ToSuperClass(RubyContext/*!*/ ec, object superClassObject) {
 715            if (superClassObject != null) {
 716                RubyClass superClass = superClassObject as RubyClass;
 717                if (superClass == null) {
 718                    throw RubyExceptions.CreateTypeError("superclass must be a Class ({0} given)", ec.GetClassOf(superClassObject).Name);
 719                }
 720
 721                if (superClass.IsSingletonClass) {
 722                    throw RubyExceptions.CreateTypeError("can't make subclass of virtual class");
 723                }
 724
 725                return superClass;
 726            } else {
 727                return ec.ObjectClass;
 728            }
 729        }
 730
 731        #endregion
 732
 733        #region Constants
 734
 735        /// <summary>
 736        /// A
 737        /// ::A
 738        /// </summary>
 739        [Emitted]
 740        public static object GetUnqualifiedConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name, bool isGlobal) {
 741            object result = null;
 742            RubyModule missingConstantOwner;
 743            var context = scope.RubyContext;
 744            using (context.ClassHierarchyLocker()) {
 745                // Thread safety:
 746                // Another thread could have already updated the value, so the site version might be the same as CAV.
 747                // We do the lookup anyways since it is no-op and this only happens rarely.
 748                //
 749                // An important invariant holds here: in any time after initialized for the first time the Value field contains a valid value.
 750                // Threads can read an older value (the previous version) but that is still correct since we don't guarantee immediate
 751                // propagation of the constant write to all readers.
 752                // 
 753                // if (site.Version = CAV) {
 754                //   <- another thread could increment CAV here - we may return old or new value (both are ok)
 755                //   value = site.Value;
 756                // } else {
 757                //   <- another thread could get here as well and update the site before we get to update it.
 758                //   GetConstant(...)
 759                // }
 760
 761                // Constants might be updated during constant resolution due to autoload. 
 762                // Any such updates need to invalidate the cache hence we need to capture the version before resolving the constant.
 763                int newVersion = context.ConstantAccessVersion;
 764
 765                ConstantStorage storage;
 766                if (!isGlobal) {
 767                    missingConstantOwner = scope.TryResolveConstantNoLock(scope.GlobalScope, name, out storage);
 768                } else if (context.ObjectClass.TryResolveConstantNoLock(scope.GlobalScope, name, out storage)) {
 769                    missingConstantOwner = null;
 770                } else {
 771                    missingConstantOwner = context.ObjectClass;
 772                }
 773
 774                object newCacheValue;
 775                if (missingConstantOwner == null) {
 776                    if (storage.WeakValue != null) {
 777                        result = storage.Value;
 778                        newCacheValue = storage.WeakValue;
 779                    } else {
 780                        result = newCacheValue = storage.Value;
 781                    }
 782                } else {
 783                    newCacheValue = ConstantSiteCache.WeakMissingConstant;
 784                }
 785
 786                cache.Update(newCacheValue, newVersion);
 787            }
 788
 789            if (missingConstantOwner != null) {
 790                result = missingConstantOwner.ConstantMissing(name);
 791            }
 792
 793            return result;
 794        }
 795
 796        /// <summary>
 797        /// A1::..::AN
 798        /// ::A1::..::AN
 799        /// </summary>
 800        [Emitted]
 801        public static object GetQualifiedConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/[]/*!*/ qualifiedName, bool isGlobal) {
 802            var globalScope = scope.GlobalScope;
 803            var context = globalScope.Context;
 804
 805            using (context.ClassHierarchyLocker()) {
 806                int newVersion = context.ConstantAccessVersion;
 807                
 808                ConstantStorage storage;
 809                bool anyMissing;
 810                RubyModule topModule = isGlobal ? context.ObjectClass : null;
 811                object result = ResolveQualifiedConstant(scope, qualifiedName, topModule, true, out storage, out anyMissing);
 812
 813                // cache result only if no constant was missing:
 814                if (!anyMissing) {
 815                    Debug.Assert(result == storage.Value);
 816                    cache.Update(storage.WeakValue ?? result, newVersion);
 817                }
 818
 819                return result;
 820            }
 821        }
 822
 823        /// <summary>
 824        /// {expr}::A1::..::AN
 825        /// </summary>
 826        [Emitted]
 827        public static object GetExpressionQualifiedConstant(object target, RubyScope/*!*/ scope, ExpressionQualifiedConstantSiteCache/*!*/ cache,
 828            string/*!*/[]/*!*/ qualifiedName) {
 829            RubyModule module = target as RubyModule;
 830            if (module == null) {
 831                throw RubyUtils.CreateNotModuleException(scope, target);
 832            }
 833
 834            var condition = cache.Condition;
 835            RubyContext context = module.Context;
 836
 837            // Note that the module can be bound to another runtime:
 838            if (module.Id == condition.ModuleId && context.ConstantAccessVersion == condition.Version) {
 839                object value = cache.Value;
 840                if (value.GetType() == typeof(WeakReference)) {
 841                    return ((WeakReference)value).Target;
 842                } else {
 843                    return value;
 844                }
 845            }
 846
 847            using (context.ClassHierarchyLocker()) {
 848                int newVersion = context.ConstantAccessVersion;
 849                
 850                ConstantStorage storage;
 851                bool anyMissing;
 852                object result = ResolveQualifiedConstant(scope, qualifiedName, module, true, out storage, out anyMissing);
 853
 854                // cache result only if no constant was missing:
 855                if (!anyMissing) {
 856                    Debug.Assert(result == storage.Value);
 857                    cache.Update(storage.WeakValue ?? result, newVersion, module);
 858                }
 859
 860                return result;
 861            }
 862        }
 863
 864        /// <summary>
 865        /// defined? A
 866        /// </summary>
 867        [Emitted]
 868        public static bool IsDefinedUnqualifiedConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache, string/*!*/ name) {
 869            var context = scope.RubyContext;
 870            using (context.ClassHierarchyLocker()) {
 871                int newVersion = context.ConstantAccessVersion;
 872                
 873                ConstantStorage storage;
 874                bool exists = scope.TryResolveConstantNoLock(null, name, out storage) == null;
 875                cache.Update(exists, newVersion);
 876                return exists;
 877            }
 878        }
 879
 880        /// <summary>
 881        /// defined? ::A
 882        /// </summary>
 883        [Emitted]
 884        public static bool IsDefinedGlobalConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache, string/*!*/ name) {
 885            var context = scope.RubyContext;
 886            using (context.ClassHierarchyLocker()) {
 887                int newVersion = context.ConstantAccessVersion;
 888
 889                ConstantStorage storage;
 890                bool exists = context.ObjectClass.TryResolveConstantNoLock(null, name, out storage);
 891                cache.Update(exists, newVersion);
 892                return exists;
 893            }
 894        }
 895
 896        /// <summary>
 897        /// defined? A1::..::AN
 898        /// defined? ::A1::..::AN
 899        /// </summary>
 900        [Emitted]
 901        public static bool IsDefinedQualifiedConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache,
 902            string/*!*/[]/*!*/ qualifiedName, bool isGlobal) {
 903
 904            var context = scope.RubyContext;
 905            using (context.ClassHierarchyLocker()) {
 906                int newVersion = context.ConstantAccessVersion;
 907
 908                ConstantStorage storage;
 909                bool anyMissing;
 910                RubyModule topModule = isGlobal ? context.ObjectClass : null;
 911                RubyModule owner;
 912                try {
 913                    owner = ResolveQualifiedConstant(scope, qualifiedName, topModule, false, out storage, out anyMissing) as RubyModule;
 914                } catch {
 915                    // autoload can raise an exception
 916                    scope.RubyContext.SetCurrentException(null);
 917                    return false;
 918                }
 919                
 920                // Note that the owner could be another runtime's module:
 921                bool exists = owner != null && owner.TryResolveConstant(context, null, qualifiedName[qualifiedName.Length - 1], out storage);
 922                
 923                // cache result only if no constant was missing:
 924                if (!anyMissing) {
 925                    cache.Update(exists, newVersion);
 926                }
 927
 928                return exists;
 929            }
 930        }
 931
 932        /// <summary>
 933        /// defined? {expr}::A
 934        /// defined? {expr}::A1::..::AN
 935        /// </summary>
 936        [Emitted]
 937        public static bool IsDefinedExpressionQualifiedConstant(object target, RubyScope/*!*/ scope,
 938            ExpressionQualifiedIsDefinedConstantSiteCache/*!*/ cache, string/*!*/[]/*!*/ qualifiedName) {
 939
 940            RubyModule module = target as RubyModule;
 941            if (module == null) {
 942                return false;
 943            }
 944
 945            var condition = cache.Condition;
 946            RubyContext context = module.Context;
 947
 948            // Note that the module can be bound to another runtime:
 949            if (module.Id == condition.ModuleId && context.ConstantAccessVersion == condition.Version) {
 950                return cache.Value;
 951            }
 952
 953            using (context.ClassHierarchyLocker()) {
 954                int newVersion = context.ConstantAccessVersion;
 955
 956                ConstantStorage storage;
 957                bool exists;
 958                if (qualifiedName.Length == 1) {
 959                    // Note that the owner could be another runtime's module:
 960                    exists = module.TryResolveConstant(context, null, qualifiedName[0], out storage);
 961                } else {
 962                    bool anyMissing;
 963                    RubyModule owner;
 964                    try {
 965                        owner = ResolveQualifiedConstant(scope, qualifiedName, module, false, out storage, out anyMissing) as RubyModule;
 966                    } catch {
 967                        // autoload can raise an exception:
 968                        return false;
 969                    }
 970
 971                    // Note that the owner could be another runtime's module:
 972                    exists = owner != null && owner.TryResolveConstant(context, null, qualifiedName[qualifiedName.Length - 1], out storage);
 973
 974                    // cache result only if no constant was missing:
 975                    if (anyMissing) {
 976                        return exists;
 977                    } 
 978                }
 979
 980                cache.Update(exists, newVersion, module);
 981                return exists;
 982            }
 983        }
 984
 985        private static object ResolveQualifiedConstant(RubyScope/*!*/ scope, string/*!*/[]/*!*/ qualifiedName, RubyModule topModule, bool isGet,
 986            out ConstantStorage storage, out bool anyMissing) {
 987
 988            Debug.Assert(qualifiedName.Length >= 2 || qualifiedName.Length == 1 && isGet);
 989            RubyContext context = scope.RubyContext;
 990            context.RequiresClassHierarchyLock();
 991
 992            RubyModule missingConstantOwner;
 993            RubyGlobalScope globalScope = scope.GlobalScope;
 994            int nameCount = (isGet) ? qualifiedName.Length : qualifiedName.Length - 1;
 995
 996            string name = qualifiedName[0];
 997            if (topModule == null) {
 998                missingConstantOwner = scope.TryResolveConstantNoLock(globalScope, name, out storage);
 999            } else if (topModule.TryResolveConstant(context, globalScope, name, out storage)) {
1000                missingConstantOwner = null;
1001            } else {
1002                missingConstantOwner = topModule;
1003            }
1004
1005            object result;
1006            if (missingConstantOwner == null) {
1007                result = storage.Value;
1008                anyMissing = false;
1009            } else {
1010                anyMissing = true;
1011                using (context.ClassHierarchyUnlocker()) {
1012                    result = missingConstantOwner.ConstantMissing(name);
1013                }
1014            }
1015
1016            for (int i = 1; i < nameCount; i++) {
1017                RubyModule owner = RubyUtils.GetModuleFromObject(scope, result);
1018                // Note that the owner could be another runtime's module:
1019                name = qualifiedName[i];
1020                if (owner.TryResolveConstant(context, globalScope, name, out storage)) {
1021                    
1022                    // Constant write updates constant version in a single runtime only. 
1023                    // Therefore if the chain mixes modules from different runtimes we cannot cache the result.
1024                    if (owner.Context != context) {
1025                        anyMissing = true;
1026                    }
1027                    
1028                    result = storage.Value;
1029                } else {
1030                    anyMissing = true;
1031                    using (context.ClassHierarchyUnlocker()) {
1032                        result = owner.ConstantMissing(name);
1033                    }
1034                }
1035            }
1036
1037            return result;
1038        }
1039
1040        [Emitted]
1041        public static object GetMissingConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name) {
1042            return scope.GetInnerMostModuleForConstantLookup().ConstantMissing(name);
1043        }
1044
1045        [Emitted]
1046        public static object GetGlobalMissingConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name) {
1047            return scope.RubyContext.ObjectClass.ConstantMissing(name);
1048        }
1049
1050
1051        [Emitted] // ConstantVariable:
1052        public static object SetGlobalConstant(object value, RubyScope/*!*/ scope, string/*!*/ name) {
1053            RubyUtils.SetConstant(scope.RubyContext.ObjectClass, name, value);
1054            return value;
1055        }
1056
1057        [Emitted] // ConstantVariable:
1058        public static object SetUnqualifiedConstant(object value, RubyScope/*!*/ scope, string/*!*/ name) {
1059            RubyUtils.SetConstant(scope.GetInnerMostModuleForConstantLookup(), name, value);
1060            return value;
1061        }
1062
1063        [Emitted] // ConstantVariable:
1064        public static object SetQualifiedConstant(object value, object target, RubyScope/*!*/ scope, string/*!*/ name) {
1065            RubyUtils.SetConstant(RubyUtils.GetModuleFromObject(scope, target), name, value);
1066            return value;
1067        }
1068
1069        #endregion
1070
1071        // MakeArray*
1072        public const int OptimizedOpCallParamCount = 5;
1073        
1074        #region MakeArray
1075        
1076        [Emitted]
1077        public static RubyArray/*!*/ MakeArray0() {
1078            return new RubyArray(0);
1079        }
1080
1081        [Emitted]
1082        public static RubyArray/*!*/ MakeArray1(object item1) {
1083            RubyArray result = new RubyArray(1);
1084            result.Add(item1);
1085            return result;
1086        }
1087
1088        [Emitted]
1089        public static RubyArray/*!*/ MakeArray2(object item1, object item2) {
1090            RubyArray result = new RubyArray(2);
1091            result.Add(item1);
1092            result.Add(item2);
1093            return result;
1094        }
1095
1096        [Emitted]
1097        public static RubyArray/*!*/ MakeArray3(object item1, object item2, object item3) {
1098            RubyArray result = new RubyArray(3);
1099            result.Add(item1);
1100            result.Add(item2);
1101            result.Add(item3);
1102            return result;
1103        }
1104
1105        [Emitted]
1106        public static RubyArray/*!*/ MakeArray4(object item1, object item2, object item3, object item4) {
1107            RubyArray result = new RubyArray(4);
1108            result.Add(item1);
1109            result.Add(item2);
1110            result.Add(item3);
1111            result.Add(item4);
1112            return result;
1113        }
1114
1115        [Emitted]
1116        public static RubyArray/*!*/ MakeArray5(object item1, object item2, object item3, object item4, object item5) {
1117            RubyArray result = new RubyArray(5);
1118            result.Add(item1);
1119            result.Add(item2);
1120            result.Add(item3);
1121            result.Add(item4);
1122            result.Add(item5);
1123            return result;
1124        }
1125
1126        [Emitted]
1127        public static RubyArray/*!*/ MakeArrayN(object[]/*!*/ items) {
1128            Debug.Assert(items != null);
1129            var array = new RubyArray(items.Length);
1130            array.AddVector(items, 0, items.Length);
1131            return array;
1132        }
1133
1134        #endregion
1135
1136        #region MakeHash
1137
1138        [Emitted]
1139        public static Hash/*!*/ MakeHash0(RubyScope/*!*/ scope) {
1140            return new Hash(scope.RubyContext.EqualityComparer, 0);
1141        }
1142        
1143        [Emitted]
1144        public static Hash/*!*/ MakeHash(RubyScope/*!*/ scope, object[]/*!*/ items) {
1145            return RubyUtils.SetHashElements(scope.RubyContext, new Hash(scope.RubyContext.EqualityComparer, items.Length / 2), items);
1146        }
1147
1148        #endregion
1149
1150        #region Array
1151
1152        [Emitted]
1153        public static RubyArray/*!*/ AddRange(RubyArray/*!*/ array, IList/*!*/ list) {
1154            return array.AddRange(list);
1155        }
1156
1157        [Emitted] // method call:
1158        public static RubyArray/*!*/ AddSubRange(RubyArray/*!*/ result, IList/*!*/ array, int start, int count) {
1159            return result.AddRange(array, start, count);
1160        }
1161
1162        [Emitted]
1163        public static RubyArray/*!*/ AddItem(RubyArray/*!*/ array, object item) {
1164            array.Add(item);
1165            return array;
1166        }
1167
1168        [Emitted]
1169        public static IList/*!*/ SplatAppend(IList/*!*/ array, IList/*!*/ list) {
1170            Utils.AddRange(array, list);
1171            return array;
1172        }
1173
1174        [Emitted]
1175        public static object Splat(IList/*!*/ list) {
1176            if (list.Count <= 1) {
1177                return (list.Count > 0) ? list[0] : null;
1178            }
1179
1180            return list;
1181        }
1182
1183        // 1.8 behavior
1184        [Emitted]
1185        public static object SplatPair(object value, IList/*!*/ list) {
1186            if (list.Count == 0) {
1187                return value;
1188            }
1189
1190            RubyArray result = new RubyArray(list.Count + 1);
1191            result.Add(value);
1192            result.AddRange(list);
1193            return result;
1194        }
1195
1196        [Emitted]
1197        public static IList/*!*/ Unsplat(object splattee) {
1198            var list = splattee as IList;
1199            if (list == null) {
1200                list = new RubyArray(1);
1201                list.Add(splattee);
1202            }
1203            return list;
1204        }
1205
1206        // CaseExpression
1207        [Emitted]
1208        public static bool ExistsUnsplatCompare(CallSite<Func<CallSite, object, object, object>>/*!*/ comparisonSite, object splattee, object value) {
1209            var list = splattee as IList;
1210            if (list != null) {
1211                for (int i = 0; i < list.Count; i++) {
1212                    if (IsTrue(comparisonSite.Target(comparisonSite, list[i], value))) {
1213                        return true;
1214                    }
1215                }
1216                return false;
1217            } else {
1218                return IsTrue(comparisonSite.Target(comparisonSite, splattee, value)); 
1219            }
1220        }
1221
1222        // CaseExpression
1223        [Emitted]
1224        public static bool ExistsUnsplat(object splattee) {
1225            var list = splattee as IList;
1226            if (list != null) {
1227                for (int i = 0; i < list.Count; i++) {
1228                    if (IsTrue(list[i])) {
1229                        return true;
1230                    }
1231                }
1232                return false;
1233            } else {
1234                return IsTrue(splattee);
1235            }
1236        }
1237
1238        [Emitted] // parallel assignment:
1239        public static object GetArrayItem(IList/*!*/ array, int index) {
1240            Debug.Assert(index >= 0);
1241            return index < array.Count ? array[index] : null;
1242        }
1243
1244        [Emitted] // parallel assignment:
1245        public static object GetTrailingArrayItem(IList/*!*/ array, int index, int explicitCount) {
1246            Debug.Assert(index >= 0);
1247            int i = Math.Max(array.Count, explicitCount) - index;
1248            return i >= 0 ? array[i] : null;
1249        }
1250
1251        [Emitted] // parallel assignment:
1252        public static RubyArray/*!*/ GetArrayRange(IList/*!*/ array, int startIndex, int explicitCount) {
1253            int size = array.Count - explicitCount;
1254            if (size > 0) {
1255                RubyArray result = new RubyArray(size);
1256                for (int i = 0; i < size; i++) {
1257                    result.Add(array[startIndex + i]);
1258                }
1259                return result;
1260            } else {
1261                return new RubyArray();
1262            }
1263        }
1264
1265        #endregion
1266
1267        #region CLR Vectors (factories mimic Ruby Array factories)
1268
1269        [Emitted, RubyConstructor]
1270        public static object/*!*/ CreateVector<TElement>(
1271            ConversionStorage<TElement>/*!*/ elementConversion, 
1272            ConversionStorage<Union<IList, int>>/*!*/ toAryToInt, 
1273            BlockParam block, RubyClass/*!*/ self, [NotNull]object/*!*/ arrayOrSize) {
1274
1275            Debug.Assert(typeof(TElement) == self.GetUnderlyingSystemType().GetElementType());
1276
1277            var site = toAryToInt.GetSite(CompositeConversionAction.Make(self.Context, CompositeConversion.ToAryToInt));
1278            var union = site.Target(site, arrayOrSize);
1279
1280            if (union.First != null) {
1281                // block ignored
1282                return CreateVectorInternal(elementConversion, union.First);
1283            } else if (block != null) {
1284                return PopulateVector(elementConversion, CreateVectorInternal<TElement>(union.Second), block);
1285            } else {
1286                return CreateVectorInternal<TElement>(union.Second);
1287            }
1288        }
1289
1290        [Emitted, RubyConstructor]
1291        public static Array/*!*/ CreateVectorWithValues<TElement>(ConversionStorage<TElement>/*!*/ elementConversion,
1292            RubyClass/*!*/ self, [DefaultProtocol]int size, [DefaultProtocol]TElement value) {
1293            Debug.Assert(typeof(TElement) == self.GetUnderlyingSystemType().GetElementType());
1294
1295            TElement[] result = CreateVectorInternal<TElement>(size);
1296            for (int i = 0; i < result.Length; i++) {
1297                result[i] = value;
1298            }
1299            return result;
1300        }
1301
1302        private static TElement[]/*!*/ CreateVectorInternal<TElement>(int size) {
1303            if (size < 0) {
1304                throw RubyExceptions.CreateArgumentError("negative array size");
1305            }
1306
1307            return new TElement[size];
1308        }
1309
1310        private static Array/*!*/ CreateVectorInternal<TElement>(ConversionStorage<TElement>/*!*/ elementConversion, IList/*!*/ list) {
1311            var site = elementConversion.GetDefaultConversionSite();
1312
1313            var result = new TElement[list.Count];
1314            for (int i = 0; i < result.Length; i++) {
1315                object item = list[i];
1316                result[i] = (item is TElement) ? (TElement)item : site.Target(site, item);
1317            }
1318
1319            return result;
1320        }
1321
1322        private static object PopulateVector<TElement>(ConversionStorage<TElement>/*!*/ elementConversion, TElement[]/*!*/ array, BlockParam/*!*/ block) {
1323            var site = elementConversion.GetDefaultConversionSite();
1324
1325            for (int i = 0; i < array.Length; i++) {
1326                object item;
1327                if (block.Yield(i, out item)) {
1328                    return item;
1329                }
1330                array[i] = site.Target(site, item);
1331            }
1332            return array;
1333        }
1334
1335        #endregion
1336
1337        #region Global Variables
1338
1339        [Emitted]
1340        public static object GetGlobalVariable(RubyScope/*!*/ scope, string/*!*/ name) {
1341            object value;
1342            // no error reported if the variable doesn't exist:
1343            scope.RubyContext.TryGetGlobalVariable(scope, name, out value);
1344            return value;
1345        }
1346
1347        [Emitted]
1348        public static bool IsDefinedGlobalVariable(RubyScope/*!*/ scope, string/*!*/ name) {
1349            GlobalVariable variable;
1350            return scope.RubyContext.TryGetGlobalVariable(name, out variable) && variable.IsDefined;
1351        }
1352
1353        [Emitted]
1354        public static object SetGlobalVariable(object value, RubyScope/*!*/ scope, string/*!*/ name) {
1355            scope.RubyContext.SetGlobalVariable(scope, name, value);
1356            return value;
1357        }
1358
1359        [Emitted]
1360        public static void AliasGlobalVariable(RubyScope/*!*/ scope, string/*!*/ newName, string/*!*/ oldName) {
1361            scope.RubyContext.AliasGlobalVariable(newName, oldName);
1362        }
1363
1364        #endregion
1365
1366        #region DLR Scopes
1367
1368        internal static bool TryGetGlobalScopeConstant(RubyContext/*!*/ context, Scope/*!*/ scope, string/*!*/ name, out object value) {
1369            string mangled;
1370            ScopeStorage scopeStorage = ((object)scope.Storage) as ScopeStorage;
1371            if (scopeStorage != null) {
1372                return scopeStorage.TryGetValue(name, false, out value)
1373                    || (mangled = RubyUtils.TryMangleName(name)) != null && scopeStorage.TryGetValue(mangled, false, out value);
1374            } else {
1375                return context.Operations.TryGetMember(scope, name, out value)
1376                    || (mangled = RubyUtils.TryMangleName(name)) != null && context.Operations.TryGetMember(scope, mangled, out value);
1377            }
1378        }
1379
1380        // TODO:
1381        internal static void ScopeSetMember(Scope scope, string name, object value) {
1382            ScopeStorage scopeStorage = ((object)scope.Storage) as ScopeStorage;
1383            if (scopeStorage != null) {
1384                scopeStorage.SetValue(name, false, value);
1385                return;
1386            }
1387
1388            throw new NotImplementedException();
1389        }
1390
1391        // TODO:
1392        internal static bool ScopeContainsMember(Scope scope, string name) {
1393            ScopeStorage scopeStorage = ((object)scope.Storage) as ScopeStorage;
1394            if (scopeStorage != null) {
1395                return scopeStorage.HasValue(name, false);
1396            }
1397
1398            throw new NotImplementedException();
1399        }
1400
1401        // TODO:
1402        internal static bool ScopeDeleteMember(Scope scope, string name) {
1403            ScopeStorage scopeStorage = ((object)scope.Storage) as ScopeStorage;
1404            if (scopeStorage != null) {
1405                return scopeStorage.DeleteValue(name, false);
1406            }
1407
1408            throw new NotImplementedException();
1409        }
1410
1411        // TODO:
1412        internal static IList<KeyValuePair<string, object>> ScopeGetItems(Scope scope) {
1413            ScopeStorage scopeStorage = ((object)scope.Storage) as ScopeStorage;
1414            if (scopeStorage != null) {
1415                return scopeStorage.GetItems();
1416            }
1417
1418            throw new NotImplementedException();
1419        }
1420
1421        #endregion
1422
1423        #region Regex
1424
1425        [Emitted] //RegexMatchReference:
1426        public static MutableString GetCurrentMatchGroup(RubyScope/*!*/ scope, int index) {
1427            Debug.Assert(index >= 0);
1428            return scope.GetInnerMostClosureScope().GetCurrentMatchGroup(index);
1429        }
1430
1431        [Emitted] //RegexMatchReference:
1432        public static MatchData GetCurrentMatchData(RubyScope/*!*/ scope) {
1433            return scope.GetInnerMostClosureScope().CurrentMatch;
1434        }
1435
1436        [Emitted] //RegexMatchReference:
1437        public static MutableString GetCurrentMatchLastGroup(RubyScope/*!*/ scope) {
1438            return scope.GetInnerMostClosureScope().GetCurrentMatchLastGroup();
1439        }
1440
1441        [Emitted] //RegexMatchReference:
1442        public static MutableString GetCurrentPreMatch(RubyScope/*!*/ scope) {
1443            return scope.GetInnerMostClosureScope().GetCurrentPreMatch();
1444        }
1445
1446        [Emitted] //RegexMatchReference:
1447        public static MutableString GetCurrentPostMatch(RubyScope/*!*/ scope) {
1448            return scope.GetInnerMostClosureScope().GetCurrentPostMatch();
1449        }
1450
1451        [Emitted] //RegularExpression:
1452        public static bool MatchLastInputLine(RubyRegex/*!*/ regex, RubyScope/*!*/ scope) {
1453            var str = scope.GetInnerMostClosureScope().LastInputLine as MutableString;
1454            return (str != null) ? RubyRegex.SetCurrentMatchData(scope, regex, str) != null : false;
1455        }
1456
1457        [Emitted] //MatchExpression:
1458        public static object MatchString(MutableString str, RubyRegex/*!*/ regex, RubyScope/*!*/ scope) {
1459            var match = RubyRegex.SetCurrentMatchData(scope, regex, str);
1460            return (match != null) ? ScriptingRuntimeHelpers.Int32ToObject(match.Index) : null;
1461        }
1462
1463        #endregion
1464
1465        public const char SuffixLiteral = 'L';       // Repr: literal string
1466        public const char SuffixMutable = 'M';       // non-literal "...#{expr}..."
1467
1468        /// <summary>
1469        /// Specialized signatures exist for upto the following number of string parts
1470        /// </summary>
1471        public const int MakeStringParamCount = 2;
1472
1473        #region CreateRegex
1474
1475        private static RubyRegex/*!*/ CreateRegexWorker(
1476            RubyRegexOptions options, 
1477            StrongBox<RubyRegex> regexpCache, 
1478            bool isLiteralWithoutSubstitutions,
1479            Func<RubyRegex> createRegex) {
1480
1481            try {
1482                bool once = ((options & RubyRegexOptions.Once) == RubyRegexOptions.Once) || isLiteralWithoutSubstitutions;
1483                if (once) {
1484                    // Note that the user is responsible for thread synchronization
1485                    if (regexpCache.Value == null) {
1486                        regexpCache.Value = createRegex();
1487                    }
1488                    return regexpCache.Value;
1489                } else {
1490                    // In the future, we can consider caching the last Regexp. For some regexp literals 
1491                    // with substitution, the substition will be the same most of the time
1492                    return createRegex();
1493                }
1494            } catch (RegexpError e) {
1495                if (isLiteralWithoutSubstitutions) {
1496                    // Ideally, this should be thrown during parsing of the source, even if the 
1497                    // expression happens to be unreachable at runtime.
1498                    throw new SyntaxError(e.Message);
1499                } else {
1500                    throw;
1501                }
1502            }
1503        }
1504
1505        [Emitted]
1506        public static RubyRegex/*!*/ CreateRegexB(byte[]/*!*/ bytes, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
1507            Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringB(bytes, encoding), options); };
1508            return CreateRegexWorker(options, regexpCache, true, createRegex);
1509        }
1510
1511        [Emitted]
1512        public static RubyRegex/*!*/ CreateRegexL(string/*!*/ str1, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
1513            Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringL(str1, encoding), options); };
1514            return CreateRegexWorker(options, regexpCache, true, createRegex);
1515        }
1516        
1517        [Emitted]
1518        public static RubyRegex/*!*/ CreateRegexM(MutableString str1, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
1519            Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringM(str1, encoding), options); };
1520            return CreateRegexWorker(options, regexpCache, false, createRegex);
1521        }
1522
1523        [Emitted]
1524        public static RubyRegex/*!*/ CreateRegexLM(string/*!*/ str1, MutableString str2, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
1525            Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringLM(str1, str2, encoding), options); };
1526            return CreateRegexWorker(options, regexpCache, false, createRegex);
1527        }
1528
1529        [Emitted]
1530        public static RubyRegex/*!*/ CreateRegexML(MutableString str1, string/*!*/ str2, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
1531            Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringML(str1, str2, encoding), options); };
1532            return CreateRegexWorker(options, regexpCache, false, createRegex);
1533        }
1534
1535        [Emitted]
1536        public static RubyRegex/*!*/ CreateRegexMM(MutableString str1, MutableString str2, RubyEncoding/*!*/ encoding, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
1537            Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringMM(str1, str2, encoding), options); };
1538            return CreateRegexWorker(options, regexpCache, false, createRegex);
1539        }
1540
1541        [Emitted]
1542        public static RubyRegex/*!*/ CreateRegexN(MutableString[]/*!*/ strings, RubyRegexOptions options, StrongBox<RubyRegex> regexpCache) {
1543            Func<RubyRegex> createRegex = delegate { return new RubyRegex(CreateMutableStringN(strings), options); };
1544            return CreateRegexWorker(options, regexpCache, false, createRegex);
1545        }
1546
1547        #endregion
1548
1549        #region CreateMutableString
1550
1551        [Emitted]
1552        public static MutableString/*!*/ CreateMutableStringB(byte[]/*!*/ bytes, RubyEncoding/*!*/ encoding) {
1553            return MutableString.CreateBinary(bytes, encoding);
1554        }
1555
1556        [Emitted]
1557        public static MutableString/*!*/ CreateMutableStringL(string/*!*/ str1, RubyEncoding/*!*/ encoding) {
1558            return MutableString.Create(str1, encoding);
1559        }
1560
1561        [Emitted]
1562        public static MutableString/*!*/ CreateMutableStringM(MutableString str1, RubyEncoding/*!*/ encoding) {
1563            return MutableString.CreateInternal(str1, encoding);
1564        }
1565
1566        [Emitted]
1567        public static MutableString/*!*/ CreateMutableStringLM(string/*!*/ str1, MutableString str2, RubyEncoding/*!*/ encoding) {
1568            return MutableString.CreateMutable(str1, encoding).Append(str2);
1569        }
1570
1571        [Emitted]
1572        public static MutableString/*!*/ CreateMutableStringML(MutableString str1, string/*!*/ str2, RubyEncoding/*!*/ encoding) {
1573            return MutableString.CreateInternal(str1, encoding).Append(str2);
1574        }
1575
1576        [Emitted]
1577        public static MutableString/*!*/ CreateMutableStringMM(MutableString str1, MutableString str2, RubyEncoding/*!*/ encoding) {
1578            return MutableString.CreateInternal(str1, encoding).Append(str2);
1579        }
1580
1581        // TODO: we should emit Append calls directly, and not create an array first
1582        [Emitted]
1583        public static MutableString/*!*/ CreateMutableStringN(MutableString/*!*/[]/*!*/ parts) {
1584            Debug.Assert(parts.Length > 0);
1585            var result = MutableString.CreateMutable(RubyEncoding.Ascii);
1586
1587            for (int i = 0; i < parts.Length; i++) {
1588                result.Append(parts[i]);
1589            }
1590
1591            return result;
1592        }
1593
1594        #endregion
1595
1596        #region CreateSymbol
1597
1598        [Emitted]
1599        public static RubySymbol/*!*/ CreateSymbolM(MutableString str1, RubyEncoding/*!*/ encoding, RubyScope/*!*/ scope) {
1600            return scope.RubyContext.CreateSymbol(CreateMutableStringM(str1, encoding), false);
1601        }
1602
1603        [Emitted]
1604        public static RubySymbol/*!*/ CreateSymbolLM(string/*!*/ str1, MutableString str2, RubyEncoding/*!*/ encoding, RubyScope/*!*/ scope) {
1605            return scope.RubyContext.CreateSymbol(CreateMutableStringLM(str1, str2, encoding), false);
1606        }
1607
1608        [Emitted]
1609        public static RubySymbol/*!*/ CreateSymbolML(MutableString str1, string/*!*/ str2, RubyEncoding/*!*/ encoding, RubyScope/*!*/ scope) {
1610            return scope.RubyContext.CreateSymbol(CreateMutableStringML(str1, str2, encoding), false);
1611        }
1612        
1613        [Emitted]
1614        public static RubySymbol/*!*/ CreateSymbolMM(MutableString str1, MutableString str2, RubyEncoding/*!*/ encoding, RubyScope/*!*/ scope) {
1615            return scope.RubyContext.CreateSymbol(CreateMutableStringMM(str1, str2, encoding), false);
1616        }
1617
1618        [Emitted]
1619        public static RubySymbol/*!*/ CreateSymbolN(MutableString[]/*!*/ strings, RubyScope/*!*/ scope) {
1620            return scope.RubyContext.CreateSymbol(CreateMutableStringN(strings), false);
1621        }
1622
1623        #endregion
1624
1625        #region Strings, Encodings
1626
1627        [Emitted]
1628        public static RubyEncoding/*!*/ CreateEncoding(int codepage) {
1629            return RubyEncoding.GetRubyEncoding(codepage);
1630        }
1631
1632        [Emitted, Obsolete("Internal only")]
1633        public static byte[]/*!*/ GetMutableStringBytes(MutableString/*!*/ str) {
1634
1635            int byteCount;
1636            var result = str.GetByteArray(out byteCount);
1637            return result;
1638        }
1639
1640        #endregion
1641
1642        #region Booleans
1643
1644        [Emitted]
1645        public static bool IsTrue(object obj) {
1646            return (obj is bool) ? (bool)obj == true : obj != null;
1647        }
1648
1649        [Emitted]
1650        public static bool IsFalse(object obj) {
1651            return (obj is bool) ? (bool)obj == false : obj == null;
1652        }
1653
1654        [Emitted]
1655        public static object NullIfFalse(object obj) {
1656            return (obj is bool && !(bool)obj) ? null : obj;
1657        }
1658
1659        [Emitted]
1660        public static object NullIfTrue(object obj) {
1661            return (obj is bool && !(bool)obj || obj == null) ? DefaultArgument : null;
1662        }
1663
1664        #endregion
1665
1666        #region Exceptions
1667
1668        //
1669        // NOTE:
1670        // Exception Ops go directly to the current exception object. MRI ignores potential aliases.
1671        //
1672
1673        /// <summary>
1674        /// Called in try-filter that wraps the entire body of a block. 
1675        /// We just need to capture stack trace, should not filter out any exception.
1676        /// </summary>
1677        [Emitted]
1678        public static bool FilterBlockException(RubyScope/*!*/ scope, Exception/*!*/ exception) {
1679            RubyExceptionData.GetInstance(exception).CaptureExceptionTrace(scope);
1680            return false;
1681        }
1682
1683        /// <summary>
1684        /// Called in try-filter that wraps the entire top-level code. 
1685        /// We just need to capture stack trace, should not filter out any exception.
1686        /// </summary>
1687        [Emitted]
1688        public static bool TraceTopLevelCodeFrame(RubyScope/*!*/ scope, Exception/*!*/ exception) {
1689            RubyExceptionData.GetInstance(exception).CaptureExceptionTrace(scope);
1690            return false;
1691        }
1692
1693        // Ruby method exit filter:
1694        [Emitted]
1695        public static bool IsMethodUnwinderTargetFrame(RubyScope/*!*/ scope, Exception/*!*/ exception) {
1696            var unwinder = exception as MethodUnwinder;
1697            if (unwinder == null) {
1698                RubyExceptionData.GetInstance(exception).CaptureExceptionTrace(scope);
1699                return false;
1700            } else {
1701                return unwinder.TargetFrame == scope.FlowControlScope;
1702            }
1703        }
1704
1705        [Emitted]
1706        public static object GetMethodUnwinderReturnValue(Exception/*!*/ exception) {
1707            return ((MethodUnwinder)exception).ReturnValue;
1708        }
1709
1710        [Emitted]
1711        public static void LeaveMethodFrame(RuntimeFlowControl/*!*/ rfc) {
1712            rfc.LeaveMethod();
1713        }
1714        
1715        /// <summary>
1716        /// Filters exceptions raised from EH-body, EH-rescue and EH-else clauses.
1717        /// </summary>
1718        [Emitted]
1719        public static bool CanRescue(RubyScope/*!*/ scope, Exception/*!*/ exception) {
1720            if (exception is StackUnwinder) {
1721                return false;
1722            }
1723
1724            LocalJumpError lje = exception as LocalJumpError;
1725            if (lje != null && lje.SkipFrame == scope.FlowControlScope) {
1726                return false;
1727            }
1728
1729            // calls "new" on the exception class if it hasn't been called yet:
1730            exception = RubyExceptionData.HandleException(scope.RubyContext, exception);
1731
1732            scope.RubyContext.CurrentException = exception;
1733            RubyExceptionData.GetInstance(exception).CaptureExceptionTrace(scope);
1734            return true;
1735        }
1736
1737        [Emitted]
1738        public static Exception/*!*/ MarkException(Exception/*!*/ exception) {
1739            RubyExceptionData.GetInstance(exception).Handled = true;
1740            return exception;
1741        }
1742
1743        [Emitted]
1744        public static Exception GetCurrentException(RubyScope/*!*/ scope) {
1745            return scope.RubyContext.CurrentException;
1746        }
1747
1748        /// <summary>
1749        /// Sets $!. Used in EH finally clauses to restore exception stored in oldExceptionVariable local.
1750        /// </summary>
1751        [Emitted] 
1752        public static void SetCurrentException(RubyScope/*!*/ scope, Exception exception) {
1753            scope.RubyContext.CurrentException = exception;
1754        }
1755
1756        [Emitted] //RescueClause:
1757        public static bool CompareException(BinaryOpStorage/*!*/ comparisonStorage, RubyScope/*!*/ scope, object classObject) {            
1758            var context = scope.RubyContext;
1759            var site = comparisonStorage.GetCallSite("===");
1760            bool result = IsTrue(site.Target(site, classObject, context.CurrentException));
1761            if (result) {
1762                RubyExceptionData.ActiveExceptionHandled(context.CurrentException);
1763            }
1764            return result;
1765        }
1766
1767        [Emitted] //RescueClause:
1768        public static bool CompareSplattedExceptions(BinaryOpStorage/*!*/ comparisonStorage, RubyScope/*!*/ scope, IList/*!*/ classObjects) {
1769            for (int i = 0; i < classObjects.Count; i++) {
1770                if (CompareException(comparisonStorage, scope, classObjects[i])) {
1771                    return true;
1772                }
1773            }
1774            return false;
1775        }
1776
1777        [Emitted] //RescueClause:
1778        public static bool CompareDefaultException(RubyScope/*!*/ scope) {
1779            RubyContext ec = scope.RubyContext;
1780
1781            // MRI doesn't call === here;
1782            bool result = ec.IsInstanceOf(ec.CurrentException, ec.StandardErrorClass);
1783            if (result) {
1784                RubyExceptionData.ActiveExceptionHandled(ec.CurrentException);
1785            }
1786            return result;
1787        }
1788
1789        [Emitted]
1790        public static string/*!*/ GetDefaultExceptionMessage(RubyClass/*!*/ exceptionClass) {
1791            return exceptionClass.Name;
1792        }
1793
1794        [Emitted]
1795        public static ArgumentException/*!*/ CreateArgumentsError(string message) {
1796            return (ArgumentException)RubyExceptions.CreateArgumentError(message);
1797        }
1798
1799        [Emitted]
1800        public static ArgumentException/*!*/ CreateArgumentsErrorForMissingBlock() {
1801            return (ArgumentException)RubyExceptions.CreateArgumentError("block not supplied");
1802        }
1803
1804        [Emitted]
1805        public static ArgumentException/*!*/ CreateArgumentsErrorForProc(string className) {
1806            return (ArgumentException)RubyExceptions.CreateArgumentError(String.Format("wrong type argument {0} (should be callable)", className));
1807        }
1808
1809        [Emitted]
1810        public static ArgumentException/*!*/ MakeWrongNumberOfArgumentsError(int actual, int expected) {
1811            return new ArgumentException(String.Format("wrong number of arguments ({0} for {1})", actual, expected));
1812        }
1813
1814        [Emitted] //SuperCall
1815        public static Exception/*!*/ MakeTopLevelSuperException() {
1816            return new MissingMethodException("super called outside of method");
1817        }
1818
1819        [Emitted] //SuperCallAction
1820        public static Exception/*!*/ MakeMissingSuperException(string/*!*/ name) {
1821            return new MissingMethodException(String.Format("super: no superclass method `{0}'", name));
1822        }
1823
1824        [Emitted]
1825        public static Exception/*!*/ MakeVirtualClassInstantiatedError() {
1826            return RubyExceptions.CreateTypeError("can't create instance of virtual class");
1827        }
1828
1829        [Emitted]
1830        public static Exception/*!*/ MakeAbstractMethodCalledError(RuntimeMethodHandle/*!*/ method) {
1831            return new NotImplementedException(String.Format("Abstract method `{0}' not implemented", MethodInfo.GetMethodFromHandle(method)));
1832        }
1833
1834        [Emitted]
1835        public static Exception/*!*/ MakeInvalidArgumentTypesError(string/*!*/ methodName) {
1836            // TODO:
1837            return new ArgumentException(String.Format("wrong number or type of arguments for `{0}'", methodName));
1838        }
1839
1840        [Emitted]
1841        public static Exception/*!*/ MakeTypeConversionError(RubyContext/*!*/ context, object value, Type/*!*/ type) {
1842            return RubyExceptions.CreateTypeConversionError(context.GetClassDisplayName(value), context.GetTypeName(type, true));
1843        }
1844
1845        [Emitted]
1846        public static Exception/*!*/ MakeAmbiguousMatchError(string/*!*/ message) {
1847            // TODO:
1848            return new AmbiguousMatchException(message);
1849        }
1850
1851        [Emitted]
1852        public static Exception/*!*/ MakeAllocatorUndefinedError(RubyClass/*!*/ classObj) {
1853            return RubyExceptions.CreateAllocatorUndefinedError(classObj);
1854        }
1855
1856        [Emitted]
1857        public static Exception/*!*/ MakeNotClrTypeError(RubyClass/*!*/ classObj) {
1858            return RubyExceptions.CreateNotClrTypeError(classObj);
1859        }
1860
1861        [Emitted]
1862        public static Exception/*!*/ MakeConstructorUndefinedError(RubyClass/*!*/ classObj) {
1863            return RubyExceptions.CreateTypeError(String.Format("`{0}' doesn't have a visible CLR constructor", 
1864                classObj.Context.GetTypeName(classObj.TypeTracker.Type, true)
1865            ));
1866        }
1867
1868        [Emitted]
1869        public static Exception/*!*/ MakeMissingDefaultConstructorError(RubyClass/*!*/ classObj, string/*!*/ initializerOwnerName) {
1870            return RubyExceptions.CreateMissingDefaultConstructorError(classObj, initializerOwnerName);
1871        }
1872
1873        [Emitted]
1874        public static Exception/*!*/ MakePrivateMethodCalledError(RubyContext/*!*/ context, object target, string/*!*/ methodName) {
1875            return RubyExceptions.CreatePrivateMethodCalled(context, target, methodName);
1876        }
1877
1878        [Emitted]
1879        public static Exception/*!*/ MakeProtectedMethodCalledError(RubyContext/*!*/ context, object target, string/*!*/ methodName) {
1880            return RubyExceptions.CreateProtectedMethodCalled(context, target, methodName);
1881        }
1882
1883        [Emitted]
1884        public static Exception/*!*/ MakeClrProtectedMethodCalledError(RubyContext/*!*/ context, object target, string/*!*/ methodName) {
1885            return new MissingMethodException(
1886                RubyExceptions.FormatMethodMissingMessage(context, target, methodName, "CLR protected method `{0}' called for {1}; " +
1887                "CLR protected methods can only be called with a receiver whose class is a Ruby subclass of the class declaring the method")
1888            );
1889        }
1890
1891        [Emitted]
1892        public static Exception/*!*/ MakeClrVirtualMethodCalledError(RubyContext/*!*/ context, object target, string/*!*/ methodName) {
1893            return new MissingMethodException(
1894                RubyExceptions.FormatMethodMissingMessage(context, target, methodName, "Virtual CLR method `{0}' called via super from {1}; " +
1895                "Super calls to virtual CLR methods can only be used in a Ruby subclass of the class declaring the method")
1896            );
1897        }
1898
1899        [Emitted]
1900        public static Exception/*!*/ MakeImplicitSuperInBlockMethodError() {
1901            return RubyExceptions.CreateRuntimeError("implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly.");
1902        }
1903
1904        [Emitted]
1905        public static Exception/*!*/ MakeMissingMethodError(RubyContext/*!*/ context, object self, string/*!*/ methodName) {
1906            return RubyExceptions.CreateMethodMissing(context, self, methodName);
1907        }
1908
1909        [Emitted]
1910        public static Exception/*!*/ MakeMissingMemberError(string/*!*/ memberName) {
1911            return new MissingMemberException(String.Format(CultureInfo.InvariantCulture, "undefined member: `{0}'", memberName));
1912        }
1913
1914        #endregion
1915
1916        #region Ranges
1917
1918        [Emitted]
1919        public static Range/*!*/ CreateInclusiveRange(object begin, object end, RubyScope/*!*/ scope, BinaryOpStorage/*!*/ comparisonStorage) {
1920            return new Range(comparisonStorage, scope.RubyContext, begin, end, false);
1921        }
1922
1923        [Emitted]
1924        public static Range/*!*/ CreateExclusiveRange(object begin, object end, RubyScope/*!*/ scope, BinaryOpStorage/*!*/ comparisonStorage) {
1925            return new Range(comparisonStorage, scope.RubyContext, begin, end, true);
1926        }
1927
1928        [Emitted]
1929        public static Range/*!*/ CreateInclusiveIntegerRange(int begin, int end) {
1930            return new Range(begin, end, false);
1931        }
1932
1933        [Emitted]
1934        public static Range/*!*/ CreateExclusiveIntegerRange(int begin, int end) {
1935            return new Range(begin, end, true);
1936        }
1937
1938        #endregion
1939
1940        #region Dynamic Operations
1941
1942        // allocator for struct instances:
1943        [Emitted]
1944        public static RubyStruct/*!*/ AllocateStructInstance(RubyClass/*!*/ self) {
1945            return RubyStruct.Create(self);
1946        }
1947
1948        // factory for struct instances:
1949        [Emitted]
1950        public static RubyStruct/*!*/ CreateStructInstance(RubyClass/*!*/ self, [NotNull]params object[]/*!*/ items) {
1951            var result = RubyStruct.Create(self);
1952            result.SetValues(items);
1953            return result;
1954        }
1955
1956        [Emitted]
1957        public static DynamicMetaObject/*!*/ GetMetaObject(IRubyObject/*!*/ obj, MSA.Expression/*!*/ parameter) {
1958            return new RubyObject.Meta(parameter, BindingRestrictions.Empty, obj);
1959        }
1960
1961        [Emitted]
1962        public static RubyMethod/*!*/ CreateBoundMember(object target, RubyMemberInfo/*!*/ info, string/*!*/ name) {
1963            return new RubyMethod(target, info, name);
1964        }
1965
1966        [Emitted]
1967        public static RubyMethod/*!*/ CreateBoundMissingMember(object target, RubyMemberInfo/*!*/ info, string/*!*/ name) {
1968            return new RubyMethod.Curried(target, info, name);
1969        }
1970
1971        [Emitted]
1972        public static bool IsClrSingletonRuleValid(RubyContext/*!*/ context, object/*!*/ target, int expectedVersion) {
1973            RubyInstanceData data;
1974            RubyClass immediate;
1975
1976            // TODO: optimize this (we can have a hashtable of singletons per class: Weak(object) => Struct { ImmediateClass, InstanceVariables, Flags }):
1977            return context.TryGetClrTypeInstanceData(target, out data) && (immediate = data.ImmediateClass) != null && immediate.IsSingletonClass
1978                && immediate.Version.Method == expectedVersion;
1979        }
1980
1981        [Emitted]
1982        public static bool IsClrNonSingletonRuleValid(RubyContext/*!*/ context, object/*!*/ target, VersionHandle/*!*/ versionHandle, int expectedVersion) {
1983            RubyInstanceData data;
1984            RubyClass immediate;
1985
1986            return versionHandle.Method == expectedVersion
1987                // TODO: optimize this (we can have a hashtable of singletons per class: Weak(object) => Struct { ImmediateClass, InstanceVariables, Flags }):
1988                && !(context.TryGetClrTypeInstanceData(target, out data) && (immediate = data.ImmediateClass) != null && immediate.IsSingletonClass);
1989        }
1990
1991        // super call condition
1992        [Emitted]
1993        public static object GetSuperCallTarget(RubyScope/*!*/ scope, int targetId) {
1994            while (true) {
1995                switch (scope.Kind) {
1996                    case ScopeKind.Method:
1997                        return targetId == 0 ? scope.SelfObject : NeedsUpdate;
1998
1999                    case ScopeKind.BlockMethod:
2000                        return targetId == ((RubyBlockScope)scope).BlockFlowControl.Proc.Method.Id ? scope.SelfObject : NeedsUpdate;
2001
2002                    case ScopeKind.TopLevel:
2003                        // This method is only called if there was method or block-method scope in lexical scope chain.
2004                        // Once there is it cannot be undone. It can only be shadowed by a block scope that became block-method scope, or
2005                        // a block-method scope's target-id can be changed.
2006                        throw Assert.Unreachable;
2007                }
2008
2009                scope = scope.Parent;
2010            }
2011        }
2012
2013        // super call condition
2014        [Emitted]
2015        public static bool IsSuperOutOfMethodScope(RubyScope/*!*/ scope) {
2016            while (true) {
2017                switch (scope.Kind) {
2018                    case ScopeKind.Method:
2019                    case ScopeKind.BlockMethod:
2020                        return false;
2021
2022                    case ScopeKind.TopLevel:
2023                        return true;
2024                }
2025
2026                scope = scope.Parent;
2027            }
2028        }
2029
2030        #endregion
2031
2032        #region Conversions
2033
2034        [Emitted] // ProtocolConversionAction
2035        public static Proc/*!*/ ToProcValidator(string/*!*/ className, object obj) {
2036            Proc result = obj as Proc;
2037            if (result == null) {
2038                throw RubyExceptions.CreateReturnTypeError(className, "to_proc", "Proc");
2039            }
2040            return result;
2041        }
2042
2043        // Used for implicit conversions from System.String to MutableString (to_str conversion like).
2044        [Emitted]
2045        public static MutableString/*!*/ StringToMutableString(string/*!*/ str) {
2046            return MutableString.Create(str, RubyEncoding.UTF8);
2047        }
2048
2049        // Used for implicit conversions from System.Object to MutableString (to_s conversion like).
2050        [Emitted]
2051        public static MutableString/*!*/ ObjectToMutableString(object/*!*/ value) {
2052            return (value != null) ? MutableString.Create(value.ToString(), RubyEncoding.UTF8) : MutableString.FrozenEmpty;
2053        }
2054
2055        [Emitted] // ProtocolConversionAction
2056        public static MutableString/*!*/ ToStringValidator(string/*!*/ className, object obj) {
2057            MutableString result = obj as MutableString;
2058            if (result == null) {
2059                throw RubyExceptions.CreateReturnTypeError(className, "to_str", "String");
2060            }
2061            return result;
2062        }
2063
2064        [Emitted] // ProtocolConversionAction
2065        public static string/*!*/ ToSymbolValidator(string/*!*/ className, object obj) {
2066            var str = obj as MutableString;
2067            if (str == null) {
2068                throw RubyExceptions.CreateReturnTypeError(className, "to_str", "String"); 
2069            }
2070            return str.ConvertToString();
2071        }
2072
2073        [Emitted] // ProtocolConversionAction
2074        public static string/*!*/ ConvertSymbolToClrString(RubySymbol/*!*/ value) {
2075            return value.ToString();
2076        }
2077
2078        [Emitted] // ProtocolConversionAction
2079        public static string/*!*/ ConvertRubySymbolToClrString(RubyContext/*!*/ context, int value) {
2080            context.ReportWarning("do not use Fixnums as Symbols");
2081
2082            RubySymbol result = context.FindSymbol(value);
2083            if (result != null) {
2084                return result.ToString();
2085            } else {
2086                throw RubyExceptions.CreateArgumentError(String.Format("{0} is not a symbol", value));
2087            }
2088        }
2089
2090        [Emitted] // ProtocolConversionAction
2091        public static string/*!*/ ConvertMutableStringToClrString(MutableString/*!*/ value) {
2092            return value.ConvertToString();
2093        }
2094
2095        [Emitted] // ProtocolConversionAction
2096        public static MutableString/*!*/ ConvertSymbolToMutableString(RubySymbol/*!*/ value) {
2097            // TODO: this is used for DefaultProtocol conversions; we might avoid clonning in some (many?) cases
2098            return value.String.Clone();
2099        }
2100        
2101        [Emitted] // ProtocolConversionAction
2102        public static RubyRegex/*!*/ ToRegexValidator(string/*!*/ className, object obj) {
2103            return new RubyRegex(RubyRegex.Escape(ToStringValidator(className, obj)), RubyRegexOptions.NONE);
2104        }
2105
2106        [Emitted] // ProtocolConversionAction
2107        public static IList/*!*/ ToArrayValidator(string/*!*/ className, object obj) {
2108            var result = obj as IList;
2109            if (result == null) {
2110                throw RubyExceptions.CreateReturnTypeError(className, "to_ary", "Array");
2111            }
2112            return result;
2113        }
2114
2115        [Emitted] // ProtocolConversionAction
2116        public static IList/*!*/ ToAValidator(string/*!*/ className, object obj) {
2117            var result = obj as IList;
2118            if (result == null) {
2119                throw RubyExceptions.CreateReturnTypeError(className, "to_a", "Array");
2120            }
2121            return result;
2122        }
2123
2124        [Emitted] // ProtocolConversionAction
2125        public static IDictionary<object, object>/*!*/ ToHashValidator(string/*!*/ className, object obj) {
2126            var result = obj as IDictionary<object, object>;
2127            if (result == null) {
2128                throw RubyExceptions.CreateReturnTypeError(className, "to_hash", "Hash");
2129            }
2130            return result;
2131        }
2132
2133        private static int ToIntValidator(string/*!*/ className, string/*!*/ targetType, object obj) {
2134            if (obj is int) {
2135                return (int)obj;
2136            }
2137
2138            var bignum = obj as BigInteger;
2139            if ((object)bignum != null) {
2140                int fixnum;
2141                if (bignum.AsInt32(out fixnum)) {
2142                    return fixnum;
2143                }
2144                throw RubyExceptions.CreateRangeError("bignum too big to convert into {0}", targetType);
2145            }
2146
2147            throw RubyExceptions.CreateReturnTypeError(className, "to_int", "Integer");
2148        }
2149
2150        [Emitted] // ProtocolConversionAction
2151        public static int ToFixnumValidator(string/*!*/ className, object obj) {
2152            return ToIntValidator(className, "Fixnum", obj);
2153        }
2154
2155        [Emitted] // ProtocolConversionAction
2156        public static Byte ToByteValidator(string/*!*/ className, object obj) {
2157            return Converter.ToByte(ToIntValidator(className, "System::Byte", obj));
2158        }
2159
2160        [Emitted] // ProtocolConversionAction
2161        public static SByte ToSByteValidator(string/*!*/ className, object obj) {
2162            return Converter.ToSByte(ToIntValidator(className, "System::SByte", obj));
2163        }
2164
2165        [Emitted] // ProtocolConversionAction
2166        public static Int16 ToInt16Validator(string/*!*/ className, object obj) {
2167            return Converter.ToInt16(ToIntValidator(className, "System::Int16", obj));
2168        }
2169
2170        [Emitted] // ProtocolConversionAction
2171        public static UInt16 ToUInt16Validator(string/*!*/ className, object obj) {
2172            return Converter.ToUInt16(ToIntValidator(className, "System::UInt16", obj));
2173        }
2174
2175        [Emitted] // ProtocolConversionAction
2176        public static UInt32 ToUInt32Validator(string/*!*/ className, object obj) {
2177            if (obj is int) {
2178                return Converter.ToUInt32((int)obj);
2179            }
2180
2181            var bignum = obj as BigInteger;
2182            if ((object)bignum != null) {
2183                return Converter.ToUInt32(bignum);
2184            }
2185
2186            throw RubyExceptions.CreateReturnTypeError(className, "to_int/to_i", "Integer");
2187        }
2188
2189        [Emitted] // ProtocolConversionAction
2190        public static Int64 ToInt64Validator(string/*!*/ className, object obj) {
2191            if (obj is int) {
2192                return (int)obj;
2193            }
2194
2195            var bignum = obj as BigInteger;
2196            if ((object)bignum != null) {
2197                return Converter.ToInt64(bignum);
2198            }
2199
2200            throw RubyExceptions.CreateReturnTypeError(className, "to_int/to_i", "Integer");
2201        }
2202
2203        [Emitted] // ProtocolConversionAction
2204        public static UInt64 ToUInt64Validator(string/*!*/ className, object obj) {
2205            if (obj is int) {
2206                return Converter.ToUInt64((int)obj);
2207            }
2208
2209            var bignum = obj as BigInteger;
2210            if ((object)bignum != null) {
2211                return Converter.ToUInt64(bignum);
2212            }
2213
2214            throw RubyExceptions.CreateReturnTypeError(className, "to_int/to_i", "Integer");
2215        }
2216
2217        [Emitted] // ProtocolConversionAction
2218        public static BigInteger ToBignumValidator(string/*!*/ className, object obj) {
2219            if (obj is int) {
2220                return (int)obj;
2221            }
2222
2223            var bignum = obj as BigInteger;
2224            if ((object)bignum != null) {
2225                return bignum;
2226            }
2227
2228            throw RubyExceptions.CreateReturnTypeError(className, "to_int/to_i", "Integer");
2229        }
2230
2231        [Emitted] // ProtocolConversionAction
2232        public static IntegerValue ToIntegerValidator(string/*!*/ className, object obj) {
2233            if (obj is int) {
2234                return new IntegerValue((int)obj);
2235            }
2236
2237            var bignum = obj as BigInteger;
2238            if ((object)bignum != null) {
2239                return new IntegerValue(bignum);
2240            }
2241
2242            throw RubyExceptions.CreateReturnTypeError(className, "to_int/to_i", "Integer");
2243        }
2244
2245        [Emitted] // ProtocolConversionAction
2246        public static double ToDoubleValidator(string/*!*/ className, object obj) {
2247            if (obj is double) {
2248                return (double)obj;
2249            }
2250
2251            if (obj is float) {
2252                return (double)(float)obj;
2253            }
2254
2255            throw RubyExceptions.CreateReturnTypeError(className, "to_f", "Float");
2256        }
2257
2258        [Emitted] // ProtocolConversionAction
2259        public static float ToSingleValidator(string/*!*/ className, object obj) {
2260            if (obj is double) {
2261                return (float)(double)obj;
2262            }
2263
2264            if (obj is float) {
2265                return (float)obj;
2266            }
2267
2268            throw RubyExceptions.CreateReturnTypeError(className, "to_f", "System::Single");
2269        }
2270
2271        [Emitted]
2272        public static double ConvertBignumToFloat(BigInteger/*!*/ value) {
2273            double result;
2274            return value.TryToFloat64(out result) ? result : (value.IsNegative() ? Double.NegativeInfinity : Double.PositiveInfinity);
2275        }
2276
2277        [Emitted]
2278        public static double ConvertMutableStringToFloat(RubyContext/*!*/ context, MutableString/*!*/ value) {
2279            return ConvertStringToFloat(context, value.ConvertToString());
2280        }
2281
2282        [Emitted]
2283        public static double ConvertStringToFloat(RubyContext/*!*/ context, string/*!*/ value) {
2284            double result;
2285            bool complete;
2286            if (Tokenizer.TryParseDouble(value, out result, out complete) && complete) {
2287                return result;
2288            }
2289
2290            throw RubyExceptions.InvalidValueForType(context, value, "Float");
2291        }
2292
2293        [Emitted] // ProtocolConversionAction
2294        public static Exception/*!*/ CreateTypeConversionError(string/*!*/ fromType, string/*!*/ toType) {
2295            return RubyExceptions.CreateTypeConversionError(fromType, toType);
2296        }
2297
2298        [Emitted] // ConvertToFixnumAction
2299        public static int ConvertBignumToFixnum(BigInteger/*!*/ bignum) {
2300            int fixnum;
2301            if (bignum.AsInt32(out fixnum)) {
2302                return fixnum;
2303            }
2304            throw RubyExceptions.CreateRangeError("bignum too big to convert into Fixnum");
2305        }
2306
2307        [Emitted] // ConvertDoubleToFixnum
2308        public static int ConvertDoubleToFixnum(double value) {
2309            try {
2310                return checked((int)value);
2311            } catch (OverflowException) {
2312                throw RubyExceptions.CreateRangeError(String.Format("float {0} out of range of Fixnum", value));
2313            }
2314        }
2315
2316        [Emitted] // ConvertToSAction
2317        public static MutableString/*!*/ ToSDefaultConversion(RubyContext/*!*/ context, object target, object converted) {
2318            return converted as MutableString ?? RubyUtils.ObjectToMutableString(context, target);
2319        }
2320
2321        #endregion
2322        
2323        #region Instance variable support
2324
2325        [Emitted]
2326        public static object GetInstanceVariable(RubyScope/*!*/ scope, object self, string/*!*/ name) {
2327            RubyInstanceData data = scope.RubyContext.TryGetInstanceData(self);
2328            return (data != null) ? data.GetInstanceVariable(name) : null;
2329        }
2330
2331        [Emitted]
2332        public static bool IsDefinedInstanceVariable(RubyScope/*!*/ scope, object self, string/*!*/ name) {
2333            RubyInstanceData data = scope.RubyContext.TryGetInstanceData(self);
2334            if (data == null) return false;
2335            object value;
2336            return data.TryGetInstanceVariable(name, out value);
2337        }
2338
2339        [Emitted]
2340        public static object SetInstanceVariable(object self, object value, RubyScope/*!*/ scope, string/*!*/ name) {
2341            scope.RubyContext.SetInstanceVariable(self, name, value);
2342            return value;
2343        }
2344
2345        #endregion
2346
2347        #region Class Variables
2348
2349        [Emitted]
2350        public static object GetClassVariable(RubyScope/*!*/ scope, string/*!*/ name) {
2351            // owner is the first module in scope:
2352            RubyModule owner = scope.GetInnerMostModuleForClassVariableLookup();
2353            return GetClassVariableInternal(owner, name);
2354        }
2355
2356        private static object GetClassVariableInternal(RubyModule/*!*/ module, string/*!*/ name) {
2357            object value;
2358            if (module.TryResolveClassVariable(name, out value) == null) {
2359                throw RubyExceptions.CreateNameError(String.Format("uninitialized class variable {0} in {1}", name, module.Name));
2360            }
2361            return value;
2362        }
2363
2364        [Emitted]
2365        public static object TryGetClassVariable(RubyScope/*!*/ scope, string/*!*/ name) {
2366            object value;
2367            // owner is the first module in scope:
2368            scope.GetInnerMostModuleForClassVariableLookup().TryResolveClassVariable(name, out value);
2369            return value;
2370        }
2371
2372        [Emitted]
2373        public static bool IsDefinedClassVariable(RubyScope/*!*/ scope, string/*!*/ name) {
2374            // owner is the first module in scope:
2375            RubyModule owner = scope.GetInnerMostModuleForClassVariableLookup();
2376            object value;
2377            return owner.TryResolveClassVariable(name, out value) != null;
2378        }
2379
2380        [Emitted]
2381        public static object SetClassVariable(object value, RubyScope/*!*/ scope, string/*!*/ name) {
2382            return SetClassVariableInternal(scope.GetInnerMostModuleForClassVariableLookup(), name, value);
2383        }
2384
2385        private static object SetClassVariableInternal(RubyModule/*!*/ lexicalOwner, string/*!*/ name, object value) {
2386            object oldValue;
2387            RubyModule owner = lexicalOwner.TryResolveClassVariable(name, out oldValue);
2388            (owner ?? lexicalOwner).SetClassVariable(name, value);
2389            return value;
2390        }
2391
2392        #endregion
2393
2394        #region Ruby Types
2395
2396        [Emitted]
2397        public static string/*!*/ ObjectToString(IRubyObject/*!*/ obj) {
2398            return RubyUtils.ObjectToMutableString(obj).ToString();
2399        }
2400
2401        [Emitted] //RubyTypeBuilder
2402        public static RubyInstanceData/*!*/ GetInstanceData(ref RubyInstanceData/*!*/ instanceData) {
2403            if (instanceData == null) {
2404                Interlocked.CompareExchange(ref instanceData, new RubyInstanceData(), null);
2405            }
2406            return instanceData;
2407        }
2408
2409        [Emitted]
2410        public static bool IsObjectFrozen(RubyInstanceData instanceData) {
2411            return instanceData != null && instanceData.IsFrozen;
2412        }
2413
2414        [Emitted]
2415        public static bool IsObjectTainted(RubyInstanceData instanceData) {
2416            return instanceData != null && instanceData.IsTainted;
2417        }
2418
2419        [Emitted]
2420        public static bool IsObjectUntrusted(RubyInstanceData instanceData) {
2421            return instanceData != null && instanceData.IsUntrusted;
2422        }
2423
2424        [Emitted]
2425        public static void FreezeObject(ref RubyInstanceData instanceData) {
2426            RubyOps.GetInstanceData(ref instanceData).Freeze();
2427        }
2428
2429        [Emitted]
2430        public static void SetObjectTaint(ref RubyInstanceData instanceData, bool value) {
2431            RubyOps.GetInstanceData(ref instanceData).IsTainted = value;
2432        }
2433
2434        [Emitted]
2435        public static void SetObjectTrustiness(ref RubyInstanceData instanceData, bool untrusted) {
2436            RubyOps.GetInstanceData(ref instanceData).IsUntrusted = untrusted;
2437        }
2438
2439#if !SILVERLIGHT // serialization
2440        [Emitted(UseReflection = true)] //RubyTypeBuilder
2441        public static void DeserializeObject(out RubyInstanceData/*!*/ instanceData, out RubyClass/*!*/ immediateClass, SerializationInfo/*!*/ info) {
2442            immediateClass = (RubyClass)info.GetValue(RubyUtils.SerializationInfoClassKey, typeof(RubyClass));
2443            RubyInstanceData newInstanceData = null;
2444            foreach (SerializationEntry entry in info) {
2445                if (entry.Name.StartsWith("@", StringComparison.Ordinal)) {
2446                    if (newInstanceData == null) {
2447                        newInstanceData = new RubyInstanceData();
2448                    }
2449                    newInstanceData.SetInstanceVariable(entry.Name, entry.Value);
2450                }
2451            }
2452            instanceData = newInstanceData;
2453        }
2454
2455        [Emitted(UseReflection = true)] //RubyTypeBuilder
2456        public static void SerializeObject(RubyInstanceData instanceData, RubyClass/*!*/ immediateClass, SerializationInfo/*!*/ info) {
2457            info.AddValue(RubyUtils.SerializationInfoClassKey, immediateClass, typeof(RubyClass));
2458            if (instanceData != null) {
2459                string[] instanceNames = instanceData.GetInstanceVariableNames();
2460                foreach (string name in instanceNames) {
2461                    object value;
2462                    if (!instanceData.TryGetInstanceVariable(name, out value)) {
2463                        value = null;
2464                    }
2465                    info.AddValue(name, value, typeof(object));
2466                }
2467            }
2468        }
2469#endif
2470        #endregion
2471
2472        #region Delegates, Events
2473
2474        /// <summary>
2475        /// Hooks up an event to call a proc at hand.
2476        /// EventInfo is passed in as object since it is an internal type.
2477        /// </summary>
2478        [Emitted]
2479        public static Proc/*!*/ HookupEvent(RubyEventInfo/*!*/ eventInfo, object/*!*/ target, Proc/*!*/ proc) {
2480            eventInfo.Tracker.AddHandler(target, proc, eventInfo.Context.DelegateCreator);
2481            return proc;
2482        }
2483
2484        [Emitted]
2485        public static RubyEvent/*!*/ CreateEvent(RubyEventInfo/*!*/ eventInfo, object/*!*/ target, string/*!*/ name) {
2486            return new RubyEvent(target, eventInfo, name);
2487        }
2488
2489        [Emitted]
2490        public static Delegate/*!*/ CreateDelegateFromProc(Type/*!*/ type, Proc proc) {
2491            if (proc == null) {
2492                throw RubyExceptions.NoBlockGiven();
2493            }
2494            BlockParam bp = CreateBfcForProcCall(proc);
2495            return proc.LocalScope.RubyContext.DelegateCreator.GetDelegate(bp, type);
2496        }
2497
2498        [Emitted]
2499        public static Delegate/*!*/ CreateDelegateFromMethod(Type/*!*/ type, RubyMethod/*!*/ method) {
2500            return method.Info.Context.DelegateCreator.GetDelegate(method, type);
2501        }
2502
2503        #endregion
2504
2505        #region Tuples
2506
2507        // Instance variable storages needs MT<n> to be a subclass of MT<m> for all n > m.
2508        // This property is not true if we used DynamicNull as a generic argument for arities that are not powers of 2 like MutableTuple.MakeTupleType does.
2509        // We make this property true for all simple tuples, thus instance variable storages can only use tuples of size <= 128.
2510        internal static Type/*!*/ MakeObjectTupleType(int fieldCount) {
2511            if (fieldCount <= MutableTuple.MaxSize) {
2512                if (fieldCount <= 1) {
2513                    return typeof(MutableTuple<object>);
2514                } else if (fieldCount <= 2) {
2515                    return typeof(MutableTuple<object, object>);
2516                } else if (fieldCount <= 4) {
2517                    return typeof(MutableTuple<object, object, object, object>);
2518                } else if (fieldCount <= 8) {
2519                    return typeof(MutableTuple<object, object, object, object, object, object, object, object>);
2520                } else if (fieldCount <= 16) {
2521                    return typeof(MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>);
2522                } else if (fieldCount <= 32) {
2523                    return typeof(MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>);
2524                } else if (fieldCount <= 64) {
2525                    return typeof(MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>);
2526                } else {
2527                    return typeof(MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>);
2528                }
2529            }
2530
2531            Type[] types = new Type[fieldCount];
2532            for (int i = 0; i < types.Length; i++) {
2533                types[i] = typeof(object);
2534            }
2535            return MutableTuple.MakeTupleType(types);
2536        }
2537
2538        internal static MutableTuple/*!*/ CreateObjectTuple(int fieldCount) {
2539            Debug.Assert(fieldCount <= MutableTuple.MaxSize);
2540            if (fieldCount <= 1) {
2541                return new MutableTuple<object>();
2542            } else if (fieldCount <= 2) {
2543                return new MutableTuple<object, object>();
2544            } else if (fieldCount <= 4) {
2545                return new MutableTuple<object, object, object, object>();
2546            } else if (fieldCount <= 8) {
2547                return new MutableTuple<object, object, object, object, object, object, object, object>();
2548            } else if (fieldCount <= 16) {
2549                return new MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>();
2550            } else if (fieldCount <= 32) {
2551                return new MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>();
2552            } else if (fieldCount <= 64) {
2553                return new MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>();
2554            } else {
2555                return new MutableTuple<object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object, object>();
2556            }
2557        }
2558        #endregion
2559
2560        [Emitted]
2561        public static void X(string marker) {
2562        }
2563        
2564        [Emitted]
2565        public static object CreateDefaultInstance() {
2566            // nop (stub)
2567            return null;
2568        }
2569    }
2570}