Просмотр исходного кода

support app framework base library in assemblyscript (#164)

Xu Jun 6 лет назад
Родитель
Сommit
5a10651dd0

+ 124 - 0
assembly-script/README.md

@@ -0,0 +1,124 @@
+# AssemblyScript_on_WAMR
+This project is based on [Wasm Micro Runtime](https://github.com/bytecodealliance/wasm-micro-runtime) (WAMR) and [AssemblyScript](https://github.com/AssemblyScript/assemblyscript). It implements some of the `wamr app framework` in *assemblyscript*, which allows you to write some applications in *assemblyscript* and dynamically installed on *WAMR Runtime*
+
+## Building
+To build the samples in this repo, you need `npm` on your system
+``` bash
+sudo apt install npm
+```
+
+Then install all the dependencies under the repo's root dir
+``` bash
+cd $repo_root
+npm install
+```
+
+Use the command to build all samples:
+``` bash
+npm run build:all
+```
+or you can build every sample individually:
+``` bash
+npm run build:timer
+npm run build:publisher
+npm run build:subscriber
+# ...
+```
+You will get the compiled wasm file under `build` folder
+
+Please refer to [package.json](./package.json) for more commands.
+
+## Run
+These applications require WAMR's application framework, you need to build WAMR first.
+
+``` bash
+cd ${WAMR_ROOT}/samples/simple
+./build.sh
+```
+
+You will get two executable files under `out` folder:
+
+`simple`: The wamr runtime with application framework
+
+`host_tool`: The tool used to dynamically install/uninstall applications
+
+1. Start the runtime:
+    ``` bash
+    ./simple -s
+    ```
+
+2. Install the compiled wasm file using `host_tool`:
+    ``` bash
+    ./host_tool -i app_name -f your_compiled_wasm_file.wasm
+    ```
+You can also use the WAMR's AoT compiler `wamrc` to compile the wasm bytecode into native code before you run them. Please refer to this [guide](../README.md#build-wamrc-aot-compiler) to build and install `WAMR AoT compiler`.
+
+After installing `wamrc`, you can compile the wasm file using command:
+``` bash
+wamrc -o file_name.aot file_name.wasm
+```
+and you can install the AoT file to the runtime:
+``` bash
+./host_tool -i app_name -f your_compiled_aot_file.aot
+```
+
+## Development
+You can develop your own application based on the `wamr_app_lib` APIs.
+
+### Console APIs
+``` typescript
+function log(a: string): void;
+function log_number(a: number): void;
+```
+
+### Timer APIs
+``` typescript
+function setTimeout(cb: () => void, timeout: i32): user_timer;
+function setInterval(cb: () => void, timeout: i32): user_timer;
+function timer_cancel(timer: user_timer): void;
+function timer_restart(timer: user_timer, interval: number): void;
+function now(): i32;
+
+// export to runtime
+function on_timer_callback(on_timer_id: i32): void;
+```
+
+### Request APIs
+``` typescript
+// register handler
+function register_resource_handler(url: string,
+                                   request_handle: request_handler_f): void;
+// request
+function post(url: string, payload: ArrayBuffer, payload_len: number,
+              tag: string, cb: (resp: wamr_response) => void): void;
+function get(url: string, tag: string,
+             cb: (resp: wamr_response) => void): void;
+function put(url: string, payload: ArrayBuffer, payload_len: number, tag: string,
+             cb: (resp: wamr_response) => void): void;
+function del(url: string, tag: string,
+             cb: (resp: wamr_response) => void): void;
+
+// response
+function make_response_for_request(req: wamr_request): wamr_response;
+function api_response_send(resp: wamr_response): void;
+
+// event
+function publish_event(url: string, fmt: number,
+                       payload: ArrayBuffer, payload_len: number): void;
+function subscribe_event(url: string, cb: request_handler_f): void;
+
+// export to runtime
+function on_request(buffer_offset: i32, size: i32): void;
+function on_response(buffer_offset : i32, size: i32): void;
+```
+
+You should export the `on_timer_callback`, `on_request` and `on_response` in your application entry file, refer to the samples for example.
+
+To build your application, you can use `asc`:
+``` bash
+asc app.ts -b build/app.wasm -t build/app.wat --sourceMap --validate --optimize
+```
+or you can add a command into [package.json](./package.json):
+``` json
+"build:app": "asc app.ts -b build/app.wasm -t build/app.wat --sourceMap --validate --optimize",
+```

+ 30 - 0
assembly-script/package-lock.json

@@ -0,0 +1,30 @@
+{
+  "name": "assembly_script",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "assemblyscript": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npm.taobao.org/assemblyscript/download/assemblyscript-0.8.1.tgz",
+      "integrity": "sha1-xcYnSSQG5th/QmiXs9kr0qUz9/4=",
+      "dev": true,
+      "requires": {
+        "binaryen": "89.0.0-nightly.20191113",
+        "long": "^4.0.0"
+      }
+    },
+    "binaryen": {
+      "version": "89.0.0-nightly.20191113",
+      "resolved": "https://registry.npm.taobao.org/binaryen/download/binaryen-89.0.0-nightly.20191113.tgz",
+      "integrity": "sha1-oNORTzXJKXhzQeApELf/rrfYl6k=",
+      "dev": true
+    },
+    "long": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npm.taobao.org/long/download/long-4.0.0.tgz",
+      "integrity": "sha1-mntxz7fTYaGU6lVSQckvdGjVvyg=",
+      "dev": true
+    }
+  }
+}

+ 20 - 0
assembly-script/package.json

@@ -0,0 +1,20 @@
+{
+  "name": "assembly_script",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1",
+    "build:request_handler": "asc samples/request_handler.ts -b build/request_handler.wasm -t build/request_handler.wat --sourceMap --validate --optimize",
+    "build:request_sender": "asc samples/request_sender.ts -b build/request_sender.wasm -t build/request_sender.wat --sourceMap --validate --optimize",
+    "build:timer": "asc samples/timer.ts -b build/timer.wasm -t build/timer.wat --sourceMap --validate --optimize",
+    "build:publisher": "asc samples/event_publisher.ts -b build/event_publisher.wasm -t build/event_publisher.wat --sourceMap --validate --optimize",
+    "build:subscriber": "asc samples/event_subscriber.ts -b build/event_subscriber.wasm -t build/event_subscriber.wat --sourceMap --validate --optimize",
+    "build:all": "npm run build:request_handler; npm run build:request_sender; npm run build:timer; npm run build:subscriber; npm run build:publisher"
+  },
+  "author": "",
+  "license": "ISC",
+  "devDependencies": {
+    "assemblyscript": "^0.8.1"
+  }
+}

+ 36 - 0
assembly-script/samples/event_publisher.ts

@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+// The entry file of your WebAssembly module.
+import * as console from "../wamr_app_lib/console"
+import * as timer from "../wamr_app_lib/timer"
+import * as request from "../wamr_app_lib/request"
+
+function publish_overheat_event(): void {
+    var payload = String.UTF8.encode("warning: temperature is over high");
+    request.publish_event("alert/overheat", 0, payload, payload.byteLength);
+}
+
+export function on_init() : void {
+    timer.setInterval(publish_overheat_event, 2000);
+}
+
+export function on_destroy() : void {
+
+}
+
+
+/* Function below are requred by wamr runtime, don't remove or modify them */
+export function _on_timer_callback(on_timer_id: i32): void {
+    timer.on_timer_callback(on_timer_id);
+}
+
+export function _on_request(buffer_offset: i32, size: i32): void {
+    request.on_request(buffer_offset, size);
+}
+
+export function _on_response(buffer_offset : i32, size: i32): void {
+    request.on_response(buffer_offset, size);
+}

+ 36 - 0
assembly-script/samples/event_subscriber.ts

@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+// The entry file of your WebAssembly module.
+import * as console from "../wamr_app_lib/console"
+import * as timer from "../wamr_app_lib/timer"
+import * as request from "../wamr_app_lib/request"
+
+export function on_init() : void {
+    request.subscribe_event("alert/overheat", (req) => {
+        console.log("### user over heat event handler called:");
+
+        console.log("");
+        console.log("    " + String.UTF8.decode(req.payload) + "\n");
+    })
+}
+
+export function on_destroy() : void {
+
+}
+
+
+/* Function below are requred by wamr runtime, don't remove or modify them */
+export function _on_timer_callback(on_timer_id: i32): void {
+    timer.on_timer_callback(on_timer_id);
+}
+
+export function _on_request(buffer_offset: i32, size: i32): void {
+    request.on_request(buffer_offset, size);
+}
+
+export function _on_response(buffer_offset : i32, size: i32): void {
+    request.on_response(buffer_offset, size);
+}

+ 40 - 0
assembly-script/samples/request_handler.ts

@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+ // The entry file of your WebAssembly module.
+import * as console from "../wamr_app_lib/console"
+import * as timer from "../wamr_app_lib/timer"
+import * as request from "../wamr_app_lib/request"
+
+export function on_init() : void {
+    request.register_resource_handler("/test", (req) => {
+        console.log("### Req: /test  " + String.UTF8.decode(req.payload));
+
+        console.log("    request payload:");
+        console.log("    " + String.UTF8.decode(req.payload) + "\n");
+
+        var resp = request.make_response_for_request(req);
+        resp.set_payload(String.UTF8.encode("Ok"), 2);
+        request.api_response_send(resp);
+    });
+}
+
+export function on_destroy() : void {
+
+}
+
+
+/* Function below are requred by wamr runtime, don't remove or modify them */
+export function _on_timer_callback(on_timer_id: i32): void {
+    timer.on_timer_callback(on_timer_id);
+}
+
+export function _on_request(buffer_offset: i32, size: i32): void {
+    request.on_request(buffer_offset, size);
+}
+
+export function _on_response(buffer_offset : i32, size: i32): void {
+    request.on_response(buffer_offset, size);
+}

+ 43 - 0
assembly-script/samples/request_sender.ts

@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+// The entry file of your WebAssembly module.
+import * as console from "../wamr_app_lib/console"
+import * as timer from "../wamr_app_lib/timer"
+import * as request from "../wamr_app_lib/request"
+
+export function on_init() : void {
+    var payload = String.UTF8.encode("test message");
+    request.post("/test", payload, payload.byteLength, "", (resp) => {
+        if (resp != null) {
+            console.log("Post Success");
+
+            if (resp.payload != null) {
+                console.log("    response payload:")
+                console.log("    " + String.UTF8.decode(resp.payload!) + "\n");
+            }
+        }
+        else
+            console.log("Post Timeout");
+    });
+}
+
+export function on_destroy() : void {
+
+}
+
+
+/* Function below are requred by wamr runtime, don't remove or modify them */
+export function _on_timer_callback(on_timer_id: i32): void {
+    timer.on_timer_callback(on_timer_id);
+}
+
+export function _on_request(buffer_offset: i32, size: i32): void {
+    request.on_request(buffer_offset, size);
+}
+
+export function _on_response(buffer_offset : i32, size: i32): void {
+    request.on_response(buffer_offset, size);
+}

+ 36 - 0
assembly-script/samples/timer.ts

@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+// The entry file of your WebAssembly module.
+import * as console from '../wamr_app_lib/console'
+import * as timer from '../wamr_app_lib/timer'
+
+/* clousure is not implemented yet, we need to declare global variables
+    so that they can be accessed inside a callback function */
+var cnt = 0;
+var my_timer: timer.user_timer;
+
+export function on_init(): void {
+    /* The callback function will be called every 2 second,
+        and will stop after 10 calls */
+    my_timer = timer.setInterval(() => {
+        cnt ++;
+        console.log((cnt * 2).toString() + " seconds passed");
+
+        if (cnt >= 10) {
+            timer.timer_cancel(my_timer);
+            console.log("Stop Timer");
+        }
+    }, 2000);
+}
+
+export function on_destroy(): void {
+
+}
+
+/* Function below are requred by wamr runtime, don't remove or modify them */
+export function _on_timer_callback(on_timer_id: i32): void {
+    timer.on_timer_callback(on_timer_id);
+}

+ 6 - 0
assembly-script/samples/tsconfig.json

@@ -0,0 +1,6 @@
+{
+  "extends": "../node_modules/assemblyscript/std/assembly.json",
+  "include": [
+    "./**/*.ts"
+  ]
+}

+ 15 - 0
assembly-script/wamr_app_lib/console.ts

@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+@external("env", "printf")
+declare function printf(a: ArrayBuffer): i32;
+
+export function log(a: string): void {
+    printf(String.UTF8.encode(a + '\n', true));
+}
+
+export function log_number(a: number): void {
+    printf(String.UTF8.encode(a.toString() + '\n'));
+}

+ 495 - 0
assembly-script/wamr_app_lib/request.ts

@@ -0,0 +1,495 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+import * as console from './console'
+import * as timer from './timer'
+
+@external("env", "wasm_response_send")
+declare function wasm_response_send(buffer: ArrayBuffer, size: i32): void;
+
+@external("env", "wasm_register_resource")
+declare function wasm_register_resource(url: ArrayBuffer): void;
+
+@external("env", "wasm_post_request")
+declare function wasm_post_request(buffer: ArrayBuffer, size: i32): void;
+
+@external("env", "wasm_sub_event")
+declare function wasm_sub_event(url: ArrayBuffer): void;
+
+var COAP_GET = 1;
+var COAP_POST = 2;
+var COAP_PUT = 3;
+var COAP_DELETE = 4;
+var COAP_EVENT = COAP_DELETE + 2;
+
+/* CoAP response codes */
+export enum CoAP_Status {
+    NO_ERROR = 0,
+
+    CREATED_2_01 = 65, /* CREATED */
+    DELETED_2_02 = 66, /* DELETED */
+    VALID_2_03 = 67, /* NOT_MODIFIED */
+    CHANGED_2_04 = 68, /* CHANGED */
+    CONTENT_2_05 = 69, /* OK */
+    CONTINUE_2_31 = 95, /* CONTINUE */
+
+    BAD_REQUEST_4_00 = 128, /* BAD_REQUEST */
+    UNAUTHORIZED_4_01 = 129, /* UNAUTHORIZED */
+    BAD_OPTION_4_02 = 130, /* BAD_OPTION */
+    FORBIDDEN_4_03 = 131, /* FORBIDDEN */
+    NOT_FOUND_4_04 = 132, /* NOT_FOUND */
+    METHOD_NOT_ALLOWED_4_05 = 133, /* METHOD_NOT_ALLOWED */
+    NOT_ACCEPTABLE_4_06 = 134, /* NOT_ACCEPTABLE */
+    PRECONDITION_FAILED_4_12 = 140, /* BAD_REQUEST */
+    REQUEST_ENTITY_TOO_LARGE_4_13 = 141, /* REQUEST_ENTITY_TOO_LARGE */
+    UNSUPPORTED_MEDIA_TYPE_4_15 = 143, /* UNSUPPORTED_MEDIA_TYPE */
+
+    INTERNAL_SERVER_ERROR_5_00 = 160, /* INTERNAL_SERVER_ERROR */
+    NOT_IMPLEMENTED_5_01 = 161, /* NOT_IMPLEMENTED */
+    BAD_GATEWAY_5_02 = 162, /* BAD_GATEWAY */
+    SERVICE_UNAVAILABLE_5_03 = 163, /* SERVICE_UNAVAILABLE */
+    GATEWAY_TIMEOUT_5_04 = 164, /* GATEWAY_TIMEOUT */
+    PROXYING_NOT_SUPPORTED_5_05 = 165, /* PROXYING_NOT_SUPPORTED */
+
+    /* Erbium errors */
+    MEMORY_ALLOCATION_ERROR = 192, PACKET_SERIALIZATION_ERROR,
+
+    /* Erbium hooks */
+    MANUAL_RESPONSE, PING_RESPONSE
+};
+
+var g_mid: i32 = 0;
+class wamr_request {
+    mid: i32 = 0;
+    url: string = "";
+    action: i32 = 0;
+    fmt: i32 = 0;
+    payload: ArrayBuffer;
+    payload_len: i32 = 0;
+
+    sender: i32 = 0;
+
+    constructor(mid: i32, url: string, action: i32, fmt: i32,
+        payload: ArrayBuffer, payload_len: number) {
+        this.mid = mid;
+        this.url = url;
+        this.action = action;
+        this.fmt = fmt;
+        this.payload = payload;
+        this.payload_len = i32(payload_len);
+    }
+}
+
+class wamr_response {
+    mid: i32 = 0;
+    status: i32 = 0;
+    fmt: i32 = 0;
+    payload: ArrayBuffer | null;
+    payload_len: i32 = 0;
+
+    receiver: i32 = 0;
+
+    constructor(mid: i32, status: i32, fmt: i32,
+        payload: ArrayBuffer | null, payload_len: i32) {
+        this.mid = mid;
+        this.status = status;
+        this.fmt = fmt;
+        this.payload = payload;
+        this.payload_len = payload_len;
+    }
+
+    set_status(status: number): void {
+        this.status = i32(status);
+    }
+
+    set_payload(payload: ArrayBuffer, payload_len: number): void {
+        this.payload = payload;
+        this.payload_len = i32(payload_len);
+    }
+}
+
+class wamr_resource {
+    url: string;
+    type: number;
+    cb: request_handler_f;
+
+    constructor(url: string, type: number, cb: request_handler_f) {
+        this.url = url;
+        this.type = type;
+        this.cb = cb;
+    }
+}
+
+function is_expire(trans: wamr_transaction, index: i32, array: Array<wamr_transaction>): bool {
+    var now = timer.now();
+
+    var elapsed_ms = (now < trans.time) ?
+        (now + (0xFFFFFFFF - trans.time) + 1) : (now - trans.time);
+
+    return elapsed_ms >= TRANSACTION_TIMEOUT_MS;
+}
+
+function not_expire(trans: wamr_transaction, index: i32, array: Array<wamr_transaction>): bool {
+    var now = timer.now();
+
+    var elapsed_ms = (now < trans.time) ?
+        (now + (0xFFFFFFFF - trans.time) + 1) : (now - trans.time);
+
+    return elapsed_ms >= TRANSACTION_TIMEOUT_MS;
+}
+
+function transaction_timeout_handler(): void {
+    var now = timer.now();
+
+    var expired = transaction_list.filter(is_expire);
+    transaction_list = transaction_list.filter(not_expire);
+
+    expired.forEach(item => {
+        item.cb(null);
+        transaction_remove(item);
+    })
+
+    if (transaction_list.length > 0) {
+        var elpased_ms: number, ms_to_expiry: number;
+        now = timer.now();
+        if (now < transaction_list[0].time) {
+            elpased_ms = now + (0xFFFFFFFF - transaction_list[0].time) + 1;
+        } else {
+            elpased_ms = now - transaction_list[0].time;
+        }
+        ms_to_expiry = TRANSACTION_TIMEOUT_MS - elpased_ms;
+        timer.timer_restart(g_trans_timer, ms_to_expiry);
+    } else {
+        timer.timer_cancel(g_trans_timer);
+    }
+}
+
+function transaction_find(mid: number): wamr_transaction | null {
+    for (let i = 0; i < transaction_list.length; i++) {
+        if (transaction_list[i].mid == mid)
+            return transaction_list[i];
+    }
+    return null;
+}
+
+function transaction_add(trans: wamr_transaction): void {
+    transaction_list.push(trans);
+
+    if (transaction_list.length == 1) {
+        g_trans_timer = timer.setTimeout(
+            transaction_timeout_handler,
+            TRANSACTION_TIMEOUT_MS
+        );
+    }
+}
+
+function transaction_remove(trans: wamr_transaction): void {
+    var index = transaction_list.indexOf(trans);
+    transaction_list.splice(index, 1);
+}
+
+var transaction_list = new Array<wamr_transaction>();
+class wamr_transaction {
+    mid: number;
+    time: number;
+    cb: (resp: wamr_response | null) => void;
+
+    constructor(mid: number, time: number, cb: (resp: wamr_response) => void) {
+        this.mid = mid;
+        this.time = time;
+        this.cb = cb;
+    }
+}
+
+var REQUEST_PACKET_FIX_PART_LEN = 18;
+var RESPONSE_PACKET_FIX_PART_LEN = 16;
+var TRANSACTION_TIMEOUT_MS = 5000;
+var g_trans_timer: timer.user_timer;
+
+var Reg_Event = 0;
+var Reg_Request = 1;
+
+function pack_request(req: wamr_request): DataView {
+    var url_len = req.url.length + 1;
+    var len = REQUEST_PACKET_FIX_PART_LEN + url_len + req.payload_len
+    var buf = new ArrayBuffer(len);
+
+    var dataview = new DataView(buf, 0, len);
+
+    dataview.setUint8(0, 1);
+    dataview.setUint8(1, u8(req.action));
+    dataview.setUint16(2, u16(req.fmt));
+    dataview.setUint32(4, req.mid);
+    dataview.setUint32(8, req.sender);
+    dataview.setUint16(12, u16(url_len))
+    dataview.setUint32(14, req.payload_len);
+
+    var i = 0;
+    for (i = 0; i < url_len - 1; i++) {
+        dataview.setUint8(i + 18, u8(req.url.codePointAt(i)));
+    }
+    dataview.setUint8(i + 18, 0);
+
+    var payload_view = new DataView(req.payload);
+    for (i = 0; i < req.payload_len; i++) {
+        dataview.setUint8(i + 18 + url_len, u8(payload_view.getUint8(i)));
+    }
+
+    return dataview;
+}
+
+function unpack_request(packet: ArrayBuffer, size: i32): wamr_request {
+    var dataview = new DataView(packet, 0, size);
+
+    if (dataview.getUint8(0) != 1)
+        throw new Error("packet version mismatch");
+
+    if (size < REQUEST_PACKET_FIX_PART_LEN)
+        throw new Error("packet size error");
+
+    var url_len = dataview.getUint16(12);
+    var payload_len = dataview.getUint32(14);
+
+    if (size != (REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len))
+        throw new Error("packet size error");
+
+    var action = dataview.getUint8(1);
+    var fmt = dataview.getUint16(2);
+    var mid = dataview.getUint32(4);
+    var sender = dataview.getUint32(8);
+
+    var url = packet.slice(REQUEST_PACKET_FIX_PART_LEN, REQUEST_PACKET_FIX_PART_LEN + url_len - 1);
+    var payload = packet.slice(REQUEST_PACKET_FIX_PART_LEN + url_len, REQUEST_PACKET_FIX_PART_LEN + url_len + payload_len);
+
+    var req = new wamr_request(mid, String.UTF8.decode(url), action, fmt, payload, payload_len);
+    req.sender = sender;
+
+    return req;
+}
+
+function pack_response(resp: wamr_response): DataView {
+    var len = RESPONSE_PACKET_FIX_PART_LEN + resp.payload_len
+    var buf = new ArrayBuffer(len);
+
+    var dataview = new DataView(buf, 0, len);
+
+    dataview.setUint8(0, 1);
+    dataview.setUint8(1, u8(resp.status));
+    dataview.setUint16(2, u16(resp.fmt));
+    dataview.setUint32(4, resp.mid);
+    dataview.setUint32(8, resp.receiver);
+    dataview.setUint32(12, resp.payload_len)
+
+    if (resp.payload != null) {
+        var payload_view = new DataView(resp.payload!);
+        for (let i = 0; i < resp.payload_len; i++) {
+            dataview.setUint8(i + 16, payload_view.getUint8(i));
+        }
+    }
+
+    return dataview;
+}
+
+function unpack_response(packet: ArrayBuffer, size: i32): wamr_response {
+    var dataview = new DataView(packet, 0, size);
+
+    if (dataview.getUint8(0) != 1)
+        throw new Error("packet version mismatch");
+
+    if (size < RESPONSE_PACKET_FIX_PART_LEN)
+        throw new Error("packet size error");
+
+    var payload_len = dataview.getUint32(12);
+    if (size != RESPONSE_PACKET_FIX_PART_LEN + payload_len)
+        throw new Error("packet size error");
+
+    var status = dataview.getUint8(1);
+    var fmt = dataview.getUint16(2);
+    var mid = dataview.getUint32(4);
+    var receiver = dataview.getUint32(8);
+
+    var payload = packet.slice(RESPONSE_PACKET_FIX_PART_LEN);
+
+    var resp = new wamr_response(mid, status, fmt, payload, payload_len);
+    resp.receiver = receiver;
+
+    return resp;
+}
+
+function do_request(req: wamr_request, cb: (resp: wamr_response) => void): void {
+    var trans = new wamr_transaction(req.mid, timer.now(), cb);
+    var msg = pack_request(req);
+
+    transaction_add(trans);
+
+    wasm_post_request(msg.buffer, msg.byteLength);
+}
+
+function do_response(resp: wamr_response): void {
+    var msg = pack_response(resp);
+
+    wasm_response_send(msg.buffer, msg.byteLength);
+}
+
+var resource_list = new Array<wamr_resource>();
+type request_handler_f = (req: wamr_request) => void;
+
+function registe_url_handler(url: string, cb: request_handler_f, type: number): void {
+    for (let i = 0; i < resource_list.length; i++) {
+        if (resource_list[i].type == type && resource_list[i].url == url) {
+            resource_list[i].cb = cb;
+            return;
+        }
+    }
+
+    var res = new wamr_resource(url, type, cb);
+    resource_list.push(res);
+
+    if (type == Reg_Request)
+        wasm_register_resource(String.UTF8.encode(url));
+    else
+        wasm_sub_event(String.UTF8.encode(url));
+}
+
+function is_event_type(req: wamr_request): bool {
+    return req.action == COAP_EVENT;
+}
+
+function check_url_start(url: string, leading_str: string): bool {
+    return url.split('/')[0] == leading_str.split('/')[0];
+}
+
+/* User APIs below */
+export function post(url: string, payload: ArrayBuffer, payload_len: number, tag: string,
+                     cb: (resp: wamr_response) => void): void {
+    var req = new wamr_request(g_mid++, url, COAP_POST, 0, payload, payload_len);
+
+    do_request(req, cb);
+}
+
+export function get(url: string, tag: string,
+                    cb: (resp: wamr_response) => void): void {
+    var req = new wamr_request(g_mid++, url, COAP_GET, 0, new ArrayBuffer(0), 0);
+
+    do_request(req, cb);
+}
+
+export function put(url: string, payload: ArrayBuffer, payload_len: number, tag: string,
+                    cb: (resp: wamr_response) => void): void {
+    var req = new wamr_request(g_mid++, url, COAP_PUT, 0, payload, payload_len);
+
+    do_request(req, cb);
+}
+
+export function del(url: string, tag: string,
+                    cb: (resp: wamr_response) => void): void {
+    var req = new wamr_request(g_mid++, url, COAP_PUT, 0, new ArrayBuffer(0), 0);
+
+    do_request(req, cb);
+}
+
+export function make_response_for_request(req: wamr_request): wamr_response {
+    var resp = new wamr_response(req.mid, CoAP_Status.CONTENT_2_05, 0, null, 0);
+    resp.receiver = req.sender;
+
+    return resp;
+}
+
+export function api_response_send(resp: wamr_response): void {
+    do_response(resp);
+}
+
+export function register_resource_handler(url: string,
+    request_handle: request_handler_f): void {
+    registe_url_handler(url, request_handle, Reg_Request);
+}
+
+export function publish_event(url: string, fmt: number,
+    payload: ArrayBuffer, payload_len: number): void {
+    var req = new wamr_request(g_mid++, url, COAP_EVENT, i32(fmt), payload, payload_len);
+
+    var msg = pack_request(req);
+
+    wasm_post_request(msg.buffer, msg.byteLength);
+}
+
+export function subscribe_event(url: string, cb: request_handler_f): void {
+    registe_url_handler(url, cb, Reg_Event);
+}
+
+
+/* These two APIs are required by wamr runtime,
+    use a wrapper to export them in the entry file
+
+    e.g:
+
+    import * as request from '.wamr_app_lib/request'
+
+    // Your code here ...
+
+    export function _on_request(buffer_offset: i32, size: i32): void {
+        on_request(buffer_offset, size);
+    }
+
+    export function _on_response(buffer_offset: i32, size: i32): void {
+        on_response(buffer_offset, size);
+    }
+*/
+export function on_request(buffer_offset: i32, size: i32): void {
+    var buffer = new ArrayBuffer(size);
+    var dataview = new DataView(buffer);
+
+    for (let i = 0; i < size; i++) {
+        dataview.setUint8(i, load<i8>(buffer_offset + i, 0, 1));
+    }
+
+    var req = unpack_request(buffer, size);
+
+    var is_event = is_event_type(req);
+
+    for (let i = 0; i < resource_list.length; i++) {
+        if ((is_event && resource_list[i].type == Reg_Event)
+            || (!is_event && resource_list[i].type == Reg_Request)) {
+            if (check_url_start(req.url, resource_list[i].url)) {
+                resource_list[i].cb(req);
+                return;
+            }
+        }
+    }
+
+    console.log("on_request: exit. no service handler.");
+}
+
+export function on_response(buffer_offset: i32, size: i32): void {
+    var buffer = new ArrayBuffer(size);
+    var dataview = new DataView(buffer);
+
+    for (let i = 0; i < size; i++) {
+        dataview.setUint8(i, load<i8>(buffer_offset + i, 0, 1));
+    }
+
+    var resp = unpack_response(buffer, size);
+    var trans = transaction_find(resp.mid);
+
+    if (trans != null) {
+        if (transaction_list.indexOf(trans) == 0) {
+            if (transaction_list.length >= 2) {
+                var elpased_ms: number, ms_to_expiry: number;
+                var now = timer.now();
+                if (now < transaction_list[1].time) {
+                    elpased_ms = now + (0xFFFFFFFF - transaction_list[1].time) + 1;
+                } else {
+                    elpased_ms = now - transaction_list[1].time;
+                }
+                ms_to_expiry = TRANSACTION_TIMEOUT_MS - elpased_ms;
+                timer.timer_restart(g_trans_timer, ms_to_expiry);
+            } else {
+                timer.timer_cancel(g_trans_timer);
+            }
+        }
+
+        trans.cb(resp);
+    }
+}

+ 80 - 0
assembly-script/wamr_app_lib/timer.ts

@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 Intel Corporation.  All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ */
+
+@external("env", "wasm_create_timer")
+declare function wasm_create_timer(a: i32, b: bool, c: bool): i32;
+
+@external("env", "wasm_timer_cancel")
+declare function wasm_timer_cancel(a: i32): void;
+
+@external("env", "wasm_timer_restart")
+declare function wasm_timer_restart(a: i32, b: i32): void;
+
+@external("env", "wasm_get_sys_tick_ms")
+declare function wasm_get_sys_tick_ms(): i32;
+
+export var timer_list = new Array<user_timer>();
+
+export class user_timer {
+    timer_id: i32 = 0;
+    timeout: i32;
+    period: bool = false;
+    cb: () => void;
+
+    constructor(cb: () => void, timeout: i32, period: bool) {
+        this.cb = cb;
+        this.timeout = timeout;
+        this.period = period
+        this.timer_id = timer_create(this.timeout, this.period, true);
+    }
+}
+
+export function timer_create(a: i32, b: bool, c: bool): i32 {
+    return wasm_create_timer(a, b, c);
+}
+
+export function setTimeout(cb: () => void, timeout: i32): user_timer {
+    var timer = new user_timer(cb, timeout, false);
+    timer_list.push(timer);
+
+    return timer;
+}
+
+export function setInterval(cb: () => void, timeout: i32): user_timer {
+    var timer = new user_timer(cb, timeout, true);
+    timer_list.push(timer);
+
+    return timer;
+}
+
+export function timer_cancel(timer: user_timer): void {
+    wasm_timer_cancel(timer.timer_id);
+
+    var i = 0;
+    for (i = 0; i < timer_list.length; i++) {
+        if (timer_list[i].timer_id == timer.timer_id)
+            break;
+    }
+
+    timer_list.splice(i, 1);
+}
+
+export function timer_restart(timer: user_timer, interval: number): void {
+    wasm_timer_restart(timer.timer_id, i32(interval));
+}
+
+export function now(): i32 {
+    return wasm_get_sys_tick_ms();
+}
+
+// This export function need to be copied to the top application file
+//
+export function on_timer_callback(on_timer_id: i32): void {
+    for (let i = 0; i < timer_list.length; i++) {
+        if (timer_list[i].timer_id == on_timer_id) {
+            timer_list[i].cb();
+        }
+    }
+}

+ 6 - 0
assembly-script/wamr_app_lib/tsconfig.json

@@ -0,0 +1,6 @@
+{
+  "extends": "../node_modules/assemblyscript/std/assembly.json",
+  "include": [
+    "./**/*.ts"
+  ]
+}

+ 5 - 7
core/iwasm/compilation/aot_emit_memory.c

@@ -245,6 +245,7 @@ fail:
         aot_set_last_error("llvm build load failed.");      \
         goto fail;                                          \
     }                                                       \
+    LLVMSetAlignment(value, 1);                             \
   } while (0)
 
 #define BUILD_TRUNC(data_type) do {                         \
@@ -256,10 +257,12 @@ fail:
   } while (0)
 
 #define BUILD_STORE() do {                                  \
-    if (!LLVMBuildStore(comp_ctx->builder, value, maddr)) { \
+    LLVMValueRef res;                                       \
+    if (!(res = LLVMBuildStore(comp_ctx->builder, value, maddr))) { \
         aot_set_last_error("llvm build store failed.");     \
         goto fail;                                          \
     }                                                       \
+    LLVMSetAlignment(res, 1);                               \
   } while (0)
 
 #define BUILD_SIGN_EXT(dst_type) do {                       \
@@ -599,12 +602,7 @@ aot_compile_op_memory_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
         return false;
     }
 
-    /* convert call result from i8 to i1 */
-    if (!(ret_value = LLVMBuildIntCast(comp_ctx->builder, ret_value,
-                                       INT1_TYPE, "mem_grow_ret"))) {
-        aot_set_last_error("llvm build bit cast failed.");
-        return false;
-    }
+    BUILD_ICMP(LLVMIntUGT, ret_value, I8_ZERO, ret_value, "mem_grow_ret");
 
     /* ret_value = ret_value == true ? delta : pre_page_count */
     if (!(ret_value = LLVMBuildSelect(comp_ctx->builder, ret_value,

+ 17 - 8
core/iwasm/compilation/aot_emit_numberic.c

@@ -405,14 +405,23 @@ aot_compile_int_bit_count(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
     CHECK_LLVM_CONST(zero_undef);
 
     /* Call the LLVM intrinsic function */
-    DEF_INT_UNARY_OP(call_llvm_intrinsic(comp_ctx,
-                                         bit_cnt_llvm_intrinsic[type],
-                                         ret_type,
-                                         param_types,
-                                         2,
-                                         operand,
-                                         zero_undef),
-                     NULL);
+    if (type < POP_CNT32)
+        DEF_INT_UNARY_OP(call_llvm_intrinsic(comp_ctx,
+                                             bit_cnt_llvm_intrinsic[type],
+                                             ret_type,
+                                             param_types,
+                                             2,
+                                             operand,
+                                             zero_undef),
+                         NULL);
+    else
+        DEF_INT_UNARY_OP(call_llvm_intrinsic(comp_ctx,
+                                             bit_cnt_llvm_intrinsic[type],
+                                             ret_type,
+                                             param_types,
+                                             1,
+                                             operand),
+                         NULL);
 
     return true;
 

+ 93 - 24
core/iwasm/interpreter/wasm_loader.c

@@ -42,6 +42,58 @@ set_error_buf(char *error_buf, uint32 error_buf_size, const char *string)
   }                                                         \
 } while (0)
 
+static bool
+skip_leb(const uint8  *buf, const uint8 *buf_end,
+         uint32 *p_offset, uint32 maxbits,
+         char* error_buf, uint32 error_buf_size)
+{
+    uint32 bcnt = 0;
+    uint64 byte;
+
+    while (true) {
+        if (bcnt + 1 > (maxbits + 6) / 7) {
+            set_error_buf(error_buf, error_buf_size,
+                          "WASM module load failed: "
+                          "integer representation too long");
+            return false;
+        }
+
+        CHECK_BUF(buf, buf_end, *p_offset + 1);
+        byte = buf[*p_offset];
+        *p_offset += 1;
+        bcnt += 1;
+        if ((byte & 0x80) == 0) {
+            break;
+        }
+    }
+
+    return true;
+}
+
+#define skip_leb_int64(p, p_end) do {               \
+  uint32 off = 0;                                   \
+  if (!skip_leb(p, p_end, &off, 64,                 \
+                error_buf, error_buf_size))         \
+    return false;                                   \
+  p += off;                                         \
+} while (0)
+
+#define skip_leb_uint32(p, p_end) do {              \
+  uint32 off = 0;                                   \
+  if (!skip_leb(p, p_end, &off, 32,                 \
+                error_buf, error_buf_size))         \
+    return false;                                   \
+  p += off;                                         \
+} while (0)
+
+#define skip_leb_int32(p, p_end) do {               \
+  uint32 off = 0;                                   \
+  if (!skip_leb(p, p_end, &off, 32,                 \
+                error_buf, error_buf_size))         \
+    return false;                                   \
+  p += off;                                         \
+} while (0)
+
 static bool
 read_leb(const uint8 *buf, const uint8 *buf_end,
          uint32 *p_offset, uint32 maxbits,
@@ -122,17 +174,18 @@ fail_integer_too_large:
 #define read_uint32(p) TEMPLATE_READ_VALUE(uint32, p)
 #define read_bool(p)   TEMPLATE_READ_VALUE(bool, p)
 
-#define read_leb_uint64(p, p_end, res) do {         \
-  uint32 off = 0;                                   \
-  uint64 res64;                                     \
-  if (!read_leb(p, p_end, &off, 64, false, &res64,  \
-                error_buf, error_buf_size))         \
-    return false;                                   \
-  p += off;                                         \
-  res = (uint64)res64;                              \
-} while (0)
-
 #define read_leb_int64(p, p_end, res) do {          \
+  if (p < p_end) {                                  \
+    uint8 _val = *p;                                \
+    if (!(_val & 0x80)) {                           \
+      res = (int64)_val;                            \
+      if (_val & 0x40)                              \
+        /* sign extend */                           \
+        res |= 0xFFFFFFFFFFFFFF80LL;                \
+      p++;                                          \
+      break;                                        \
+    }                                               \
+  }                                                 \
   uint32 off = 0;                                   \
   uint64 res64;                                     \
   if (!read_leb(p, p_end, &off, 64, true, &res64,   \
@@ -143,6 +196,14 @@ fail_integer_too_large:
 } while (0)
 
 #define read_leb_uint32(p, p_end, res) do {         \
+  if (p < p_end) {                                  \
+    uint8 _val = *p;                                \
+    if (!(_val & 0x80)) {                           \
+      res = _val;                                   \
+      p++;                                          \
+      break;                                        \
+    }                                               \
+  }                                                 \
   uint32 off = 0;                                   \
   uint64 res64;                                     \
   if (!read_leb(p, p_end, &off, 32, false, &res64,  \
@@ -153,6 +214,17 @@ fail_integer_too_large:
 } while (0)
 
 #define read_leb_int32(p, p_end, res) do {          \
+  if (p < p_end) {                                  \
+    uint8 _val = *p;                                \
+    if (!(_val & 0x80)) {                           \
+      res = (int32)_val;                            \
+      if (_val & 0x40)                              \
+        /* sign extend */                           \
+        res |= 0xFFFFFF80;                          \
+      p++;                                          \
+      break;                                        \
+    }                                               \
+  }                                                 \
   uint32 off = 0;                                   \
   uint64 res64;                                     \
   if (!read_leb(p, p_end, &off, 32, true, &res64,   \
@@ -1878,8 +1950,7 @@ wasm_loader_find_block_addr(WASMModule *module,
 {
     const uint8 *p = start_addr, *p_end = code_end_addr;
     uint8 *else_addr = NULL;
-    uint32 block_nested_depth = 1, count, i, u32;
-    uint64 u64;
+    uint32 block_nested_depth = 1, count, i;
     uint8 opcode, u8;
 
     BlockAddr block_stack[16] = { 0 }, *block;
@@ -1969,24 +2040,24 @@ wasm_loader_find_block_addr(WASMModule *module,
 
             case WASM_OP_BR:
             case WASM_OP_BR_IF:
-                read_leb_uint32(p, p_end, u32); /* labelidx */
+                skip_leb_uint32(p, p_end); /* labelidx */
                 break;
 
             case WASM_OP_BR_TABLE:
                 read_leb_uint32(p, p_end, count); /* lable num */
                 for (i = 0; i <= count; i++) /* lableidxs */
-                    read_leb_uint32(p, p_end, u32);
+                    skip_leb_uint32(p, p_end);
                 break;
 
             case WASM_OP_RETURN:
                 break;
 
             case WASM_OP_CALL:
-                read_leb_uint32(p, p_end, u32); /* funcidx */
+                skip_leb_uint32(p, p_end); /* funcidx */
                 break;
 
             case WASM_OP_CALL_INDIRECT:
-                read_leb_uint32(p, p_end, u32); /* typeidx */
+                skip_leb_uint32(p, p_end); /* typeidx */
                 CHECK_BUF(p, p_end, 1);
                 u8 = read_uint8(p); /* 0x00 */
                 break;
@@ -2004,7 +2075,7 @@ wasm_loader_find_block_addr(WASMModule *module,
             case WASM_OP_TEE_LOCAL:
             case WASM_OP_GET_GLOBAL:
             case WASM_OP_SET_GLOBAL:
-                read_leb_uint32(p, p_end, u32); /* localidx */
+                skip_leb_uint32(p, p_end); /* localidx */
                 break;
 
             case WASM_OP_GET_LOCAL_FAST:
@@ -2039,20 +2110,20 @@ wasm_loader_find_block_addr(WASMModule *module,
             case WASM_OP_I64_STORE8:
             case WASM_OP_I64_STORE16:
             case WASM_OP_I64_STORE32:
-                read_leb_uint32(p, p_end, u32); /* align */
-                read_leb_uint32(p, p_end, u32); /* offset */
+                skip_leb_uint32(p, p_end); /* align */
+                skip_leb_uint32(p, p_end); /* offset */
                 break;
 
             case WASM_OP_MEMORY_SIZE:
             case WASM_OP_MEMORY_GROW:
-                read_leb_uint32(p, p_end, u32); /* 0x00 */
+                skip_leb_uint32(p, p_end); /* 0x00 */
                 break;
 
             case WASM_OP_I32_CONST:
-                read_leb_int32(p, p_end, u32);
+                skip_leb_int32(p, p_end);
                 break;
             case WASM_OP_I64_CONST:
-                read_leb_int64(p, p_end, u64);
+                skip_leb_int64(p, p_end);
                 break;
             case WASM_OP_F32_CONST:
                 p += sizeof(float32);
@@ -2195,8 +2266,6 @@ wasm_loader_find_block_addr(WASMModule *module,
         }
     }
 
-    (void)u32;
-    (void)u64;
     (void)u8;
     return false;
 }

+ 1 - 1
core/iwasm/libraries/libc-wasi/libc_wasi_wrapper.c

@@ -200,7 +200,7 @@ wasi_environ_get(wasm_exec_env_t exec_env,
                                          &environ_count, &environ_buf_size);
     WASI_CHECK_ERR();
 
-    total_size = sizeof(uint32) * ((uint64)environ_count + 1);
+    total_size = sizeof(char*) * ((uint64)environ_count + 1);
     if (total_size >= UINT32_MAX
         || !validate_app_addr(environ_offset, (uint32)total_size)
         || environ_buf_size >= UINT32_MAX