Explorar el Código

Add the tail-call feature support for classic-interp (#401)

* Add the tail-call feature support for classic-interp

Signed-off-by: Xiaokang Qin <xiaokang.qxk@antgroup.com>

* add CI for tail call and custom name section

* add CI for tail call and custom name section

* update CI for mac

Co-authored-by: Xu Jun <693788454@qq.com>
Xiaokang Qin hace 5 años
padre
commit
a70daed17d

+ 14 - 0
.github/workflows/linux.yml

@@ -70,6 +70,20 @@ jobs:
         cmake .. -DWAMR_BUILD_MEMORY_PROFILING=1
         make
         cd .. && rm -rf build
+    - name: Build iwasm [tail call]
+      run: |
+        cd product-mini/platforms/linux
+        mkdir build && cd build
+        cmake .. -DWAMR_BUILD_TAIL_CALL=1
+        make
+        cd .. && rm -rf build
+    - name: Build iwasm [custom name section]
+      run: |
+        cd product-mini/platforms/linux
+        mkdir build && cd build
+        cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1
+        make
+        cd .. && rm -rf build
     - name: download wasi-sdk
       run: |
         cd /opt

+ 14 - 0
.github/workflows/mac.yml

@@ -70,6 +70,20 @@ jobs:
         cmake .. -DWAMR_BUILD_MEMORY_PROFILING=1
         make
         cd .. && rm -rf build
+    - name: Build iwasm [tail call]
+      run: |
+        cd product-mini/platforms/darwin
+        mkdir build && cd build
+        cmake .. -DWAMR_BUILD_TAIL_CALL=1
+        make
+        cd .. && rm -rf build
+    - name: Build iwasm [custom name section]
+      run: |
+        cd product-mini/platforms/darwin
+        mkdir build && cd build
+        cmake .. -DWAMR_BUILD_CUSTOM_NAME_SECTION=1
+        make
+        cd .. && rm -rf build
     - name: Build Sample [wasm-c-api]
       run: |
         cd samples/wasm-c-api

+ 4 - 0
build-scripts/config_common.cmake

@@ -173,4 +173,8 @@ if (WAMR_BUILD_CUSTOM_NAME_SECTION EQUAL 1)
   add_definitions (-DWASM_ENABLE_CUSTOM_NAME_SECTION=1)
   message ("     Custom name section enabled")
 endif ()
+if (WAMR_BUILD_TAIL_CALL EQUAL 1)
+  add_definitions (-DWASM_ENABLE_TAIL_CALL=1)
+  message ("     Tail call enabled")
+endif ()
 

+ 4 - 0
core/config.h

@@ -244,5 +244,9 @@
     wasm_runtime_set_max_thread_num */
 #define CLUSTER_MAX_THREAD_NUM 4
 
+#ifndef WASM_ENABLE_TAIL_CALL
+#define WASM_ENABLE_TAIL_CALL 0
+#endif
+
 #endif /* end of _CONFIG_H_ */
 

+ 40 - 4
core/iwasm/interpreter/wasm_interp_classic.c

@@ -1285,11 +1285,33 @@ label_pop_csp_n:
         cur_func = module->functions + fidx;
         goto call_func_from_interp;
 
+#if WASM_ENABLE_TAIL_CALL != 0
+      HANDLE_OP (WASM_OP_RETURN_CALL):
+#if WASM_ENABLE_THREAD_MGR != 0
+        CHECK_SUSPEND_FLAGS();
+#endif
+        read_leb_uint32(frame_ip, frame_ip_end, fidx);
+#if WASM_ENABLE_MULTI_MODULE != 0
+        if (fidx >= module->function_count) {
+          wasm_set_exception(module, "unknown function");
+          goto got_exception;
+        }
+#endif
+        cur_func = module->functions + fidx;
+
+        goto call_func_from_return_call;
+#endif /* WASM_ENABLE_TAIL_CALL */
+
       HANDLE_OP (WASM_OP_CALL_INDIRECT):
+#if WASM_ENABLE_TAIL_CALL != 0
+      HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT):
+#endif
         {
           WASMType *cur_type, *cur_func_type;
           WASMTableInstance *cur_table_inst;
-
+#if WASM_ENABLE_TAIL_CALL != 0
+          opcode = *(frame_ip - 1);
+#endif
 #if WASM_ENABLE_THREAD_MGR != 0
           CHECK_SUSPEND_FLAGS();
 #endif
@@ -1352,7 +1374,10 @@ label_pop_csp_n:
             wasm_set_exception(module, "indirect call type mismatch");
             goto got_exception;
           }
-
+#if WASM_ENABLE_TAIL_CALL != 0
+          if (opcode == WASM_OP_RETURN_CALL_INDIRECT)
+            goto call_func_from_return_call;
+#endif
           goto call_func_from_interp;
         }
 
@@ -3121,8 +3146,10 @@ label_pop_csp_n:
     HANDLE_OP (WASM_OP_UNUSED_0x08):
     HANDLE_OP (WASM_OP_UNUSED_0x09):
     HANDLE_OP (WASM_OP_UNUSED_0x0a):
-    HANDLE_OP (WASM_OP_UNUSED_0x12):
-    HANDLE_OP (WASM_OP_UNUSED_0x13):
+#if WASM_ENABLE_TAIL_CALL == 0
+    HANDLE_OP (WASM_OP_RETURN_CALL):
+    HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT):
+#endif
     HANDLE_OP (WASM_OP_UNUSED_0x14):
     HANDLE_OP (WASM_OP_UNUSED_0x15):
     HANDLE_OP (WASM_OP_UNUSED_0x16):
@@ -3151,6 +3178,15 @@ label_pop_csp_n:
     FETCH_OPCODE_AND_DISPATCH ();
 #endif
 
+#if WASM_ENABLE_TAIL_CALL != 0
+  call_func_from_return_call:
+    POP(cur_func->param_cell_num);
+    word_copy(frame->lp, frame_sp, cur_func->param_cell_num);
+    FREE_FRAME(exec_env, frame);
+    wasm_exec_env_set_cur_frame(exec_env,
+                                (WASMRuntimeFrame *)prev_frame);
+    goto call_func_from_entry;
+#endif
   call_func_from_interp:
     /* Only do the copy when it's called from interpreter.  */
     {

+ 2 - 2
core/iwasm/interpreter/wasm_interp_fast.c

@@ -3125,8 +3125,8 @@ recover_br_info:
     HANDLE_OP (WASM_OP_UNUSED_0x08):
     HANDLE_OP (WASM_OP_UNUSED_0x09):
     HANDLE_OP (WASM_OP_UNUSED_0x0a):
-    HANDLE_OP (WASM_OP_UNUSED_0x12):
-    HANDLE_OP (WASM_OP_UNUSED_0x13):
+    HANDLE_OP (WASM_OP_RETURN_CALL):
+    HANDLE_OP (WASM_OP_RETURN_CALL_INDIRECT):
     HANDLE_OP (WASM_OP_UNUSED_0x14):
     HANDLE_OP (WASM_OP_UNUSED_0x15):
     HANDLE_OP (WASM_OP_UNUSED_0x16):

+ 79 - 12
core/iwasm/interpreter/wasm_loader.c

@@ -3307,10 +3307,16 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
                 break;
 
             case WASM_OP_CALL:
+#if WASM_ENABLE_TAIL_CALL != 0
+            case WASM_OP_RETURN_CALL:
+#endif
                 skip_leb_uint32(p, p_end); /* funcidx */
                 break;
 
             case WASM_OP_CALL_INDIRECT:
+#if WASM_ENABLE_TAIL_CALL != 0
+            case WASM_OP_RETURN_CALL_INDIRECT:
+#endif
                 skip_leb_uint32(p, p_end); /* typeidx */
                 CHECK_BUF(p, p_end, 1);
                 u8 = read_uint8(p); /* 0x00 */
@@ -5812,6 +5818,9 @@ handle_op_block_and_loop:
             }
 
             case WASM_OP_CALL:
+#if WASM_ENABLE_TAIL_CALL != 0
+            case WASM_OP_RETURN_CALL:
+#endif
             {
                 WASMType *func_type;
                 uint32 func_idx;
@@ -5844,22 +5853,53 @@ handle_op_block_and_loop:
                     }
                 }
 
-                for (i = 0; i < func_type->result_count; i++) {
-                    PUSH_TYPE(func_type->types[func_type->param_count + i]);
+#if WASM_ENABLE_TAIL_CALL != 0
+                if (opcode == WASM_OP_CALL) {
+#endif
+                    for (i = 0; i < func_type->result_count; i++) {
+                        PUSH_TYPE(func_type->types[func_type->param_count + i]);
 #if WASM_ENABLE_FAST_INTERP != 0
-                    /* Here we emit each return value's dynamic_offset. But in fact
-                     * these offsets are continuous, so interpreter only need to get
-                     * the first return value's offset.
-                     */
-                    PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
+                        /* Here we emit each return value's dynamic_offset. But in fact
+                         * these offsets are continuous, so interpreter only need to get
+                         * the first return value's offset.
+                         */
+                        PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
 #endif
+                    }
+#if WASM_ENABLE_TAIL_CALL != 0
                 }
-
+                else {
+                    char *type_str[] = { "f64", "f32", "i64", "i32" };
+                    uint8 type;
+                    if (func_type->result_count != func->func_type->result_count) {
+                        set_error_buf_v(error_buf, error_buf_size,
+                                        "%s%u%s", "type mismatch: expect ",
+                                        func->func_type->result_count,
+                                        " return values but got other");
+                        goto fail;
+                    }
+                    for (i = 0; i < func_type->result_count; i++) {
+                        type = func->func_type->types[func->func_type->param_count + i];
+                        if (func_type->types[func_type->param_count + i] != type) {
+                            set_error_buf_v(error_buf, error_buf_size,
+                                            "%s%s%s", "type mismatch: expect ",
+                                            type_str[type - VALUE_TYPE_F64],
+                                            " but got other");
+                            goto fail;
+                        }
+                    }
+                    RESET_STACK();
+                    SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+                }
+#endif
                 func->has_op_func_call = true;
                 break;
             }
 
             case WASM_OP_CALL_INDIRECT:
+#if WASM_ENABLE_TAIL_CALL != 0
+            case WASM_OP_RETURN_CALL_INDIRECT:
+#endif
             {
                 int32 idx;
                 WASMType *func_type;
@@ -5904,13 +5944,40 @@ handle_op_block_and_loop:
                     }
                 }
 
-                for (i = 0; i < func_type->result_count; i++) {
-                    PUSH_TYPE(func_type->types[func_type->param_count + i]);
+#if WASM_ENABLE_TAIL_CALL != 0
+                if (opcode == WASM_OP_CALL_INDIRECT) {
+#endif
+                    for (i = 0; i < func_type->result_count; i++) {
+                        PUSH_TYPE(func_type->types[func_type->param_count + i]);
 #if WASM_ENABLE_FAST_INTERP != 0
-                    PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
+                        PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
 #endif
+                    }
+#if WASM_ENABLE_TAIL_CALL != 0
                 }
-
+                else {
+                    char *type_str[] = { "f64", "f32", "i64", "i32" };
+                    uint8 type;
+                    if (func_type->result_count != func->func_type->result_count) {
+                        set_error_buf_v(error_buf, error_buf_size,
+                                        "%s%u%s", "type mismatch: expect ",
+                                        func->func_type->result_count,
+                                        " return values but got other");
+                        goto fail;
+                    }
+                    for (i = 0; i < func_type->result_count; i++) {
+                        type = func->func_type->types[func->func_type->param_count + i];
+                        if (func_type->types[func_type->param_count + i] != type)
+                            set_error_buf_v(error_buf, error_buf_size, "%s%s%s",
+                                            "type mismatch: expect ",
+                                            type_str[type - VALUE_TYPE_F64],
+                                            " but got other");
+                        goto fail;
+                    }
+                    RESET_STACK();
+                    SET_CUR_BLOCK_STACK_POLYMORPHIC_STATE(true);
+                }
+#endif
                 func->has_op_func_call = true;
                 break;
             }

+ 48 - 11
core/iwasm/interpreter/wasm_mini_loader.c

@@ -2235,10 +2235,16 @@ wasm_loader_find_block_addr(BlockAddr *block_addr_cache,
                 break;
 
             case WASM_OP_CALL:
+#if WASM_ENABLE_TAIL_CALL != 0
+            case WASM_OP_RETURN_CALL:
+#endif
                 skip_leb_uint32(p, p_end); /* funcidx */
                 break;
 
             case WASM_OP_CALL_INDIRECT:
+#if WASM_ENABLE_TAIL_CALL != 0
+            case WASM_OP_RETURN_CALL_INDIRECT:
+#endif
                 skip_leb_uint32(p, p_end); /* typeidx */
                 CHECK_BUF(p, p_end, 1);
                 u8 = read_uint8(p); /* 0x00 */
@@ -4612,6 +4618,9 @@ handle_op_block_and_loop:
             }
 
             case WASM_OP_CALL:
+#if WASM_ENABLE_TAIL_CALL != 0
+            case WASM_OP_RETURN_CALL:
+#endif
             {
                 WASMType *func_type;
                 uint32 func_idx;
@@ -4641,22 +4650,37 @@ handle_op_block_and_loop:
                     }
                 }
 
-                for (i = 0; i < func_type->result_count; i++) {
-                    PUSH_TYPE(func_type->types[func_type->param_count + i]);
+#if WASM_ENABLE_TAIL_CALL != 0
+                if (opcode == WASM_OP_CALL) {
+#endif
+                    for (i = 0; i < func_type->result_count; i++) {
+                        PUSH_TYPE(func_type->types[func_type->param_count + i]);
 #if WASM_ENABLE_FAST_INTERP != 0
-                    /* Here we emit each return value's dynamic_offset. But in fact
-                     * these offsets are continuous, so interpreter only need to get
-                     * the first return value's offset.
-                     */
-                    PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
+                        /* Here we emit each return value's dynamic_offset. But in fact
+                         * these offsets are continuous, so interpreter only need to get
+                         * the first return value's offset.
+                         */
+                        PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
 #endif
+                    }
+#if WASM_ENABLE_TAIL_CALL != 0
                 }
-
+                else {
+                    bh_assert(func_type->result_count == func->func_type->result_count);
+                    for (i = 0; i < func_type->result_count; i++) {
+                        bh_assert(func_type->types[func_type->param_count + i] ==
+                                  func->func_type->types[func->func_type->param_count + i]);
+                    }
+                }
+#endif
                 func->has_op_func_call = true;
                 break;
             }
 
             case WASM_OP_CALL_INDIRECT:
+#if WASM_ENABLE_TAIL_CALL != 0
+            case WASM_OP_RETURN_CALL_INDIRECT:
+#endif
             {
                 int32 idx;
                 WASMType *func_type;
@@ -4690,12 +4714,25 @@ handle_op_block_and_loop:
                     }
                 }
 
-                for (i = 0; i < func_type->result_count; i++) {
-                    PUSH_TYPE(func_type->types[func_type->param_count + i]);
+#if WASM_ENABLE_TAIL_CALL != 0
+                if (opcode == WASM_OP_CALL) {
+#endif
+                    for (i = 0; i < func_type->result_count; i++) {
+                        PUSH_TYPE(func_type->types[func_type->param_count + i]);
 #if WASM_ENABLE_FAST_INTERP != 0
-                    PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
+                        PUSH_OFFSET_TYPE(func_type->types[func_type->param_count + i]);
 #endif
+                    }
+#if WASM_ENABLE_TAIL_CALL != 0
                 }
+                else {
+                    bh_assert(func_type->result_count == func->func_type->result_count);
+                    for (i = 0; i < func_type->result_count; i++) {
+                        bh_assert(func_type->types[func_type->param_count + i] ==
+                                  func->func_type->types[func->func_type->param_count + i]);
+                    }
+                }
+#endif
 
                 func->has_op_func_call = true;
                 break;

+ 4 - 4
core/iwasm/interpreter/wasm_opcode.h

@@ -34,9 +34,9 @@ typedef enum WASMOpcode {
     WASM_OP_RETURN        = 0x0f, /* return */
     WASM_OP_CALL          = 0x10, /* call */
     WASM_OP_CALL_INDIRECT = 0x11, /* call_indirect */
+    WASM_OP_RETURN_CALL   = 0x12, /* return_call */
+    WASM_OP_RETURN_CALL_INDIRECT = 0x13, /* return_call_indirect */
 
-    WASM_OP_UNUSED_0x12   = 0x12,
-    WASM_OP_UNUSED_0x13   = 0x13,
     WASM_OP_UNUSED_0x14   = 0x14,
     WASM_OP_UNUSED_0x15   = 0x15,
     WASM_OP_UNUSED_0x16   = 0x16,
@@ -403,8 +403,8 @@ static type _name[WASM_INSTRUCTION_NUM] = {                  \
   HANDLE_OPCODE (WASM_OP_RETURN),        /* 0x0f */          \
   HANDLE_OPCODE (WASM_OP_CALL),          /* 0x10 */          \
   HANDLE_OPCODE (WASM_OP_CALL_INDIRECT), /* 0x11 */          \
-  HANDLE_OPCODE (WASM_OP_UNUSED_0x12),   /* 0x12 */          \
-  HANDLE_OPCODE (WASM_OP_UNUSED_0x13),   /* 0x13 */          \
+  HANDLE_OPCODE (WASM_OP_RETURN_CALL),   /* 0x12 */          \
+  HANDLE_OPCODE (WASM_OP_RETURN_CALL_INDIRECT),   /* 0x13 */ \
   HANDLE_OPCODE (WASM_OP_UNUSED_0x14),   /* 0x14 */          \
   HANDLE_OPCODE (WASM_OP_UNUSED_0x15),   /* 0x15 */          \
   HANDLE_OPCODE (WASM_OP_UNUSED_0x16),   /* 0x16 */          \