internal override object MarshalToScript()

in ClearScript/V8/V8ScriptEngine.cs [1369:1486]


        internal override object MarshalToScript(object obj, HostItemFlags flags)
        {
            const long maxIntInDouble = (1L << 53) - 1;

            if (obj == null)
            {
                return DBNull.Value;
            }

            if (obj is Undefined)
            {
                return null;
            }

            if (obj is Nonexistent)
            {
                return obj;
            }

            if (obj is INothingTag)
            {
                return null;
            }

            if (obj is BigInteger)
            {
                return obj;
            }

            if (obj is long longValue)
            {
                if (engineFlags.HasFlag(V8ScriptEngineFlags.MarshalAllLongAsBigInt))
                {
                    return new BigInteger(longValue);
                }

                if (engineFlags.HasFlag(V8ScriptEngineFlags.MarshalUnsafeLongAsBigInt) && (Math.Abs(longValue) > maxIntInDouble))
                {
                    return new BigInteger(longValue);
                }
            }

            if (obj is ulong ulongValue)
            {
                if (engineFlags.HasFlag(V8ScriptEngineFlags.MarshalAllLongAsBigInt))
                {
                    return new BigInteger(ulongValue);
                }

                if (engineFlags.HasFlag(V8ScriptEngineFlags.MarshalUnsafeLongAsBigInt) && (ulongValue > maxIntInDouble))
                {
                    return new BigInteger(ulongValue);
                }
            }

            if (engineFlags.HasFlag(V8ScriptEngineFlags.EnableDateTimeConversion) && (obj is DateTime))
            {
                return obj;
            }

            if (engineFlags.HasFlag(V8ScriptEngineFlags.EnableTaskPromiseConversion))
            {
                // .NET Core async functions return Task subclass instances that trigger result wrapping

                var testObject = obj;
                if (testObject is HostObject testHostObject)
                {
                    testObject = testHostObject.Target;
                }

                if (testObject != null)
                {
                    if (testObject.GetType().IsAssignableToGenericType(typeof(Task<>), out var typeArgs))
                    {
                        obj = typeof(TaskConverter<>).MakeSpecificType(typeArgs).InvokeMember("ToPromise", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, new[] { testObject, this });
                    }
                    else if (testObject is Task task)
                    {
                        obj = task.ToPromise(this);
                    }
                    else if (engineFlags.HasFlag(V8ScriptEngineFlags.EnableValueTaskPromiseConversion))
                    {
                        TryConvertValueTaskToPromise(testObject, result => obj = result);
                    }
                }
            }

            if (obj is HostItem hostItem)
            {
                if ((hostItem.Engine == this) && (hostItem.Flags == flags))
                {
                    return obj;
                }

                obj = hostItem.Target;
            }

            var hostTarget = obj as HostTarget;
            if ((hostTarget != null) && !(hostTarget is IHostVariable))
            {
                obj = hostTarget.Target;
            }

            if (obj is ScriptItem scriptItem)
            {
                if ((scriptItem.Engine is V8ScriptEngine that) && (that.runtime == runtime))
                {
                    return scriptItem.Unwrap();
                }

                if ((scriptItem is V8ScriptItem v8ScriptItem) && v8ScriptItem.IsShared)
                {
                    return scriptItem.Unwrap();
                }
            }

            return HostItem.Wrap(this, hostTarget ?? obj, flags);
        }