소스 검색

feat: 增加尾调用优化错误回溯

SongZihuan 3 년 전
부모
커밋
51525aa0b4
3개의 변경된 파일145개의 추가작업 그리고 9개의 파일을 삭제
  1. 22 0
      src/core/__env.h
  2. 117 9
      src/core/env.c
  3. 6 0
      src/core/run.c

+ 22 - 0
src/core/__env.h

@@ -4,6 +4,7 @@
 
 typedef struct af_Core af_Core;
 typedef struct af_Activity af_Activity;
+typedef struct af_ActivityTrackBack af_ActivityTrackBack;
 typedef struct af_EnvVarSpace af_EnvVarSpace;
 typedef struct af_EnvVar af_EnvVar;
 typedef struct af_TopMsgProcess af_TopMsgProcess;
@@ -150,10 +151,31 @@ struct af_Activity {  // 活动记录器
 
             /* Import使用 */
             char *import_mark;
+
+            af_ActivityTrackBack *tb;
         };
     };
 };
 
+struct af_ActivityTrackBack {
+    /* 记录Activity尾调用优化的回溯信息 */
+    /* af_ActivityType不用记录, 因为必定是act_func */
+
+    FilePath file;
+    FileLine line;
+    enum af_ActivityStatus status;
+    bool return_first;
+    bool run_in_func;
+    bool is_macro_call;  // 宏函数隐式调用
+    bool is_gc_call;
+    bool is_literal;  // 处于字面量运算 意味着函数调用结束后会调用指定API
+    bool is_obj_func;  // 对象函数的调用
+    bool is_execution;
+    bool optimization;
+
+    struct af_ActivityTrackBack *next;
+};
+
 typedef void TopMsgProcessFunc(af_Message *msg, bool is_gc, af_Environment *env);
 NEW_DLC_SYMBOL(TopMsgProcessFunc, TopMsgProcessFunc);
 

+ 117 - 9
src/core/env.c

@@ -23,6 +23,11 @@ static void clearActivity(af_Activity *activity);
 static void freeMark(af_Activity *activity);
 static void newActivity(af_Code *bt, const af_Code *next, bool return_first, af_Environment *env);
 
+/* ActivityTrackBack 创建与释放 */
+static af_ActivityTrackBack *makeActivityTrackBack(af_Activity *activity);
+static af_ActivityTrackBack *freeActivityTrackBack(af_ActivityTrackBack *atb);
+static void freeAllActivityTrackBack(af_ActivityTrackBack *atb);
+
 /* 环境变量 创建与释放 */
 static af_EnvVar *makeEnvVar(char *name, char *data);
 static af_EnvVar *freeEnvVar(af_EnvVar *var);
@@ -53,6 +58,7 @@ static void freeAllErrorBacktracking(af_ErrorBacktracking *ebt);
 
 /* af_ErrorBacktracking 相关函数 */
 static char *getActivityInfoToBacktracking(af_Activity *activity);
+static char *getActivityTrackBackInfoToBacktracking(af_ActivityTrackBack *atb);
 static void fprintfNote(FILE *file, char *note);
 
 /* 内置顶层消息处理器 */
@@ -166,6 +172,7 @@ static af_Activity *makeActivity(af_Message *msg_up, af_VarSpaceListNode *vsl, a
     activity->var_list = vsl;
     activity->new_vs_count = 0;
     activity->belong = belong;
+    activity->line = 1;
     return activity;
 }
 
@@ -215,8 +222,8 @@ static af_Activity *makeGcActivity(gc_DestructList *dl, gc_DestructList **pdl, a
     activity->var_list = makeVarSpaceList(getProtectVarSpace(env));
     activity->new_vs_count = 1;
 
-    activity->file = strCopy("aFun-gc.aun.sys");
-    activity->line = 0;
+    activity->file = strCopy("gc.aun.sys");
+    activity->line = 1;
     activity->dl = dl;
     activity->pdl = pdl;
     activity->dl_next = dl;
@@ -245,6 +252,7 @@ static af_Activity *freeActivity(af_Activity *activity) {
             freeFuncInfo(activity->fi);
         freeAllLiteralData(activity->ld);
 
+        freeAllActivityTrackBack(activity->tb);
         free(activity->import_mark);
     }
 
@@ -289,8 +297,54 @@ static void clearActivity(af_Activity *activity) {
     /* mark在setFuncActivityToNormal被清理*/
     /* 只有FuncBody执行到最后一个(意味着Mark被清理)后才会有尾调用优化 */
     activity->mark = NULL;
-    free(activity->file);
-    activity->line = 0;
+
+    /* file和line都遗留 */
+}
+
+/*
+ * 函数名: af_ActivityTrackBack
+ * 目标: 把 activity 上的内容转移到新的 af_ActivityTrackBack 上
+ */
+static af_ActivityTrackBack *makeActivityTrackBack(af_Activity *activity) {
+    af_ActivityTrackBack *atb = calloc(1, sizeof(af_ActivityTrackBack));
+#define EXCHANGE(name) (atb->name = activity->name)
+    EXCHANGE(file);
+    atb->file = strCopy(activity->file);
+    EXCHANGE(status);
+    EXCHANGE(line);
+    EXCHANGE(return_first);
+    EXCHANGE(run_in_func);
+    EXCHANGE(is_macro_call);
+    EXCHANGE(is_gc_call);
+    EXCHANGE(is_literal);
+    EXCHANGE(is_obj_func);
+    EXCHANGE(is_execution);
+    EXCHANGE(optimization);
+#undef EXCHANGE
+    return atb;
+}
+
+static af_ActivityTrackBack *freeActivityTrackBack(af_ActivityTrackBack *atb) {
+    af_ActivityTrackBack *next = atb->next;
+    free(atb->file);
+    free(atb);
+    return next;
+}
+
+static void freeAllActivityTrackBack(af_ActivityTrackBack *atb) {
+    while (atb != NULL)
+        atb = freeActivityTrackBack(atb);
+}
+
+/*
+ * 函数名: tailCallActivity
+ * 目标: 记录ActivityTrackBack然后清除Activity
+ */
+static void tailCallActivity(af_Activity *activity) {
+    af_ActivityTrackBack *atb = makeActivityTrackBack(activity);
+    atb->next = activity->tb;
+    activity->tb = atb;
+    clearActivity(activity);
 }
 
 /*
@@ -309,7 +363,7 @@ void setActivityBtTop(af_Code *bt_top, af_Activity *activity) {
             activity->file = strCopy(bt_top->path);
         }
     } else
-        activity->line = 0;
+        activity->line = 1;
 }
 
 /*
@@ -327,7 +381,7 @@ void setActivityBtStart(af_Code *bt_start, af_Activity *activity) {
             activity->file = strCopy(bt_start->path);
         }
     } else
-        activity->line = 0;
+        activity->line = 1;
 }
 
 /*
@@ -343,7 +397,7 @@ void setActivityBtNext(af_Code *bt_next, af_Activity *activity) {
             activity->file = strCopy(bt_next->path);
         }
     } else
-        activity->line = 0;
+        activity->line = 1;
 }
 
 /*
@@ -482,10 +536,22 @@ af_Message *makeERRORMessage(char *type, char *error, af_Environment *env) {
     af_ErrorInfo *ei = makeErrorInfo(type, error, info, env->activity->line, env->activity->file);
     free(info);
 
+    for (af_ActivityTrackBack *atb = env->activity->tb; atb != NULL; atb = atb->next) {
+        info = getActivityTrackBackInfoToBacktracking(atb);
+        pushErrorBacktracking(atb->line, atb->file, info, ei);
+        free(info);
+    }
+
     for (af_Activity *activity = env->activity->prev; activity != NULL; activity = activity->prev) {
         info = getActivityInfoToBacktracking(activity);
         pushErrorBacktracking(activity->line, activity->file, info, ei);
         free(info);
+
+        for (af_ActivityTrackBack *atb = activity->tb; atb != NULL; atb = atb->next) {
+            info = getActivityTrackBackInfoToBacktracking(atb);
+            pushErrorBacktracking(atb->line, atb->file, info, ei);
+            free(info);
+        }
     }
 
     af_Message *msg = makeMessage("ERROR", sizeof(af_ErrorInfo *));
@@ -702,7 +768,7 @@ bool addTopMsgProcess(char *type, DLC_SYMBOL(TopMsgProcessFunc) func,
 static void newActivity(af_Code *bt, const af_Code *next, bool return_first, af_Environment *env){
     if (next == NULL && env->activity->body_next == NULL && env->activity->type == act_func) {
         printf("Tail call optimization\n");
-        clearActivity(env->activity);
+        tailCallActivity(env->activity);
         setActivityBtTop(bt, env->activity);
         env->activity->optimization = true;
         if (!env->activity->return_first)  // 若原本就有设置 return_first 则没有在设置的必要了, 因为该执行不会被返回
@@ -840,7 +906,7 @@ bool pushMacroFuncActivity(af_Object *func, af_Environment *env) {
     env->activity->macro_vs_count = 0;
     env->activity->is_macro_call = true;
 
-    clearActivity(env->activity);  /* 隐式调用不设置 bt_top */
+    tailCallActivity(env->activity);  /* 隐式调用不设置 bt_top */
     return setFuncActivityToArg(func, env);
 }
 
@@ -1363,6 +1429,48 @@ static char *getActivityInfoToBacktracking(af_Activity *activity){
     return info;
 }
 
+static char *getActivityTrackBackInfoToBacktracking(af_ActivityTrackBack *atb) {
+    char *info = "backtracking;";
+    if (atb->is_execution)
+        info = strJoin(info, "\nexecution-activity;", false, false);
+    else if (atb->is_gc_call)
+        info = strJoin(info, "\ngc-destruct-function-call-activity;", false, false);
+    else
+        info = strJoin(info, "\nfunction-call-activity;", false, false);
+
+    switch (atb->status) {
+        case act_func_get:
+            info = strJoin(info, "\nfunc-get;", true, false);
+            break;
+        case act_func_arg:
+            info = strJoin(info, "\nfunc-arg;", true, false);
+            if (atb->run_in_func)
+                info = strJoin(info, " run-in-function-var-space;", true, false);
+            break;
+        case act_func_normal:
+            info = strJoin(info, "\nrun-code;", true, false);
+            if (atb->return_first)
+                info = strJoin(info, " return-first-result;", true, false);
+            break;
+        default:
+            break;
+    }
+
+    if (atb->is_macro_call)
+        info = strJoin(info, "\nmacro-call;", true, false);
+
+    if (atb->is_literal)
+        info = strJoin(info, "\nliteral-call;", true, false);
+
+    if (atb->is_obj_func)
+        info = strJoin(info, "\nobject-function-call;", true, false);
+
+    if (atb->optimization)
+        info = strJoin(info, "\ntail-call-optimization;", true, false);
+
+    return info;
+}
+
 af_ImportInfo *makeImportInfo(char *mark, af_Object *obj) {
     af_ImportInfo *ii = calloc(1, sizeof(af_ImportInfo));
     if (mark != NULL)

+ 6 - 0
src/core/run.c

@@ -129,6 +129,8 @@ static bool iterCodeInit(af_Code *code, int mode, af_Environment *env) {
         case 1: {
             if (env->activity->type != act_top)
                 return false;
+            env->activity->file = strCopy("top.aun.sys");
+
             char *name = getFileName(code->path);
             pushImportActivity(code, NULL, name, env);
             printf("name = %s\n", name);
@@ -136,6 +138,10 @@ static bool iterCodeInit(af_Code *code, int mode, af_Environment *env) {
             break;
         }
         case 2:
+            if (env->activity->prev == NULL || env->activity->prev->type != act_top)
+                return false;
+            env->activity->file = strCopy("top-gc.aun.sys");
+
             if (env->activity->type == act_gc || !codeSemanticCheck(env->activity->bt_start) || env->activity->bt_next == NULL || code != NULL)
                 return false;
             break;