日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:52000
  • 待審:37
  • 小程序:12
  • 文章:1037587
  • 會員:756

一、JAVAScript

 

1.JavaScript語言

JavaScript是ECMAScript的實現(xiàn),由ECMA 39(歐洲計算機制造商協(xié)會39號技術(shù)委員會)負(fù)責(zé)制定ECMAScript標(biāo)準(zhǔn)。

ECMAScript發(fā)展史:

 

2.JavaScript引擎

JavaScript引擎是指用于處理以及執(zhí)行JavaScript腳本的虛擬機。

常見的JavaScript引擎:

?3.JavaScript引擎工作原理

a.V8引擎工作原理

b.Turbofan技術(shù)實例說明

function sum(a, b) {

return a + b;

}

這里a和b可以是任意類型數(shù)據(jù),當(dāng)執(zhí)行sum函數(shù)時,Ignition解釋器會檢查a和b的數(shù)據(jù)類型,并相應(yīng)地執(zhí)行加法或者連接字符串的操作。

如果 sum函數(shù)被調(diào)用多次,每次執(zhí)行時都要檢查參數(shù)的數(shù)據(jù)類型是很浪費時間的。此時TurboFan就出場了。它會分析函數(shù)的執(zhí)行信息,如果以前每次調(diào)用sum函數(shù)時傳遞的參數(shù)類型都是數(shù)字,那么TurboFan就預(yù)設(shè)sum的參數(shù)類型是數(shù)字類型,然后將其編譯為機器碼。

但是如果某一次的調(diào)用傳入的參數(shù)不再是數(shù)字時,表示TurboFan的假設(shè)是錯誤的,此時優(yōu)化編譯生成的機器代碼就不能再使用了,于是就需要進(jìn)行回退到字節(jié)碼的操作。

三、QuickJS

1.QuickJS作者簡介

法布里斯·貝拉 (Fabrice Bellard)

2.QuickJS簡介

QuickJS 是一個小型的嵌入式 Javascript 引擎。 它支持 ES2023 規(guī)范,包括模塊、異步生成器、代理和 BigInt。

它可以選擇支持?jǐn)?shù)學(xué)擴展,例如大十進(jìn)制浮點數(shù) (BigDecimal)、大二進(jìn)制浮點數(shù) (BigFloat) 和運算符重載。

•小且易于嵌入:只需幾個 C 文件,無外部依賴項,一個簡單的 hello world 程序的 210 KiB x86 代碼。

•啟動時間極短的快速解釋器:在臺式 PC 的單核上運行 ECMAScript 測試套件的 76000 次測試只需不到 2 分鐘。 運行時實例的完整生命周期在不到 300 微秒的時間內(nèi)完成。

•幾乎完整的 ES2023 支持,包括模塊、異步生成器和完整的附錄 B 支持(舊版 Web 兼容性)。

•通過了近 100% 的 ECMAScript 測試套件測試: Test262 Report(https://test262.fyi/#)。

•可以將 Javascript 源代碼編譯為可執(zhí)行文件,無需外部依賴。

•使用引用計數(shù)(以減少內(nèi)存使用并具有確定性行為)和循環(huán)刪除的垃圾收集。

•數(shù)學(xué)擴展:BigDecimal、BigFloat、運算符重載、bigint 模式、數(shù)學(xué)模式。

•用 Javascript 實現(xiàn)的帶有上下文著色的命令行解釋器。

•帶有 C 庫包裝器的小型內(nèi)置標(biāo)準(zhǔn)庫。

3.QuickJS工程簡介

5.94MB quickjs

├── 17.6kB cutils.c /// 輔助函數(shù)

├── 7.58kB cutils.h /// 輔助函數(shù)

├── 241kB libbf.c /// BigFloat相關(guān)

├── 17.9kB libbf.h /// BigFloat相關(guān)

├── 2.25kB libregexp-opcode.h /// 正則表達(dá)式操作符

├── 82.3kB libregexp.c /// 正則表達(dá)式相關(guān)

├── 3.26kB libregexp.h /// 正則表達(dá)式相關(guān)

├── 3.09kB list.h /// 鏈表實現(xiàn)

├── 16.7kB qjs.c /// QuickJS stand alone interpreter

├── 22kB qjsc.c /// QuickJS command line compiler

├── 73.1kB qjscalc.js /// 數(shù)學(xué)計算器

├── 7.97kB quickjs-atom.h /// 定義了javascript中的關(guān)鍵字

├── 114kB quickjs-libc.c

├── 2.57kB quickjs-libc.h /// C API

├── 15.9kB quickjs-opcode.h /// 字節(jié)碼操作符定義

├── 1.81MB quickjs.c

├── 41.9kB quickjs.h /// QuickJS Engine

├── 49.8kB repl.js /// REPL

├── 218kB libunicode-table.h /// unicode相關(guān)

├── 53kB libunicode.c /// unicode相關(guān)

├── 3.86kB libunicode.h /// unicode相關(guān)

├── 86.4kB unicode_gen.c /// unicode相關(guān)

└── 6.99kB unicode_gen_def.h /// unicode相關(guān)

4.QuickJS工作原理

QuickJS的解釋器是基于棧的。

QuickJS的對byte-code會優(yōu)化兩次,通過一個簡單例子看看QuickJS的字節(jié)碼與優(yōu)化器的輸出,以及執(zhí)行過程。

function sum(a, b) {

return a + b;

}

•第一階段(未經(jīng)過優(yōu)化的字節(jié)碼)

;; function sum(a, b) {

enter_scope 1

;; return a + b;

line_num 2

scope_get_var a,1 ///通用的獲取變量的指令

scope_get_var b,1

add

return

;; }

•第二階段

;; function sum(a, b) {

;; return a + b;

line_num 2

get_arg 0: a /// 獲取參數(shù)列表中的變量

get_arg 1: b

add

return

;; }

•第三階段

;; function sum(a, b) {

;; return a + b;

get_arg0 0: a /// 精簡成獲取參數(shù)列表中第0個參數(shù)

get_arg1 1: b

add

return

;; }

sum(1,2);

通過上述簡單的函數(shù)調(diào)用,觀察sum函數(shù)調(diào)用過程中棧幀的變化,通過計算可知sum函數(shù)最棧幀大小為兩個字節(jié)

get_arg0

get_arg1

add

return

1

2

3

將棧頂?shù)臄?shù)據(jù)3返回

1

5.內(nèi)存管理

QuickJS通過引用計算來管理內(nèi)存,在使用C API時需要根據(jù)不同API的說明手動增加或者減少引用計數(shù)器。

對于循環(huán)引用的對象,QuickJS通過臨時減引用保存到臨時數(shù)組中的方法來判斷相互引用的對象是否可以回收。

6.QuickJS簡單使用

從Github上clone完最新的源碼后,通過執(zhí)行(macos 環(huán)境)以下代碼即可在本地安裝好qjs、qjsc、qjscalc幾個命令行程序

sudo make

sudo make install

qjs: JavaScript代碼解釋器

qjsc: JavaScript代碼編譯器

qjscalc: 基于QuickJS的REPL計算器程序

通過使用qjs可以直接運行一個JavaScript源碼,通過qsjc的如下命令,則可以輸出一個帶有byte-code源碼的可直接運行的C源文件:

qjsc -e -o add.c examples/add.js

#include "quickjs-libc.h"

const uint32_t qjsc_add_size = 135;

const uint8_t qjsc_add[135] = {

0x02, 0x06, 0x06, 0x73, 0x75, 0x6d, 0x0e, 0x63,

0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x06, 0x6c,

0x6f, 0x67, 0x1e, 0x65, 0x78, 0x61, 0x6d, 0x70,

0x6c, 0x65, 0x73, 0x2f, 0x61, 0x64, 0x64, 0x2e,

0x6a, 0x73, 0x02, 0x61, 0x02, 0x62, 0x0e, 0x00,

0x06, 0x00, 0xa2, 0x01, 0x00, 0x01, 0x00, 0x05,

0x00, 0x01, 0x25, 0x01, 0xa4, 0x01, 0x00, 0x00,

0x00, 0x3f, 0xe3, 0x00, 0x00, 0x00, 0x40, 0xc2,

0x00, 0x40, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x38,

0xe4, 0x00, 0x00, 0x00, 0x42, 0xe5, 0x00, 0x00,

0x00, 0x38, 0xe3, 0x00, 0x00, 0x00, 0xb8, 0xb9,

0xf2, 0x24, 0x01, 0x00, 0xcf, 0x28, 0xcc, 0x03,

0x01, 0x04, 0x1f, 0x00, 0x08, 0x0a, 0x0e, 0x43,

0x06, 0x00, 0xc6, 0x03, 0x02, 0x00, 0x02, 0x02,

0x00, 0x00, 0x04, 0x02, 0xce, 0x03, 0x00, 0x01,

0x00, 0xd0, 0x03, 0x00, 0x01, 0x00, 0xd3, 0xd4,

0x9e, 0x28, 0xcc, 0x03, 0x01, 0x01, 0x03,

};

static JSContext *JS_NewCustomContext(JSRuntime *rt)

{

JSContext *ctx = JS_NewContextRaw(rt);

if (!ctx)

return NULL;

JS_AddIntrinsicBaseobjects(ctx);

JS_AddIntrinsicDate(ctx);

JS_AddIntrinsicEval(ctx);

JS_AddIntrinsicStringNormalize(ctx);

JS_AddIntrinsicRegExp(ctx);

JS_AddIntrinsicJSON(ctx);

JS_AddIntrinsicProxy(ctx);

JS_AddIntrinsicMapSet(ctx);

JS_AddIntrinsicTypedArrays(ctx);

JS_AddIntrinsicPromise(ctx);

JS_AddIntrinsicBigInt(ctx);

return ctx;

}

int mAIn(int argc, char **argv)

{

JSRuntime *rt;

JSContext *ctx;

rt = JS_NewRuntime();

js_std_set_worker_new_context_func(JS_NewCustomContext);

js_std_init_handlers(rt);

JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);

ctx = JS_NewCustomContext(rt);

js_std_add_helpers(ctx, argc, argv);

js_std_eval_binary(ctx, qjsc_add, qjsc_add_size, 0);

js_std_loop(ctx);

js_std_free_handlers(rt);

JS_FreeContext(ctx);

JS_FreeRuntime(rt);

return 0;

}

上面的這個C源文件,通過如下命令即可編譯成可執(zhí)行文件:

gcc add.c -o add_exec -I/usr/local/include quickjs-libc.c quickjs.c cutils.c libbf.c libregexp.c libunicode.c -DCONFIG_BIGNUM

也可以直接使用如下命令,將JavaScript文件直接編譯成可執(zhí)行文件:

qjsc -o add_exec examples/add.js

7.給qjsc添加擴展

QuickJS只實現(xiàn)了最基本的JavaScript能力,同時QuickJS也可以實現(xiàn)能力的擴展,比如給QuickJS添加打開文件并讀取文件內(nèi)容的內(nèi)容,這樣在JavaScript代碼中即可通過js代碼打開并讀取到文件內(nèi)容了。

通過一個例子來看看添加擴展都需要做哪些操作:

•編寫一個C語言的擴展模塊

#include "quickjs.h"

#include "cutils.h"

/// js中對應(yīng)plus函數(shù)的C語言函數(shù)

static JSValue plusNumbers(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {

int a, b;

if (JS_ToInt32(ctx, &a, argv[0]))

return JS_EXCEPTION;

if (JS_ToInt32(ctx, &b, argv[1]))

return JS_EXCEPTION;

return JS_NewInt32(ctx, a + b);

}

/// 模塊需要導(dǎo)致的列表

static const JSCFunctionListEntry js_my_module_funcs[] = {

JS_CFUNC_DEF("plus", 2, plusNumbers),

};

/// 模塊初始化函數(shù),并將plus導(dǎo)出

static int js_my_module_init(JSContext *ctx, JSModuleDef *m) {

return JS_SetModuleExportList(ctx, m, js_my_module_funcs, countof(js_my_module_funcs));

}

JSModuleDef *js_init_module_my_module(JSContext *ctx, const char *module_name) {

JSModuleDef *m;

m = JS_NewCModule(ctx, module_name, js_my_module_init);

if (!m)

return NULL;

JS_AddModuleExportList(ctx, m, js_my_module_funcs, countof(js_my_module_funcs));

return m;

}

•Makefile文件中添加my_module.c模塊的編譯

QJS_LIB_OBJS= ... $(OBJDIR)/my_module.o

•在qjsc.c文件中注冊模塊

namelist_add(&cmodule_list,“my_module”,“my_module”,0);

•編寫一個my_module.js測試文件

import * as mm from 'my_module';

const value = mm.plus(1, 2);

console.log(`my_module.plus: ${value}`);

•重新編譯

sudo make && sudo make install

qjsc -m -o my_module examples/my_module.js /// 這里需要指定my_module模塊

最終生成的my_module可執(zhí)行文件,通過執(zhí)行my_module輸出:

my_module.plus: 3

8.使用C API

在第5個步驟時,生成了add.c文件中實際上已經(jīng)給出了一個簡單的使用C API最基本的代碼。當(dāng)編寫一下如下的js源碼時,會發(fā)現(xiàn)當(dāng)前的qjsc編譯后的可執(zhí)行文件或者qjs執(zhí)行這段js代碼與我們的預(yù)期不符:

function getName() {

return new Promise((resolve, reject) => {

setTimeout(() => {

resolve("張三峰");

}, 2000);

});

}

console.log(`開始執(zhí)行`);

getName().then(name => console.log(`promise name: ${name}`));

上面的代碼并不會按預(yù)期的效果輸出結(jié)果,因為js環(huán)境下的loop只執(zhí)行了一次,任務(wù)隊列還沒有來得急執(zhí)行程序就結(jié)束了,稍微改動一下讓程序可以正常輸出,如下:

#include <stdio.h>

#include <pthread.h>

#include <stdlib.h>

#include <uv.h>

/* File generated automatically by the QuickJS compiler. */

#include "quickjs-libc.h"

#include <string.h>

static JSContext *JS_NewCustomContext(JSRuntime *rt) {

JSContext *ctx = JS_NewContextRaw(rt);

if (!ctx)

return NULL;

JS_AddIntrinsicBaseObjects(ctx);

JS_AddIntrinsicDate(ctx);

JS_AddIntrinsicEval(ctx);

JS_AddIntrinsicStringNormalize(ctx);

JS_AddIntrinsicRegExp(ctx);

JS_AddIntrinsicJSON(ctx);

JS_AddIntrinsicProxy(ctx);

JS_AddIntrinsicMapSet(ctx);

JS_AddIntrinsicTypedArrays(ctx);

JS_AddIntrinsicPromise(ctx);

JS_AddIntrinsicBigInt(ctx);

return ctx;

}

JSRuntime *rt = NULL;

JSContext *ctx = NULL;

void *run(void *args) {

const char *file_path = "/Volumes/Work/分享/quickjs/code/quickjs/examples/promise.js";

size_t pbuf_len = 0;

js_std_set_worker_new_context_func(JS_NewCustomContext);

js_std_init_handlers(rt);

JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);

ctx = JS_NewCustomContext(rt);

js_std_add_helpers(ctx, 0, NULL);

js_init_module_os(ctx, "test");

const uint8_t *code = js_load_file(ctx, &pbuf_len, file_path);

JSValue js_ret_val = JS_Eval(ctx, (char *)code, pbuf_len, "add", JS_EVAL_TYPE_MODULE);

if(JS_IsError(ctx, js_ret_val) || JS_IsException(js_ret_val)) {

js_std_dump_error(ctx);

}

return NULL;

}

pthread_t quickjs_t;

int main(int argc, char **argv) {

rt = JS_NewRuntime();

pthread_create(&quickjs_t, NULL, run, NULL);

while (1) {

if(ctx) js_std_loop(ctx);

}

js_std_free_handlers(rt);

JS_FreeContext(ctx);

JS_FreeRuntime(rt);

return 0;

}

這樣的操作只適合用于測試一下功能,實際生產(chǎn)中使用需要一個即可以在必要的時候調(diào)用loop又可以做到不搶占過多的CPU或者只搶占較少的CPU時間片。

四、libuv

1.libuv簡價

libuv 是一個使用C語言編寫的多平臺支持庫,專注于異步 I/O。 它主要是為 Node.js 使用而開發(fā)的,但 Luvit、Julia、uvloop 等也使用它。

功能亮點

•由 epoll、kqueue、IOCP、事件端口支持的全功能事件循環(huán)。

•異步 TCP 和 UDP 套接字

•異步 DNS 解析

•異步文件和文件系統(tǒng)操作

•文件系統(tǒng)事件

•ANSI 轉(zhuǎn)義碼控制的 TTY

•具有套接字共享的 IPC,使用 Unix 域套接字或命名管道 (windows)

•子進(jìn)程

•線程池

•信號處理

•高分辨率時鐘

•線程和同步原語

2.libuv運行原理

int uv_run(uv_loop_t* loop, uv_run_mode mode) {

r = uv__loop_alive(loop);

if (!r)

uv__update_time(loop);

while (r != 0 && loop->stop_flag == 0) {

uv__update_time(loop);

uv__run_timers(loop);

ran_pending = uv__run_pending(loop);

uv__run_idle(loop);

uv__run_prepare(loop);

uv__io_poll(loop, timeout);

uv__run_check(loop);

uv__run_closing_handles(loop);

}

}

3.簡單使用

static void timer_cb(uv_timer_t *handler) {

printf("timer_cb exec.rn");

}

int main(int argc, const char * argv[]) {

uv_loop_t *loop = uv_default_loop();

uv_timer_t *timer = (uv_timer_t*)malloc(sizeof(uv_timer_t));

uv_timer_init(loop, timer);

uv_timer_start(timer, timer_cb, 2000, 0);

uv_run(loop, UV_RUN_DEFAULT);

}

五、QuickJS + libuv

console.log(`開始執(zhí)行`);

function getName() {

return new Promise((resolve, reject) => {

setTimeout(() => {

resolve("張三峰");

}, 2000);

});

}

getName().then(name => console.log(`promise name: ${name}`));

#include <stdio.h>

#include <pthread.h>

#include <stdlib.h>

#include <uv.h>

/* File generated automatically by the QuickJS compiler. */

#include "quickjs-libc.h"

#include <string.h>

typedef struct once_timer_data {

JSValue func;

JSValue this_val;

JSContext *ctx;

} once_timer_data;

void once_timer_cb(uv_timer_t *once_timer) {

once_timer_data *data = (once_timer_data *)once_timer->data;

JSContext *ctx = data->ctx;

JSValue js_ret_val = JS_Call(data->ctx, data->func, data->this_val, 0, NULL);

if(JS_IsError(ctx, js_ret_val) || JS_IsException(js_ret_val)) {

js_std_dump_error(ctx);

}

JS_FreeValue(data->ctx, js_ret_val);

JS_FreeValue(data->ctx, data->func);

JS_FreeValue(data->ctx, data->this_val);

free(data);

uv_timer_stop(once_timer);

free(once_timer);

}

void check_cb(uv_check_t *check) {

JSContext *ctx = (JSContext *)check->data;

js_std_loop(ctx);

}

void idle_cb(uv_idle_t *idle) {

}

JSValue set_timeout(JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {

if(argc != 2) return JS_NULL;

JSValue func_val = argv[0];

JSValue delay_val = argv[1];

int64_t delay = 0;

int ret = JS_ToInt64(ctx, &delay, delay_val);

if(ret < 0) js_std_dump_error(ctx);

uv_timer_t *once_timer = (uv_timer_t *)malloc(sizeof(uv_timer_t));

once_timer_data *data = (once_timer_data *)malloc(sizeof(once_timer_data));

data->func = JS_DupValue(ctx, func_val);

data->this_val = JS_DupValue(ctx, this_val);

data->ctx = ctx;

once_timer->data = data;

uv_timer_init(uv_default_loop(), once_timer);

uv_timer_start(once_timer, once_timer_cb, delay, 0);

JSValue js_timer = JS_NewInt64(ctx, (uint64_t)once_timer);

return js_timer;

}

static JSContext *JS_NewCustomContext(JSRuntime *rt) {

JSContext *ctx = JS_NewContextRaw(rt);

if (!ctx)

return NULL;

JS_AddIntrinsicBaseObjects(ctx);

JS_AddIntrinsicDate(ctx);

JS_AddIntrinsicEval(ctx);

JS_AddIntrinsicStringNormalize(ctx);

JS_AddIntrinsicRegExp(ctx);

JS_AddIntrinsicJSON(ctx);

JS_AddIntrinsicProxy(ctx);

JS_AddIntrinsicMapSet(ctx);

JS_AddIntrinsicTypedArrays(ctx);

JS_AddIntrinsicPromise(ctx);

JS_AddIntrinsicBigInt(ctx);

return ctx;

}

void js_job(uv_timer_t *timer) {

JSRuntime *rt = timer->data;

const char *file_path = "/Volumes/Work/分享/quickjs/code/quickjs/examples/promise.js";

size_t pbuf_len = 0;

JSContext *ctx;

js_std_set_worker_new_context_func(JS_NewCustomContext);

js_std_init_handlers(rt);

JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);

ctx = JS_NewCustomContext(rt);

uv_check_t *check = (uv_check_t *)malloc(sizeof(uv_check_t));

uv_check_init(uv_default_loop(), check);

check->data = ctx;

uv_check_start(check, check_cb);

JSValue global = JS_GetGlobalObject(ctx);

JSValue func_val = JS_NewCFunction(ctx, set_timeout, "setTimeout", 1);

JS_SetPropertyStr(ctx, global, "setTimeout", func_val);

JS_FreeValue(ctx, global);

js_std_add_helpers(ctx, 0, NULL);

js_init_module_os(ctx, "test");

const uint8_t *code = js_load_file(ctx, &pbuf_len, file_path);

JSValue js_ret_val = JS_Eval(ctx, (char *)code, pbuf_len, "add", JS_EVAL_TYPE_MODULE);

if(JS_IsError(ctx, js_ret_val) || JS_IsException(js_ret_val)) {

js_std_dump_error(ctx);

}

js_std_free_handlers(rt);

JS_FreeContext(ctx);

}

int main(int argc, char **argv) {

JSRuntime *rt = JS_NewRuntime();

uv_loop_t *loop = uv_default_loop();

uv_timer_t *timer = (uv_timer_t*)malloc(sizeof(uv_timer_t));

timer->data = rt;

uv_timer_init(loop, timer);

uv_timer_start(timer, js_job, 0, 0);

uv_idle_t *idle = (uv_idle_t *)malloc(sizeof(uv_idle_t));

uv_idle_init(loop, idle);

uv_idle_start(idle, idle_cb);

uv_run(loop, UV_RUN_DEFAULT);

JS_FreeRuntime(rt);

return 0;

}

分享到:
標(biāo)簽:JavaScript
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 52000

    網(wǎng)站

  • 12

    小程序

  • 1037587

    文章

  • 756

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨大挑戰(zhàn)2018-06-03

數(shù)獨一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運動步數(shù)有氧達(dá)人2018-06-03

記錄運動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定