| 837 | |
| 838 | |
| 839 | void FFunctionBuildList::Build() |
| 840 | { |
| 841 | VMDisassemblyDumper disasmdump(VMDisassemblyDumper::Overwrite); |
| 842 | |
| 843 | for (auto &item : mItems) |
| 844 | { |
| 845 | // [Player701] Do not emit code for abstract functions |
| 846 | bool isAbstract = item.Func->Variants[0].Implementation->VarFlags & VARF_Abstract; |
| 847 | if (isAbstract) continue; |
| 848 | |
| 849 | assert(item.Code != NULL); |
| 850 | |
| 851 | // We don't know the return type in advance for anonymous functions. |
| 852 | FCompileContext ctx(item.CurGlobals, item.Func, item.Func->SymbolName == NAME_None ? nullptr : item.Func->Variants[0].Proto, item.FromDecorate, item.StateIndex, item.StateCount, item.Lump, item.Version); |
| 853 | |
| 854 | // Allocate registers for the function's arguments and create local variable nodes before starting to resolve it. |
| 855 | VMFunctionBuilder buildit(item.Func->GetImplicitArgs()); |
| 856 | for (unsigned i = 0; i < item.Func->Variants[0].Proto->ArgumentTypes.Size(); i++) |
| 857 | { |
| 858 | auto type = item.Func->Variants[0].Proto->ArgumentTypes[i]; |
| 859 | auto name = item.Func->Variants[0].ArgNames[i]; |
| 860 | auto flags = item.Func->Variants[0].ArgFlags[i]; |
| 861 | // this won't get resolved and won't get emitted. It is only needed so that the code generator can retrieve the necessary info about this argument to do its work. |
| 862 | auto local = new FxLocalVariableDeclaration(type, name, nullptr, flags, FScriptPosition()); |
| 863 | if (!(flags & VARF_Out)) local->RegNum = buildit.Registers[type->GetRegType()].Get(type->GetRegCount()); |
| 864 | else local->RegNum = buildit.Registers[REGT_POINTER].Get(1); |
| 865 | ctx.FunctionArgs.Push(local); |
| 866 | } |
| 867 | |
| 868 | FScriptPosition::StrictErrors = !item.FromDecorate || strictdecorate; |
| 869 | item.Code = item.Code->Resolve(ctx); |
| 870 | // If we need extra space, load the frame pointer into a register so that we do not have to call the wasteful LFP instruction more than once. |
| 871 | if (item.Function->ExtraSpace > 0) |
| 872 | { |
| 873 | buildit.FramePointer = ExpEmit(&buildit, REGT_POINTER); |
| 874 | buildit.FramePointer.Fixed = true; |
| 875 | buildit.Emit(OP_LFP, buildit.FramePointer.RegNum); |
| 876 | } |
| 877 | |
| 878 | // Make sure resolving it didn't obliterate it. |
| 879 | if (item.Code != nullptr) |
| 880 | { |
| 881 | if (!item.Code->CheckReturn()) |
| 882 | { |
| 883 | if (ctx.ReturnProto == nullptr || !ctx.ReturnProto->ReturnTypes.Size()) |
| 884 | { |
| 885 | auto newcmpd = new FxCompoundStatement(item.Code->ScriptPosition); |
| 886 | newcmpd->Add(item.Code); |
| 887 | newcmpd->Add(new FxReturnStatement(nullptr, item.Code->ScriptPosition)); |
| 888 | item.Code = newcmpd->Resolve(ctx); |
| 889 | } |
| 890 | else |
| 891 | { |
| 892 | item.Code->ScriptPosition.Message(MSG_ERROR, "Missing return statement in %s", item.PrintableName.GetChars()); |
| 893 | continue; |
| 894 | } |
| 895 | } |
| 896 |
no test coverage detected