Ver código fonte

Implement Go language binding (#1196)

Implement Go binding APIs of runtime, module and instance
Add sample, build scripts and update the document

Co-authored-by: venus-taibai <97893654+venus-taibai@users.noreply.github.com>
Wenyong Huang 3 anos atrás
pai
commit
5b1dcf2fa2

+ 97 - 7
core/iwasm/common/wasm_runtime_common.c

@@ -445,7 +445,7 @@ wasm_runtime_register_module_internal(const char *module_name,
                                       WASMModuleCommon *module,
                                       uint8 *orig_file_buf,
                                       uint32 orig_file_buf_size,
-                                      char *error_buf, uint32_t error_buf_size)
+                                      char *error_buf, uint32 error_buf_size)
 {
     WASMRegisteredModule *node = NULL;
 
@@ -500,7 +500,7 @@ wasm_runtime_register_module_internal(const char *module_name,
 
 bool
 wasm_runtime_register_module(const char *module_name, WASMModuleCommon *module,
-                             char *error_buf, uint32_t error_buf_size)
+                             char *error_buf, uint32 error_buf_size)
 {
     if (!error_buf || !error_buf_size) {
         LOG_ERROR("error buffer is required");
@@ -823,7 +823,7 @@ wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,
 
 WASMModuleCommon *
 wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
-                                char *error_buf, uint32_t error_buf_size)
+                                char *error_buf, uint32 error_buf_size)
 {
     WASMModuleCommon *module_common;
 
@@ -980,6 +980,23 @@ wasm_runtime_destroy_thread_env(void)
 #endif
 }
 
+bool
+wasm_runtime_thread_env_inited(void)
+{
+#ifdef BH_PLATFORM_WINDOWS
+    if (!os_thread_env_inited())
+        return false;
+#endif
+
+#if WASM_ENABLE_AOT != 0
+#ifdef OS_ENABLE_HW_BOUND_CHECK
+    if (!os_thread_signal_inited())
+        return false;
+#endif
+#endif
+    return true;
+}
+
 #if (WASM_ENABLE_MEMORY_PROFILING != 0) || (WASM_ENABLE_MEMORY_TRACING != 0)
 void
 wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module)
@@ -1222,8 +1239,81 @@ wasm_runtime_lookup_function(WASMModuleInstanceCommon *const module_inst,
     return NULL;
 }
 
+uint32
+wasm_func_get_param_count(WASMFunctionInstanceCommon *const func_inst,
+                          WASMModuleInstanceCommon *const module_inst)
+{
+    WASMType *type =
+        wasm_runtime_get_function_type(func_inst, module_inst->module_type);
+    return type->param_count;
+}
+
+uint32
+wasm_func_get_result_count(WASMFunctionInstanceCommon *const func_inst,
+                           WASMModuleInstanceCommon *const module_inst)
+{
+    WASMType *type =
+        wasm_runtime_get_function_type(func_inst, module_inst->module_type);
+    return type->result_count;
+}
+
+static uint8
+val_type_to_val_kind(uint8 value_type)
+{
+    switch (value_type) {
+        case VALUE_TYPE_I32:
+            return WASM_I32;
+        case VALUE_TYPE_I64:
+            return WASM_I64;
+        case VALUE_TYPE_F32:
+            return WASM_F32;
+        case VALUE_TYPE_F64:
+            return WASM_F64;
+        case VALUE_TYPE_FUNCREF:
+            return WASM_FUNCREF;
+        case VALUE_TYPE_EXTERNREF:
+            return WASM_ANYREF;
+        default:
+#if WASM_ENABLE_GC != 0
+            if (wasm_is_type_reftype(value_type))
+                return WASM_ANYREF;
+#endif
+            bh_assert(0);
+            return 0;
+    }
+}
+
+void
+wasm_func_get_param_types(WASMFunctionInstanceCommon *const func_inst,
+                          WASMModuleInstanceCommon *const module_inst,
+                          wasm_valkind_t *param_types)
+{
+    WASMType *type =
+        wasm_runtime_get_function_type(func_inst, module_inst->module_type);
+    uint32 i;
+
+    for (i = 0; i < type->param_count; i++) {
+        param_types[i] = val_type_to_val_kind(type->types[i]);
+    }
+}
+
+void
+wasm_func_get_result_types(WASMFunctionInstanceCommon *const func_inst,
+                           WASMModuleInstanceCommon *const module_inst,
+                           wasm_valkind_t *result_types)
+{
+    WASMType *type =
+        wasm_runtime_get_function_type(func_inst, module_inst->module_type);
+    uint32 i;
+
+    for (i = 0; i < type->result_count; i++) {
+        result_types[i] =
+            val_type_to_val_kind(type->types[type->param_count + i]);
+    }
+}
+
 #if WASM_ENABLE_REF_TYPES != 0
-/* (uintptr_t)externref -> (uint32_t)index */
+/* (uintptr_t)externref -> (uint32)index */
 /*   argv               ->   *ret_argv */
 static bool
 wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
@@ -1321,7 +1411,7 @@ wasm_runtime_prepare_call_function(WASMExecEnv *exec_env,
     return true;
 }
 
-/* (uintptr_t)externref <- (uint32_t)index */
+/* (uintptr_t)externref <- (uint32)index */
 /*   argv               <-   new_argv */
 static bool
 wasm_runtime_finalize_call_function(WASMExecEnv *exec_env,
@@ -3952,8 +4042,8 @@ fail:
                  || defined(BUILD_TARGET_RISCV64_LP64) */
 
 bool
-wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32_t element_indices,
-                           uint32_t argc, uint32_t argv[])
+wasm_runtime_call_indirect(WASMExecEnv *exec_env, uint32 element_indices,
+                           uint32 argc, uint32 argv[])
 {
     if (!wasm_runtime_exec_env_check(exec_env)) {
         LOG_ERROR("Invalid exec env stack info.");

+ 22 - 0
core/iwasm/common/wasm_runtime_common.h

@@ -471,6 +471,28 @@ WASMType *
 wasm_runtime_get_function_type(const WASMFunctionInstanceCommon *function,
                                uint32 module_type);
 
+/* See wasm_export.h for description */
+WASM_RUNTIME_API_EXTERN uint32
+wasm_func_get_param_count(WASMFunctionInstanceCommon *const func_inst,
+                          WASMModuleInstanceCommon *const module_inst);
+
+/* See wasm_export.h for description */
+WASM_RUNTIME_API_EXTERN uint32
+wasm_func_get_result_count(WASMFunctionInstanceCommon *const func_inst,
+                           WASMModuleInstanceCommon *const module_inst);
+
+/* See wasm_export.h for description */
+WASM_RUNTIME_API_EXTERN void
+wasm_func_get_param_types(WASMFunctionInstanceCommon *const func_inst,
+                          WASMModuleInstanceCommon *const module_inst,
+                          wasm_valkind_t *param_types);
+
+/* See wasm_export.h for description */
+WASM_RUNTIME_API_EXTERN void
+wasm_func_get_result_types(WASMFunctionInstanceCommon *const func_inst,
+                           WASMModuleInstanceCommon *const module_inst,
+                           wasm_valkind_t *result_types);
+
 /* See wasm_export.h for description */
 WASM_RUNTIME_API_EXTERN WASMExecEnv *
 wasm_runtime_create_exec_env(WASMModuleInstanceCommon *module_inst,

+ 56 - 2
core/iwasm/include/wasm_export.h

@@ -407,6 +407,54 @@ WASM_RUNTIME_API_EXTERN wasm_function_inst_t
 wasm_runtime_lookup_function(wasm_module_inst_t const module_inst,
                              const char *name, const char *signature);
 
+/**
+ * Get parameter count of the function instance
+ *
+ * @param func_inst the function instance
+ * @param module_inst the module instance the function instance belongs to
+ *
+ * @return the parameter count of the function instance
+ */
+WASM_RUNTIME_API_EXTERN uint32_t
+wasm_func_get_param_count(wasm_function_inst_t const func_inst,
+                          wasm_module_inst_t const module_inst);
+
+/**
+ * Get result count of the function instance
+ *
+ * @param func_inst the function instance
+ * @param module_inst the module instance the function instance belongs to
+ *
+ * @return the result count of the function instance
+ */
+WASM_RUNTIME_API_EXTERN uint32_t
+wasm_func_get_result_count(wasm_function_inst_t const func_inst,
+                           wasm_module_inst_t const module_inst);
+
+/**
+ * Get parameter types of the function instance
+ *
+ * @param func_inst the function instance
+ * @param module_inst the module instance the function instance belongs to
+ * @param param_types the parameter types returned
+ */
+WASM_RUNTIME_API_EXTERN void
+wasm_func_get_param_types(wasm_function_inst_t const func_inst,
+                          wasm_module_inst_t const module_inst,
+                          wasm_valkind_t *param_types);
+
+/**
+ * Get result types of the function instance
+ *
+ * @param func_inst the function instance
+ * @param module_inst the module instance the function instance belongs to
+ * @param result_types the result types returned
+ */
+WASM_RUNTIME_API_EXTERN void
+wasm_func_get_result_types(wasm_function_inst_t const func_inst,
+                           wasm_module_inst_t const module_inst,
+                           wasm_valkind_t *result_types);
+
 /**
  * Create execution environment for a WASM module instance.
  *
@@ -449,7 +497,7 @@ WASM_RUNTIME_API_EXTERN uint32_t
 wasm_runtime_start_debug_instance(wasm_exec_env_t exec_env);
 
 /**
- * Initialize thread environment.
+ * Initialize the thread environment.
  * Note:
  *   If developer creates a child thread by himself to call the
  *   the wasm function in that thread, he should call this API
@@ -464,11 +512,17 @@ WASM_RUNTIME_API_EXTERN bool
 wasm_runtime_init_thread_env(void);
 
 /**
- * Destroy thread environment
+ * Destroy the thread environment
  */
 WASM_RUNTIME_API_EXTERN void
 wasm_runtime_destroy_thread_env(void);
 
+/**
+ * Whether the thread environment is initialized
+ */
+WASM_RUNTIME_API_EXTERN bool
+wasm_runtime_thread_env_inited(void);
+
 /**
  * Get WASM module instance from execution environment
  *

+ 6 - 0
core/shared/platform/include/platform_api_extension.h

@@ -107,6 +107,12 @@ os_thread_env_init();
 void
 os_thread_env_destroy();
 
+/**
+ * Whether the thread environment is initialized
+ */
+bool
+os_thread_env_inited();
+
 /**
  * Suspend execution of the calling thread for (at least)
  * usec microseconds

+ 7 - 0
core/shared/platform/windows/win_thread.c

@@ -360,6 +360,13 @@ os_thread_env_destroy()
     }
 }
 
+bool
+os_thread_env_inited()
+{
+    os_thread_data *thread_data = TlsGetValue(thread_data_key);
+    return thread_data ? true : false;
+}
+
 int
 os_sem_init(korp_sem *sem)
 {

+ 104 - 0
language-bindings/go/README.md

@@ -0,0 +1,104 @@
+WAMR Go binding: Embedding WAMR in Go guideline
+===============================================
+
+This Go library uses CGO to consume the runtime APIs of the WAMR project which are defined in [core/iwasm/include/wasm_export.h](../../core/iwasm/include/wasm_export.h). The API details are available in the header files.
+
+## Installation
+
+### Installing from the source code
+
+Installing from local source tree is in _development mode_.
+
+Run `./build.sh` in this folder to build the package, which builds the WAMR runtime library firstly and then builds the Go binding library.
+
+Run `./build.sh` under `samples` folder to build and test the sample.
+
+```bash
+cd samples
+./build.sh
+```
+
+## Supported APIs
+
+All the embedding APIs supported are defined under folder [wamr](./wamr).
+
+### Runtime APIs
+
+```Go
+func Runtime() *_Runtime
+func (self *_Runtime) FullInit(alloc_with_pool bool, heap_buf []byte,
+                               max_thread_num uint) error
+func (self *_Runtime) Init() error
+func (self *_Runtime) Destroy()
+func (self *_Runtime) SetLogLevel(level LogLevel)
+func (self *_Runtime) Malloc(size uint32) *uint8
+func (self *_Runtime) Free(ptr *uint8)
+```
+
+### Module APIs
+
+```Go
+func NewModule(wasmBytes []byte) (*Module, error)
+func (self *Module) Destroy()
+func (self *Module) SetWasiArgs(dirList [][]byte, mapDirList [][]byte,
+                                env [][]byte, argv[][]byte)
+func (self *Module) SetWasiArgsEx(dirList [][]byte, mapDirList [][]byte,
+                                env [][]byte, argv[][]byte,
+                                stdinfd int, stdoutfd int, stderrfd int)
+func (self *Module) SetWasiAddrPool(addrPool [][]byte)
+```
+
+### Instance APIs
+
+```Go
+func NewInstance(module *Module,
+                 stackSize uint, heapSize uint) (*Instance, error)
+func (self *Instance) Destroy()
+func (self *Instance) CallFunc(funcName string,
+                               argc uint32, args []uint32) error
+func (self *Instance) CallFuncV(funcName string,
+                                num_results uint32, results []interface{},
+                                args ... interface{}) error
+func (self *Instance) GetException() string
+func (self Instance) ModuleMalloc(size uint32) (uint32, *uint8)
+func (self Instance) ModuleFree(offset uint32)
+func (self Instance) ValidateAppAddr(app_offset uint32, size uint32) bool
+func (self Instance) ValidateNativeAddr(native_ptr *uint8, size uint32) bool
+func (self Instance) AddrAppToNative(app_offset uint32) *uint8
+func (self Instance) AddrNativeToApp(native_ptr *uint8) uint32
+func (self Instance) GetAppAddrRange(app_offset uint32) (bool, uint32, uint32)
+func (self Instance) GetNativeAddrRange(native_ptr *uint8) (bool, *uint8, *uint8)
+func (self Instance) DumpMemoryConsumption()
+func (self Instance) DumpCallStack()
+```
+
+## Sample codes
+
+```Go
+    var module *wamr.Module
+    var instance *wamr.Instance
+    var results []interface{}
+    var err error
+
+    /* Runtime initialization */
+    err = wamr.Runtime().FullInit(false, nil, 1)
+
+    /* Read WASM/AOT file into a memory buffer */
+    wasmBytes := read_wasm_binary_to_buffer(...)
+
+    /* Load WASM/AOT module from the memory buffer */
+    module, err = wamr.NewModule(wasmBytes)
+
+    /* Create WASM/AOT instance from the module */
+    instance, err = wamr.NewInstance(module, 16384, 16384)
+
+    /* Call the `fib` function */
+    results = make([]interface{}, 1, 1)
+    err = instance.CallFuncV("fib", 1, results, (int32)32)
+    fmt.Printf("fib(32) return: %d\n", results[0].(int32));
+
+    /* Destroy runtime */
+    wamr.Runtime().Destroy()
+```
+
+More samples can be found in [test.go](./samples/test.go)

+ 21 - 0
language-bindings/go/build.sh

@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+PLATFORM=$(uname -s | tr A-Z a-z)
+CUR_DIR=$PWD
+WAMR_DIR=$PWD/../..
+WAMR_GO_DIR=$PWD/wamr
+
+cp -a ${WAMR_DIR}/core/iwasm/include/*.h ${WAMR_GO_DIR}/packaged/include
+
+mkdir -p build && cd build
+cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} \
+    -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_DUMP_CALL_STACK=1 \
+    -DWAMR_BUILD_MEMORY_PROFILING=1
+make -j ${nproc}
+cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-amd64
+
+cd ${WAMR_GO_DIR}
+go test

+ 5 - 0
language-bindings/go/go.mod

@@ -0,0 +1,5 @@
+module gitlab.alipay-inc.com/TNT_Runtime/ant-runtime/bindings/go
+
+go 1.15
+
+require github.com/stretchr/testify v1.7.0

+ 10 - 0
language-bindings/go/go.sum

@@ -0,0 +1,10 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 23 - 0
language-bindings/go/samples/build.sh

@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+PLATFORM=$(uname -s | tr A-Z a-z)
+CUR_DIR=$PWD
+WAMR_DIR=$PWD/../../..
+WAMR_GO_DIR=$PWD/../wamr
+
+cp -a ${WAMR_DIR}/core/iwasm/include/*.h ${WAMR_GO_DIR}/packaged/include
+
+mkdir -p build && cd build
+cmake ${WAMR_DIR}/product-mini/platforms/${PLATFORM} \
+    -DWAMR_BUILD_LIB_PTHREAD=1 -DWAMR_BUILD_DUMP_CALL_STACK=1 \
+    -DWAMR_BUILD_MEMORY_PROFILING=1
+make -j ${nproc}
+cp -a libvmlib.a ${WAMR_GO_DIR}/packaged/lib/${PLATFORM}-amd64
+
+cd ${CUR_DIR}
+rm -f test
+go build test.go
+./test

+ 7 - 0
language-bindings/go/samples/run.sh

@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+go build test.go
+./test

+ 235 - 0
language-bindings/go/samples/test.go

@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package main
+
+import (
+    "gitlab.alipay-inc.com/TNT_Runtime/ant-runtime/bindings/go/wamr"
+    "fmt"
+)
+
+var wasmBytes = []byte {
+    0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00, 0x01, 0x29, 0x07, 0x60,
+    0x01, 0x7F, 0x01, 0x7F, 0x60, 0x02, 0x7F, 0x7F, 0x01, 0x7F, 0x60, 0x01,
+    0x7F, 0x00, 0x60, 0x04, 0x7F, 0x7E, 0x7D, 0x7C, 0x00, 0x60, 0x02, 0x7E,
+    0x7E, 0x01, 0x7E, 0x60, 0x02, 0x7C, 0x7F, 0x01, 0x7D, 0x60, 0x02, 0x7D,
+    0x7C, 0x01, 0x7C, 0x02, 0x31, 0x04, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x70,
+    0x72, 0x69, 0x6E, 0x74, 0x66, 0x00, 0x01, 0x03, 0x65, 0x6E, 0x76, 0x04,
+    0x70, 0x75, 0x74, 0x73, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x06, 0x6D,
+    0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x00, 0x00, 0x03, 0x65, 0x6E, 0x76, 0x04,
+    0x66, 0x72, 0x65, 0x65, 0x00, 0x02, 0x03, 0x07, 0x06, 0x00, 0x03, 0x04,
+    0x06, 0x05, 0x01, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x13, 0x03, 0x7F,
+    0x01, 0x41, 0x90, 0x29, 0x0B, 0x7F, 0x00, 0x41, 0x90, 0x09, 0x0B, 0x7F,
+    0x00, 0x41, 0x90, 0x29, 0x0B, 0x07, 0x5F, 0x09, 0x06, 0x6D, 0x65, 0x6D,
+    0x6F, 0x72, 0x79, 0x02, 0x00, 0x04, 0x66, 0x69, 0x62, 0x32, 0x00, 0x04,
+    0x05, 0x74, 0x65, 0x73, 0x74, 0x31, 0x00, 0x05, 0x05, 0x74, 0x65, 0x73,
+    0x74, 0x32, 0x00, 0x06, 0x05, 0x74, 0x65, 0x73, 0x74, 0x33, 0x00, 0x07,
+    0x05, 0x74, 0x65, 0x73, 0x74, 0x34, 0x00, 0x08, 0x10, 0x5F, 0x5F, 0x6D,
+    0x61, 0x69, 0x6E, 0x5F, 0x61, 0x72, 0x67, 0x63, 0x5F, 0x61, 0x72, 0x67,
+    0x76, 0x00, 0x09, 0x0A, 0x5F, 0x5F, 0x64, 0x61, 0x74, 0x61, 0x5F, 0x65,
+    0x6E, 0x64, 0x03, 0x01, 0x0B, 0x5F, 0x5F, 0x68, 0x65, 0x61, 0x70, 0x5F,
+    0x62, 0x61, 0x73, 0x65, 0x03, 0x02, 0x0A, 0xA5, 0x03, 0x06, 0x37, 0x01,
+    0x01, 0x7F, 0x41, 0x01, 0x21, 0x01, 0x20, 0x00, 0x41, 0x02, 0x4F, 0x04,
+    0x7F, 0x41, 0x00, 0x21, 0x01, 0x03, 0x40, 0x20, 0x00, 0x41, 0x02, 0x6B,
+    0x10, 0x04, 0x20, 0x01, 0x6A, 0x21, 0x01, 0x20, 0x00, 0x41, 0x01, 0x6B,
+    0x22, 0x00, 0x41, 0x01, 0x4B, 0x0D, 0x00, 0x0B, 0x20, 0x01, 0x41, 0x01,
+    0x6A, 0x05, 0x41, 0x01, 0x0B, 0x0B, 0x3F, 0x01, 0x01, 0x7F, 0x23, 0x00,
+    0x41, 0x20, 0x6B, 0x22, 0x04, 0x24, 0x00, 0x20, 0x04, 0x41, 0x18, 0x6A,
+    0x20, 0x03, 0x39, 0x03, 0x00, 0x20, 0x04, 0x41, 0x10, 0x6A, 0x20, 0x02,
+    0xBB, 0x39, 0x03, 0x00, 0x20, 0x04, 0x20, 0x01, 0x37, 0x03, 0x08, 0x20,
+    0x04, 0x20, 0x00, 0x36, 0x02, 0x00, 0x41, 0xD0, 0x08, 0x20, 0x04, 0x10,
+    0x00, 0x1A, 0x20, 0x04, 0x41, 0x20, 0x6A, 0x24, 0x00, 0x0B, 0x3B, 0x01,
+    0x01, 0x7F, 0x23, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, 0x24, 0x00, 0x20,
+    0x02, 0x20, 0x00, 0x37, 0x03, 0x00, 0x20, 0x02, 0x20, 0x01, 0x37, 0x03,
+    0x08, 0x20, 0x02, 0x41, 0x10, 0x6A, 0x20, 0x00, 0x20, 0x01, 0x7C, 0x22,
+    0x00, 0x37, 0x03, 0x00, 0x41, 0xF6, 0x08, 0x20, 0x02, 0x10, 0x00, 0x1A,
+    0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x00, 0x20, 0x00, 0x0B, 0x40, 0x02,
+    0x01, 0x7F, 0x01, 0x7C, 0x23, 0x00, 0x41, 0x20, 0x6B, 0x22, 0x02, 0x24,
+    0x00, 0x20, 0x02, 0x20, 0x01, 0x39, 0x03, 0x08, 0x20, 0x02, 0x20, 0x00,
+    0xBB, 0x22, 0x03, 0x39, 0x03, 0x00, 0x20, 0x02, 0x41, 0x10, 0x6A, 0x20,
+    0x03, 0x20, 0x01, 0xA2, 0x22, 0x01, 0x39, 0x03, 0x00, 0x41, 0xB4, 0x08,
+    0x20, 0x02, 0x10, 0x00, 0x1A, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24, 0x00,
+    0x20, 0x01, 0x0B, 0x3D, 0x01, 0x01, 0x7F, 0x23, 0x00, 0x41, 0x20, 0x6B,
+    0x22, 0x02, 0x24, 0x00, 0x20, 0x02, 0x20, 0x00, 0x39, 0x03, 0x00, 0x20,
+    0x02, 0x20, 0x01, 0x36, 0x02, 0x08, 0x20, 0x02, 0x41, 0x10, 0x6A, 0x20,
+    0x00, 0x20, 0x01, 0xB7, 0xA3, 0x22, 0x00, 0x39, 0x03, 0x00, 0x41, 0xC2,
+    0x08, 0x20, 0x02, 0x10, 0x00, 0x1A, 0x20, 0x02, 0x41, 0x20, 0x6A, 0x24,
+    0x00, 0x20, 0x00, 0xB6, 0x0B, 0x70, 0x00, 0x23, 0x00, 0x41, 0x20, 0x6B,
+    0x22, 0x00, 0x24, 0x00, 0x41, 0x9A, 0x08, 0x10, 0x01, 0x1A, 0x02, 0x7F,
+    0x41, 0x80, 0x08, 0x10, 0x02, 0x22, 0x01, 0x45, 0x04, 0x40, 0x41, 0x88,
+    0x08, 0x10, 0x01, 0x1A, 0x41, 0x7F, 0x0C, 0x01, 0x0B, 0x20, 0x00, 0x20,
+    0x01, 0x36, 0x02, 0x10, 0x41, 0xA7, 0x08, 0x20, 0x00, 0x41, 0x10, 0x6A,
+    0x10, 0x00, 0x1A, 0x20, 0x01, 0x41, 0x04, 0x6A, 0x41, 0x8E, 0x09, 0x2F,
+    0x00, 0x00, 0x3B, 0x00, 0x00, 0x20, 0x01, 0x41, 0x8A, 0x09, 0x28, 0x00,
+    0x00, 0x36, 0x00, 0x00, 0x20, 0x00, 0x20, 0x01, 0x36, 0x02, 0x00, 0x41,
+    0x80, 0x08, 0x20, 0x00, 0x10, 0x00, 0x1A, 0x20, 0x01, 0x10, 0x03, 0x41,
+    0x00, 0x0B, 0x20, 0x00, 0x41, 0x20, 0x6A, 0x24, 0x00, 0x0B, 0x0B, 0x97,
+    0x01, 0x01, 0x00, 0x41, 0x80, 0x08, 0x0B, 0x8F, 0x01, 0x62, 0x75, 0x66,
+    0x3A, 0x20, 0x25, 0x73, 0x00, 0x6D, 0x61, 0x6C, 0x6C, 0x6F, 0x63, 0x20,
+    0x62, 0x75, 0x66, 0x20, 0x66, 0x61, 0x69, 0x6C, 0x65, 0x64, 0x00, 0x48,
+    0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x00,
+    0x62, 0x75, 0x66, 0x20, 0x70, 0x74, 0x72, 0x3A, 0x20, 0x25, 0x70, 0x0A,
+    0x00, 0x25, 0x66, 0x20, 0x2A, 0x20, 0x25, 0x66, 0x20, 0x3D, 0x20, 0x25,
+    0x66, 0x0A, 0x00, 0x25, 0x66, 0x20, 0x2F, 0x20, 0x25, 0x64, 0x20, 0x3D,
+    0x20, 0x25, 0x66, 0x0A, 0x00, 0x69, 0x33, 0x32, 0x3A, 0x20, 0x25, 0x64,
+    0x2C, 0x20, 0x69, 0x36, 0x34, 0x3A, 0x20, 0x25, 0x6C, 0x6C, 0x64, 0x2C,
+    0x20, 0x66, 0x33, 0x32, 0x3A, 0x20, 0x25, 0x66, 0x2C, 0x20, 0x66, 0x36,
+    0x34, 0x3A, 0x20, 0x25, 0x66, 0x0A, 0x00, 0x25, 0x6C, 0x6C, 0x64, 0x20,
+    0x2B, 0x20, 0x25, 0x6C, 0x6C, 0x64, 0x20, 0x3D, 0x20, 0x25, 0x6C, 0x6C,
+    0x64, 0x0A, 0x00, 0x31, 0x32, 0x33, 0x34, 0x0A }
+
+var global_heap []byte = make([]byte, 128 * 1024, 128 * 1024)
+
+func main() {
+    var module *wamr.Module
+    var instance *wamr.Instance
+    var argv []uint32
+    var results []interface{}
+    var offset uint32
+    var native_addr *uint8
+    var err error
+
+    fmt.Print("Init wasm runtime with global heap buf\n");
+    err = wamr.Runtime().FullInit(true, global_heap, 1)
+    if err != nil {
+        return
+    }
+    fmt.Print("Destroy runtime\n");
+    wamr.Runtime().Destroy()
+
+    fmt.Print("Init wasm runtime without global heap buf\n");
+    err = wamr.Runtime().FullInit(false, nil, 1)
+    if err != nil {
+        return
+    }
+
+    wamr.Runtime().SetLogLevel(wamr.LOG_LEVEL_WARNING)
+
+    fmt.Print("Load wasm module\n");
+    module, err = wamr.NewModule(wasmBytes)
+    if err != nil {
+        fmt.Println(err)
+        goto fail
+    }
+
+    fmt.Print("Instantiate wasm module\n");
+    instance, err = wamr.NewInstance(module, 16384, 16384)
+    if err != nil {
+        fmt.Println(err)
+        goto fail
+    }
+
+    results = make([]interface{}, 8, 8)
+    argv = make([]uint32, 8)
+
+    fmt.Print("\nCall func __main_argc_argv with CallFunc:\n");
+    err = instance.CallFunc("__main_argc_argv", 2, argv)
+    if err != nil {
+        fmt.Println(err)
+        goto fail
+    }
+
+    fmt.Print("\nCall func __main_argc_argv with CallFuncV:\n");
+    err = instance.CallFuncV("__main_argc_argv", 2, results,
+                             (int32)(0), (int32)(0))
+    if err != nil {
+        fmt.Println(err)
+        goto fail
+    }
+
+    fmt.Print("\nCall func `i32 fib2(i32)` with CallFunc:\n");
+    argv[0] = 32
+    err = instance.CallFunc("fib2", 1, argv)
+    if err != nil {
+        fmt.Println(err)
+        goto fail
+    }
+    fmt.Printf("fib2(32) return: %d\n", argv[0]);
+
+    fmt.Print("\nCall func `void test1(i32, i64, f32, f64)` with CallFuncV:\n");
+    err = instance.CallFuncV("test1", 0, nil,
+                             (int32)(12345678),
+                             (int64)(3344556677889900),
+                             (float32)(5678.1234),
+                             (float64)(987654321.5678))
+    if err != nil {
+        fmt.Println(err)
+        goto fail
+    }
+
+    fmt.Print("\nCall func `i64 test2(i64, i64)` with CallFuncV:\n");
+    err = instance.CallFuncV("test2", 1, results,
+                             (int64)(3344556677889900),
+                             (int64)(1122331122110099))
+    if err != nil {
+        fmt.Println(err)
+        goto fail
+    }
+    fmt.Printf("test2(3344556677889900, 1122331122110099) return: %d\n",
+               results[0].(int64))
+
+    fmt.Print("\nCall func `f64 test3(f32, f64)` with CallFuncV:\n");
+    err = instance.CallFuncV("test3", 1, results,
+                             (float32)(3456.1234),
+                             (float64)(7890.4567))
+    if err != nil {
+        fmt.Println(err)
+        goto fail
+    }
+    fmt.Printf("test3(3456.1234, 7890.4567) return: %f\n",
+               results[0].(float64))
+
+    fmt.Print("\nCall func `f32 test4(f64, i32)` with CallFuncV:\n");
+    err = instance.CallFuncV("test4", 1, results,
+                             (float64)(8912.3456),
+                             (int32)(123))
+    if err != nil {
+        fmt.Println(err)
+        goto fail
+    }
+    fmt.Printf("test4(8912.3456, 123) return: %f\n",
+               results[0].(float32))
+
+    fmt.Print("\nTest ModuleMalloc")
+    offset, native_addr = instance.ModuleMalloc(1024)
+    fmt.Printf("ModuleMalloc(%d) return offset: %d, native addr: %p\n",
+               1024, offset, native_addr)
+
+    if (!instance.ValidateAppAddr(offset, 1024)) {
+        fmt.Print("Validate app addr failed\n")
+    }
+    if (!instance.ValidateNativeAddr(native_addr, 1024)) {
+        fmt.Print("Validate native addr failed\n")
+    }
+    if (native_addr != instance.AddrAppToNative(offset)) {
+        fmt.Print("Convert app addr to native addr failed\n")
+    }
+    if (offset != instance.AddrNativeToApp(native_addr)) {
+        fmt.Print("Convert app addr to native addr failed\n")
+    }
+
+    instance.ModuleFree(offset)
+
+    /*
+    instance.DumpMemoryConsumption()
+    instance.DumpCallStack()
+    */
+
+    fmt.Print("\n");
+
+fail:
+    if (instance != nil) {
+        fmt.Print("Destroy instance\n");
+        instance.Destroy()
+    }
+
+    if (module != nil) {
+        fmt.Print("Destroy module\n");
+        module.Destroy()
+    }
+
+    fmt.Print("Destroy wasm runtime\n");
+    wamr.Runtime().Destroy()
+}

+ 32 - 0
language-bindings/go/samples/wasm-app/build.sh

@@ -0,0 +1,32 @@
+# Copyright (C) 2019 Intel Corporation.  All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+WAMR_DIR=${PWD}/../../..
+
+echo "Build wasm app .."
+/opt/wasi-sdk/bin/clang -O3 \
+        -z stack-size=4096 -Wl,--initial-memory=65536 \
+        -o test.wasm main.c \
+        -Wl,--export=main -Wl,--export=__main_argc_argv \
+        -Wl,--export=fib2 \
+        -Wl,--export=test1 \
+        -Wl,--export=test2 \
+        -Wl,--export=test3 \
+        -Wl,--export=test4 \
+        -Wl,--export=__data_end -Wl,--export=__heap_base \
+        -Wl,--strip-all,--no-entry \
+        -Wl,--allow-undefined \
+        -nostdlib \
+
+echo "Build binarydump tool .."
+rm -fr build && mkdir build && cd build
+cmake ../../../../../test-tools/binarydump-tool
+make
+cd ..
+
+echo "Generate test_wasm.h .."
+./build/binarydump -o test_wasm.h -n wasm_test_file test.wasm
+
+rm -fr build
+
+echo "Done"

+ 65 - 0
language-bindings/go/samples/wasm-app/main.c

@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+unsigned
+fib2(unsigned n)
+{
+    if (n < 2) {
+        return 1;
+    }
+    return fib2(n - 2) + fib2(n - 1);
+}
+
+void
+test1(int32_t i32, int64_t i64, float f32, double f64)
+{
+    printf("i32: %d, i64: %lld, f32: %f, f64: %f\n", i32, i64, f32, f64);
+}
+
+int64_t
+test2(int64_t x, int64_t y)
+{
+    printf("%lld + %lld = %lld\n", x, y, x + y);
+    return x + y;
+}
+
+double
+test3(float x, double y)
+{
+    printf("%f * %f = %f\n", x, y, x * y);
+    return x * y;
+}
+
+float
+test4(double x, int32_t y)
+{
+    printf("%f / %d = %f\n", x, y, x / y);
+    return x / y;
+}
+
+int
+main(int argc, char **argv)
+{
+    char *buf;
+
+    printf("Hello world!\n");
+
+    buf = malloc(1024);
+    if (!buf) {
+        printf("malloc buf failed\n");
+        return -1;
+    }
+
+    printf("buf ptr: %p\n", buf);
+
+    snprintf(buf, 1024, "%s", "1234\n");
+    printf("buf: %s", buf);
+
+    free(buf);
+    return 0;
+}

+ 20 - 0
language-bindings/go/wamr/cgo.go

@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package wamr
+
+// #cgo CFLAGS: -I${SRCDIR}/packaged/include
+// #cgo LDFLAGS: -lvmlib -lm
+//
+// #cgo linux,amd64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/linux-amd64 -L${SRCDIR}/packaged/lib/linux-amd64
+// #cgo linux,arm64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/linux-aarch64 -L${SRCDIR}/packaged/lib/linux-aarch64
+// #cgo darwin,amd64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/darwin-amd64 -L${SRCDIR}/packaged/lib/darwin-amd64
+// #cgo darwin,arm64 LDFLAGS: -Wl,-rpath,${SRCDIR}/packaged/lib/darwin-aarch64 -L${SRCDIR}/packaged/lib/darwin-aarch64
+//
+// #include <wasm_export.h>
+import "C"
+
+import (
+)

+ 385 - 0
language-bindings/go/wamr/instance.go

@@ -0,0 +1,385 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package wamr
+
+/*
+#include <stdlib.h>
+#include <wasm_export.h>
+
+static inline void
+PUT_I64_TO_ADDR(uint32_t *addr, int64_t value)
+{
+    union {
+        int64_t val;
+        uint32_t parts[2];
+    } u;
+    u.val = value;
+    addr[0] = u.parts[0];
+    addr[1] = u.parts[1];
+}
+
+static inline void
+PUT_F64_TO_ADDR(uint32_t *addr, double value)
+{
+    union {
+        double val;
+        uint32_t parts[2];
+    } u;
+    u.val = value;
+    addr[0] = u.parts[0];
+    addr[1] = u.parts[1];
+}
+
+static inline int64_t
+GET_I64_FROM_ADDR(uint32_t *addr)
+{
+    union {
+        int64_t val;
+        uint32_t parts[2];
+    } u;
+    u.parts[0] = addr[0];
+    u.parts[1] = addr[1];
+    return u.val;
+}
+
+static inline double
+GET_F64_FROM_ADDR(uint32_t *addr)
+{
+    union {
+        double val;
+        uint32_t parts[2];
+    } u;
+    u.parts[0] = addr[0];
+    u.parts[1] = addr[1];
+    return u.val;
+}
+*/
+import "C"
+
+import (
+    "runtime"
+    "unsafe"
+    "fmt"
+)
+
+type Instance struct {
+    _instance C.wasm_module_inst_t
+    _exec_env C.wasm_exec_env_t
+    _module *Module
+    _exportsCache map[string]C.wasm_function_inst_t
+}
+
+/* Create instance from the module */
+func NewInstance(module *Module,
+                 stackSize uint, heapSize uint) (*Instance, error) {
+    if (module == nil) {
+        return nil, fmt.Errorf("NewInstance error: invalid input")
+    }
+
+    errorBytes := make([]byte, 128)
+    errorPtr := (*C.char)(unsafe.Pointer(&errorBytes[0]))
+    errorLen := C.uint(len(errorBytes))
+
+    instance := C.wasm_runtime_instantiate(module.module, C.uint(stackSize),
+                                           C.uint(heapSize), errorPtr, errorLen)
+    if (instance == nil) {
+        return nil, fmt.Errorf("NewInstance Error: %s", string(errorBytes))
+    }
+
+    exec_env := C.wasm_runtime_create_exec_env(instance, C.uint(stackSize))
+    if (exec_env == nil) {
+        C.wasm_runtime_deinstantiate(instance)
+        return nil, fmt.Errorf("NewInstance Error: create exec_env failed")
+    }
+
+    self := &Instance{
+        _instance: instance,
+        _exec_env: exec_env,
+        _module: module,
+        _exportsCache: make(map[string]C.wasm_function_inst_t),
+    }
+
+    runtime.SetFinalizer(self, func(self *Instance) {
+        self.Destroy()
+    })
+
+    return self, nil
+}
+
+/* Destroy the instance */
+func (self *Instance) Destroy() {
+    runtime.SetFinalizer(self, nil)
+    if (self._instance != nil) {
+        C.wasm_runtime_deinstantiate(self._instance)
+    }
+    if (self._exec_env != nil) {
+        C.wasm_runtime_destroy_exec_env(self._exec_env)
+    }
+}
+
+/* Call the wasm function with argument in the uint32 array, and store
+   the return values back into the array */
+func (self *Instance) CallFunc(funcName string,
+                               argc uint32, args []uint32) error {
+    _func := self._exportsCache[funcName]
+    if _func == nil {
+        cName := C.CString(funcName)
+        defer C.free(unsafe.Pointer(cName))
+
+        _func = C.wasm_runtime_lookup_function(self._instance,
+                                               cName, (*C.char)(C.NULL))
+        if _func == nil {
+            return fmt.Errorf("CallFunc error: lookup function failed")
+        }
+        self._exportsCache[funcName] = _func
+    }
+
+    thread_env_inited := Runtime().ThreadEnvInited()
+    if (!thread_env_inited) {
+        Runtime().InitThreadEnv()
+    }
+
+    var args_C *C.uint32_t
+    if (argc > 0) {
+        args_C = (*C.uint32_t)(unsafe.Pointer(&args[0]))
+    }
+    if (!C.wasm_runtime_call_wasm(self._exec_env, _func,
+                                  C.uint(argc), args_C)) {
+        if (!thread_env_inited) {
+            Runtime().DestroyThreadEnv()
+        }
+        return fmt.Errorf("CallFunc error: %s", string(self.GetException()))
+    }
+
+    if (!thread_env_inited) {
+        Runtime().DestroyThreadEnv()
+    }
+    return nil
+}
+
+/* Call the wasm function with variant arguments, and store the return
+   values back into the results array */
+func (self *Instance) CallFuncV(funcName string,
+                                num_results uint32, results []interface{},
+                                args ... interface{}) error {
+    _func := self._exportsCache[funcName]
+    if _func == nil {
+        cName := C.CString(funcName)
+        defer C.free(unsafe.Pointer(cName))
+
+        _func = C.wasm_runtime_lookup_function(self._instance,
+                                               cName, (*C.char)(C.NULL))
+        if _func == nil {
+            return fmt.Errorf("CallFunc error: lookup function failed")
+        }
+        self._exportsCache[funcName] = _func
+    }
+
+    param_count := uint32(C.wasm_func_get_param_count(_func, self._instance))
+    result_count := uint32(C.wasm_func_get_result_count(_func, self._instance))
+
+    if (num_results < result_count) {
+        str := "CallFunc error: invalid result count %d, " +
+               "must be no smaller than %d"
+        return fmt.Errorf(str, num_results, result_count)
+    }
+
+    param_types := make([]C.uchar, param_count, param_count)
+    result_types := make([]C.uchar, result_count, result_count)
+    if (param_count > 0) {
+        C.wasm_func_get_param_types(_func, self._instance,
+                                    (*C.uchar)(unsafe.Pointer(&param_types[0])))
+    }
+    if (result_count > 0) {
+        C.wasm_func_get_result_types(_func, self._instance,
+                                     (*C.uchar)(unsafe.Pointer(&result_types[0])))
+    }
+
+    argv_size := param_count * 2
+    if (result_count > param_count) {
+        argv_size = result_count * 2
+    }
+    argv := make([]uint32, argv_size, argv_size)
+
+    var i, argc uint32
+    for _, arg := range args {
+        if (i >= param_count) {
+            break;
+        }
+        switch arg.(type) {
+            case int32:
+                if (param_types[i] != C.WASM_I32 &&
+                    param_types[i] != C.WASM_FUNCREF &&
+                    param_types[i] != C.WASM_ANYREF) {
+                    str := "CallFunc error: invalid param type %d, " +
+                           "expect i32 but got other"
+                    return fmt.Errorf(str, param_types[i])
+                }
+                argv[argc] = (uint32)(arg.(int32))
+                argc++
+                break
+            case int64:
+                if (param_types[i] != C.WASM_I64) {
+                    str := "CallFunc error: invalid param type %d, " +
+                           "expect i64 but got other"
+                    return fmt.Errorf(str, param_types[i])
+                }
+                addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
+                C.PUT_I64_TO_ADDR(addr, (C.int64_t)(arg.(int64)))
+                argc += 2
+                break
+            case float32:
+                if (param_types[i] != C.WASM_F32) {
+                    str := "CallFunc error: invalid param type %d, " +
+                           "expect f32 but got other"
+                    return fmt.Errorf(str, param_types[i])
+                }
+                *(*C.float)(unsafe.Pointer(&argv[argc])) = (C.float)(arg.(float32))
+                argc++
+                break
+            case float64:
+                if (param_types[i] != C.WASM_F64) {
+                    str := "CallFunc error: invalid param type %d, " +
+                           "expect f64 but got other"
+                    return fmt.Errorf(str, param_types[i])
+                }
+                addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
+                C.PUT_F64_TO_ADDR(addr, (C.double)(arg.(float64)))
+                argc += 2
+                break
+            default:
+                return fmt.Errorf("CallFunc error: unknown param type %d",
+                                  param_types[i])
+        }
+        i++
+    }
+
+    if (i < param_count) {
+        str := "CallFunc error: invalid param count, " +
+               "must be no smaller than %d"
+        return fmt.Errorf(str, param_count)
+    }
+
+    err := self.CallFunc(funcName, argc, argv)
+    if (err != nil) {
+        return err
+    }
+
+    argc = 0
+    for i = 0; i < result_count; i++ {
+        switch result_types[i] {
+            case C.WASM_I32:
+            case C.WASM_FUNCREF:
+            case C.WASM_ANYREF:
+                i32 := (int32)(argv[argc])
+                results[i] = i32
+                argc++
+                break
+            case C.WASM_I64:
+                addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
+                results[i] = (int64)(C.GET_I64_FROM_ADDR(addr))
+                argc += 2
+                break
+            case C.WASM_F32:
+                addr := (*C.float)(unsafe.Pointer(&argv[argc]))
+                results[i] = (float32)(*addr)
+                argc++
+                break
+            case C.WASM_F64:
+                addr := (*C.uint32_t)(unsafe.Pointer(&argv[argc]))
+                results[i] = (float64)(C.GET_F64_FROM_ADDR(addr))
+                argc += 2
+                break
+        }
+    }
+
+    return nil
+}
+
+/* Get exception info of the instance */
+func (self *Instance) GetException() string {
+    cStr := C.wasm_runtime_get_exception(self._instance)
+    goStr := C.GoString(cStr)
+    return goStr
+}
+
+/* Allocate memory from the heap of the instance */
+func (self Instance) ModuleMalloc(size uint32) (uint32, *uint8) {
+    var offset C.uint32_t
+    native_addrs := make([]*uint8, 1, 1)
+    ptr := unsafe.Pointer(&native_addrs[0])
+    offset = C.wasm_runtime_module_malloc(self._instance, (C.uint32_t)(size),
+                                          (*unsafe.Pointer)(ptr))
+    return (uint32)(offset), native_addrs[0]
+}
+
+/* Free memory to the heap of the instance */
+func (self Instance) ModuleFree(offset uint32) {
+    C.wasm_runtime_module_free(self._instance, (C.uint32_t)(offset))
+}
+
+func (self Instance) ValidateAppAddr(app_offset uint32, size uint32) bool {
+    ret := C.wasm_runtime_validate_app_addr(self._instance,
+                                            (C.uint32_t)(app_offset),
+                                            (C.uint32_t)(size))
+    return (bool)(ret)
+}
+
+func (self Instance) ValidateStrAddr(app_str_offset uint32) bool {
+    ret := C.wasm_runtime_validate_app_str_addr(self._instance,
+                                                (C.uint32_t)(app_str_offset))
+    return (bool)(ret)
+}
+
+func (self Instance) ValidateNativeAddr(native_ptr *uint8, size uint32) bool {
+    native_ptr_C := (unsafe.Pointer)(native_ptr)
+    ret := C.wasm_runtime_validate_native_addr(self._instance,
+                                               native_ptr_C,
+                                               (C.uint32_t)(size))
+    return (bool)(ret)
+}
+
+func (self Instance) AddrAppToNative(app_offset uint32) *uint8 {
+    native_ptr := C.wasm_runtime_addr_app_to_native(self._instance,
+                                                    (C.uint32_t)(app_offset))
+    return (*uint8)(native_ptr)
+}
+
+func (self Instance) AddrNativeToApp(native_ptr *uint8) uint32 {
+    native_ptr_C := (unsafe.Pointer)(native_ptr)
+    offset := C.wasm_runtime_addr_native_to_app(self._instance,
+                                                native_ptr_C)
+    return (uint32)(offset)
+}
+
+func (self Instance) GetAppAddrRange(app_offset uint32) (bool,
+                                                         uint32,
+                                                         uint32) {
+    var start_offset, end_offset C.uint32_t
+    ret := C.wasm_runtime_get_app_addr_range(self._instance,
+                                             (C.uint32_t)(app_offset),
+                                             &start_offset, &end_offset)
+    return (bool)(ret), (uint32)(start_offset), (uint32)(end_offset)
+}
+
+func (self Instance) GetNativeAddrRange(native_ptr *uint8) (bool,
+                                                            *uint8,
+                                                            *uint8) {
+    var start_addr, end_addr *C.uint8_t
+    native_ptr_C := (*C.uint8_t)((unsafe.Pointer)(native_ptr))
+    ret := C.wasm_runtime_get_native_addr_range(self._instance,
+                                                native_ptr_C,
+                                                &start_addr, &end_addr)
+    return (bool)(ret), (*uint8)(start_addr), (*uint8)(end_addr)
+}
+
+func (self Instance) DumpMemoryConsumption() {
+    C.wasm_runtime_dump_mem_consumption(self._exec_env)
+}
+
+func (self Instance) DumpCallStack() {
+    C.wasm_runtime_dump_call_stack(self._exec_env)
+}

+ 19 - 0
language-bindings/go/wamr/instance_test.go

@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package wamr
+
+import (
+    //"github.com/stretchr/testify/assert"
+    "testing"
+)
+
+func TestInstance(t *testing.T) {
+    /* TODO */
+}
+
+func TestCallFunc(t *testing.T) {
+    /* TODO */
+}

+ 134 - 0
language-bindings/go/wamr/module.go

@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package wamr
+
+// #include <wasm_export.h>
+import "C"
+import (
+    "unsafe"
+    "runtime"
+    "fmt"
+)
+
+type Module struct {
+    module C.wasm_module_t
+}
+
+/* Create WASM/AOT module from the memory buffer */
+func NewModule(wasmBytes []byte) (*Module, error) {
+    if (wasmBytes == nil || len(wasmBytes) == 0) {
+        return nil, fmt.Errorf("NewModule error: invalid input")
+    }
+
+    wasmPtr := (*C.uint8_t)(unsafe.Pointer(&wasmBytes[0]))
+    wasmLen := C.uint(len(wasmBytes))
+
+    errorBytes := make([]byte, 128)
+    errorPtr := (*C.char)(unsafe.Pointer(&errorBytes[0]))
+    errorLen := C.uint(len(errorBytes))
+
+    m := C.wasm_runtime_load(wasmPtr, wasmLen, errorPtr, errorLen)
+    if (m == nil) {
+        return nil, fmt.Errorf("NewModule error: %s", string(errorBytes))
+    }
+
+    self := &Module{
+        module: m,
+    }
+
+    runtime.SetFinalizer(self, func(self *Module) {
+        self.Destroy()
+    })
+
+    return self, nil
+}
+
+/* Destroy the module */
+func (self *Module) Destroy() {
+    runtime.SetFinalizer(self, nil)
+    if (self.module != nil) {
+        C.wasm_runtime_unload(self.module)
+    }
+}
+
+/* Set module's wasi arguments */
+func (self *Module) SetWasiArgs(dirList [][]byte, mapDirList [][]byte,
+                                env [][]byte, argv[][]byte) {
+    var dirPtr, mapDirPtr, envPtr, argvPtr **C.char
+    var dirCount, mapDirCount, envCount C.uint
+    var argc C.int
+
+    if (dirList != nil) {
+        dirPtr = (**C.char)(unsafe.Pointer(&dirList[0]))
+        dirCount = C.uint(len(dirList))
+    }
+
+    if (mapDirList != nil) {
+        mapDirPtr = (**C.char)(unsafe.Pointer(&mapDirList[0]))
+        mapDirCount = C.uint(len(mapDirList))
+    }
+
+    if (env != nil) {
+        envPtr = (**C.char)(unsafe.Pointer(&env[0]))
+        envCount = C.uint(len(env))
+    }
+
+    if (argv != nil) {
+        argvPtr = (**C.char)(unsafe.Pointer(&argv[0]))
+        argc = C.int(len(argv))
+    }
+
+    C.wasm_runtime_set_wasi_args(self.module, dirPtr, dirCount,
+                                 mapDirPtr, mapDirCount,
+                                 envPtr, envCount, argvPtr, argc)
+}
+
+/* Set module's wasi arguments */
+func (self *Module) SetWasiArgsEx(dirList [][]byte, mapDirList [][]byte,
+                                env [][]byte, argv[][]byte,
+                                stdinfd int, stdoutfd int, stderrfd int) {
+    var dirPtr, mapDirPtr, envPtr, argvPtr **C.char
+    var dirCount, mapDirCount, envCount C.uint
+    var argc C.int
+
+    if (dirList != nil) {
+        dirPtr = (**C.char)(unsafe.Pointer(&dirList[0]))
+        dirCount = C.uint(len(dirList))
+    }
+
+    if (mapDirList != nil) {
+        mapDirPtr = (**C.char)(unsafe.Pointer(&mapDirList[0]))
+        mapDirCount = C.uint(len(mapDirList))
+    }
+
+    if (env != nil) {
+        envPtr = (**C.char)(unsafe.Pointer(&env[0]))
+        envCount = C.uint(len(env))
+    }
+
+    if (argv != nil) {
+        argvPtr = (**C.char)(unsafe.Pointer(&argv[0]))
+        argc = C.int(len(argv))
+    }
+
+    C.wasm_runtime_set_wasi_args_ex(self.module, dirPtr, dirCount,
+                                    mapDirPtr, mapDirCount,
+                                    envPtr, envCount, argvPtr, argc,
+                                    C.int(stdinfd), C.int(stdoutfd),
+                                    C.int(stderrfd))
+}
+
+/* Set module's wasi network address pool */
+func (self *Module) SetWasiAddrPool(addrPool [][]byte) {
+    var addrPoolPtr **C.char
+    var addrPoolSize C.uint
+
+    if (addrPool != nil) {
+        addrPoolPtr = (**C.char)(unsafe.Pointer(&addrPool[0]))
+        addrPoolSize = C.uint(len(addrPool))
+    }
+    C.wasm_runtime_set_wasi_addr_pool(self.module, addrPoolPtr, addrPoolSize)
+}

+ 15 - 0
language-bindings/go/wamr/module_test.go

@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package wamr
+
+import (
+    //"github.com/stretchr/testify/assert"
+    "testing"
+)
+
+func TestModule(t *testing.T) {
+    /* TODO */
+}

+ 6 - 0
language-bindings/go/wamr/packaged/include/dummy.go

@@ -0,0 +1,6 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package include

+ 6 - 0
language-bindings/go/wamr/packaged/lib/darwin-amd64/dummy.go

@@ -0,0 +1,6 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package darwin_amd64

+ 6 - 0
language-bindings/go/wamr/packaged/lib/dummy.go

@@ -0,0 +1,6 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package lib

+ 6 - 0
language-bindings/go/wamr/packaged/lib/linux-amd64/dummy.go

@@ -0,0 +1,6 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package linux_amd64

+ 153 - 0
language-bindings/go/wamr/runtime.go

@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package wamr
+
+/*
+#include <stdlib.h>
+#include <string.h>
+
+#include <wasm_export.h>
+
+void
+bh_log_set_verbose_level(uint32_t level);
+
+bool
+init_wamr_runtime(bool alloc_with_pool, uint8_t *heap_buf,
+                  uint32_t heap_size, uint32_t max_thread_num)
+{
+    RuntimeInitArgs init_args;
+
+    memset(&init_args, 0, sizeof(RuntimeInitArgs));
+
+    if (alloc_with_pool) {
+        init_args.mem_alloc_type = Alloc_With_Pool;
+        init_args.mem_alloc_option.pool.heap_buf = heap_buf;
+        init_args.mem_alloc_option.pool.heap_size = heap_size;
+    }
+    else {
+        init_args.mem_alloc_type = Alloc_With_System_Allocator;
+    }
+
+    return wasm_runtime_full_init(&init_args);
+}
+*/
+import "C"
+import (
+    "fmt"
+    "unsafe"
+)
+
+type LogLevel uint32
+const (
+    LOG_LEVEL_FATAL   LogLevel = 0
+    LOG_LEVEL_ERROR   LogLevel = 1
+    LOG_LEVEL_WARNING LogLevel = 2
+    LOG_LEVEL_DEBUG   LogLevel = 3
+    LOG_LEVEL_VERBOSE LogLevel = 4
+)
+
+/*
+type NativeSymbol struct {
+    symbol string
+    func_ptr *uint8
+    signature string
+}
+*/
+
+type _Runtime struct {
+    initialized bool
+}
+
+var _runtime_singleton *_Runtime
+
+/* Return the runtime singleton */
+func Runtime() *_Runtime {
+    if (_runtime_singleton == nil) {
+        self := &_Runtime{}
+        _runtime_singleton = self
+    }
+    return _runtime_singleton;
+}
+
+/* Initialize the WASM runtime environment */
+func (self *_Runtime) FullInit(alloc_with_pool bool, heap_buf []byte,
+                               max_thread_num uint) error {
+    var heap_buf_C *C.uchar
+
+    if (self.initialized) {
+        return nil
+    }
+
+    if (alloc_with_pool) {
+        if (heap_buf == nil) {
+            return fmt.Errorf("Failed to init WAMR runtime")
+        }
+        heap_buf_C = (*C.uchar)(unsafe.Pointer(&heap_buf[0]))
+    }
+
+    if (!C.init_wamr_runtime((C.bool)(alloc_with_pool), heap_buf_C,
+                             (C.uint)(len(heap_buf)),
+                             (C.uint)(max_thread_num))) {
+        return fmt.Errorf("Failed to init WAMR runtime")
+    }
+
+    self.initialized = true
+    return nil
+}
+
+/* Initialize the WASM runtime environment */
+func (self *_Runtime) Init() error {
+    return self.FullInit(false, nil, 1)
+}
+
+/* Destroy the WASM runtime environment */
+func (self *_Runtime) Destroy() {
+    if (self.initialized) {
+        C.wasm_runtime_destroy()
+        self.initialized = false
+    }
+}
+
+/* Set log verbose level (0 to 5, default is 2),
+   larger level with more log */
+func (self *_Runtime) SetLogLevel(level LogLevel) {
+    C.bh_log_set_verbose_level(C.uint32_t(level))
+}
+
+/*
+func (self *_Runtime) RegisterNatives(moduleName string,
+                                      nativeSymbols []NativeSymbol) {
+}
+*/ /* TODO */
+
+func (self *_Runtime) InitThreadEnv() bool {
+    if (!C.wasm_runtime_init_thread_env()) {
+        return false
+    }
+    return true
+}
+
+func (self *_Runtime) DestroyThreadEnv() {
+    C.wasm_runtime_destroy_thread_env();
+}
+
+func (self *_Runtime) ThreadEnvInited() bool {
+    if (!C.wasm_runtime_thread_env_inited()) {
+        return false
+    }
+    return true
+}
+
+/* Allocate memory from runtime memory environment */
+func (self *_Runtime) Malloc(size uint32) *uint8 {
+    ptr := C.wasm_runtime_malloc((C.uint32_t)(size))
+    return (*uint8)(ptr)
+}
+
+/* Free memory to runtime memory environment */
+func (self *_Runtime) Free(ptr *uint8) {
+    C.wasm_runtime_free((unsafe.Pointer)(ptr))
+}

+ 42 - 0
language-bindings/go/wamr/runtime_test.go

@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+package wamr
+
+import (
+    "github.com/stretchr/testify/assert"
+    "testing"
+)
+
+func TestRuntime(t *testing.T) {
+    res := false
+    if (Runtime() != nil) {
+        res = true;
+    }
+    assert.Equal(t, res, true)
+
+    err := Runtime().Init()
+    assert.NoError(t, err)
+    Runtime().Destroy()
+
+    err = Runtime().FullInit(false, nil, 6)
+    assert.NoError(t, err)
+    Runtime().Destroy()
+
+    err = Runtime().FullInit(false, nil, 0)
+    assert.NoError(t, err)
+    Runtime().Destroy()
+
+    heap_buf := make([]byte, 128 * 1024)
+    err = Runtime().FullInit(true, heap_buf, 4)
+    assert.NoError(t, err)
+    Runtime().Destroy()
+
+    Runtime().FullInit(false, nil, 0)
+    err = Runtime().FullInit(false, nil, 0)
+    assert.NoError(t, err)
+    Runtime().Destroy()
+    Runtime().Destroy()
+}