@@ -138,6 +138,7 @@ enum {
138138 JS_CLASS_BYTECODE_FUNCTION, /* u.func */
139139 JS_CLASS_BOUND_FUNCTION, /* u.bound_function */
140140 JS_CLASS_C_FUNCTION_DATA, /* u.c_function_data_record */
141+ JS_CLASS_C_CLOSURE, /* u.c_closure_record */
141142 JS_CLASS_GENERATOR_FUNCTION, /* u.func */
142143 JS_CLASS_FOR_IN_ITERATOR, /* u.for_in_iterator */
143144 JS_CLASS_REGEXP, /* u.regexp */
@@ -980,6 +981,7 @@ struct JSObject {
980981 void *opaque;
981982 struct JSBoundFunction *bound_function; /* JS_CLASS_BOUND_FUNCTION */
982983 struct JSCFunctionDataRecord *c_function_data_record; /* JS_CLASS_C_FUNCTION_DATA */
984+ struct JSCClosureRecord *c_closure_record; /* JS_CLASS_C_CLOSURE */
983985 struct JSForInIterator *for_in_iterator; /* JS_CLASS_FOR_IN_ITERATOR */
984986 struct JSArrayBuffer *array_buffer; /* JS_CLASS_ARRAY_BUFFER, JS_CLASS_SHARED_ARRAY_BUFFER */
985987 struct JSTypedArray *typed_array; /* JS_CLASS_UINT8C_ARRAY..JS_CLASS_DATAVIEW */
@@ -1343,6 +1345,10 @@ static void js_c_function_data_mark(JSRuntime *rt, JSValueConst val,
13431345static JSValue js_call_c_function_data(JSContext *ctx, JSValueConst func_obj,
13441346 JSValueConst this_val,
13451347 int argc, JSValueConst *argv, int flags);
1348+ static void js_c_closure_finalizer(JSRuntime *rt, JSValue val);
1349+ static JSValue js_call_c_closure(JSContext *ctx, JSValueConst func_obj,
1350+ JSValueConst this_val,
1351+ int argc, JSValueConst *argv, int flags);
13461352static JSAtom js_symbol_to_atom(JSContext *ctx, JSValueConst val);
13471353static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
13481354 JSGCObjectTypeEnum type);
@@ -1746,6 +1752,7 @@ static JSClassShortDef const js_std_class_def[] = {
17461752 { JS_ATOM_Function, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_BYTECODE_FUNCTION */
17471753 { JS_ATOM_Function, js_bound_function_finalizer, js_bound_function_mark }, /* JS_CLASS_BOUND_FUNCTION */
17481754 { JS_ATOM_Function, js_c_function_data_finalizer, js_c_function_data_mark }, /* JS_CLASS_C_FUNCTION_DATA */
1755+ { JS_ATOM_Function, js_c_closure_finalizer, NULL}, /* JS_CLASS_C_CLOSURE */
17491756 { JS_ATOM_GeneratorFunction, js_bytecode_function_finalizer, js_bytecode_function_mark }, /* JS_CLASS_GENERATOR_FUNCTION */
17501757 { JS_ATOM_ForInIterator, js_for_in_iterator_finalizer, js_for_in_iterator_mark }, /* JS_CLASS_FOR_IN_ITERATOR */
17511758 { JS_ATOM_RegExp, js_regexp_finalizer, NULL }, /* JS_CLASS_REGEXP */
@@ -1870,6 +1877,7 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
18701877
18711878 rt->class_array[JS_CLASS_C_FUNCTION].call = js_call_c_function;
18721879 rt->class_array[JS_CLASS_C_FUNCTION_DATA].call = js_call_c_function_data;
1880+ rt->class_array[JS_CLASS_C_CLOSURE].call = js_call_c_closure;
18731881 rt->class_array[JS_CLASS_BOUND_FUNCTION].call = js_call_bound_function;
18741882 rt->class_array[JS_CLASS_GENERATOR_FUNCTION].call = js_call_generator_function;
18751883 if (init_shape_hash(rt))
@@ -5547,6 +5555,75 @@ static void js_autoinit_mark(JSRuntime *rt, JSProperty *pr,
55475555 mark_func(rt, &js_autoinit_get_realm(pr)->header);
55485556}
55495557
5558+ typedef struct JSCClosureRecord {
5559+ JSCClosure *func;
5560+ uint16_t length;
5561+ uint16_t magic;
5562+ void *opaque;
5563+ void (*opaque_finalize)(void*);
5564+ } JSCClosureRecord;
5565+
5566+ static void js_c_closure_finalizer(JSRuntime *rt, JSValue val)
5567+ {
5568+ JSCClosureRecord *s = JS_GetOpaque(val, JS_CLASS_C_CLOSURE);
5569+
5570+ if (s) {
5571+ if (s->opaque_finalize)
5572+ s->opaque_finalize(s->opaque);
5573+
5574+ js_free_rt(rt, s);
5575+ }
5576+ }
5577+
5578+ static JSValue js_call_c_closure(JSContext *ctx, JSValueConst func_obj,
5579+ JSValueConst this_val,
5580+ int argc, JSValueConst *argv, int flags)
5581+ {
5582+ JSCClosureRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_CLOSURE);
5583+ JSValueConst *arg_buf;
5584+ int i;
5585+
5586+ /* XXX: could add the function on the stack for debug */
5587+ if (unlikely(argc < s->length)) {
5588+ arg_buf = alloca(sizeof(arg_buf[0]) * s->length);
5589+ for(i = 0; i < argc; i++)
5590+ arg_buf[i] = argv[i];
5591+ for(i = argc; i < s->length; i++)
5592+ arg_buf[i] = JS_UNDEFINED;
5593+ } else {
5594+ arg_buf = argv;
5595+ }
5596+
5597+ return s->func(ctx, this_val, argc, arg_buf, s->magic, s->opaque);
5598+ }
5599+
5600+ JSValue JS_NewCClosure(JSContext *ctx, JSCClosure *func,
5601+ int length, int magic, void *opaque,
5602+ void (*opaque_finalize)(void*))
5603+ {
5604+ JSCClosureRecord *s;
5605+ JSValue func_obj;
5606+
5607+ func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
5608+ JS_CLASS_C_CLOSURE);
5609+ if (JS_IsException(func_obj))
5610+ return func_obj;
5611+ s = js_malloc(ctx, sizeof(*s));
5612+ if (!s) {
5613+ JS_FreeValue(ctx, func_obj);
5614+ return JS_EXCEPTION;
5615+ }
5616+ s->func = func;
5617+ s->length = length;
5618+ s->magic = magic;
5619+ s->opaque = opaque;
5620+ s->opaque_finalize = opaque_finalize;
5621+ JS_SetOpaque(func_obj, s);
5622+ js_function_set_properties(ctx, func_obj,
5623+ JS_ATOM_empty_string, length);
5624+ return func_obj;
5625+ }
5626+
55505627static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
55515628{
55525629 if (unlikely(prop_flags & JS_PROP_TMASK)) {
@@ -6455,6 +6532,15 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
64556532 }
64566533 }
64576534 break;
6535+ case JS_CLASS_C_CLOSURE: /* u.c_closure_record */
6536+ {
6537+ JSCClosureRecord *c = p->u.c_closure_record;
6538+ if (c) {
6539+ s->memory_used_count += 1;
6540+ s->memory_used_size += sizeof(*c);
6541+ }
6542+ }
6543+ break;
64586544 case JS_CLASS_REGEXP: /* u.regexp */
64596545 compute_jsstring_size(p->u.regexp.pattern, hp);
64606546 compute_jsstring_size(p->u.regexp.bytecode, hp);
0 commit comments