using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Microsoft.Iris.Debug;
using Microsoft.Iris.Debug.Data;
using Microsoft.Iris.Library;
using Microsoft.Iris.Markup.UIX;
using Microsoft.Iris.Session;

namespace Microsoft.Iris.Markup
{
    // Token: 0x0200018B RID: 395
    internal class Interpreter
    {
        // Token: 0x06000F21 RID: 3873 RVA: 0x00029E78 File Offset: 0x00028E78
        public static object Run(InterpreterContext context)
        {
            object result = null;
            ByteCodeReader byteCodeReader = null;
            long num = -1L;
            bool isErrored = true;
            ErrorManager.EnterContext(context);
            try
            {
                byteCodeReader = context.LoadResult.ObjectSection;
                num = (long)(ulong)byteCodeReader.CurrentOffset;
                byteCodeReader.CurrentOffset = context.InitialBytecodeOffset;
                if (Application.DebugSettings.UseDecompiler)
                    result = RunDecompile(context, byteCodeReader);
                else
                    result = Run(context, byteCodeReader);
                isErrored = false;
            }
            finally
            {
                if (isErrored)
                    ExceptionContext = context.ToString();
                ErrorManager.ExitContext();

                if (byteCodeReader != null && num != -1L)
                    byteCodeReader.CurrentOffset = (uint)num;
            }
            return result;
        }
        
        // Token: 0x06000F22 RID: 3874 RVA: 0x00029EF8 File Offset: 0x00028EF8
        private static object Run(InterpreterContext context, ByteCodeReader reader)
        {
            MarkupLoadResult loadResult = context.LoadResult;
            IMarkupTypeBase instance = context.Instance;
            MarkupImportTables importTables = loadResult.ImportTables;
            MarkupConstantsTable constantsTable = loadResult.ConstantsTable;
            SymbolReference[] symbolReferenceTable = context.MarkupType.SymbolReferenceTable;
            ErrorWatermark watermark = ErrorManager.Watermark;

            Trace.IsCategoryEnabled(TraceCategory.Markup);

            Stack stack = _stack;
            int count = stack.Count;
            if (instance != null)
            {
                stack.Push(instance);
            }

            bool errorsDetected = false;
            object result = null;
            bool wasInDebugState = false;
            bool debugging = Application.Debugger != null;

            context.LoadResult.LineNumberTable.DumpTable();
            
            void OnDecode(InterpreterEntry entry)
            {
                if (!debugging) return;
                
                Application.Debugger.LogInterpreterDecode(context, entry.Instruction);

                // Fetch line and column numbers from the table
                uint offset = entry.Instruction.Offset;
                int line = -1, column = -1;
                context.LoadResult.LineNumberTable.TryLookup(offset, out line, out column);

                bool ShouldBreak(Breakpoint b) =>
                    b.Enabled && b.Equals(loadResult, line, column, offset);

                // Check if a breakpoint has been set at this location
                bool shouldBreakHere = Application.DebugSettings.Breakpoints.Any(ShouldBreak);
                if (shouldBreakHere)
                    Application.Debugger.DebuggerCommand = InterpreterCommand.Break;

                // Stop execution while the debugger is in break mode
                Application.Debugger.WaitForContinue();

                // If the debugger requested a single step, immediately set the debugger
                // to break again for the next instruction
                if (Application.Debugger.DebuggerCommand == InterpreterCommand.Step)
                    Application.Debugger.DebuggerCommand = InterpreterCommand.Break;
            }

            while (!errorsDetected)
            {
                OpCode opCode = (OpCode)reader.ReadByte();
                InterpreterEntry entry = new(new(opCode, reader.CurrentOffset, loadResult.Uri));

                switch (opCode)
                {
                    case OpCode.ConstructObject:
                        {
                            int typeIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(typeIndex);
                            OnDecode(entry);
                            
                            TypeSchema typeSchema = importTables.TypeImports[typeIndex];
                            entry.Parameters.Add(new InterpreterObject("type", typeof(TypeSchema),
                                typeSchema, InstructionObjectSource.TypeImports, typeIndex));

                            object newObj = typeSchema.ConstructDefault();
                            
                            ReportErrorOnNull(newObj, "Construction", typeSchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                RegisterDisposable(newObj, typeSchema, instance);

                                stack.Push(newObj);
                                entry.ReturnValues.Add(new(newObj));
                            }
                            break;
                        }
                    case OpCode.ConstructObjectIndirect:
                        {
                            int assignmentTypeIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(assignmentTypeIndex);
                            OnDecode(entry);
                            
                            TypeSchema assignmentTypeSchema = importTables.TypeImports[assignmentTypeIndex];
                            entry.Parameters.Add(new("assignmentType", typeof(TypeSchema),
                                assignmentTypeSchema, InstructionObjectSource.TypeImports, assignmentTypeIndex));

                            TypeSchema targetTypeSchema = (TypeSchema)stack.Pop();
                            entry.Parameters.Add(new("targetType", typeof(TypeSchema),
                                targetTypeSchema, InstructionObjectSource.Stack));

                            if (!assignmentTypeSchema.IsAssignableFrom(targetTypeSchema))
                            {
                                ErrorManager.ReportError("Script runtime failure: Dynamic construction type override failed. Attempting to construct '{0}' in place of '{1}'", (targetTypeSchema != null) ? targetTypeSchema.Name : "null", assignmentTypeSchema.Name);
                                if (ErrorsDetected(watermark, ref result, ref errorsDetected))
                                    break;
                            }

                            object newObj = targetTypeSchema is IDynamicConstructionSchema dynamicConstructionSchema
                                ? dynamicConstructionSchema.ConstructDefault(assignmentTypeSchema)
                                : targetTypeSchema.ConstructDefault();

                            ReportErrorOnNull(newObj, "Construction", targetTypeSchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                RegisterDisposable(newObj, targetTypeSchema, instance);

                                stack.Push(newObj);
                                entry.ReturnValues.Add(new(newObj));
                            }
                            break;
                        }
                    case OpCode.ConstructObjectParam:
                        {
                            int targetTypeIndex = reader.ReadUInt16();
                            int constructorIndex = reader.ReadUInt16();
                            
                            entry.Instruction.Operands.Add(targetTypeIndex);
                            entry.Instruction.Operands.Add(constructorIndex);
                            OnDecode(entry);
                            
                            TypeSchema targetTypeSchema = importTables.TypeImports[targetTypeIndex];
                            ConstructorSchema constructorSchema = importTables.ConstructorImports[constructorIndex];

                            int parameterCount = constructorSchema.ParameterTypes.Length;
                            object[] array = ParameterListAllocator.Alloc(parameterCount);
                            for (parameterCount--; parameterCount >= 0; parameterCount--)
                                array[parameterCount] = stack.Pop();
                            entry.Parameters.Add(new("ctorParams", typeof(object[]),
                                array, InstructionObjectSource.Stack));

                            object newObj = constructorSchema.Construct(array);

                            ReportErrorOnNull(newObj, "Construction", targetTypeSchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                RegisterDisposable(newObj, targetTypeSchema, instance);

                                stack.Push(newObj);
                                entry.ReturnValues.Add(new(newObj));

                                ParameterListAllocator.Free(array);
                            }
                            break;
                        }
                    case OpCode.ConstructFromString:
                        {
                            int typeIndex = reader.ReadUInt16();
                            int stringIndex = reader.ReadUInt16();
                            
                            entry.Instruction.Operands.Add(typeIndex);
                            entry.Instruction.Operands.Add(stringIndex);
                            OnDecode(entry);
                            
                            TypeSchema typeSchema = importTables.TypeImports[typeIndex];
                            entry.Parameters.Add(new("type", typeof(TypeSchema),
                                typeSchema, InstructionObjectSource.TypeImports, typeIndex));

                            string fromString = (string)constantsTable.Get(stringIndex);
                            entry.Parameters.Add(new("fromString", typeof(string),
                                fromString, InstructionObjectSource.Constants, stringIndex));

                            typeSchema.TypeConverter(fromString, StringSchema.Type, out object newObj);

                            ReportErrorOnNull(newObj, "Construction", typeSchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                RegisterDisposable(newObj, typeSchema, instance);

                                stack.Push(newObj);
                                entry.ReturnValues.Add(new(newObj));
                            }
                            break;
                        }
                    case OpCode.ConstructFromBinary:
                        {
                            int typeIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(typeIndex);
                            OnDecode(entry);
                            
                            TypeSchema typeSchema = importTables.TypeImports[typeIndex];
                            entry.Parameters.Add(new("type", typeof(TypeSchema),
                                typeSchema, InstructionObjectSource.TypeImports, typeIndex));

                            uint blobStart = reader.CurrentOffset;
                            object newObj = typeSchema.DecodeBinary(reader);
                            if (debugging)
                            {
                                // Potentially expensive operation, only do this if a debugger is attached
                                uint blobEnd = reader.CurrentOffset;
                                uint blobLength = blobEnd - blobStart;

                                byte[] blob = new byte[blobLength];
                                reader.CurrentOffset = blobStart;
                                while (reader.CurrentOffset < blobEnd)
                                    blob[reader.CurrentOffset - blobStart] = reader.ReadByte();

                                entry.Parameters.Add(new("blob", typeof(byte[]),
                                    blob, InstructionObjectSource.Inline, 0));
                            }

                            ReportErrorOnNull(newObj, "Construction", typeSchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                RegisterDisposable(newObj, typeSchema, instance);

                                stack.Push(newObj);
                                entry.ReturnValues.Add(new(newObj));
                            }
                            break;
                        }
                    case OpCode.InitializeInstance:
                        {
                            int typeIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(typeIndex);
                            OnDecode(entry);
                            
                            TypeSchema typeSchema = importTables.TypeImports[typeIndex];
                            entry.Parameters.Add(new("type", typeof(TypeSchema),
                                typeSchema, InstructionObjectSource.TypeImports, typeIndex));

                            object objToInit = stack.Pop();
                            entry.Parameters.Add(new("objToInit", typeof(object),
                                objToInit, InstructionObjectSource.Stack));

                            typeSchema.InitializeInstance(ref objToInit);

                            ReportErrorOnNull(objToInit, "Initialize", typeSchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                stack.Push(objToInit);
                                entry.ReturnValues.Add(new(objToInit));
                            }
                            break;
                        }
                    case OpCode.InitializeInstanceIndirect:
                        {
                            OnDecode(entry);
                            
                            TypeSchema typeSchema = (TypeSchema)stack.Pop();
                            entry.Parameters.Add(new("type", typeof(TypeSchema),
                                typeSchema, InstructionObjectSource.Stack));

                            object objToInit = stack.Pop();
                            entry.Parameters.Add(new("objToInit", typeof(object),
                                objToInit, InstructionObjectSource.Stack));

                            typeSchema.InitializeInstance(ref objToInit);

                            ReportErrorOnNull(objToInit, "Initialize", typeSchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                stack.Push(objToInit);
                                entry.ReturnValues.Add(new(objToInit));
                            }
                            break;
                        }
                    case OpCode.LookupSymbol:
                        {
                            int symbolRefIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(symbolRefIndex);
                            OnDecode(entry);
                            
                            SymbolReference symbolRef = symbolReferenceTable[symbolRefIndex];
                            entry.Parameters.Add(new("symbolRef", typeof(SymbolReference),
                                symbolRef, InstructionObjectSource.SymbolReference, symbolRefIndex));

                            object symbol = context.ReadSymbol(symbolRef);

                            stack.Push(symbol);
                            entry.ReturnValues.Add(new(symbol));

                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.WriteSymbol:
                    case OpCode.WriteSymbolPeek:
                        {
                            int symbolRefIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(symbolRefIndex);
                            OnDecode(entry);
                            
                            object symbol = (opCode == OpCode.WriteSymbolPeek) ? stack.Peek() : stack.Pop();
                            entry.Parameters.Add(new("symbol", typeof(object),
                                symbol, InstructionObjectSource.Stack));

                            SymbolReference symbolRef = symbolReferenceTable[symbolRefIndex];
                            entry.Parameters.Add(new("symbolRef", typeof(SymbolReference),
                                symbolRef, InstructionObjectSource.SymbolReference, symbolRefIndex));

                            context.WriteSymbol(symbolRef, symbol);

                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.ClearSymbol:
                        {
                            int symbolRefIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(symbolRefIndex);
                            OnDecode(entry);
                            
                            SymbolReference symbolRef = symbolReferenceTable[symbolRefIndex];
                            entry.Parameters.Add(new("symbolRef", typeof(SymbolReference),
                                symbolRef, InstructionObjectSource.SymbolReference, symbolRefIndex));

                            context.ClearSymbol(symbolRef);

                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.PropertyInitialize:
                    case OpCode.PropertyInitializeIndirect:
                        {
                            int propertyIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(propertyIndex);
                            OnDecode(entry);
                            
                            bool isIndirect = opCode == OpCode.PropertyInitializeIndirect;
                            TypeSchema parentTypeSchema = null;
                            if (isIndirect)
                            {
                                parentTypeSchema = (TypeSchema)stack.Pop();
                                entry.Parameters.Add(new("parentType", typeof(TypeSchema),
                                    parentTypeSchema, InstructionObjectSource.Stack));
                            }

                            PropertySchema propertySchema = importTables.PropertyImports[propertyIndex];
                            entry.Parameters.Add(new("property", typeof(PropertySchema),
                                propertySchema, InstructionObjectSource.PropertyImports, propertyIndex));

                            object propertyValue = stack.Pop();
                            entry.Parameters.Add(new("value", typeof(object),
                                propertyValue, InstructionObjectSource.Stack));

                            object parentObj = stack.Pop();
                            entry.Parameters.Add(new("parent", typeof(object),
                                parentObj, InstructionObjectSource.Stack));

                            ReportErrorOnNull(parentObj, "Property Set", propertySchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                if (isIndirect)
                                {
                                    PropertySchema inheritedPropertySchema = parentTypeSchema.FindPropertyDeep(propertySchema.Name);
                                    if (inheritedPropertySchema != propertySchema)
                                    {
                                        TypeSchema propertyType = inheritedPropertySchema.PropertyType;
                                        if (!propertyType.IsAssignableFrom(propertyValue))
                                        {
                                            string param = TypeSchema.NameFromInstance(propertyValue);
                                            ErrorManager.ReportError("Script runtime failure: Incompatible value for property '{0}' supplied (expecting values of type '{1}' but got '{2}') while constructing runtime replacement type '{3}' (original type '{4}')", propertySchema.Name, propertyType.Name, param, parentTypeSchema.Name, propertySchema.Owner.Name);
                                            result = ScriptError;
                                        }
                                        if (ErrorsDetected(watermark, ref result, ref errorsDetected))
                                        {
                                            break;
                                        }
                                    }
                                }

                                propertySchema.SetValue(ref parentObj, propertyValue);

                                if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                                {
                                    stack.Push(parentObj);
                                    entry.ReturnValues.Add(new(parentObj));
                                }
                            }
                            break;
                        }
                    case OpCode.PropertyListAdd:
                        {
                            int propertyIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(propertyIndex);
                            OnDecode(entry);
                            
                            object objToAdd = stack.Pop();
                            entry.Parameters.Add(new("objToAdd", typeof(object),
                                objToAdd, InstructionObjectSource.Stack));

                            object collection = GetCollection(stack.Peek(), importTables, propertyIndex, out var propertySchema);
                            entry.Parameters.Add(new("collection", typeof(IList),
                                collection, InstructionObjectSource.Dynamic));
                            if (propertySchema != null)
                                entry.Parameters.Add(new("collectionProperty", typeof(PropertySchema),
                                    propertySchema, InstructionObjectSource.TypeImports, propertyIndex));

                            ReportErrorOnNull(collection, "List Add");
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                ((IList)collection).Add(objToAdd);
                                if (ErrorsDetected(watermark, ref result, ref errorsDetected))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.PropertyDictionaryAdd:
                        {
                            int propertyIndex = reader.ReadUInt16();
                            int keyIndex = reader.ReadUInt16();
                            
                            entry.Instruction.Operands.Add(propertyIndex);
                            entry.Instruction.Operands.Add(keyIndex);
                            OnDecode(entry);

                            string key = (string)constantsTable.Get(keyIndex);
                            entry.Parameters.Add(new("key", typeof(string),
                                key, InstructionObjectSource.Constants, keyIndex));

                            object objToAdd = stack.Pop();
                            entry.Parameters.Add(new("objToAdd", typeof(object),
                                objToAdd, InstructionObjectSource.Stack));

                            object dictionary = GetCollection(stack.Peek(), importTables, propertyIndex, out var propertySchema);
                            entry.Parameters.Add(new("dictionary", typeof(IDictionary),
                                dictionary, InstructionObjectSource.Dynamic));
                            if (propertySchema != null)
                                entry.Parameters.Add(new("dictionaryProperty", typeof(PropertySchema),
                                    propertySchema, InstructionObjectSource.TypeImports, propertyIndex));

                            ReportErrorOnNull(dictionary, "Dictionary Add");
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                ((IDictionary)dictionary)[key] = objToAdd;
                                if (ErrorsDetected(watermark, ref result, ref errorsDetected))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.PropertyAssign:
                    case OpCode.PropertyAssignStatic:
                        {
                            int propertyIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(propertyIndex);
                            OnDecode(entry);
                            
                            PropertySchema propertySchema = importTables.PropertyImports[propertyIndex];
                            entry.Parameters.Add(new("property", typeof(PropertySchema),
                                propertySchema, InstructionObjectSource.PropertyImports, propertyIndex));

                            object parentObj = null;

                            if (opCode == OpCode.PropertyAssign)
                            {
                                parentObj = stack.Pop();
                                entry.Parameters.Add(new("parent", typeof(object),
                                    parentObj, InstructionObjectSource.Stack));

                                ReportErrorOnNullOrDisposed(parentObj, "Property Set", propertySchema.Name, propertySchema.Owner);
                                if (ErrorsDetected(watermark, ref result, ref errorsDetected))
                                {
                                    break;
                                }
                            }

                            object propertyValue = stack.Peek();
                            entry.Parameters.Add(new("value", typeof(object),
                                propertyValue, InstructionObjectSource.Stack, 1));

                            propertySchema.SetValue(ref parentObj, propertyValue);

                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected) && Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.PropertyGet:
                    case OpCode.PropertyGetPeek:
                    case OpCode.PropertyGetStatic:
                        {
                            int propertyIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(propertyIndex);
                            OnDecode(entry);
                            
                            PropertySchema propertySchema = importTables.PropertyImports[propertyIndex];
                            entry.Parameters.Add(new("property", typeof(PropertySchema),
                                propertySchema, InstructionObjectSource.PropertyImports, propertyIndex));

                            object parentObj = null;

                            if (opCode != OpCode.PropertyGetStatic)
                            {
                                parentObj = opCode == OpCode.PropertyGet ? stack.Pop() : stack.Peek();
                                entry.Parameters.Add(new("parent", typeof(object),
                                    parentObj, InstructionObjectSource.Stack));

                                ReportErrorOnNullOrDisposed(parentObj, "Property Get", propertySchema.Name, propertySchema.Owner);
                                if (ErrorsDetected(watermark, ref result, ref errorsDetected))
                                {
                                    break;
                                }
                            }

                            object propertyValue = propertySchema.GetValue(parentObj);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                stack.Push(propertyValue);
                                entry.ReturnValues.Add(new(propertyValue));

                                if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.MethodInvoke:
                    case OpCode.MethodInvokePeek:
                    case OpCode.MethodInvokeStatic:
                    case OpCode.MethodInvokePushLastParam:
                    case OpCode.MethodInvokeStaticPushLastParam:
                        {
                            int methodIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(methodIndex);
                            OnDecode(entry);
                            
                            MethodSchema methodSchema = importTables.MethodImports[methodIndex];

                            int parameterCount = methodSchema.ParameterTypes.Length;
                            object[] parameters = ParameterListAllocator.Alloc(parameterCount);
                            for (parameterCount--; parameterCount >= 0; parameterCount--)
                                parameters[parameterCount] = stack.Pop();
                            entry.Parameters.Add(new("parameters", typeof(object[]),
                                parameters, InstructionObjectSource.Stack));

                            object parentObj = null;
                            bool isStatic = opCode == OpCode.MethodInvokeStatic || opCode == OpCode.MethodInvokeStaticPushLastParam;
                            bool peek = opCode == OpCode.MethodInvokePeek;
                            bool pushLastParam = opCode == OpCode.MethodInvokePushLastParam || opCode == OpCode.MethodInvokeStaticPushLastParam;

                            if (!isStatic)
                            {
                                parentObj = !peek ? stack.Pop() : stack.Peek();
                                entry.Parameters.Add(new("parent", typeof(object),
                                    parentObj, InstructionObjectSource.Stack));

                                ReportErrorOnNullOrDisposed(parentObj, "Method Invoke", methodSchema.Name, methodSchema.Owner);
                                if (ErrorsDetected(watermark, ref result, ref errorsDetected))
                                {
                                    break;
                                }
                            }

                            object methodResult = methodSchema.Invoke(parentObj, parameters);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                if (!pushLastParam)
                                {
                                    if (methodSchema.ReturnType != VoidSchema.Type)
                                    {
                                        stack.Push(methodResult);
                                        entry.ReturnValues.Add(new(methodResult));
                                    }
                                }
                                else
                                {
                                    stack.Push(parameters[parameters.Length - 1]);
                                }

                                ParameterListAllocator.Free(parameters);
                            }
                            break;
                        }
                    case OpCode.VerifyTypeCast:
                        {
                            int typeIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(typeIndex);
                            OnDecode(entry);
                            
                            TypeSchema typeSchema = importTables.TypeImports[typeIndex];
                            entry.Parameters.Add(new("type", typeof(TypeSchema),
                                typeSchema, InstructionObjectSource.TypeImports, typeIndex));

                            object objToCheck = stack.Peek();
                            entry.Parameters.Add(new("objToCheck", typeof(object),
                                objToCheck, InstructionObjectSource.Stack, 1));

                            if (objToCheck != null)
                            {
                                if (!typeSchema.IsAssignableFrom(objToCheck))
                                {
                                    string runtimeTypeName = TypeSchema.NameFromInstance(objToCheck);
                                    string name = typeSchema.Name;
                                    ErrorManager.ReportError("Script runtime failure: Invalid type cast while attempting to cast an instance with a runtime type of '{0}' to '{1}'", runtimeTypeName, name);
                                    result = ScriptError;
                                }

                                if (ErrorsDetected(watermark, ref result, ref errorsDetected))
                                {
                                }
                            }
                            else if (!typeSchema.IsNullAssignable)
                            {
                                ReportErrorOnNull(objToCheck, "Verify Type Cast", typeSchema.Name);
                                if (ErrorsDetected(watermark, ref result, ref errorsDetected))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.ConvertType:
                        {
                            int toTypeIndex = reader.ReadUInt16();
                            int fromTypeIndex = reader.ReadUInt16();
                            
                            entry.Instruction.Operands.Add(toTypeIndex);
                            entry.Instruction.Operands.Add(fromTypeIndex);
                            OnDecode(entry);
                            
                            TypeSchema toTypeSchema = importTables.TypeImports[toTypeIndex];
                            entry.Parameters.Add(new("toType", typeof(TypeSchema),
                                toTypeSchema, InstructionObjectSource.TypeImports, toTypeIndex));

                            TypeSchema fromTypeSchema = importTables.TypeImports[fromTypeIndex];
                            entry.Parameters.Add(new("fromType", typeof(TypeSchema),
                                fromTypeSchema, InstructionObjectSource.TypeImports, fromTypeIndex));

                            object objToConvert = stack.Pop();
                            entry.Parameters.Add(new("objToConvert", typeof(object),
                                objToConvert, InstructionObjectSource.Stack));

                            ReportErrorOnNull(objToConvert, "Type Conversion", toTypeSchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                Result castResult = toTypeSchema.TypeConverter(objToConvert, fromTypeSchema, out object obj14);
                                if (castResult.Failed)
                                    ErrorManager.ReportError("Script runtime failure: Type conversion failed while attempting to convert to '{0}' ({1})", toTypeSchema.Name, castResult.Error);

                                if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                                {
                                    stack.Push(obj14);
                                    entry.ReturnValues.Add(new(obj14));
                                }
                            }
                            break;
                        }
                    case OpCode.Operation:
                        {
                            int opHostIndex = reader.ReadUInt16();
                            OperationType op = (OperationType)reader.ReadByte();
                            
                            entry.Instruction.Operands.Add(opHostIndex);
                            entry.Instruction.Operands.Add(op);
                            OnDecode(entry);
                            
                            TypeSchema opHost = importTables.TypeImports[opHostIndex];
                            entry.Parameters.Add(new("opHost", typeof(TypeSchema),
                                opHost, InstructionObjectSource.TypeImports, opHostIndex));

                            entry.Parameters.Add(new("op", typeof(OperationType),
                                op, InstructionObjectSource.Inline));

                            object right = null;
                            if (!TypeSchema.IsUnaryOperation(op))
                            {
                                right = stack.Pop();
                                entry.Parameters.Add(new("right", typeof(object),
                                    right, InstructionObjectSource.Stack));
                            }

                            object left = stack.Pop();
                            entry.Parameters.Add(new("left", typeof(object),
                                left, InstructionObjectSource.Stack));

                            object opResult = opHost.PerformOperationDeep(left, right, op);

                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                stack.Push(opResult);
                                entry.ReturnValues.Add(new(opResult));

                                if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.IsCheck:
                        {
                            int targetTypeIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(targetTypeIndex);
                            OnDecode(entry);
                            
                            TypeSchema targetTypeSchema = importTables.TypeImports[targetTypeIndex];
                            entry.Parameters.Add(new("targetType", typeof(TypeSchema),
                                targetTypeSchema, InstructionObjectSource.TypeImports, targetTypeIndex));

                            object objToCheck = stack.Pop();
                            entry.Parameters.Add(new("objToCheck", typeof(object),
                                objToCheck, InstructionObjectSource.Stack));

                            bool checkResult = false;
                            if (objToCheck != null)
                                checkResult = targetTypeSchema.IsAssignableFrom(objToCheck);

                            stack.Push(BooleanBoxes.Box(checkResult));
                            entry.ReturnValues.Add(new(checkResult));

                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.As:
                        {
                            int targetTypeIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(targetTypeIndex);
                            OnDecode(entry);
                            
                            TypeSchema targetTypeSchema = importTables.TypeImports[targetTypeIndex];
                            entry.Parameters.Add(new("targetType", typeof(TypeSchema),
                                targetTypeSchema, InstructionObjectSource.TypeImports, targetTypeIndex));

                            object objToCheck = stack.Peek();
                            entry.Parameters.Add(new("objToCheck", typeof(object),
                                objToCheck, InstructionObjectSource.Stack, 1));

                            if (objToCheck != null && !targetTypeSchema.IsAssignableFrom(objToCheck))
                            {
                                stack.Pop();
                                stack.Push(null);
                            }
                            else if (debugging)
                            {
                                // The opcode isn't implemented like this,
                                // but technically As returns a value.
                                entry.ReturnValues.Add(new(objToCheck));
                            }

                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.TypeOf:
                        {
                            int typeIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(typeIndex);
                            OnDecode(entry);
                            
                            entry.Parameters.Add(new("typeIndex", typeof(ushort),
                                typeIndex, InstructionObjectSource.Inline));

                            TypeSchema typeSchema = importTables.TypeImports[typeIndex];

                            stack.Push(typeSchema);
                            entry.ReturnValues.Add(new(typeSchema));
                            break;
                        }
                    case OpCode.PushNull:
                        OnDecode(entry);
                        stack.Push(null);
                        entry.ReturnValues.Add(new(null));
                        break;
                    case OpCode.PushConstant:
                        {
                            int constantIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(constantIndex);
                            OnDecode(entry);
                            
                            entry.Parameters.Add(new("constantIndex", typeof(ushort),
                                constantIndex, InstructionObjectSource.Inline));

                            object constant = constantsTable.Get(constantIndex);

                            stack.Push(constant);
                            entry.ReturnValues.Add(new(constant));
                            break;
                        }
                    case OpCode.PushThis:
                        OnDecode(entry);
                        stack.Push(instance);
                        entry.ReturnValues.Add(new(instance));
                        break;
                    case OpCode.DiscardValue:
                        OnDecode(entry);
                        stack.Pop();
                        break;
                    case OpCode.ReturnValue:
                        {
                            OnDecode(entry);
                            
                            object thisResult = stack.Pop();
                            entry.ReturnValues.Add(new(thisResult));

                            result = thisResult;
                            errorsDetected = true;
                            break;
                        }
                    case OpCode.ReturnVoid:
                        OnDecode(entry);
                        result = VoidReturnValue;
                        errorsDetected = true;
                        break;
                    case OpCode.JumpIfFalse:
                    case OpCode.JumpIfFalsePeek:
                    case OpCode.JumpIfTruePeek:
                        {
                            uint jumpTo = reader.ReadUInt32();
                            entry.Instruction.Operands.Add(jumpTo);
                            OnDecode(entry);
                            
                            entry.Parameters.Add(new("jumpTo", typeof(uint),
                                jumpTo, InstructionObjectSource.Inline));

                            bool value = (bool)((opCode == OpCode.JumpIfFalse) ? stack.Pop() : stack.Peek());
                            entry.Parameters.Add(new("value", typeof(bool),
                                value, InstructionObjectSource.Stack));

                            bool jumpIfTrue = opCode == OpCode.JumpIfTruePeek;
                            if (jumpIfTrue == value)
                            {
                                reader.CurrentOffset = jumpTo;

                                if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.JumpIfDictionaryContains:
                        {
                            ushort propertyIndex = reader.ReadUInt16();
                            ushort keyIndex = reader.ReadUInt16();
                            uint jumpTo = reader.ReadUInt32();
                            
                            entry.Instruction.Operands.Add(propertyIndex);
                            entry.Instruction.Operands.Add(keyIndex);
                            entry.Instruction.Operands.Add(jumpTo);
                            OnDecode(entry);

                            entry.Parameters.Add(new("jumpTo", typeof(uint),
                                jumpTo, InstructionObjectSource.Inline));

                            string key = (string)constantsTable.Get(keyIndex);
                            entry.Parameters.Add(new("key", typeof(string),
                                key, InstructionObjectSource.Constants, keyIndex));

                            object dictionary = GetCollection(stack.Peek(), importTables, propertyIndex, out var propertySchema);
                            entry.Parameters.Add(new("dictionary", typeof(IDictionary),
                                dictionary, InstructionObjectSource.Dynamic));
                            if (propertySchema != null)
                                entry.Parameters.Add(new("dictionaryProperty", typeof(PropertySchema),
                                    propertySchema, InstructionObjectSource.TypeImports, propertyIndex));

                            ReportErrorOnNull(dictionary, "Dictionary Contains");
                            if (!ErrorsDetected(watermark, ref result, ref errorsDetected))
                            {
                                bool dictionaryContains = ((IDictionary)dictionary).Contains(key);

                                Trace.IsCategoryEnabled(TraceCategory.Markup);
                                if (dictionaryContains)
                                {
                                    reader.CurrentOffset = jumpTo;

                                    if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                                    {
                                    }
                                }
                            }
                            break;
                        }
                    case OpCode.JumpIfNullPeek:
                        {
                            uint jumpTo = reader.ReadUInt32();
                            entry.Instruction.Operands.Add(jumpTo);
                            OnDecode(entry);
                            
                            entry.Parameters.Add(new("jumpTo", typeof(uint),
                                jumpTo, InstructionObjectSource.Inline));

                            object objToCheck = stack.Peek();
                            entry.Parameters.Add(new("objToCheck", typeof(object),
                                objToCheck, InstructionObjectSource.Stack));

                            Trace.IsCategoryEnabled(TraceCategory.Markup);
                            if (objToCheck == null)
                            {
                                reader.CurrentOffset = jumpTo;

                                if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.Jump:
                        {
                            uint jumpTo = reader.ReadUInt32();
                            entry.Instruction.Operands.Add(jumpTo);
                            OnDecode(entry);
                            
                            entry.Parameters.Add(new("jumpTo", typeof(uint),
                                jumpTo, InstructionObjectSource.Inline));

                            reader.CurrentOffset = jumpTo;

                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.ConstructListenerStorage:
                        {
                            int listenerCount = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(listenerCount);
                            OnDecode(entry);
                            
                            entry.Parameters.Add(new("listenerCount", typeof(int),
                                listenerCount, InstructionObjectSource.Inline));

                            if (instance.Listeners == null)
                            {
                                MarkupListeners markupListeners = new(listenerCount);
                                markupListeners.DeclareOwner(instance);
                                instance.Listeners = markupListeners;
                            }
                            else
                            {
                                instance.Listeners.AddEntries(listenerCount);
                            }

                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.Listen:
                    case OpCode.DestructiveListen:
                        {
                            int listenerIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(listenerIndex);
                            entry.Parameters.Add(new("listenerIndex", typeof(int),
                                listenerIndex, InstructionObjectSource.Inline));

                            ListenerType listenerType = (ListenerType)reader.ReadByte();
                            entry.Instruction.Operands.Add(listenerType);
                            entry.Parameters.Add(new("listenerType", typeof(ListenerType),
                                listenerType, InstructionObjectSource.Inline));

                            int watchIndex = reader.ReadUInt16();
                            entry.Instruction.Operands.Add(watchIndex);

                            uint handlerOffset = reader.ReadUInt32();
                            entry.Instruction.Operands.Add(handlerOffset);
                            entry.Parameters.Add(new("handlerOffset", typeof(uint),
                                handlerOffset, InstructionObjectSource.Inline));

                            uint refreshOffset = uint.MaxValue;
                            if (opCode == OpCode.DestructiveListen)
                            {
                                refreshOffset = reader.ReadUInt32();
                                entry.Instruction.Operands.Add(refreshOffset);
                                entry.Parameters.Add(new("refreshOffset", typeof(uint),
                                    refreshOffset, InstructionObjectSource.Inline));
                            }
                            
                            OnDecode(entry);
                            
                            string watch = null;
                            InstructionObjectSource watchSource = InstructionObjectSource.Dynamic;
                            switch (listenerType)
                            {
                                case ListenerType.Property:
                                    watch = importTables.PropertyImports[watchIndex].Name;
                                    watchSource = InstructionObjectSource.PropertyImports;
                                    break;
                                case ListenerType.Event:
                                    watch = importTables.EventImports[watchIndex].Name;
                                    watchSource = InstructionObjectSource.EventImports;
                                    break;
                                case ListenerType.Symbol:
                                    watch = symbolReferenceTable[watchIndex].Symbol;
                                    watchSource = InstructionObjectSource.SymbolReference;
                                    break;
                            }
                            entry.Parameters.Add(new("watch", typeof(string),
                                watch, watchSource, watchIndex));

                            object handlerObj = stack.Peek();
                            entry.Parameters.Add(new("handlerObj", typeof(object),
                                handlerObj, InstructionObjectSource.Stack, 1));

                            if (handlerObj is INotifyObject notifier)
                            {
                                MarkupListeners listeners = instance.Listeners;
                                listeners.RefreshListener(listenerIndex, notifier, watch, instance, handlerOffset, refreshOffset);
                            }
                            else
                            {
                                Trace.IsCategoryEnabled(TraceCategory.Markup);
                            }
                            break;
                        }
                    case OpCode.EnterDebugState:
                        {
                            int breakpointIndex = reader.ReadInt32();
                            entry.Instruction.Operands.Add(breakpointIndex);
                            OnDecode(entry);
                            
                            entry.Parameters.Add(new("breakpointIndex", typeof(int),
                                breakpointIndex, InstructionObjectSource.Inline));

                            if (MarkupSystem.IsDebuggingEnabled(2))
                            {
                                wasInDebugState = MarkupDebugHelper.EnterDebugState(wasInDebugState, loadResult, breakpointIndex, instance.Storage);
                            }
                            break;
                        }
                }

                Application.Debugger?.LogInterpreterExecute(context, entry);
            }
            while (stack.Count > count)
            {
                stack.Pop();
            }
            return result;
        }

        // Token: 0x06000F23 RID: 3875 RVA: 0x0002ADA7 File Offset: 0x00029DA7
        private static bool ErrorsDetected(ErrorWatermark watermark, ref object result, ref bool done)
        {
            if (watermark.ErrorsDetected)
            {
                result = ScriptError;
                done = true;
                return true;
            }
            return false;
        }

        // Token: 0x06000F24 RID: 3876 RVA: 0x0002ADC0 File Offset: 0x00029DC0
        private static void RegisterDisposable(object instance, TypeSchema type, IMarkupTypeBase root)
        {
            if (type.Disposable && root != null)
            {
                IDisposableObject disposableObject = (IDisposableObject)instance;
                root.RegisterDisposable(disposableObject);
                disposableObject.DeclareOwner(root);
            }
        }

        // Token: 0x06000F25 RID: 3877 RVA: 0x0002ADF0 File Offset: 0x00029DF0
        private static object GetCollection(object stackInstance, MarkupImportTables importTables, int propertyIndex, out PropertySchema propertySchema)
        {
            object result = null;
            if (propertyIndex == 0xFFFF)
            {
                result = stackInstance;
                propertySchema = null;
            }
            else
            {
                propertySchema = importTables.PropertyImports[propertyIndex];
                ReportErrorOnNull(stackInstance, "Property Get", propertySchema.Name);
                if (stackInstance != null)
                    result = propertySchema.GetValue(stackInstance);
            }
            return result;
        }

        // Token: 0x06000F26 RID: 3878 RVA: 0x0002AE31 File Offset: 0x00029E31
        private static void ReportErrorOnNull(object instance, string operation, string member)
        {
            if (instance == null)
            {
                ErrorManager.ReportError("Script runtime failure: Null-reference while attempting a '{0}' of '{1}' on a null instance", operation, member);
            }
        }

        // Token: 0x06000F27 RID: 3879 RVA: 0x0002AE42 File Offset: 0x00029E42
        private static void ReportErrorOnNull(object instance, string operation)
        {
            if (instance == null)
            {
                ErrorManager.ReportError("Script runtime failure: Null-reference while attempting a '{0}'", operation);
            }
        }

        // Token: 0x06000F28 RID: 3880 RVA: 0x0002AE54 File Offset: 0x00029E54
        private static void ReportErrorOnNullOrDisposed(object instance, string operation, string member, TypeSchema typeSchema)
        {
            if (instance == null)
            {
                ErrorManager.ReportError("Script runtime failure: Null-reference while attempting a '{0}' of '{1}' on a null instance", operation, member);
                return;
            }
            if (typeSchema.Disposable)
            {
                IDisposableObject disposableObject = (IDisposableObject)instance;
                if (disposableObject.IsDisposed)
                {
                    ErrorManager.ReportError("Script runtime failure: Attempting a '{0}' of '{1}' on an object '{2}' that has already been disposed", operation, member, TypeSchema.NameFromInstance(instance));
                }
            }
        }

        // Token: 0x04000947 RID: 2375
        public const uint InvalidOffset = 4294967295U;

        // Token: 0x04000948 RID: 2376
        private static object VoidReturnValue = new object();

        // Token: 0x04000949 RID: 2377
        private static Stack _stack = new Stack();
        private static Stack<XmlNode> _xmlStack = new Stack<XmlNode>();

        // Token: 0x0400094A RID: 2378
        public static object ScriptError = new Interpreter.ScriptErrorObject();

        // Token: 0x0400094B RID: 2379
        public static string ExceptionContext;

        // Token: 0x0200018C RID: 396
        private class ScriptErrorObject
        {
        }

        // Token: 0x0200018D RID: 397
        private struct ParameterListAllocator
        {
            // Token: 0x06000F2C RID: 3884 RVA: 0x0002AECC File Offset: 0x00029ECC
            public static object[] Alloc(int count)
            {
                object[] array;
                if (count == 0)
                {
                    array = s_params0;
                }
                else if (count < MAX_CACHED_LIST_SIZE)
                {
                    array = s_cachedLists[count];
                    if (array != null)
                    {
                        s_cachedLists[count] = null;
                    }
                    else
                    {
                        array = new object[count];
                    }
                }
                else
                {
                    array = new object[count];
                }
                return array;
            }

            // Token: 0x06000F2D RID: 3885 RVA: 0x0002AF10 File Offset: 0x00029F10
            public static void Free(object[] paramList)
            {
                int num = paramList.Length;
                if (num != 0 && num < MAX_CACHED_LIST_SIZE && s_cachedLists[num] == null)
                {
                    Array.Clear(paramList, 0, paramList.Length);
                    s_cachedLists[num] = paramList;
                }
            }

            // Token: 0x0400094C RID: 2380
            private const int MAX_CACHED_LIST_SIZE = 20;

            // Token: 0x0400094D RID: 2381
            private static object[] s_params0 = new object[0];

            // Token: 0x0400094E RID: 2382
            private static object[][] s_cachedLists = new object[MAX_CACHED_LIST_SIZE][];
        }

        private static XmlElement UIXElem;

        private static XmlDocument _xmlDoc;
        public static XmlDocument XmlDoc
        {
            get
            {
                if (_xmlDoc == null)
                {
                    _xmlDoc = new XmlDocument();
                    UIXElem = _xmlDoc.CreateElement("UIX");
                    UIXElem.SetAttribute("xmlns", "http://schemas.microsoft.com/2007/uix");
                    _xmlDoc.AppendChild(UIXElem);
                }
                return _xmlDoc;
            }
        }

        /// <summary>
        /// Attempts to generate source UIX from a compiled result
        /// </summary>
        private static object RunDecompile(InterpreterContext context, ByteCodeReader reader)
        {
            MarkupLoadResult loadResult = context.LoadResult;
            IMarkupTypeBase instance = context.Instance;
            MarkupImportTables importTables = loadResult.ImportTables;
            MarkupConstantsTable constantsTable = loadResult.ConstantsTable;
            SymbolReference[] symbolReferenceTable = context.MarkupType.SymbolReferenceTable;

            Trace.IsCategoryEnabled(TraceCategory.Markup);
            bool decompile = Application.DebugSettings.UseDecompiler;

            Stack stack = _stack;
            Stack<XmlNode> xmlStack = _xmlStack;
            int count = stack.Count;

            if (instance != null)
            {
                stack.Push(instance);

                // Make sure XmlDoc has been initialized
                _ = XmlDoc;

                // Add UI container to root
                string key = instance.TypeSchema.Name;
                XmlElement instanceXml = UIXElem.ChildNodes.OfType<XmlElement>()
                    .FirstOrDefault(elem => elem?.GetAttribute("Name") == key);
                if (instanceXml == null)
                {
                    instanceXml = XmlDoc.CreateElement("UI");
                    instanceXml.SetAttribute("Name", key);
                    UIXElem.AppendChild(instanceXml);
                }
                xmlStack.Push(instanceXml);
            }
            ErrorWatermark watermark = ErrorManager.Watermark;
            bool flag = false;
            object result = null;
            bool wasInDebugState = false;
            while (!flag)
            {
                OpCode opCode = (OpCode)reader.ReadByte();

                switch (opCode)
                {
                    case OpCode.ConstructObject:
                        {
                            int num = reader.ReadUInt16();
                            TypeSchema typeSchema = importTables.TypeImports[num];
                            object obj = typeSchema.ConstructDefault();

                            string typeName = obj.GetType().Name;
                            int idxTilde = typeName.IndexOf('`');
                            if (idxTilde >= 0)
                                typeName = typeName.Substring(0, idxTilde);
                            var objXml = XmlDoc.CreateElement(typeName);

                            ReportErrorOnNull(obj, "Construction", typeSchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                RegisterDisposable(obj, typeSchema, instance);
                                stack.Push(obj);
                                xmlStack.Push(objXml);
                            }
                            break;
                        }
                    case OpCode.ConstructObjectIndirect:
                        {
                            int num2 = reader.ReadUInt16();
                            TypeSchema typeSchema2 = importTables.TypeImports[num2];
                            TypeSchema typeSchema3 = (TypeSchema)stack.Pop();
                            xmlStack.Pop();
                            if (!typeSchema2.IsAssignableFrom(typeSchema3))
                            {
                                ErrorManager.ReportError("Script runtime failure: Dynamic construction type override failed. Attempting to construct '{0}' in place of '{1}'", (typeSchema3 != null) ? typeSchema3.Name : "null", typeSchema2.Name);
                                if (ErrorsDetected(watermark, ref result, ref flag))
                                {
                                    break;
                                }
                            }
                            IDynamicConstructionSchema dynamicConstructionSchema = typeSchema3 as IDynamicConstructionSchema;
                            object obj2;
                            if (dynamicConstructionSchema != null)
                            {
                                obj2 = dynamicConstructionSchema.ConstructDefault(typeSchema2);
                            }
                            else
                            {
                                obj2 = typeSchema3.ConstructDefault();
                            }
                            var objXml2 = XmlDoc.CreateElement(obj2.GetType().Name);
                            ReportErrorOnNull(obj2, "Construction", typeSchema3.Name);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                RegisterDisposable(obj2, typeSchema3, instance);
                                stack.Push(obj2);
                                xmlStack.Push(objXml2);
                            }
                            break;
                        }
                    case OpCode.ConstructObjectParam:
                        {
                            int num3 = reader.ReadUInt16();
                            TypeSchema typeSchema4 = importTables.TypeImports[num3];
                            int num4 = reader.ReadUInt16();
                            ConstructorSchema constructorSchema = importTables.ConstructorImports[num4];
                            int i = constructorSchema.ParameterTypes.Length;
                            object[] array = ParameterListAllocator.Alloc(i);
                            for (i--; i >= 0; i--)
                            {
                                array[i] = stack.Pop();
                                xmlStack.Pop(); // TODO
                            }
                            object obj3 = constructorSchema.Construct(array);
                            var objXml3 = XmlDoc.CreateElement(obj3.GetType().Name);
                            ReportErrorOnNull(obj3, "Construction", typeSchema4.Name);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                RegisterDisposable(obj3, typeSchema4, instance);
                                stack.Push(obj3);
                                xmlStack.Push(objXml3);
                                ParameterListAllocator.Free(array);
                            }
                            break;
                        }
                    case OpCode.ConstructFromString:
                        {
                            int num5 = reader.ReadUInt16();
                            TypeSchema typeSchema5 = importTables.TypeImports[num5];
                            int index = reader.ReadUInt16();
                            string from = (string)constantsTable.Get(index);
                            object obj4;
                            typeSchema5.TypeConverter(from, StringSchema.Type, out obj4);
                            var objXml4 = XmlDoc.CreateElement(obj4.GetType().Name);
                            ReportErrorOnNull(obj4, "Construction", typeSchema5.Name);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                RegisterDisposable(obj4, typeSchema5, instance);
                                stack.Push(obj4);
                                xmlStack.Push(objXml4);
                            }
                            break;
                        }
                    case OpCode.ConstructFromBinary:
                        {
                            int num6 = reader.ReadUInt16();
                            TypeSchema typeSchema6 = importTables.TypeImports[num6];
                            object obj5 = typeSchema6.DecodeBinary(reader);
                            var objXml5 = XmlDoc.CreateElement(obj5.GetType().Name);
                            ReportErrorOnNull(obj5, "Construction", typeSchema6.Name);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                RegisterDisposable(obj5, typeSchema6, instance);
                                stack.Push(obj5);
                                xmlStack.Push(objXml5);
                            }
                            break;
                        }
                    case OpCode.InitializeInstance:
                        {
                            int num7 = reader.ReadUInt16();
                            TypeSchema typeSchema7 = importTables.TypeImports[num7];
                            object obj6 = stack.Pop();
                            var objXml6 = (XmlElement)xmlStack.Pop();
                            typeSchema7.InitializeInstance(ref obj6);
                            objXml6.SetAttribute("Name", typeSchema7.Name);
                            ReportErrorOnNull(obj6, "Initialize", typeSchema7.Name);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                stack.Push(obj6);
                                xmlStack.Push(objXml6);
                            }
                            break;
                        }
                    case OpCode.InitializeInstanceIndirect:
                        {
                            TypeSchema typeSchema8 = (TypeSchema)stack.Pop();
                            object obj7 = stack.Pop();
                            typeSchema8.InitializeInstance(ref obj7);
                            xmlStack.Pop();
                            var objXml7 = (XmlElement)xmlStack.Pop();
                            objXml7.SetAttribute("Name", typeSchema8.Name);
                            ReportErrorOnNull(obj7, "Initialize", typeSchema8.Name);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                stack.Push(obj7);
                                xmlStack.Push(objXml7);
                            }
                            break;
                        }
                    case OpCode.LookupSymbol:
                        {
                            int num8 = reader.ReadUInt16();
                            SymbolReference symbolRef = symbolReferenceTable[num8];

                            object obj8 = context.ReadSymbol(symbolRef);
                            var objXml8 = GenerateXmlRepresentation(obj8);

                            stack.Push(obj8);
                            xmlStack.Push(objXml8);

                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.WriteSymbol:
                    case OpCode.WriteSymbolPeek:
                        {
                            object value = (opCode == OpCode.WriteSymbolPeek) ? stack.Peek() : stack.Pop();
                            if (opCode == OpCode.WriteSymbol) xmlStack.Pop();
                            int num9 = reader.ReadUInt16();
                            SymbolReference symbolRef2 = symbolReferenceTable[num9];

                            context.WriteSymbol(symbolRef2, value);

                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.ClearSymbol:
                        {
                            int num10 = reader.ReadUInt16();
                            SymbolReference symbolRef3 = symbolReferenceTable[num10];
                            context.ClearSymbol(symbolRef3);
                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.PropertyInitialize:
                    case OpCode.PropertyInitializeIndirect:
                        {
                            bool isPropInitIndirect = opCode == OpCode.PropertyInitializeIndirect;
                            TypeSchema typeSchema9 = null;
                            if (isPropInitIndirect)
                            {
                                typeSchema9 = (TypeSchema)stack.Pop();
                                xmlStack.Pop();
                            }
                            int num11 = reader.ReadUInt16();
                            PropertySchema propertySchema = importTables.PropertyImports[num11];
                            object propValue = stack.Pop();
                            object destObj = stack.Pop();
                            XmlNode propValueXml = xmlStack.Pop();
                            var destObjXml = (XmlElement)xmlStack.Pop();
                            ReportErrorOnNull(destObj, "Property Set", propertySchema.Name);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                if (isPropInitIndirect)
                                {
                                    PropertySchema propertySchema2 = typeSchema9.FindPropertyDeep(propertySchema.Name);
                                    if (propertySchema2 != propertySchema)
                                    {
                                        TypeSchema propertyType = propertySchema2.PropertyType;
                                        if (!propertyType.IsAssignableFrom(propValue))
                                        {
                                            string param = TypeSchema.NameFromInstance(propValue);
                                            ErrorManager.ReportError("Script runtime failure: Incompatible value for property '{0}' supplied (expecting values of type '{1}' but got '{2}') while constructing runtime replacement type '{3}' (original type '{4}')", propertySchema.Name, propertyType.Name, param, typeSchema9.Name, propertySchema.Owner.Name);
                                            result = ScriptError;
                                        }
                                        if (ErrorsDetected(watermark, ref result, ref flag))
                                        {
                                            break;
                                        }
                                    }
                                }

                                propertySchema.SetValue(ref destObj, propValue);
                                if (!IsDefaultValue(propValue))
                                    SetXmlPropValue(destObjXml, propertySchema.Name, propValueXml);

                                if (!ErrorsDetected(watermark, ref result, ref flag))
                                {
                                    stack.Push(destObj);
                                    xmlStack.Push(destObjXml);
                                }
                            }
                            break;
                        }
                    case OpCode.PropertyListAdd:
                        {
                            int propertyIndex = reader.ReadUInt16();
                            object value2 = stack.Pop();
                            XmlNode valueXml2 = xmlStack.Pop();
                            object collection = GetCollectionDecompile(stack.Peek(), importTables, propertyIndex, out var propertySchema);
                            ReportErrorOnNull(collection, "List Add");
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                ((IList)collection).Add(value2);
                                if (ErrorsDetected(watermark, ref result, ref flag))
                                {
                                }

                                // Add value to list
                                var destObjXml = xmlStack.Peek();
                                if (!IsDefaultValue(value2) && valueXml2 != null)
                                {
                                    if (propertySchema != null)
                                    {
                                        // Create element if needed
                                        if (destObjXml.SelectSingleNode(propertySchema.Name) is not XmlElement propXmlElem2)
                                        {
                                            propXmlElem2 = XmlDoc.CreateElement(propertySchema.Name);
                                            destObjXml.AppendChild(propXmlElem2);
                                        }
                                        propXmlElem2.AppendChild(valueXml2);
                                    }
                                    else
                                    {
                                        // Add straight to parent element
                                        var valueXmlElem2 = XmlDoc.CreateElement("String");
                                        valueXmlElem2.AppendChild(valueXml2);
                                        destObjXml.AppendChild(valueXmlElem2);
                                    }
                                }
                            }
                            break;
                        }
                    case OpCode.PropertyDictionaryAdd:
                        {
                            int propertyIndex2 = reader.ReadUInt16();
                            int index2 = reader.ReadUInt16();
                            string key = (string)constantsTable.Get(index2);
                            object value3 = stack.Pop();
                            XmlNode valueXml3 = xmlStack.Pop();
                            object collection2 = GetCollectionDecompile(stack.Peek(), importTables, propertyIndex2, out var propertySchema2);
                            ReportErrorOnNull(collection2, "Dictionary Add");
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                ((IDictionary)collection2)[key] = value3;
                                if (ErrorsDetected(watermark, ref result, ref flag))
                                {
                                }

                                if (!IsDefaultValue(value3) && valueXml3 != null)
                                {
                                    // Prepare value XML element
                                    if (valueXml3 is not XmlElement valueXmlElem3)
                                    {
                                        // Need to create an XML element from the node
                                        valueXmlElem3 = XmlDoc.CreateElement(value3.GetType().Name);
                                        valueXmlElem3.AppendChild(valueXml3);
                                    }

                                    // Add value to dictionary
                                    var destObjXml2 = xmlStack.Peek();
                                    // Create element if needed
                                    if (propertySchema2 != null)
                                    {
                                        if (destObjXml2.SelectSingleNode(propertySchema2.Name) is not XmlElement propXmlElem2)
                                        {
                                            propXmlElem2 = XmlDoc.CreateElement(propertySchema2.Name);
                                            destObjXml2.AppendChild(propXmlElem2);
                                        }
                                        propXmlElem2.AppendChild(valueXmlElem3);
                                    }
                                    valueXmlElem3.SetAttribute("Name", key);
                                }
                            }
                            break;
                        }
                    case OpCode.PropertyAssign:
                    case OpCode.PropertyAssignStatic:
                        {
                            int num12 = reader.ReadUInt16();
                            PropertySchema propertySchema3 = importTables.PropertyImports[num12];
                            object instance2 = null;
                            if (opCode == OpCode.PropertyAssign)
                            {
                                instance2 = stack.Pop();
                                ReportErrorOnNullOrDisposed(instance2, "Property Set", propertySchema3.Name, propertySchema3.Owner);
                                if (ErrorsDetected(watermark, ref result, ref flag))
                                {
                                    break;
                                }
                            }
                            object value4 = stack.Peek();
                            propertySchema3.SetValue(ref instance2, value4);

                            if (opCode == OpCode.PropertyAssign)
                            {
                                var xmlInstance2 = (XmlElement)xmlStack.Pop();
                                SetXmlPropValue(xmlInstance2, propertySchema3.Name, value4);
                            }

                            if (!ErrorsDetected(watermark, ref result, ref flag) && Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.PropertyGet:
                    case OpCode.PropertyGetPeek:
                    case OpCode.PropertyGetStatic:
                        {
                            int num13 = reader.ReadUInt16();
                            PropertySchema propertySchema4 = importTables.PropertyImports[num13];

                            object instance3 = null;

                            if (opCode != OpCode.PropertyGetStatic)
                            {
                                bool pop = opCode == OpCode.PropertyGet;
                                instance3 = pop ? stack.Pop() : stack.Peek();
                                if (pop) xmlStack.Pop();

                                ReportErrorOnNullOrDisposed(instance3, "Property Get", propertySchema4.Name, propertySchema4.Owner);
                                if (ErrorsDetected(watermark, ref result, ref flag))
                                {
                                    break;
                                }
                            }
                            object value5 = propertySchema4.GetValue(instance3);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                stack.Push(value5);
                                xmlStack.Push(GenerateXmlRepresentation(value5));
                                if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.MethodInvoke:
                    case OpCode.MethodInvokePeek:
                    case OpCode.MethodInvokeStatic:
                    case OpCode.MethodInvokePushLastParam:
                    case OpCode.MethodInvokeStaticPushLastParam:
                        {
                            int num14 = reader.ReadUInt16();
                            MethodSchema methodSchema = importTables.MethodImports[num14];
                            int j = methodSchema.ParameterTypes.Length;
                            object[] array2 = ParameterListAllocator.Alloc(j);
                            for (j--; j >= 0; j--)
                            {
                                array2[j] = stack.Pop();
                                xmlStack.Pop();
                            }
                            object instance4 = null;
                            bool flag3 = opCode != OpCode.MethodInvokeStatic && opCode != OpCode.MethodInvokeStaticPushLastParam;
                            bool flag4 = opCode == OpCode.MethodInvokePeek;
                            bool flag5 = opCode == OpCode.MethodInvokePushLastParam || opCode == OpCode.MethodInvokeStaticPushLastParam;
                            if (flag3)
                            {
                                if (!flag4)
                                {
                                    instance4 = stack.Pop();
                                    xmlStack.Pop();
                                }
                                else
                                {
                                    instance4 = stack.Peek();
                                }
                                ReportErrorOnNullOrDisposed(instance4, "Method Invoke", methodSchema.Name, methodSchema.Owner);
                                if (ErrorsDetected(watermark, ref result, ref flag))
                                {
                                    break;
                                }
                            }

                            if (methodSchema.Name == "PlayOrPreview")
                                System.Diagnostics.Debugger.Break();

                            object obj11 = methodSchema.Invoke(instance4, array2);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                if (!flag5)
                                {
                                    if (methodSchema.ReturnType != VoidSchema.Type)
                                    {
                                        stack.Push(obj11);
                                        xmlStack.Push(GenerateXmlRepresentation(obj11));
                                    }
                                }
                                else
                                {
                                    var lastParam = array2[array2.Length - 1];
                                    stack.Push(lastParam);
                                    xmlStack.Push(GenerateXmlRepresentation(lastParam));
                                }
                                ParameterListAllocator.Free(array2);
                            }
                            break;
                        }
                    case OpCode.VerifyTypeCast:
                        {
                            int num15 = reader.ReadUInt16();
                            TypeSchema typeSchema10 = importTables.TypeImports[num15];
                            object obj12 = stack.Peek();
                            if (obj12 != null)
                            {
                                if (!typeSchema10.IsAssignableFrom(obj12))
                                {
                                    string param2 = TypeSchema.NameFromInstance(obj12);
                                    string name = typeSchema10.Name;
                                    ErrorManager.ReportError("Script runtime failure: Invalid type cast while attempting to cast an instance with a runtime type of '{0}' to '{1}'", param2, name);
                                    result = ScriptError;
                                }
                                if (ErrorsDetected(watermark, ref result, ref flag))
                                {
                                }
                            }
                            else if (!typeSchema10.IsNullAssignable)
                            {
                                ReportErrorOnNull(obj12, "Verify Type Cast", typeSchema10.Name);
                                if (ErrorsDetected(watermark, ref result, ref flag))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.ConvertType:
                        {
                            int num16 = reader.ReadUInt16();
                            TypeSchema typeSchema11 = importTables.TypeImports[num16];
                            int num17 = reader.ReadUInt16();
                            TypeSchema fromType = importTables.TypeImports[num17];
                            object obj13 = stack.Pop();
                            var xmlObj13 = xmlStack.Pop();
                            ReportErrorOnNull(obj13, "Type Conversion", typeSchema11.Name);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                object obj14;
                                Result result2 = typeSchema11.TypeConverter(obj13, fromType, out obj14);
                                if (result2.Failed)
                                {
                                    ErrorManager.ReportError("Script runtime failure: Type conversion failed while attempting to convert to '{0}' ({1})", typeSchema11.Name, result2.Error);
                                }
                                if (!ErrorsDetected(watermark, ref result, ref flag))
                                {
                                    stack.Push(obj14);
                                    xmlStack.Push(GenerateXmlRepresentation(obj14));
                                }
                            }
                            break;
                        }
                    case OpCode.Operation:
                        {
                            int num18 = reader.ReadUInt16();
                            TypeSchema typeSchema12 = importTables.TypeImports[num18];
                            OperationType op = (OperationType)reader.ReadByte();
                            object right = null;
                            if (!TypeSchema.IsUnaryOperation(op))
                            {
                                right = stack.Pop();
                                xmlStack.Pop();
                            }
                            object left = stack.Pop();
                            xmlStack.Pop();
                            object obj15 = typeSchema12.PerformOperationDeep(left, right, op);
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                stack.Push(obj15);
                                xmlStack.Push(GenerateXmlRepresentation(obj15));
                                if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.IsCheck:
                        {
                            int num19 = reader.ReadUInt16();
                            TypeSchema typeSchema13 = importTables.TypeImports[num19];
                            object obj16 = stack.Pop();
                            var xmlObj16 = xmlStack.Pop();
                            bool value6 = false;
                            if (obj16 != null)
                            {
                                value6 = typeSchema13.IsAssignableFrom(obj16);
                            }
                            stack.Push(BooleanBoxes.Box(value6));
                            xmlStack.Push(GenerateXmlRepresentation(value6));
                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.As:
                        {
                            int num20 = reader.ReadUInt16();
                            TypeSchema typeSchema14 = importTables.TypeImports[num20];
                            object obj17 = stack.Peek();
                            if (obj17 != null && !typeSchema14.IsAssignableFrom(obj17))
                            {
                                stack.Pop();
                                stack.Push(null);
                                xmlStack.Pop();
                                xmlStack.Push(GenerateXmlRepresentation(null));
                            }
                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.TypeOf:
                        {
                            int num21 = reader.ReadUInt16();
                            TypeSchema obj18 = importTables.TypeImports[num21];
                            stack.Push(obj18);
                            xmlStack.Push(GenerateXmlRepresentation(obj18));
                            break;
                        }
                    case OpCode.PushNull:
                        stack.Push(null);
                        xmlStack.Push(GenerateXmlRepresentation(null));
                        break;
                    case OpCode.PushConstant:
                        {
                            int index3 = reader.ReadUInt16();
                            object obj19 = constantsTable.Get(index3);
                            stack.Push(obj19);
                            xmlStack.Push(GenerateXmlRepresentation(obj19));
                            break;
                        }
                    case OpCode.PushThis:
                        stack.Push(instance);
                        xmlStack.Push(GenerateXmlRepresentation(instance));
                        break;
                    case OpCode.DiscardValue:
                        stack.Pop();
                        xmlStack.Pop();
                        break;
                    case OpCode.ReturnValue:
                        {
                            object obj20 = stack.Pop();
                            xmlStack.Pop();
                            result = obj20;
                            flag = true;
                            break;
                        }
                    case OpCode.ReturnVoid:
                        result = VoidReturnValue;
                        flag = true;
                        break;
                    case OpCode.JumpIfFalse:
                    case OpCode.JumpIfFalsePeek:
                    case OpCode.JumpIfTruePeek:
                        {
                            uint currentOffset = reader.ReadUInt32();
                            object obj21 = (opCode == OpCode.JumpIfFalse) ? stack.Pop() : stack.Peek();
                            if (opCode == OpCode.JumpIfFalse) xmlStack.Pop();
                            bool flag6 = (bool)obj21;
                            bool flag7 = opCode == OpCode.JumpIfTruePeek;
                            Trace.IsCategoryEnabled(TraceCategory.Markup);
                            if (flag7 == flag6)
                            {
                                reader.CurrentOffset = currentOffset;
                                if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.JumpIfDictionaryContains:
                        {
                            ushort propertyIndex3 = reader.ReadUInt16();
                            ushort index4 = reader.ReadUInt16();
                            uint currentOffset2 = reader.ReadUInt32();
                            string key2 = (string)constantsTable.Get(index4);
                            object collection3 = GetCollection(stack.Peek(), importTables, propertyIndex3, out _);
                            ReportErrorOnNull(collection3, "Dictionary Contains");
                            if (!ErrorsDetected(watermark, ref result, ref flag))
                            {
                                bool flag8 = ((IDictionary)collection3).Contains(key2);
                                Trace.IsCategoryEnabled(TraceCategory.Markup);
                                if (flag8)
                                {
                                    reader.CurrentOffset = currentOffset2;
                                    if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                                    {
                                    }
                                }
                            }
                            break;
                        }
                    case OpCode.JumpIfNullPeek:
                        {
                            uint currentOffset3 = reader.ReadUInt32();
                            object obj22 = stack.Peek();
                            Trace.IsCategoryEnabled(TraceCategory.Markup);
                            if (obj22 == null)
                            {
                                reader.CurrentOffset = currentOffset3;
                                if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                                {
                                }
                            }
                            break;
                        }
                    case OpCode.Jump:
                        {
                            uint currentOffset4 = reader.ReadUInt32();
                            reader.CurrentOffset = currentOffset4;
                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.ConstructListenerStorage:
                        {
                            int listenerCount = reader.ReadUInt16();
                            if (instance.Listeners == null)
                            {
                                MarkupListeners markupListeners = new MarkupListeners(listenerCount);
                                markupListeners.DeclareOwner(instance);
                                instance.Listeners = markupListeners;
                            }
                            else
                            {
                                instance.Listeners.AddEntries(listenerCount);
                            }
                            if (Trace.IsCategoryEnabled(TraceCategory.Markup))
                            {
                            }
                            break;
                        }
                    case OpCode.Listen:
                    case OpCode.DestructiveListen:
                        {
                            int index5 = reader.ReadUInt16();
                            ListenerType listenerType = (ListenerType)reader.ReadByte();
                            int num22 = reader.ReadUInt16();
                            uint scriptOffset = reader.ReadUInt32();
                            uint refreshOffset = uint.MaxValue;
                            if (opCode == OpCode.DestructiveListen)
                            {
                                refreshOffset = reader.ReadUInt32();
                            }
                            string watch = null;
                            switch (listenerType)
                            {
                                case ListenerType.Property:
                                    watch = importTables.PropertyImports[num22].Name;
                                    break;
                                case ListenerType.Event:
                                    watch = importTables.EventImports[num22].Name;
                                    break;
                                case ListenerType.Symbol:
                                    watch = symbolReferenceTable[num22].Symbol;
                                    break;
                            }
                            object obj23 = stack.Peek();
                            if (obj23 != null)
                            {
                                INotifyObject notifier = (INotifyObject)obj23;
                                Trace.IsCategoryEnabled(TraceCategory.Markup);
                                MarkupListeners listeners = instance.Listeners;
                                listeners.RefreshListener(index5, notifier, watch, instance, scriptOffset, refreshOffset);
                            }
                            else
                            {
                                Trace.IsCategoryEnabled(TraceCategory.Markup);
                            }
                            break;
                        }
                    case OpCode.EnterDebugState:
                        {
                            int breakpointIndex = reader.ReadInt32();
                            if (MarkupSystem.IsDebuggingEnabled(2))
                            {
                                wasInDebugState = MarkupDebugHelper.EnterDebugState(wasInDebugState, loadResult, breakpointIndex, instance.Storage);
                            }
                            break;
                        }
                }

                if (stack.Count != xmlStack.Count)
                    throw new InvalidOperationException(
                        $"Invalid stacks, stack:{stack.Count} != xmlStack{xmlStack.Count}! " +
                        $"Check implementations for {opCode}");
            }
            while (stack.Count > count)
            {
                stack.Pop();
                xmlStack.Pop();
            }

            CleanUpXmlDoc();
            Application.DebugSettings.DecompileResults.Add(new(loadResult.Uri, XmlDoc));
            return result;
        }

        // Token: 0x06000F25 RID: 3877 RVA: 0x0002ADF0 File Offset: 0x00029DF0
        private static object GetCollectionDecompile(object stackInstance, MarkupImportTables importTables, int propertyIndex, out PropertySchema prop)
        {
            object result = null;
            prop = null;
            if (propertyIndex == 65535)
            {
                result = stackInstance;
            }
            else
            {
                PropertySchema propertySchema = importTables.PropertyImports[propertyIndex];
                ReportErrorOnNull(stackInstance, "Property Get", propertySchema.Name);
                if (stackInstance != null)
                {
                    result = propertySchema.GetValue(stackInstance);
                    prop = propertySchema;
                }
            }
            return result;
        }

        private static XmlNode GenerateXmlRepresentation(object obj, int recursionLevel = 5)
        {
            if (obj == null || recursionLevel < 0)
            {
                return null;
            }

            var objType = obj.GetType();

            if (objType.IsPrimitive || objType.IsEnum || objType == typeof(string))
            {
                return XmlDoc.CreateTextNode(obj.ToString());
            }
            else if (obj is AssemblyObjectProxyHelper.IAssemblyProxyObject objProxy
                && obj != objProxy.AssemblyObject)
            {
                // This is a proxy object, meaning it doesn't actually hold any values itself.
                return GenerateXmlRepresentation(objProxy.AssemblyObject, recursionLevel);
            }
            else if (typeof(IEnumerable).IsAssignableFrom(objType))
            {
                // This is a list or array
                var objXml = XmlDoc.CreateElement("List");
                foreach (object item in obj as IEnumerable)
                {
                    var itemXml = GenerateXmlRepresentation(item, recursionLevel);
                    if (itemXml != null)
                        objXml.AppendChild(itemXml);
                }
                return objXml;
            }
            else
            {
                var objXml = XmlDoc.CreateElement(objType.Name);

                // Use reflection to recursively generate XML representations for each property
                foreach (System.Reflection.PropertyInfo prop in objType.GetProperties())
                {
                    if (!prop.CanWrite || !prop.CanRead)
                        continue;

                    try
                    {
                        object value = prop.GetValue(obj, null);
                        if (IsDefaultValue(value))
                            continue;

                        SetXmlPropValue(objXml, prop.Name, value, recursionLevel - 1);
                    }
                    catch
                    {
                        // Ignore errors, sometimes things aren't initialized yet
                        continue;
                    }
                }

                return objXml;
            }
        }

        private static void SetXmlPropValue(XmlElement objXml, string propName, object value, int recursionLevel = 10)
        {
            var valueXml = GenerateXmlRepresentation(value, recursionLevel);
            SetXmlPropValue(objXml, propName, valueXml);
        }

        private static void SetXmlPropValue(XmlElement objXml, string propName, XmlNode valueXml)
        {
            if (valueXml is XmlElement propValueXml)
            {
                var propXml = XmlDoc.CreateElement(propName);
                propXml.AppendChild(propValueXml);
                objXml.AppendChild(propXml);
            }
            else if (valueXml != null)
            {
                // Primitive type, set as attribute
                objXml.SetAttribute(propName, valueXml.InnerText);
            }
        }

        private static bool IsDefaultValue(object value)
        {
            if (value == null)
                return true;

            var type = value.GetType();
            object defaultValue = type.IsValueType ? Activator.CreateInstance(type) : null;
            return value?.Equals(defaultValue) ?? true;
        }

        private static void CleanUpXmlDoc()
        {
            XmlNamespaceManager nsManager = new XmlNamespaceManager(XmlDoc.NameTable);
            var hosts = XmlDoc.DocumentElement.SelectNodes("*//Host", nsManager);
            foreach (XmlNode node in hosts)
            {
                if (!(node is XmlElement host))
                    continue;

                if (host.Attributes.Count == 1 && host.HasAttribute("Name"))
                {
                    string uiElemName = host.GetAttribute("Name");
                    nsManager.AddNamespace("me", "Me");
                    XmlDoc.DocumentElement.SetAttribute("xmlns:me", "Me");

                    XmlElement uiElem = XmlDoc.CreateElement("me", uiElemName, "Me");
                    host.ParentNode.ReplaceChild(uiElem, host);
                }
            }
        }
    }
}
