MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1// stub: minimal node:async_hooks implementation
2// just enough for react to render tree
3
4#include <stdlib.h>
5
6#include "ant.h"
7#include "internal.h"
8#include "silver/engine.h"
9
10#include "descriptors.h"
11#include "modules/async_hooks.h"
12#include "modules/symbol.h"
13
14static ant_value_t async_hooks_call_with_tail_args(
15 ant_t *js, ant_value_t fn, ant_value_t this_arg, ant_value_t *args, int nargs, int start_idx
16) {
17 int call_nargs = nargs - start_idx;
18 if (call_nargs <= 0) return sv_vm_call(js->vm, js, fn, this_arg, NULL, 0, NULL, false);
19
20 ant_value_t *call_args = (ant_value_t *)malloc((size_t)call_nargs * sizeof(ant_value_t));
21 if (!call_args) return js_mkerr(js, "Out of memory");
22
23 for (int i = 0; i < call_nargs; i++) call_args[i] = args[start_idx + i];
24 ant_value_t result = sv_vm_call(js->vm, js, fn, this_arg, call_args, call_nargs, NULL, false);
25 free(call_args);
26 return result;
27}
28
29static ant_value_t async_local_storage_run(ant_params_t) {
30 if (nargs < 2 || !is_callable(args[1])) {
31 return js_mkerr(js, "AsyncLocalStorage.run(store, callback, ...args) requires a callback");
32 }
33
34 ant_value_t this_obj = js_getthis(js);
35 if (!is_object_type(this_obj)) {
36 return js_mkerr(js, "AsyncLocalStorage.run() requires an AsyncLocalStorage instance");
37 }
38
39 ant_value_t prev = js_get_slot(this_obj, SLOT_DATA);
40 js_set_slot_wb(js, this_obj, SLOT_DATA, args[0]);
41 ant_value_t result = async_hooks_call_with_tail_args(js, args[1], js_mkundef(), args, nargs, 2);
42 js_set_slot_wb(js, this_obj, SLOT_DATA, prev);
43 return result;
44}
45
46static ant_value_t async_local_storage_exit(ant_params_t) {
47 if (nargs < 1 || !is_callable(args[0])) {
48 return js_mkerr(js, "AsyncLocalStorage.exit(callback, ...args) requires a callback");
49 }
50
51 ant_value_t this_obj = js_getthis(js);
52 if (!is_object_type(this_obj)) {
53 return js_mkerr(js, "AsyncLocalStorage.exit() requires an AsyncLocalStorage instance");
54 }
55
56 ant_value_t prev = js_get_slot(this_obj, SLOT_DATA);
57 js_set_slot_wb(js, this_obj, SLOT_DATA, js_mkundef());
58 ant_value_t result = async_hooks_call_with_tail_args(js, args[0], js_mkundef(), args, nargs, 1);
59 js_set_slot_wb(js, this_obj, SLOT_DATA, prev);
60 return result;
61}
62
63static ant_value_t async_local_storage_enterWith(ant_params_t) {
64 ant_value_t this_obj = js_getthis(js);
65 if (!is_object_type(this_obj)) {
66 return js_mkerr(js, "AsyncLocalStorage.enterWith() requires an AsyncLocalStorage instance");
67 }
68 js_set_slot_wb(js, this_obj, SLOT_DATA, nargs > 0 ? args[0] : js_mkundef());
69 return js_mkundef();
70}
71
72static ant_value_t async_local_storage_getStore(ant_params_t) {
73 ant_value_t this_obj = js_getthis(js);
74 if (!is_object_type(this_obj)) return js_mkundef();
75 return js_get_slot(this_obj, SLOT_DATA);
76}
77
78static ant_value_t async_local_storage_disable(ant_params_t) {
79 ant_value_t this_obj = js_getthis(js);
80 if (is_object_type(this_obj)) js_set_slot_wb(js, this_obj, SLOT_DATA, js_mkundef());
81 return js_mkundef();
82}
83
84static ant_value_t async_resource_runInAsyncScope(ant_params_t) {
85 if (nargs < 1 || !is_callable(args[0])) {
86 return js_mkerr(js, "AsyncResource.runInAsyncScope(fn[, thisArg, ...args]) requires a function");
87 }
88 ant_value_t this_arg = nargs > 1 ? args[1] : js_mkundef();
89 return async_hooks_call_with_tail_args(js, args[0], this_arg, args, nargs, 2);
90}
91
92static ant_value_t async_resource_emitDestroy(ant_params_t) {
93 return js_getthis(js);
94}
95
96static ant_value_t async_resource_asyncId(ant_params_t) {
97 return js_mknum(0);
98}
99
100static ant_value_t async_resource_triggerAsyncId(ant_params_t) {
101 return js_mknum(0);
102}
103
104static ant_value_t async_hook_enable(ant_params_t) {
105 return js_getthis(js);
106}
107
108static ant_value_t async_hook_disable(ant_params_t) {
109 return js_getthis(js);
110}
111
112static ant_value_t async_hooks_createHook(ant_params_t) {
113 ant_value_t hook = js_mkobj(js);
114 js_set(js, hook, "enable", js_mkfun(async_hook_enable));
115 js_set(js, hook, "disable", js_mkfun(async_hook_disable));
116 return hook;
117}
118
119static ant_value_t async_hooks_executionAsyncId(ant_params_t) {
120 return js_mknum(1);
121}
122
123static ant_value_t async_hooks_triggerAsyncId(ant_params_t) {
124 return js_mknum(0);
125}
126
127static ant_value_t async_hooks_executionAsyncResource(ant_params_t) {
128 return js_mkobj(js);
129}
130
131ant_value_t async_hooks_library(ant_t *js) {
132 ant_value_t lib = js_mkobj(js);
133
134 ant_value_t als_ctor = js_mkobj(js);
135 ant_value_t als_proto = js_mkobj(js);
136 js_set(js, als_proto, "run", js_mkfun(async_local_storage_run));
137 js_set(js, als_proto, "exit", js_mkfun(async_local_storage_exit));
138 js_set(js, als_proto, "enterWith", js_mkfun(async_local_storage_enterWith));
139 js_set(js, als_proto, "getStore", js_mkfun(async_local_storage_getStore));
140 js_set(js, als_proto, "disable", js_mkfun(async_local_storage_disable));
141 js_set_sym(js, als_proto, get_toStringTag_sym(), ANT_STRING("AsyncLocalStorage"));
142 js_mkprop_fast(js, als_ctor, "prototype", 9, als_proto);
143 js_mkprop_fast(js, als_ctor, "name", 4, ANT_STRING("AsyncLocalStorage"));
144 js_set_descriptor(js, als_ctor, "name", 4, 0);
145 js_set(js, lib, "AsyncLocalStorage", js_obj_to_func_ex(als_ctor, SV_CALL_IS_DEFAULT_CTOR));
146
147 ant_value_t resource_ctor = js_mkobj(js);
148 ant_value_t resource_proto = js_mkobj(js);
149 js_set(js, resource_proto, "runInAsyncScope", js_mkfun(async_resource_runInAsyncScope));
150 js_set(js, resource_proto, "emitDestroy", js_mkfun(async_resource_emitDestroy));
151 js_set(js, resource_proto, "asyncId", js_mkfun(async_resource_asyncId));
152 js_set(js, resource_proto, "triggerAsyncId", js_mkfun(async_resource_triggerAsyncId));
153 js_set_sym(js, resource_proto, get_toStringTag_sym(), ANT_STRING("AsyncResource"));
154 js_mkprop_fast(js, resource_ctor, "prototype", 9, resource_proto);
155 js_mkprop_fast(js, resource_ctor, "name", 4, ANT_STRING("AsyncResource"));
156 js_set_descriptor(js, resource_ctor, "name", 4, 0);
157 js_set(js, lib, "AsyncResource", js_obj_to_func_ex(resource_ctor, SV_CALL_IS_DEFAULT_CTOR));
158
159 js_set(js, lib, "createHook", js_mkfun(async_hooks_createHook));
160 js_set(js, lib, "executionAsyncId", js_mkfun(async_hooks_executionAsyncId));
161 js_set(js, lib, "triggerAsyncId", js_mkfun(async_hooks_triggerAsyncId));
162 js_set(js, lib, "executionAsyncResource", js_mkfun(async_hooks_executionAsyncResource));
163 js_set(js, lib, "asyncWrapProviders", js_mkobj(js));
164 js_set_sym(js, lib, get_toStringTag_sym(), ANT_STRING("async_hooks"));
165
166 return lib;
167}