@@ -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, JSValueConst 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,101 @@ 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 *opaque);
5564+ } JSCClosureRecord;
5565+
5566+ static void js_c_closure_finalizer(JSRuntime *rt, JSValueConst 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+ JSRuntime *rt = ctx->rt;
5583+ JSStackFrame sf_s, *sf = &sf_s, *prev_sf;
5584+ JSCClosureRecord *s = JS_GetOpaque(func_obj, JS_CLASS_C_CLOSURE);
5585+ JSValueConst *arg_buf;
5586+ JSValue ret;
5587+ int arg_count;
5588+ int i;
5589+ size_t stack_size;
5590+
5591+ arg_buf = argv;
5592+ arg_count = s->length;
5593+ if (unlikely(argc < arg_count)) {
5594+ stack_size = arg_count * sizeof(arg_buf[0]);
5595+ if (js_check_stack_overflow(rt, stack_size))
5596+ return JS_ThrowStackOverflow(ctx);
5597+ arg_buf = alloca(stack_size);
5598+ for (i = 0; i < argc; i++)
5599+ arg_buf[i] = argv[i];
5600+ for (i = argc; i < arg_count; i++)
5601+ arg_buf[i] = JS_UNDEFINED;
5602+ }
5603+
5604+ prev_sf = rt->current_stack_frame;
5605+ sf->prev_frame = prev_sf;
5606+ rt->current_stack_frame = sf;
5607+ // TODO(bnoordhuis) switch realms like js_call_c_function does
5608+ sf->is_strict_mode = false;
5609+ sf->cur_func = unsafe_unconst(func_obj);
5610+ sf->arg_count = argc;
5611+ ret = s->func(ctx, this_val, argc, arg_buf, s->magic, s->opaque);
5612+ rt->current_stack_frame = sf->prev_frame;
5613+
5614+ return ret;
5615+ }
5616+
5617+ JSValue JS_NewCClosure(JSContext *ctx, JSCClosure *func, const char *name,
5618+ JSCClosureFinalizerFunc *opaque_finalize,
5619+ int length, int magic, void *opaque)
5620+ {
5621+ JSCClosureRecord *s;
5622+ JSAtom name_atom;
5623+ JSValue func_obj;
5624+
5625+ func_obj = JS_NewObjectProtoClass(ctx, ctx->function_proto,
5626+ JS_CLASS_C_CLOSURE);
5627+ if (JS_IsException(func_obj))
5628+ return func_obj;
5629+ s = js_malloc(ctx, sizeof(*s));
5630+ if (!s) {
5631+ JS_FreeValue(ctx, func_obj);
5632+ return JS_EXCEPTION;
5633+ }
5634+ s->func = func;
5635+ s->length = length;
5636+ s->magic = magic;
5637+ s->opaque = opaque;
5638+ s->opaque_finalize = opaque_finalize;
5639+ JS_SetOpaqueInternal(func_obj, s);
5640+ name_atom = JS_ATOM_empty_string;
5641+ if (name && *name) {
5642+ name_atom = JS_NewAtom(ctx, name);
5643+ if (name_atom == JS_ATOM_NULL) {
5644+ JS_FreeValue(ctx, func_obj);
5645+ return JS_EXCEPTION;
5646+ }
5647+ }
5648+ js_function_set_properties(ctx, func_obj, name_atom, length);
5649+ JS_FreeAtom(ctx, name_atom);
5650+ return func_obj;
5651+ }
5652+
55505653static void free_property(JSRuntime *rt, JSProperty *pr, int prop_flags)
55515654{
55525655 if (unlikely(prop_flags & JS_PROP_TMASK)) {
@@ -6455,6 +6558,15 @@ void JS_ComputeMemoryUsage(JSRuntime *rt, JSMemoryUsage *s)
64556558 }
64566559 }
64576560 break;
6561+ case JS_CLASS_C_CLOSURE: /* u.c_closure_record */
6562+ {
6563+ JSCClosureRecord *c = p->u.c_closure_record;
6564+ if (c) {
6565+ s->memory_used_count += 1;
6566+ s->memory_used_size += sizeof(*c);
6567+ }
6568+ }
6569+ break;
64586570 case JS_CLASS_REGEXP: /* u.regexp */
64596571 compute_jsstring_size(p->u.regexp.pattern, hp);
64606572 compute_jsstring_size(p->u.regexp.bytecode, hp);
0 commit comments