Beispiel #1
0
        private static void InternalConvertSetupExecutionFrame(
            CodeTextWriter tw,
            IExtractContextHost extractContext,
            PreparedMethodInformation preparedMethod,
            ILocalVariableInformation[] objRefEntries,
            ILocalVariableInformation[] valueEntries,
            DebugInformationWriteController debugInformationController)
        {
            tw.WriteLine("//-------------------");
            tw.WriteLine("// [3-5] Setup execution frame:");
            tw.SplitLine();

            // Important NULL assigner (p = NULL):
            //   Because these variables are pointer (of object reference 'O' type).
            //   So GC will traverse these variables just setup the stack frame.
            debugInformationController.WriteInformationBeforeCode(tw);
            tw.WriteLine(
                "{0}_EXECUTION_FRAME__ frame__ =",
                preparedMethod.Method.CLanguageFunctionName);
            using (var __ = tw.Shift())
            {
                if (valueEntries.Length >= 1)
                {
                    tw.WriteLine(
                        "{{ NULL, {0}, {1}, {2} }};",
                        objRefEntries.Length,
                        valueEntries.Length,
                        string.Join(
                            ", ",
                            objRefEntries.Select(___ => "NULL").
                            Concat(valueEntries.
                                   Select(valueEntry =>
                                          string.Format(
                                              "il2c_typeof({0}), NULL",
                                              valueEntry.TargetType.MangledUniqueName)))));
                }
                else
                {
                    // Make short initializer expression if value type not included,
                    // maybe C compiler makes better code.
                    tw.WriteLine(
                        "{{ NULL, {0} }};",
                        objRefEntries.Length);
                }
            }

            foreach (var valueEntry in valueEntries)
            {
                debugInformationController.WriteInformationBeforeCode(tw);
                tw.WriteLine(
                    "frame__.{0}_value_ptr__ = &{0};",
                    extractContext.GetSymbolName(valueEntry));
            }

            debugInformationController.WriteInformationBeforeCode(tw);
            tw.WriteLine("il2c_link_execution_frame(&frame__);");
            tw.SplitLine();
        }
Beispiel #2
0
        private static void InternalConvertExecutionFrame(
            CodeTextWriter tw,
            IExtractContextHost extractContext,
            PreparedMethodInformation preparedMethod,
            ILocalVariableInformation[] objRefEntries,
            ILocalVariableInformation[] valueEntries)
        {
            tw.WriteLine("//-------------------");
            tw.WriteLine("// [3-7] Declare execution frame:");
            tw.SplitLine();

            tw.WriteLine(
                "typedef struct {0}_EXECUTION_FRAME_DECL",
                preparedMethod.Method.CLanguageFunctionName);
            tw.WriteLine("{");

            using (var _ = tw.Shift())
            {
                tw.WriteLine("const IL2C_EXECUTION_FRAME* pNext__;");
                tw.WriteLine("const uint16_t objRefCount__;");
                tw.WriteLine("const uint16_t valueCount__;");

                if (objRefEntries.Length >= 1)
                {
                    tw.WriteLine("//-------------------- objref");
                    foreach (var objRefEntry in objRefEntries)
                    {
                        tw.WriteLine(
                            "{0} {1};",
                            objRefEntry.TargetType.CLanguageTypeName,
                            extractContext.GetSymbolName(objRefEntry));
                    }
                }

                if (valueEntries.Length >= 1)
                {
                    tw.WriteLine("//-------------------- value type");
                    foreach (var valueEntry in valueEntries)
                    {
                        var name = extractContext.GetSymbolName(valueEntry);
                        tw.WriteLine(
                            "const IL2C_RUNTIME_TYPE {0}_type__;",
                            name);
                        tw.WriteLine(
                            "const {0}* {1}_value_ptr__;",
                            valueEntry.TargetType.CLanguageTypeName,
                            name);
                    }
                }
            }

            tw.WriteLine(
                "}} {0}_EXECUTION_FRAME__;",
                preparedMethod.Method.CLanguageFunctionName);
            tw.SplitLine();
        }
Beispiel #3
0
        private static void InternalConvertFromFunction(
            CodeTextWriter tw,
            IExtractContextHost extractContext,
            PreparedMethodInformation preparedMethod,
            DebugInformationOptions debugInformationOption)
        {
            var locals = preparedMethod.Method.LocalVariables;

            tw.SplitLine();
            tw.WriteLine("///////////////////////////////////////");
            tw.WriteLine(
                "// [3] {0}{1}",
                preparedMethod.Method.IsVirtual ? "Virtual: " : string.Empty,
                preparedMethod.Method.FriendlyName);

            var codeStream = preparedMethod.Method.CodeStream;

            // Write exception filters:
            if (codeStream.ExceptionHandlers.Length >= 1)
            {
                tw.SplitLine();
                tw.WriteLine("//-------------------");
                tw.WriteLine("// [3-1] Exception filters:");
                tw.SplitLine();

                for (var handlerIndex = 0;
                     handlerIndex < codeStream.ExceptionHandlers.Length;
                     handlerIndex++)
                {
                    var handler = codeStream.ExceptionHandlers[handlerIndex];

                    var filterName = string.Format(
                        "{0}_ExceptionFilter{1}__",
                        preparedMethod.Method.CLanguageFunctionName,
                        handlerIndex);
                    tw.WriteLine(
                        "static int16_t {0}(System_Exception* ex)",
                        filterName);
                    tw.WriteLine("{");

                    using (var _ = tw.Shift())
                    {
                        tw.WriteLine("il2c_assert(ex != NULL);");

                        for (var catchHandlerIndex = 0;
                             catchHandlerIndex < handler.CatchHandlers.Length;
                             catchHandlerIndex++)
                        {
                            var catchHandler = handler.CatchHandlers[catchHandlerIndex];
                            if (catchHandler.CatchHandlerType == ExceptionCatchHandlerTypes.Catch)
                            {
                                tw.WriteLine(
                                    "if (il2c_isinst__(ex, il2c_typeof({0}))) return {1};",
                                    catchHandler.CatchType.MangledName,
                                    catchHandlerIndex + 1);
                            }
                        }

                        // Write finally block index if contains.
                        var finallyHandler = handler.CatchHandlers.
                                             Select((catchHandler, index) => new { catchHandler, index }).
                                             FirstOrDefault(entry => entry.catchHandler.CatchHandlerType == ExceptionCatchHandlerTypes.Finally);
                        if (finallyHandler != null)
                        {
                            tw.WriteLine("return IL2C_FILTER_FINALLY;  // Not matched (will go to finally)");
                        }
                        else
                        {
                            tw.WriteLine("return IL2C_FILTER_NOMATCH;  // Not matched");
                        }
                    }

                    tw.WriteLine("}");
                }
            }

            // Start function:
            tw.SplitLine();
            tw.WriteLine("//-------------------");
            tw.WriteLine("// [3-2] Function body:");
            tw.SplitLine();
            tw.WriteLine(preparedMethod.Method.CLanguageFunctionPrototype);
            tw.WriteLine("{");

            using (var _ = tw.Shift())
            {
                if (!preparedMethod.Method.IsStatic)
                {
                    tw.WriteLine("il2c_assert(this__ != NULL);");
                    tw.SplitLine();
                }

                var localDefinitions = preparedMethod.Method.LocalVariables.
                                       Where(local => !local.TargetType.IsReferenceType).
                                       ToArray();
                if (localDefinitions.Length >= 1)
                {
                    tw.WriteLine("//-------------------");
                    tw.WriteLine("// [3-3] Local variables (not objref):");
                    tw.SplitLine();

                    foreach (var local in localDefinitions)
                    {
                        // HACK: The local variables mark to "volatile."
                        //   Because the gcc misread these variables calculated statically (or maybe assigned to the registers)
                        //   at compile time with optimization.
                        //   It will cause the strange results for exception handling (with sjlj.)
                        tw.WriteLine(
                            "{0}{1} {2};",
                            (codeStream.ExceptionHandlers.Length >= 1) ? "volatile " : string.Empty,
                            local.TargetType.CLanguageTypeName,
                            extractContext.GetSymbolName(local));
                    }

                    tw.SplitLine();
                }

                var stackDefinitions = preparedMethod.Stacks.
                                       Where(stack => !stack.TargetType.IsReferenceType).
                                       ToArray();
                if (stackDefinitions.Length >= 1)
                {
                    tw.WriteLine("//-------------------");
                    tw.WriteLine("// [3-4] Evaluation stacks (not objref):");
                    tw.SplitLine();

                    foreach (var stack in stackDefinitions)
                    {
                        tw.WriteLine(
                            "{0} {1};",
                            stack.TargetType.CLanguageTypeName,
                            extractContext.GetSymbolName(stack));
                    }

                    tw.SplitLine();
                }

                var objRefEntries = locals.
                                    Concat(preparedMethod.Stacks).
                                    Where(v => v.TargetType.IsReferenceType). // Only objref
                                    ToArray();
                if (objRefEntries.Length >= 1)
                {
                    tw.WriteLine("//-------------------");
                    tw.WriteLine("// [3-5] Setup execution frame:");
                    tw.SplitLine();

                    tw.WriteLine(
                        "struct {0}_EXECUTION_FRAME__",
                        preparedMethod.Method.CLanguageFunctionName);
                    tw.WriteLine("{");

                    using (var __ = tw.Shift())
                    {
                        tw.WriteLine("uint8_t objRefCount__;");
                        tw.WriteLine("uint8_t objRefRefCount__;");
                        tw.WriteLine("IL2C_EXECUTION_FRAME* pNext__;");

                        foreach (var objRefEntry in objRefEntries)
                        {
                            tw.WriteLine(
                                "{0} {1};",
                                objRefEntry.TargetType.CLanguageTypeName,
                                extractContext.GetSymbolName(objRefEntry));
                        }
                    }

                    // Important NULL assigner (p = NULL):
                    //   Because these variables are pointer (of object reference 'O' type).
                    //   So GC will traverse these variables just setup the stack frame.
                    // TODO: https://github.com/kekyo/IL2C/issues/12
                    tw.WriteLine("}} frame__ = {{ {0}, 0 }};", objRefEntries.Length);
                    tw.WriteLine("il2c_link_execution_frame(&frame__);");
                    tw.SplitLine();
                }

                tw.WriteLine("//-------------------");
                tw.WriteLine("// [3-6] IL body:");
                tw.SplitLine();

                // Set symbol prefix to make valid access variables.
                using (var __ = extractContext.BeginLocalVariablePrefix(
                           local => local.TargetType.IsReferenceType ? "frame__." : null))
                {
                    // Construct exception handler controller.
                    var exceptionHandlerController = new ExceptionHandlerController(
                        codeStream.ExceptionHandlers,
                        (handler, handlerIndex, nestedIndex) =>
                    {
                        var nestedIndexName = string.Format("nest{0}", nestedIndex);
                        extractContext.SetNestedExceptionFrameIndexName(nestedIndexName);

                        // Reached try block:
                        var filterName = string.Format(
                            "{0}_ExceptionFilter{1}__",
                            preparedMethod.Method.CLanguageFunctionName,
                            handlerIndex);
                        tw.WriteLine("il2c_try({0}, {1})", nestedIndexName, filterName);
                        tw.WriteLine("{");
                        tw.Shift();
                    },
                        (handler, handlerIndex, nestedIndex) =>
                    {
                        // Reached try end block:
                        tw.Shift(-1);
                        tw.WriteLine("}");
                    },
                        (handler, handlerIndex, nestedIndex, catchHandler, catchHandlerIndex) =>
                    {
                        var nestedIndexName = extractContext.GetExceptionNestedFrameIndexName();
                        switch (catchHandler.CatchHandlerType)
                        {
                        case ExceptionCatchHandlerTypes.Catch:
                            // Reached catch block:
                            tw.WriteLine(
                                "il2c_catch({0}, {1}, {2})  // catch ({3})",
                                nestedIndexName,
                                catchHandlerIndex + 1,
                                extractContext.GetSymbolName(preparedMethod.CatchVariables[catchHandler.CatchStart]),
                                catchHandler.CatchType.MangledName);
                            break;

                        case ExceptionCatchHandlerTypes.Finally:
                            // Reached finally block:
                            tw.WriteLine("il2c_finally({0})", nestedIndexName);
                            break;
                        }
                        tw.WriteLine("{");
                        tw.Shift();
                    },
                        (handler, handlerIndex, nestedIndex, catchHandler, catchHandlerIndex) =>
                    {
                        // Reached catch end block:
                        tw.Shift(-1);
                        tw.WriteLine("}");
                    },
                        (handler, handlerIndex, nestedIndex, parentHandler, parentHandlerIndex, parentNestedIndex) =>
                    {
                        var nestedIndexName       = extractContext.GetExceptionNestedFrameIndexName();
                        var parentNestedIndexName = (parentNestedIndex >= 0) ? string.Format("nest{0}", parentNestedIndex) : null;

                        // Write leave bind expressions if needed.
                        // Extract the continuation fromOffset inside at mostly inner exception handler.
                        var bindEntries =
                            preparedMethod.LeaveContinuations.
                            SelectMany(entry => codeStream.ExceptionHandlers.
                                       // nested exception handlers: inner --> outer
                                       Reverse().
                                       // Is this handler contains leave continuation target?
                                       Where(h => entry.Value.fromOffsets.Any(offset => h.ContainsOffset(offset))).
                                       // Found.
                                       Select(h => new { handler = h, continuationIndex = entry.Key, entry.Value.targetOffset })).
                            // ... is current handler?
                            Where(entry => entry.handler.Equals(handler)).
                            ToArray();
                        if (bindEntries.Length >= 1)
                        {
                            tw.WriteLine("il2c_leave_to({0})", nestedIndexName);
                            tw.WriteLine("{");
                            using (var ___ = tw.Shift())
                            {
                                foreach (var bind in bindEntries)
                                {
                                    if ((parentNestedIndex < 0) ||
                                        codeStream.ExceptionHandlers[parentNestedIndex].ContainsOffset(bind.targetOffset))
                                    {
                                        var labelName = preparedMethod.LabelNames[bind.targetOffset];
                                        tw.WriteLine(
                                            "il2c_leave_bind({0}, {1}, {2});",
                                            nestedIndexName,
                                            bind.continuationIndex,
                                            labelName);
                                    }
                                    else
                                    {
                                        tw.WriteLine(
                                            "il2c_leave_through({0}, {1}, {2});",
                                            nestedIndexName, bind.continuationIndex, parentNestedIndexName);
                                    }
                                }
                            }
                            tw.WriteLine("}");
                        }

                        // Reached end of entire try block.
                        tw.WriteLine("il2c_end_try({0});", nestedIndexName);

                        extractContext.SetNestedExceptionFrameIndexName(parentNestedIndexName);
                    });

                    // Traverse code fragments.
                    var canWriteSequencePoint = true;
                    foreach (var ci in codeStream)
                    {
                        // 1: Update the exception handler controller.
                        //    (Will write exception related sentences.)
                        exceptionHandlerController.Update(ci);

                        // 2: Write label if available and used.
                        if (preparedMethod.LabelNames.TryGetValue(ci.Offset, out var labelName))
                        {
                            using (var ___ = tw.Shift(-1))
                            {
                                tw.WriteLine("{0}:", labelName);
                            }
                        }

                        // 3: Write the line preprocessor directive if available.
                        if (canWriteSequencePoint && ci.Debug.Any())
                        {
                            var sp = ci.Debug.First();
                            switch (debugInformationOption)
                            {
                            case DebugInformationOptions.Full:
                                tw.Parent.WriteLine(
                                    "#line {0} \"{1}\"",
                                    sp.Line,
                                    sp.Path.Replace("\\", "\\\\"));
                                break;

                            case DebugInformationOptions.CommentOnly:
                                tw.Parent.WriteLine(
                                    "/* {0}({1}): */",
                                    sp.Path.Replace("\\", "\\\\"),
                                    sp.Line);
                                break;
                            }

                            canWriteSequencePoint = false;
                        }

                        // 4: Generate source code fragments and write.
                        if (debugInformationOption != DebugInformationOptions.None)
                        {
                            // Write debugging information.
                            tw.WriteLine(
                                "/* {0} */",
                                ci);
                        }

                        var sourceCodes = preparedMethod.Generators[ci.Offset](extractContext);
                        foreach (var sourceCode in sourceCodes)
                        {
                            // Dirty hack:
                            //   Write unlink execution frame code if cause exiting method.
                            if (sourceCode.StartsWith("return") &&
                                (objRefEntries.Length >= 1))
                            {
                                tw.WriteLine(
                                    "il2c_unlink_execution_frame(&frame__);");
                            }

                            tw.WriteLine(
                                "{0};",
                                sourceCode);

                            canWriteSequencePoint = true;
                        }
                    }

                    if (!exceptionHandlerController.IsFinished)
                    {
                        throw new InvalidProgramSequenceException(
                                  "Invalid exception handler range. MethodName={0}, ExceptionHandlers=[{1}]",
                                  preparedMethod.Method.FriendlyName,
                                  string.Join(
                                      ",",
                                      codeStream.ExceptionHandlers.
                                      Select(handler => string.Format("[{0}]", handler))));
                    }
                }
            }

            tw.WriteLine("}");
            tw.SplitLine();
        }
Beispiel #4
0
        private static void InternalConvertFromFunction(
            CodeTextWriter tw,
            IExtractContextHost extractContext,
            PreparedMethodInformation preparedMethod,
            DebugInformationOptions debugInformationOption)
        {
            var locals = preparedMethod.Method.LocalVariables;

            tw.WriteLine("///////////////////////////////////////");
            tw.WriteLine(
                "// [3] {0}{1}",
                preparedMethod.Method.IsVirtual ? "Virtual: " : string.Empty,
                preparedMethod.Method.FriendlyName);
            tw.SplitLine();

            var codeStream    = preparedMethod.Method.CodeStream;
            var objRefEntries = locals.
                                Concat(preparedMethod.Stacks).
                                Where(v => v.TargetType.IsReferenceType). // Only objref
                                ToArray();
            var valueEntries = locals.
                               Concat(preparedMethod.Stacks).
                               Where(v => v.TargetType.IsValueType && v.TargetType.IsRequiredTraverse).
                               ToArray();

            // Write declaring exception handlers
            if (codeStream.ExceptionHandlers.Length >= 1)
            {
                InternalConvertExceptionFilter(
                    tw,
                    extractContext,
                    preparedMethod,
                    codeStream);
            }

            // Write declaring execution frame
            if ((objRefEntries.Length >= 1) || (valueEntries.Length >= 1))
            {
                InternalConvertExecutionFrame(
                    tw,
                    extractContext,
                    preparedMethod,
                    objRefEntries,
                    valueEntries);
            }

            // Make readable debugging comment, it was splitting and reducing same informations.
            var debugInformationController =
                new DebugInformationWriteController(
                    preparedMethod.Method,
                    debugInformationOption);

            // Start function:
            tw.WriteLine("//-------------------");
            tw.WriteLine("// [3-2] Function body:");
            tw.SplitLine();
            tw.WriteLine(preparedMethod.Method.CLanguageFunctionPrototype);
            tw.WriteLine("{");

            using (var _ = tw.Shift())
            {
                if (!preparedMethod.Method.IsStatic)
                {
                    debugInformationController.WriteInformationBeforeCode(tw);
                    tw.WriteLine("il2c_assert(this__ != NULL);");
                    tw.SplitLine();
                }

                var localDefinitions = preparedMethod.Method.LocalVariables.
                                       Where(local => !local.TargetType.IsReferenceType).
                                       ToArray();
                if (localDefinitions.Length >= 1)
                {
                    tw.WriteLine("//-------------------");
                    tw.WriteLine("// [3-3] Local variables (!objref):");
                    tw.SplitLine();

                    foreach (var local in localDefinitions)
                    {
                        var name = extractContext.GetSymbolName(local);

                        // HACK: The local variables mark to "volatile."
                        //   Because the gcc misread these variables calculated statically (or maybe assigned to the registers)
                        //   at compile time with optimization.
                        //   It will cause the strange results for exception handling (with sjlj.)

                        // We have to initialize the local variables.
                        if (local.TargetType.IsPrimitive ||
                            local.TargetType.IsPointer ||
                            local.TargetType.IsByReference)
                        {
                            debugInformationController.WriteInformationBeforeCode(tw);
                            tw.WriteLine(
                                "{0}{1} {2} = {3};",
                                (codeStream.ExceptionHandlers.Length >= 1) ? "volatile " : string.Empty,
                                local.TargetType.CLanguageTypeName,
                                name,
                                Utilities.GetCLanguageExpression(local.TargetType.InternalStaticEmptyValue));
                        }
                        else
                        {
                            Debug.Assert(local.TargetType.IsValueType);

                            debugInformationController.WriteInformationBeforeCode(tw);
                            tw.WriteLine(
                                "{0}{1} {2};",
                                (codeStream.ExceptionHandlers.Length >= 1) ? "volatile " : string.Empty,
                                local.TargetType.CLanguageTypeName,
                                name);

                            debugInformationController.WriteInformationBeforeCode(tw);
                            tw.WriteLine(
                                "memset({0}&{1}, 0x00, sizeof {1});",
                                (codeStream.ExceptionHandlers.Length >= 1) ? "(void*)" : string.Empty,
                                name);
                        }
                    }

                    tw.SplitLine();
                }

                var stackDefinitions = preparedMethod.Stacks.
                                       Where(stack => !stack.TargetType.IsReferenceType).
                                       ToArray();
                if (stackDefinitions.Length >= 1)
                {
                    tw.WriteLine("//-------------------");
                    tw.WriteLine("// [3-4] Evaluation stacks (!objref):");
                    tw.SplitLine();

                    foreach (var stack in stackDefinitions)
                    {
                        var name = extractContext.GetSymbolName(stack);

                        debugInformationController.WriteInformationBeforeCode(tw);
                        tw.WriteLine(
                            "{0} {1};",
                            stack.TargetType.CLanguageTypeName,
                            name);

                        // Note: We often don't have to initalize the evaluation stack variables.
                        //   Because these variables push value at first usage.
                        //   But the value type may contains objref field,
                        //   so we have to initialize for value type.
                        if (stack.TargetType.IsRequiredTraverse)
                        {
                            debugInformationController.WriteInformationBeforeCode(tw);
                            tw.WriteLine(
                                "memset(&{0}, 0, sizeof {0});",
                                name);
                        }
                    }

                    tw.SplitLine();
                }

                // Write doing setup execution frame
                if ((objRefEntries.Length >= 1) || (valueEntries.Length >= 1))
                {
                    InternalConvertSetupExecutionFrame(
                        tw,
                        extractContext,
                        preparedMethod,
                        objRefEntries,
                        valueEntries,
                        debugInformationController);
                }

                tw.WriteLine("//-------------------");
                tw.WriteLine("// [3-6] IL body:");
                tw.SplitLine();

                // Set symbol prefix to make valid access variables.
                using (var __ = extractContext.BeginLocalVariablePrefix(
                           local => local.TargetType.IsReferenceType ? "frame__." : null))
                {
                    // Construct exception handler controller.
                    var exceptionHandlerController = new ExceptionHandlerController(
                        codeStream.ExceptionHandlers,
                        (handler, handlerIndex, nestedIndex) =>
                    {
                        var nestedIndexName = string.Format("nest{0}", nestedIndex);
                        extractContext.SetNestedExceptionFrameIndexName(nestedIndexName);

                        // Reached try block:
                        var filterName = string.Format(
                            "{0}_ExceptionFilter{1}__",
                            preparedMethod.Method.CLanguageFunctionName,
                            handlerIndex);

                        debugInformationController.WriteInformationBeforeCode(tw);
                        tw.WriteLine("il2c_try({0}, {1})", nestedIndexName, filterName);

                        debugInformationController.WriteInformationBeforeCode(tw);
                        tw.WriteLine("{");
                        tw.Shift();
                    },
                        (handler, handlerIndex, nestedIndex) =>
                    {
                        // Reached try end block:
                        debugInformationController.WriteInformationBeforeCode(tw);
                        tw.Shift(-1);
                        tw.WriteLine("}");
                    },
                        (handler, handlerIndex, nestedIndex, catchHandler, catchHandlerIndex) =>
                    {
                        var nestedIndexName = extractContext.GetExceptionNestedFrameIndexName();
                        switch (catchHandler.CatchHandlerType)
                        {
                        case ExceptionCatchHandlerTypes.Catch:
                            // Reached catch block:
                            debugInformationController.WriteInformationBeforeCode(tw);
                            tw.WriteLine(
                                "il2c_catch({0}, {1}, {2})  // catch ({3})",
                                nestedIndexName,
                                catchHandlerIndex + 1,
                                extractContext.GetSymbolName(preparedMethod.CatchVariables[catchHandler.CatchStart]),
                                catchHandler.CatchType.MangledUniqueName);
                            break;

                        case ExceptionCatchHandlerTypes.Finally:
                            // Reached finally block:
                            debugInformationController.WriteInformationBeforeCode(tw);
                            tw.WriteLine("il2c_finally({0})", nestedIndexName);
                            break;
                        }
                        debugInformationController.WriteInformationBeforeCode(tw);
                        tw.WriteLine("{");
                        tw.Shift();
                    },
                        (handler, handlerIndex, nestedIndex, catchHandler, catchHandlerIndex) =>
                    {
                        // Reached catch end block:
                        debugInformationController.WriteInformationBeforeCode(tw);
                        tw.Shift(-1);
                        tw.WriteLine("}");
                    },
                        (handler, handlerIndex, nestedIndex, parentHandler, parentHandlerIndex, parentNestedIndex) =>
                    {
                        var nestedIndexName       = extractContext.GetExceptionNestedFrameIndexName();
                        var parentNestedIndexName = (parentNestedIndex >= 0) ? string.Format("nest{0}", parentNestedIndex) : null;

                        // Write leave bind expressions if needed.
                        // Extract the continuation fromOffset inside at mostly inner exception handler.
                        var bindEntries =
                            preparedMethod.LeaveContinuations.
                            SelectMany(entry => codeStream.ExceptionHandlers.
                                       // nested exception handlers: inner --> outer
                                       Reverse().
                                       // Is this handler contains leave continuation target?
                                       Where(h => entry.Value.fromOffsets.Any(offset => h.ContainsOffset(offset))).
                                       // Found.
                                       Select(h => new { handler = h, continuationIndex = entry.Key, entry.Value.targetOffset })).
                            // ... is current handler?
                            Where(entry => entry.handler.Equals(handler)).
                            ToArray();
                        if (bindEntries.Length >= 1)
                        {
                            debugInformationController.WriteInformationBeforeCode(tw);
                            tw.WriteLine("il2c_leave_to({0})", nestedIndexName);

                            debugInformationController.WriteInformationBeforeCode(tw);
                            tw.WriteLine("{");

                            using (var ___ = tw.Shift())
                            {
                                foreach (var bind in bindEntries)
                                {
                                    if ((parentNestedIndex < 0) ||
                                        codeStream.ExceptionHandlers[parentNestedIndex].ContainsOffset(bind.targetOffset))
                                    {
                                        var labelName = preparedMethod.LabelNames[bind.targetOffset];

                                        debugInformationController.WriteInformationBeforeCode(tw);
                                        tw.WriteLine(
                                            "il2c_leave_bind({0}, {1}, {2});",
                                            nestedIndexName,
                                            bind.continuationIndex,
                                            labelName);
                                    }
                                    else
                                    {
                                        debugInformationController.WriteInformationBeforeCode(tw);
                                        tw.WriteLine(
                                            "il2c_leave_through({0}, {1}, {2});",
                                            nestedIndexName, bind.continuationIndex, parentNestedIndexName);
                                    }
                                }
                            }

                            debugInformationController.WriteInformationBeforeCode(tw);
                            tw.WriteLine("}");
                        }

                        // Reached end of entire try block.
                        debugInformationController.WriteInformationBeforeCode(tw);
                        tw.WriteLine("il2c_end_try({0});", nestedIndexName);

                        extractContext.SetNestedExceptionFrameIndexName(parentNestedIndexName);
                    });

                    // Traverse code fragments.
                    foreach (var ci in codeStream)
                    {
                        debugInformationController.SetNextCode(ci);

                        // 1: Update the exception handler controller.
                        //    (Will write exception related sentences.)
                        exceptionHandlerController.Update(ci);

                        // 2: Write label if available and used.
                        if (preparedMethod.LabelNames.TryGetValue(ci.Offset, out var labelName))
                        {
                            using (var ___ = tw.Shift(-1))
                            {
                                tw.WriteLine("{0}:", labelName);
                            }
                        }

                        // 3: Write source code comment.
                        debugInformationController.WriteCodeComment(tw);

                        // 4: Generate source code fragments and write.
                        var sourceCodes = preparedMethod.Generators[ci.Offset](extractContext);
                        foreach (var sourceCode in sourceCodes)
                        {
                            // DIRTY HACK:
                            //   Write unlink execution frame code if cause exiting method.
                            if (sourceCode.StartsWith("return") &&
                                ((objRefEntries.Length >= 1) || (valueEntries.Length >= 1)))
                            {
                                debugInformationController.WriteInformationBeforeCode(tw);
                                tw.WriteLine(
                                    "il2c_unlink_execution_frame(&frame__);");
                            }

                            debugInformationController.WriteInformationBeforeCode(tw);
                            tw.WriteLine(
                                "{0};",
                                sourceCode);
                        }
                    }

                    // If last opcode is 'endfinally' and not emitted 'ret',
                    // can't finished for exceptionHandlerController.
                    // We can check and force update the TryFinish method for this situation.
                    exceptionHandlerController.TryFinish();

                    if (!exceptionHandlerController.IsFinished)
                    {
                        throw new InvalidProgramSequenceException(
                                  "Invalid exception handler range. MethodName={0}, ExceptionHandlers=[{1}]",
                                  preparedMethod.Method.FriendlyName,
                                  string.Join(
                                      ",",
                                      codeStream.ExceptionHandlers.
                                      Select(handler => string.Format("[{0}]", handler))));
                    }
                }
            }

            debugInformationController.WriteInformationBeforeCode(tw);
            tw.WriteLine("}");
            tw.SplitLine();
        }
Beispiel #5
0
        private static void InternalConvertExceptionFilter(
            CodeTextWriter tw,
            IExtractContextHost extractContext,
            PreparedMethodInformation preparedMethod,
            ICodeStream codeStream)
        {
            tw.WriteLine("//-------------------");
            tw.WriteLine("// [3-1] Exception filters:");
            tw.SplitLine();

            for (var handlerIndex = 0;
                 handlerIndex < codeStream.ExceptionHandlers.Length;
                 handlerIndex++)
            {
                var handler = codeStream.ExceptionHandlers[handlerIndex];

                var filterName = string.Format(
                    "{0}_ExceptionFilter{1}__",
                    preparedMethod.Method.CLanguageFunctionName,
                    handlerIndex);
                tw.WriteLine(
                    "static int16_t {0}(System_Exception* ex)",
                    filterName);
                tw.WriteLine("{");

                using (var _ = tw.Shift())
                {
                    tw.WriteLine("il2c_assert(ex != NULL);");

                    for (var catchHandlerIndex = 0;
                         catchHandlerIndex < handler.CatchHandlers.Length;
                         catchHandlerIndex++)
                    {
                        var catchHandler = handler.CatchHandlers[catchHandlerIndex];
                        if (catchHandler.CatchHandlerType == ExceptionCatchHandlerTypes.Catch)
                        {
                            tw.WriteLine(
                                "if (il2c_unlikely__(il2c_isinst__(ex, il2c_typeof({0})))) return {1};",
                                catchHandler.CatchType.MangledUniqueName,
                                catchHandlerIndex + 1);
                        }
                    }

                    // Write finally block index if contains.
                    var finallyHandler = handler.CatchHandlers.
                                         Select((catchHandler, index) => new { catchHandler, index }).
                                         FirstOrDefault(entry => entry.catchHandler.CatchHandlerType == ExceptionCatchHandlerTypes.Finally);
                    if (finallyHandler != null)
                    {
                        tw.WriteLine("return IL2C_FILTER_FINALLY;  // Not matched (will go to finally)");
                    }
                    else
                    {
                        tw.WriteLine("return IL2C_FILTER_NOMATCH;  // Not matched");
                    }
                }

                tw.WriteLine("}");
                tw.SplitLine();
            }
        }