/IronPython_Main/Languages/Ruby/Ruby/Runtime/RubyOps.cs
C# | 2570 lines | 1954 code | 449 blank | 167 comment | 303 complexity | 59b560ffd38a41d8fd908eeb89bd675a MD5 | raw file
Possible License(s): GPL-2.0, MPL-2.0-no-copyleft-exception, CPL-1.0, CC-BY-SA-3.0, BSD-3-Clause, ISC, AGPL-3.0, LGPL-2.1, Apache-2.0
Large files files are truncated, but you can click here to view the full file
- /* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * ironruby@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
- #if !CLR2
- using MSA = System.Linq.Expressions;
- #else
- using MSA = Microsoft.Scripting.Ast;
- #endif
-
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Dynamic;
- using System.Globalization;
- using System.IO;
- using System.Reflection;
- using System.Runtime.CompilerServices;
- using System.Runtime.Serialization;
- using System.Threading;
- using IronRuby.Builtins;
- using IronRuby.Compiler;
- using IronRuby.Compiler.Generation;
- using IronRuby.Runtime.Calls;
- using Microsoft.Scripting;
- using Microsoft.Scripting.Interpreter;
- using Microsoft.Scripting.Math;
- using Microsoft.Scripting.Runtime;
- using Microsoft.Scripting.Utils;
- using IronRuby.Compiler.Ast;
- using IronRuby.Runtime.Conversions;
-
- namespace IronRuby.Runtime {
- [ReflectionCached, CLSCompliant(false)]
- public static partial class RubyOps {
- [Emitted]
- public static readonly object DefaultArgument = new object();
-
- // Returned by a virtual site if a base call should be performed.
- [Emitted]
- public static readonly object ForwardToBase = new object();
-
- // an instance of a dummy type that causes any rule based on instance type check to fail
- private sealed class _NeedsUpdate {
- }
-
- [Emitted]
- public static readonly object NeedsUpdate = new _NeedsUpdate();
-
- #region Scopes
-
- [Emitted]
- public static MutableTuple GetLocals(RubyScope/*!*/ scope) {
- return scope.Locals;
- }
-
- [Emitted]
- public static MutableTuple GetParentLocals(RubyScope/*!*/ scope) {
- return scope.Parent.Locals;
- }
-
- [Emitted]
- public static RubyScope/*!*/ GetParentScope(RubyScope/*!*/ scope) {
- return scope.Parent;
- }
-
- [Emitted]
- public static Proc GetMethodBlockParameter(RubyScope/*!*/ scope) {
- var methodScope = scope.GetInnerMostMethodScope();
- return methodScope != null ? methodScope.BlockParameter : null;
- }
-
- [Emitted]
- public static object GetMethodBlockParameterSelf(RubyScope/*!*/ scope) {
- Proc proc = scope.GetInnerMostMethodScope().BlockParameter;
- Debug.Assert(proc != null, "CreateBfcForYield is called before this method and it checks non-nullity");
- return proc.Self;
- }
-
- [Emitted]
- public static object GetProcSelf(Proc/*!*/ proc) {
- return proc.Self;
- }
-
- [Emitted]
- public static int GetProcArity(Proc/*!*/ proc) {
- return proc.Dispatcher.Arity;
- }
-
- [Emitted]
- public static void InitializeScope(RubyScope/*!*/ scope, MutableTuple locals, string[] variableNames,
- InterpretedFrame interpretedFrame) {
-
- if (!scope.LocalsInitialized) {
- scope.SetLocals(locals, variableNames ?? ArrayUtils.EmptyStrings);
- }
- scope.InterpretedFrame = interpretedFrame;
- }
-
- [Emitted]
- public static void InitializeScopeNoLocals(RubyScope/*!*/ scope, InterpretedFrame interpretedFrame) {
- scope.InterpretedFrame = interpretedFrame;
- }
-
- [Emitted]
- public static void SetDataConstant(RubyScope/*!*/ scope, string/*!*/ dataPath, int dataOffset) {
- Debug.Assert(dataOffset >= 0);
- RubyFile dataFile;
- RubyContext context = scope.RubyContext;
- if (context.DomainManager.Platform.FileExists(dataPath)) {
- dataFile = new RubyFile(context, dataPath, IOMode.ReadOnly);
- dataFile.Seek(dataOffset, SeekOrigin.Begin);
- } else {
- dataFile = null;
- }
-
- context.ObjectClass.SetConstant("DATA", dataFile);
- }
-
- [Emitted]
- public static RubyModuleScope/*!*/ CreateModuleScope(MutableTuple locals, string[] variableNames,
- RubyScope/*!*/ parent, RubyModule/*!*/ module) {
-
- if (parent.RubyContext != module.Context) {
- throw RubyExceptions.CreateTypeError("Cannot open a module `{0}' defined in a foreign runtime #{1}", module.Name, module.Context.RuntimeId);
- }
-
- RubyModuleScope scope = new RubyModuleScope(parent, module);
- scope.SetDebugName((module.IsClass ? "class" : "module") + " " + module.Name);
- scope.SetLocals(locals, variableNames ?? ArrayUtils.EmptyStrings);
- return scope;
- }
-
- [Emitted]
- public static RubyMethodScope/*!*/ CreateMethodScope(MutableTuple locals, string[] variableNames, int visibleParameterCount,
- RubyScope/*!*/ parentScope, RubyModule/*!*/ declaringModule, string/*!*/ definitionName,
- object selfObject, Proc blockParameter, InterpretedFrame interpretedFrame) {
-
- return new RubyMethodScope(
- locals, variableNames ?? ArrayUtils.EmptyStrings, visibleParameterCount,
- parentScope, declaringModule, definitionName, selfObject, blockParameter,
- interpretedFrame
- );
- }
-
- [Emitted]
- public static RubyScope/*!*/ CreateFileInitializerScope(MutableTuple locals, string[] variableNames, RubyScope/*!*/ parent) {
- return new RubyFileInitializerScope(locals, variableNames ?? ArrayUtils.EmptyStrings, parent);
- }
-
- [Emitted]
- public static RubyBlockScope/*!*/ CreateBlockScope(MutableTuple locals, string[] variableNames,
- BlockParam/*!*/ blockParam, object selfObject, InterpretedFrame interpretedFrame) {
-
- return new RubyBlockScope(locals, variableNames ?? ArrayUtils.EmptyStrings, blockParam, selfObject, interpretedFrame);
- }
-
- [Emitted]
- public static void TraceMethodCall(RubyMethodScope/*!*/ scope, string fileName, int lineNumber) {
- // MRI:
- // Reports DeclaringModule even though an aliased method in a sub-module is called.
- // Also works for singleton module-function, which shares DeclaringModule with instance module-function.
- RubyModule module = scope.DeclaringModule;
- scope.RubyContext.ReportTraceEvent("call", scope, module, scope.DefinitionName, fileName, lineNumber);
- }
-
- [Emitted]
- public static void TraceMethodReturn(RubyMethodScope/*!*/ scope, string fileName, int lineNumber) {
- RubyModule module = scope.DeclaringModule;
- scope.RubyContext.ReportTraceEvent("return", scope, module, scope.DefinitionName, fileName, lineNumber);
- }
-
- [Emitted]
- public static void TraceBlockCall(RubyBlockScope/*!*/ scope, BlockParam/*!*/ block, string fileName, int lineNumber) {
- var method = block.Proc.Method;
- if (method != null) {
- scope.RubyContext.ReportTraceEvent("call", scope, method.DeclaringModule, method.DefinitionName, fileName, lineNumber);
- }
- }
-
- [Emitted]
- public static void TraceBlockReturn(RubyBlockScope/*!*/ scope, BlockParam/*!*/ block, string fileName, int lineNumber) {
- var method = block.Proc.Method;
- if (method != null) {
- scope.RubyContext.ReportTraceEvent("return", scope, method.DeclaringModule, method.DefinitionName, fileName, lineNumber);
- }
- }
-
- [Emitted]
- public static void PrintInteractiveResult(RubyScope/*!*/ scope, MutableString/*!*/ value) {
- var writer = scope.RubyContext.DomainManager.SharedIO.OutputStream;
- writer.WriteByte((byte)'=');
- writer.WriteByte((byte)'>');
- writer.WriteByte((byte)' ');
- var bytes = value.ToByteArray();
- writer.Write(bytes, 0, bytes.Length);
- writer.WriteByte((byte)'\r');
- writer.WriteByte((byte)'\n');
- }
-
- [Emitted]
- public static object GetLocalVariable(RubyScope/*!*/ scope, string/*!*/ name) {
- return scope.ResolveLocalVariable(name);
- }
-
- [Emitted]
- public static object SetLocalVariable(object value, RubyScope/*!*/ scope, string/*!*/ name) {
- return scope.ResolveAndSetLocalVariable(name, value);
- }
-
- [Emitted]
- public static VersionHandle/*!*/ GetSelfClassVersionHandle(RubyScope/*!*/ scope) {
- return scope.SelfImmediateClass.Version;
- }
-
- #endregion
-
- #region Context
-
- [Emitted]
- public static RubyContext/*!*/ GetContextFromModule(RubyModule/*!*/ module) {
- return module.Context;
- }
-
- [Emitted]
- public static RubyContext/*!*/ GetContextFromIRubyObject(IRubyObject/*!*/ obj) {
- return obj.ImmediateClass.Context;
- }
-
- [Emitted]
- public static RubyContext/*!*/ GetContextFromScope(RubyScope/*!*/ scope) {
- return scope.RubyContext;
- }
-
- [Emitted]
- public static RubyContext/*!*/ GetContextFromMethod(RubyMethod/*!*/ method) {
- return method.Info.Context;
- }
-
- [Emitted]
- public static RubyContext/*!*/ GetContextFromBlockParam(BlockParam/*!*/ block) {
- return block.RubyContext;
- }
-
- [Emitted]
- public static RubyContext/*!*/ GetContextFromProc(Proc/*!*/ proc) {
- return proc.LocalScope.RubyContext;
- }
-
- [Emitted]
- public static RubyScope/*!*/ GetEmptyScope(RubyContext/*!*/ context) {
- return context.EmptyScope;
- }
-
- [Emitted]
- public static Scope/*!*/ GetGlobalScopeFromScope(RubyScope/*!*/ scope) {
- return scope.GlobalScope.Scope;
- }
-
- #endregion
-
- #region Blocks
-
- [Emitted]
- public static Proc InstantiateBlock(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher) {
- return (dispatcher.Method != null) ? new Proc(ProcKind.Block, self, scope, dispatcher) : null;
- }
- [Emitted]
- public static Proc InstantiateLambda(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher) {
- return (dispatcher.Method != null) ? new Proc(ProcKind.Lambda, self, scope, dispatcher) : null;
- }
-
- [Emitted]
- public static Proc/*!*/ DefineBlock(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher, object/*!*/ clrMethod) {
- // DLR closures should not be used:
- Debug.Assert(!(((Delegate)clrMethod).Target is Closure) || ((Closure)((Delegate)clrMethod).Target).Locals == null);
- return new Proc(ProcKind.Block, self, scope, dispatcher.SetMethod(clrMethod));
- }
-
- [Emitted]
- public static Proc/*!*/ DefineLambda(RubyScope/*!*/ scope, object self, BlockDispatcher/*!*/ dispatcher, object/*!*/ clrMethod) {
- // DLR closures should not be used:
- Debug.Assert(!(((Delegate)clrMethod).Target is Closure) || ((Closure)((Delegate)clrMethod).Target).Locals == null);
- return new Proc(ProcKind.Lambda, self, scope, dispatcher.SetMethod(clrMethod));
- }
-
- /// <summary>
- /// Used in a method call with a block to reset proc-kind when the call is retried
- /// </summary>
- [Emitted]
- public static void InitializeBlock(Proc/*!*/ proc) {
- Assert.NotNull(proc);
- proc.Kind = ProcKind.Block;
- }
-
- /// <summary>
- /// Implements END block - like if it was a call to at_exit { ... } library method.
- /// </summary>
- [Emitted]
- public static void RegisterShutdownHandler(Proc/*!*/ proc) {
- proc.LocalScope.RubyContext.RegisterShutdownHandler(proc);
- }
-
- #endregion
-
- #region Yield: TODO: generate
-
- [Emitted]
- public static object Yield0(Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.Invoke(blockParam, self, procArg);
- } catch(EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object Yield1(object arg1, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- // YieldNoAutoSplat1 uses InvokeNoAutoSplat instead of Invoke (used by Call1)
- internal static object YieldNoAutoSplat1(object arg1, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.InvokeNoAutoSplat(blockParam, self, procArg, arg1);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object Yield2(object arg1, object arg2, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object Yield3(object arg1, object arg2, object arg3, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2, arg3);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object Yield4(object arg1, object arg2, object arg3, object arg4, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.Invoke(blockParam, self, procArg, arg1, arg2, arg3, arg4);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object YieldN(object[]/*!*/ args, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- Debug.Assert(args.Length > BlockDispatcher.MaxBlockArity);
-
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.Invoke(blockParam, self, procArg, args);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- internal static object Yield(object[]/*!*/ args, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- switch (args.Length) {
- case 0: return RubyOps.Yield0(procArg, self, blockParam);
- case 1: return RubyOps.Yield1(args[0], procArg, self, blockParam);
- case 2: return RubyOps.Yield2(args[0], args[1], procArg, self, blockParam);
- case 3: return RubyOps.Yield3(args[0], args[1], args[2], procArg, self, blockParam);
- case 4: return RubyOps.Yield4(args[0], args[1], args[2], args[3], procArg, self, blockParam);
- default: return RubyOps.YieldN(args, procArg, self, blockParam);
- }
- }
-
- [Emitted]
- public static object YieldSplat0(IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, splattee);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object YieldSplat1(object arg1, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, splattee);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object YieldSplat2(object arg1, object arg2, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, splattee);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object YieldSplat3(object arg1, object arg2, object arg3, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, arg3, splattee);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object YieldSplat4(object arg1, object arg2, object arg3, object arg4, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, arg1, arg2, arg3, arg4, splattee);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object YieldSplatN(object[]/*!*/ args, IList/*!*/ splattee, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.InvokeSplat(blockParam, self, procArg, args, splattee);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- [Emitted]
- public static object YieldSplatNRhs(object[]/*!*/ args, IList/*!*/ splattee, object rhs, Proc procArg, object self, BlockParam/*!*/ blockParam) {
- object result;
- var proc = blockParam.Proc;
- try {
- result = proc.Dispatcher.InvokeSplatRhs(blockParam, self, procArg, args, splattee, rhs);
- } catch (EvalUnwinder evalUnwinder) {
- result = blockParam.GetUnwinderResult(evalUnwinder);
- }
-
- return result;
- }
-
- #endregion
-
- #region Methods
-
- [Emitted] // MethodDeclaration:
- public static object DefineMethod(object target, RubyScope/*!*/ scope, RubyMethodBody/*!*/ body) {
- Assert.NotNull(body, scope);
-
- RubyModule instanceOwner, singletonOwner;
- RubyMemberFlags instanceFlags, singletonFlags;
- bool moduleFunction = false;
-
- if (body.HasTarget) {
- if (!RubyUtils.CanDefineSingletonMethod(target)) {
- throw RubyExceptions.CreateTypeError("can't define singleton method for literals");
- }
-
- instanceOwner = null;
- instanceFlags = RubyMemberFlags.Invalid;
- singletonOwner = scope.RubyContext.GetOrCreateSingletonClass(target);
- singletonFlags = RubyMemberFlags.Public;
- } else {
- var attributesScope = scope.GetMethodAttributesDefinitionScope();
- if ((attributesScope.MethodAttributes & RubyMethodAttributes.ModuleFunction) == RubyMethodAttributes.ModuleFunction) {
- // Singleton module-function's scope points to the instance method's RubyMemberInfo.
- // This affects:
- // 1) super call
- // Super call is looking for Method.DeclaringModule while searching MRO, which would fail if the singleton module-function
- // was in MRO. Since module-function can only be used on module the singleton method could only be on module's singleton.
- // Module's singleton is never part of MRO so we are safe.
- // 2) trace
- // Method call trace reports non-singleton module.
-
- // MRI 1.8: instance method owner is self -> it is possible (via define_method) to define m.f. on a class (bug)
- // MRI 1.9: instance method owner GetMethodDefinitionOwner
- // MRI allows to define m.f. on classes but then doesn't work correctly with it.
- instanceOwner = scope.GetMethodDefinitionOwner();
- if (instanceOwner.IsClass) {
- throw RubyExceptions.CreateTypeError("A module function cannot be defined on a class.");
- }
-
- instanceFlags = RubyMemberFlags.Private;
- singletonOwner = instanceOwner.GetOrCreateSingletonClass();
- singletonFlags = RubyMemberFlags.Public;
- moduleFunction = true;
- } else {
- instanceOwner = scope.GetMethodDefinitionOwner();
- instanceFlags = (RubyMemberFlags)RubyUtils.GetSpecialMethodVisibility(attributesScope.Visibility, body.Name);
- singletonOwner = null;
- singletonFlags = RubyMemberFlags.Invalid;
- }
- }
-
- RubyMethodInfo instanceMethod = null, singletonMethod = null;
-
- if (instanceOwner != null) {
- SetMethod(scope.RubyContext, instanceMethod =
- new RubyMethodInfo(body, scope, instanceOwner, instanceFlags)
- );
- }
-
- if (singletonOwner != null) {
- SetMethod(scope.RubyContext, singletonMethod =
- new RubyMethodInfo(body, scope, singletonOwner, singletonFlags)
- );
- }
-
- // the method's scope saves the result => singleton module-function uses instance-method
- var method = instanceMethod ?? singletonMethod;
-
- method.DeclaringModule.MethodAdded(body.Name);
-
- if (moduleFunction) {
- Debug.Assert(!method.DeclaringModule.IsClass);
- method.DeclaringModule.GetOrCreateSingletonClass().MethodAdded(body.Name);
- }
-
- return null;
- }
-
- private static void SetMethod(RubyContext/*!*/ callerContext, RubyMethodInfo/*!*/ method) {
- var owner = method.DeclaringModule;
-
- // Do not trigger the add-method event just yet, we need to assign the result into closure before executing any user code.
- // If the method being defined is "method_added" itself, we would call that method before the info gets assigned to the closure.
- owner.SetMethodNoEvent(callerContext, method.DefinitionName, method);
-
- // expose RubyMethod in the scope (the method is bound to the main singleton instance):
- if (owner.GlobalScope != null) {
- RubyOps.ScopeSetMember(
- owner.GlobalScope.Scope,
- method.DefinitionName,
- new RubyMethod(owner.GlobalScope.MainObject, method, method.DefinitionName)
- );
- }
- }
-
- [Emitted] // AliasStatement:
- public static void AliasMethod(RubyScope/*!*/ scope, string/*!*/ newName, string/*!*/ oldName) {
- scope.GetMethodDefinitionOwner().AddMethodAlias(newName, oldName);
- }
-
- [Emitted] // UndefineMethod:
- public static void UndefineMethod(RubyScope/*!*/ scope, string/*!*/ name) {
- RubyModule owner = scope.GetMethodDefinitionOwner();
-
- if (!owner.ResolveMethod(name, VisibilityContext.AllVisible).Found) {
- throw RubyExceptions.CreateUndefinedMethodError(owner, name);
- }
- owner.UndefineMethod(name);
- }
-
- #endregion
-
- #region Modules
-
- [Emitted]
- public static RubyModule/*!*/ DefineGlobalModule(RubyScope/*!*/ scope, string/*!*/ name) {
- return DefineModule(scope, scope.Top.TopModuleOrObject, name);
- }
-
- [Emitted]
- public static RubyModule/*!*/ DefineNestedModule(RubyScope/*!*/ scope, string/*!*/ name) {
- return DefineModule(scope, scope.GetInnerMostModuleForConstantLookup(), name);
- }
-
- [Emitted]
- public static RubyModule/*!*/ DefineModule(RubyScope/*!*/ scope, object target, string/*!*/ name) {
- return DefineModule(scope, RubyUtils.GetModuleFromObject(scope, target), name);
- }
-
- // thread-safe:
- private static RubyModule/*!*/ DefineModule(RubyScope/*!*/ scope, RubyModule/*!*/ owner, string/*!*/ name) {
- Assert.NotNull(scope, owner);
-
- ConstantStorage existing;
- if (owner.TryGetConstant(scope.GlobalScope, name, out existing)) {
- RubyModule module = existing.Value as RubyModule;
- if (module == null || module.IsClass) {
- throw RubyExceptions.CreateTypeError(String.Format("{0} is not a module", name));
- }
- return module;
- } else {
- // create class/module object:
- return owner.Context.DefineModule(owner, name);
- }
- }
-
- #endregion
-
- #region Classes
-
- [Emitted]
- public static RubyClass/*!*/ DefineSingletonClass(RubyScope/*!*/ scope, object obj) {
- if (!RubyUtils.HasSingletonClass(obj)) {
- throw RubyExceptions.CreateTypeError(String.Format("no virtual class for {0}", scope.RubyContext.GetClassOf(obj).Name));
- }
- return scope.RubyContext.GetOrCreateSingletonClass(obj);
- }
-
- [Emitted]
- public static RubyModule/*!*/ DefineGlobalClass(RubyScope/*!*/ scope, string/*!*/ name, object superClassObject) {
- return DefineClass(scope, scope.Top.TopModuleOrObject, name, superClassObject);
- }
-
- [Emitted]
- public static RubyModule/*!*/ DefineNestedClass(RubyScope/*!*/ scope, string/*!*/ name, object superClassObject) {
- return DefineClass(scope, scope.GetInnerMostModuleForConstantLookup(), name, superClassObject);
- }
-
- [Emitted]
- public static RubyModule/*!*/ DefineClass(RubyScope/*!*/ scope, object target, string/*!*/ name, object superClassObject) {
- return DefineClass(scope, RubyUtils.GetModuleFromObject(scope, target), name, superClassObject);
- }
-
- // thread-safe:
- private static RubyClass/*!*/ DefineClass(RubyScope/*!*/ scope, RubyModule/*!*/ owner, string/*!*/ name, object superClassObject) {
- Assert.NotNull(owner);
- RubyClass superClass = ToSuperClass(owner.Context, superClassObject);
-
- ConstantStorage existing;
- if (owner.IsObjectClass
- ? owner.TryResolveConstant(scope.GlobalScope, name, out existing)
- : owner.TryGetConstant(scope.GlobalScope, name, out existing)) {
-
- RubyClass cls = existing.Value as RubyClass;
- if (cls == null || !cls.IsClass) {
- throw RubyExceptions.CreateTypeError("{0} is not a class", name);
- }
-
- if (superClassObject != null && !ReferenceEquals(cls.SuperClass, superClass)) {
- throw RubyExceptions.CreateTypeError("superclass mismatch for class {0}", name);
- }
- return cls;
- } else {
- return owner.Context.DefineClass(owner, name, superClass, null);
- }
- }
-
- private static RubyClass/*!*/ ToSuperClass(RubyContext/*!*/ ec, object superClassObject) {
- if (superClassObject != null) {
- RubyClass superClass = superClassObject as RubyClass;
- if (superClass == null) {
- throw RubyExceptions.CreateTypeError("superclass must be a Class ({0} given)", ec.GetClassOf(superClassObject).Name);
- }
-
- if (superClass.IsSingletonClass) {
- throw RubyExceptions.CreateTypeError("can't make subclass of virtual class");
- }
-
- return superClass;
- } else {
- return ec.ObjectClass;
- }
- }
-
- #endregion
-
- #region Constants
-
- /// <summary>
- /// A
- /// ::A
- /// </summary>
- [Emitted]
- public static object GetUnqualifiedConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name, bool isGlobal) {
- object result = null;
- RubyModule missingConstantOwner;
- var context = scope.RubyContext;
- using (context.ClassHierarchyLocker()) {
- // Thread safety:
- // Another thread could have already updated the value, so the site version might be the same as CAV.
- // We do the lookup anyways since it is no-op and this only happens rarely.
- //
- // An important invariant holds here: in any time after initialized for the first time the Value field contains a valid value.
- // Threads can read an older value (the previous version) but that is still correct since we don't guarantee immediate
- // propagation of the constant write to all readers.
- //
- // if (site.Version = CAV) {
- // <- another thread could increment CAV here - we may return old or new value (both are ok)
- // value = site.Value;
- // } else {
- // <- another thread could get here as well and update the site before we get to update it.
- // GetConstant(...)
- // }
-
- // Constants might be updated during constant resolution due to autoload.
- // Any such updates need to invalidate the cache hence we need to capture the version before resolving the constant.
- int newVersion = context.ConstantAccessVersion;
-
- ConstantStorage storage;
- if (!isGlobal) {
- missingConstantOwner = scope.TryResolveConstantNoLock(scope.GlobalScope, name, out storage);
- } else if (context.ObjectClass.TryResolveConstantNoLock(scope.GlobalScope, name, out storage)) {
- missingConstantOwner = null;
- } else {
- missingConstantOwner = context.ObjectClass;
- }
-
- object newCacheValue;
- if (missingConstantOwner == null) {
- if (storage.WeakValue != null) {
- result = storage.Value;
- newCacheValue = storage.WeakValue;
- } else {
- result = newCacheValue = storage.Value;
- }
- } else {
- newCacheValue = ConstantSiteCache.WeakMissingConstant;
- }
-
- cache.Update(newCacheValue, newVersion);
- }
-
- if (missingConstantOwner != null) {
- result = missingConstantOwner.ConstantMissing(name);
- }
-
- return result;
- }
-
- /// <summary>
- /// A1::..::AN
- /// ::A1::..::AN
- /// </summary>
- [Emitted]
- public static object GetQualifiedConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/[]/*!*/ qualifiedName, bool isGlobal) {
- var globalScope = scope.GlobalScope;
- var context = globalScope.Context;
-
- using (context.ClassHierarchyLocker()) {
- int newVersion = context.ConstantAccessVersion;
-
- ConstantStorage storage;
- bool anyMissing;
- RubyModule topModule = isGlobal ? context.ObjectClass : null;
- object result = ResolveQualifiedConstant(scope, qualifiedName, topModule, true, out storage, out anyMissing);
-
- // cache result only if no constant was missing:
- if (!anyMissing) {
- Debug.Assert(result == storage.Value);
- cache.Update(storage.WeakValue ?? result, newVersion);
- }
-
- return result;
- }
- }
-
- /// <summary>
- /// {expr}::A1::..::AN
- /// </summary>
- [Emitted]
- public static object GetExpressionQualifiedConstant(object target, RubyScope/*!*/ scope, ExpressionQualifiedConstantSiteCache/*!*/ cache,
- string/*!*/[]/*!*/ qualifiedName) {
- RubyModule module = target as RubyModule;
- if (module == null) {
- throw RubyUtils.CreateNotModuleException(scope, target);
- }
-
- var condition = cache.Condition;
- RubyContext context = module.Context;
-
- // Note that the module can be bound to another runtime:
- if (module.Id == condition.ModuleId && context.ConstantAccessVersion == condition.Version) {
- object value = cache.Value;
- if (value.GetType() == typeof(WeakReference)) {
- return ((WeakReference)value).Target;
- } else {
- return value;
- }
- }
-
- using (context.ClassHierarchyLocker()) {
- int newVersion = context.ConstantAccessVersion;
-
- ConstantStorage storage;
- bool anyMissing;
- object result = ResolveQualifiedConstant(scope, qualifiedName, module, true, out storage, out anyMissing);
-
- // cache result only if no constant was missing:
- if (!anyMissing) {
- Debug.Assert(result == storage.Value);
- cache.Update(storage.WeakValue ?? result, newVersion, module);
- }
-
- return result;
- }
- }
-
- /// <summary>
- /// defined? A
- /// </summary>
- [Emitted]
- public static bool IsDefinedUnqualifiedConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache, string/*!*/ name) {
- var context = scope.RubyContext;
- using (context.ClassHierarchyLocker()) {
- int newVersion = context.ConstantAccessVersion;
-
- ConstantStorage storage;
- bool exists = scope.TryResolveConstantNoLock(null, name, out storage) == null;
- cache.Update(exists, newVersion);
- return exists;
- }
- }
-
- /// <summary>
- /// defined? ::A
- /// </summary>
- [Emitted]
- public static bool IsDefinedGlobalConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache, string/*!*/ name) {
- var context = scope.RubyContext;
- using (context.ClassHierarchyLocker()) {
- int newVersion = context.ConstantAccessVersion;
-
- ConstantStorage storage;
- bool exists = context.ObjectClass.TryResolveConstantNoLock(null, name, out storage);
- cache.Update(exists, newVersion);
- return exists;
- }
- }
-
- /// <summary>
- /// defined? A1::..::AN
- /// defined? ::A1::..::AN
- /// </summary>
- [Emitted]
- public static bool IsDefinedQualifiedConstant(RubyScope/*!*/ scope, IsDefinedConstantSiteCache/*!*/ cache,
- string/*!*/[]/*!*/ qualifiedName, bool isGlobal) {
-
- var context = scope.RubyContext;
- using (context.ClassHierarchyLocker()) {
- int newVersion = context.ConstantAccessVersion;
-
- ConstantStorage storage;
- bool anyMissing;
- RubyModule topModule = isGlobal ? context.ObjectClass : null;
- RubyModule owner;
- try {
- owner = ResolveQualifiedConstant(scope, qualifiedName, topModule, false, out storage, out anyMissing) as RubyModule;
- } catch {
- // autoload can raise an exception
- scope.RubyContext.SetCurrentException(null);
- return false;
- }
-
- // Note that the owner could be another runtime's module:
- bool exists = owner != null && owner.TryResolveConstant(context, null, qualifiedName[qualifiedName.Length - 1], out storage);
-
- // cache result only if no constant was missing:
- if (!anyMissing) {
- cache.Update(exists, newVersion);
- }
-
- return exists;
- }
- }
-
- /// <summary>
- /// defined? {expr}::A
- /// defined? {expr}::A1::..::AN
- /// </summary>
- [Emitted]
- public static bool IsDefinedExpressionQualifiedConstant(object target, RubyScope/*!*/ scope,
- ExpressionQualifiedIsDefinedConstantSiteCache/*!*/ cache, string/*!*/[]/*!*/ qualifiedName) {
-
- RubyModule module = target as RubyModule;
- if (module == null) {
- return false;
- }
-
- var condition = cache.Condition;
- RubyContext context = module.Context;
-
- // Note that the module can be bound to another runtime:
- if (module.Id == condition.ModuleId && context.ConstantAccessVersion == condition.Version) {
- return cache.Value;
- }
-
- using (context.ClassHierarchyLocker()) {
- int newVersion = context.ConstantAccessVersion;
-
- ConstantStorage storage;
- bool exists;
- if (qualifiedName.Length == 1) {
- // Note that the owner could be another runtime's module:
- exists = module.TryResolveConstant(context, null, qualifiedName[0], out storage);
- } else {
- bool anyMissing;
- RubyModule owner;
- try {
- owner = ResolveQualifiedConstant(scope, qualifiedName, module, false, out storage, out anyMissing) as RubyModule;
- } catch {
- // autoload can raise an exception:
- return false;
- }
-
- // Note that the owner could be another runtime's module:
- exists = owner != null && owner.TryResolveConstant(context, null, qualifiedName[qualifiedName.Length - 1], out storage);
-
- // cache result only if no constant was missing:
- if (anyMissing) {
- return exists;
- }
- }
-
- cache.Update(exists, newVersion, module);
- return exists;
- }
- }
-
- private static object ResolveQualifiedConstant(RubyScope/*!*/ scope, string/*!*/[]/*!*/ qualifiedName, RubyModule topModule, bool isGet,
- out ConstantStorage storage, out bool anyMissing) {
-
- Debug.Assert(qualifiedName.Length >= 2 || qualifiedName.Length == 1 && isGet);
- RubyContext context = scope.RubyContext;
- context.RequiresClassHierarchyLock();
-
- RubyModule missingConstantOwner;
- RubyGlobalScope globalScope = scope.GlobalScope;
- int nameCount = (isGet) ? qualifiedName.Length : qualifiedName.Length - 1;
-
- string name = qualifiedName[0];
- if (topModule == null) {
- missingConstantOwner = scope.TryResolveConstantNoLock(globalScope, name, out storage);
- } else if (topModule.TryResolveConstant(context, globalScope, name, out storage)) {
- missingConstantOwner = null;
- } else {
- missingConstantOwner = topModule;
- }
-
- object result;
- if (missingConstantOwner == null) {
- result = storage.Value;
- anyMissing = false;
- } else {
- anyMissing = true;
- using (context.ClassHierarchyUnlocker()) {
- result = missingConstantOwner.ConstantMissing(name);
- }
- }
-
- for (int i = 1; i < nameCount; i++) {
- RubyModule owner = RubyUtils.GetModuleFromObject(scope, result);
- // Note that the owner could be another runtime's module:
- name = qualifiedName[i];
- if (owner.TryResolveConstant(context, globalScope, name, out storage)) {
-
- // Constant write updates constant version in a single runtime only.
- // Therefore if the chain mixes modules from different runtimes we cannot cache the result.
- if (owner.Context != context) {
- anyMissing = true;
- }
-
- result = storage.Value;
- } else {
- anyMissing = true;
- using (context.ClassHierarchyUnlocker()) {
- result = owner.ConstantMissing(name);
- }
- }
- }
-
- return result;
- }
-
- [Emitted]
- public static object GetMissingConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name) {
- return scope.GetInnerMostModuleForConstantLookup().ConstantMissing(name);
- }
-
- [Emitted]
- public static object GetGlobalMissingConstant(RubyScope/*!*/ scope, ConstantSiteCache/*!*/ cache, string/*!*/ name) {
- return scope.RubyContext.ObjectClass.ConstantMissing(name);
- }
-
-
- [Emitted] // ConstantVariable:
- public static object SetGlobalConstant(object value, RubyScope/*!*/ scope, string/*!*/ name) {
- RubyUtils.SetConstant(scope.RubyContext.ObjectClass, name, value);
- return value;
- }
-
- [Emitted] // ConstantVariable:
- public static object SetUnqualifiedConstant(object value, RubyScope/*!*/ scope, string/*!*/ name) {
- RubyUtils.SetConstant(scope.GetInnerMostModuleForConstantLookup(), name, value);
- return value;
- }
-
- [Emitted] // ConstantVariable:
- public static object SetQualifiedConstant(object value, object target, RubyScope/*!*/ scope, string/*!*/ name) {
- RubyUtils.SetConstant(RubyUtils.GetModuleFromObject(scope, target), name, value);
- return value;
- }
-
- #endregion
-
- // MakeArray*
- public const int OptimizedOpCallParamCount = 5;
-
- #region MakeArray
-
- [Emitted]
- public static RubyArray/*!*/ MakeArray0() {
- return new RubyArray(0);
- }
-
- [Emitted]
- public static RubyArray/*!*/ MakeArray1(object item1) {
- RubyArray result = new RubyArray(1);
- result.Add(item1);
- return result;
- }
-
- [Emitted]
- public static RubyArray/*!*/ MakeArray2(object item1, object item2) {
- RubyArray result = new RubyArray(2);
- result.Add(item1);
- result.Add(item2);
- return result;
- }
-
- [Emitted]
- public static RubyArray/*!*/ MakeArray3(object item1, object item2, object item3) {
- RubyArray result = new RubyArray(3);
- result.Add(item1);
- result.Add(item2);
- result.Add(item3);
- return result;
- }
-
- [Emitted]
- public static RubyArray/*!*/ MakeArray4(object item1, object item2, object item3, object item4) {
- RubyArray result = new RubyArray(4);
- result.Add(item1);
- result.Add(item2);
- result.Add(item3);
- result.Add(item4);
- return result;
- }
-
- [Emitted]
- public static RubyArray/*!*/ MakeArray5(object item1, object item2, object item3, object item4, object item5) {
- RubyArray result = new RubyArray(5);
- result.Add(item1);
- result.Add(item2);
- result.Add(item3);
- result.Add(item4);
- result.Add(item5);
- return result;
- }
-
- [Emitted]
- public static RubyArray/*!*/ MakeArrayN(object[]/*!*/ items) {
- Debug.Assert(items != null);
- var array = new RubyArray(items.Length);
- array.AddVector(items, 0, items.Length);
- return array;
- }
-
- #endregion
-
- #region MakeHash
-
- [Emitted]
- public static Hash/*!*/ MakeHash0(RubyScope/*!*/ scope) {
- return new Hash(scope.RubyContext.EqualityComparer, 0);
- }
-
- [Emitted]
- public static Hash/*!*/ MakeHash(RubyScope/*!*/ scope, object[]/*!*/ items) {
- return RubyUtils.SetHashElements(scope.RubyContext, new Hash(scope.RubyContext.EqualityComparer, items.Length / 2), items);
- }
-
- #endregion
-
- #region Array
-
- [Emitted]
- public static RubyArray/*!*/ AddRange(RubyArray/*!*/ array, IList/*!*/ list) {
- return array.AddRange(list);
- }
-
- [Emitted] // method call:
- public static RubyArray/*!*/ AddSubRange(RubyArray/*!*/ result, IList/*!*/ array, int start, int count) {
- return result.AddRange(array, start, count);
- }
-
- [Emitted]
- public static RubyArray/*!*/ AddItem(RubyArray/*!*/ array, object item) {
- array.Add(item);
- return array;
- }
-
- [Emitted]
- public static IList/*!*/ SplatAppend(IList/*!*/ array, IList/*!*/ list) {
- Utils.AddRange(array, list);
- return array;
- }
-
- [Emitted]
- public static object Splat(IList/*!*/ list) {
- if (list.Count <= 1) {
- return (list.Count > 0) ? list[0] : null;
- }
-
- return list;
- }
-
- // 1.8 behavior
- [Emitted]
- public static object SplatPair(object value, IList/*!*/ list) {
- if (list.Count == 0) {
- return value;
- }
-
- RubyArray result = new RubyArray(list.Count + 1);
- result.Add(value);
- result.AddRange(list);
- return result;
- }
-
- [Emitted]
- public static IList/*!*/ Unsplat(object splattee) {
- var list = splattee as IList;
- if (list == null) {
- list = new RubyArray(1);
- list.Add(splattee);
- }
- return list;
- }
-
- // CaseExpression
- [Emitted]
- public static bool ExistsUnsplatCompare(CallSite<Func<CallSite, obje…
Large files files are truncated, but you can click here to view the full file