~ubuntu-branches/ubuntu/raring/gjs/raring

« back to all changes in this revision

Viewing changes to gi/function.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2012-03-13 19:15:08 UTC
  • mfrom: (1.6.7)
  • Revision ID: package-import@ubuntu.com-20120313191508-k44let6s97mb45uv
Tags: 1.31.20-0ubuntu1
* New upstream release.
* Add gir package
* debian/control.in: Require minimum glib 2.31
* Drop all patches since they've been applied upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
#include <jsapi.h>
37
37
 
38
38
#include <girepository.h>
39
 
#include <girffi.h>
40
39
#include <sys/mman.h>
41
40
#include <unistd.h>
42
41
#include <errno.h>
47
46
 */
48
47
#define GJS_ARG_INDEX_INVALID G_MAXUINT8
49
48
 
50
 
typedef enum {
51
 
    PARAM_NORMAL,
52
 
    PARAM_SKIPPED,
53
 
    PARAM_ARRAY,
54
 
    PARAM_CALLBACK
55
 
} ParamType;
56
 
 
57
49
typedef struct {
58
50
    GIFunctionInfo *info;
59
51
 
60
 
    ParamType *param_types;
 
52
    GjsParamType *param_types;
61
53
 
62
54
    guint8 expected_js_argc;
63
55
    guint8 js_out_argc;
72
64
 */
73
65
static GSList *completed_trampolines = NULL;  /* GjsCallbackTrampoline */
74
66
 
75
 
typedef struct {
76
 
    gint ref_count;
77
 
    JSRuntime *runtime;
78
 
    GICallableInfo *info;
79
 
    jsval js_function;
80
 
    ffi_cif cif;
81
 
    ffi_closure *closure;
82
 
    GIScopeType scope;
83
 
} GjsCallbackTrampoline;
84
 
 
85
67
GJS_DEFINE_PRIV_FROM_JS(Function, gjs_function_class)
86
68
 
87
69
/*
123
105
    return JS_TRUE;
124
106
}
125
107
 
126
 
static void
 
108
void
127
109
gjs_callback_trampoline_ref(GjsCallbackTrampoline *trampoline)
128
110
{
129
111
    trampoline->ref_count++;
130
112
}
131
113
 
132
 
static void
 
114
void
133
115
gjs_callback_trampoline_unref(GjsCallbackTrampoline *trampoline)
134
116
{
135
117
    /* Not MT-safe, like all the rest of GJS */
140
122
 
141
123
        context = gjs_runtime_get_current_context(trampoline->runtime);
142
124
 
143
 
        JS_RemoveValueRoot(context, &trampoline->js_function);
 
125
        if (!trampoline->is_vfunc)
 
126
            JS_RemoveValueRoot(context, &trampoline->js_function);
144
127
        g_callable_info_free_closure(trampoline->info, trampoline->closure);
145
128
        g_base_info_unref( (GIBaseInfo*) trampoline->info);
 
129
        g_free (trampoline->param_types);
146
130
        g_slice_free(GjsCallbackTrampoline, trampoline);
147
131
    }
148
132
}
197
181
                *(ffi_arg *) result = (ffi_arg) return_value->v_pointer;
198
182
                break;
199
183
            }
 
184
 
 
185
            g_base_info_unref(interface_info);
200
186
        }
201
187
    default:
202
188
        *(ffi_arg *) result = (ffi_arg) return_value->v_uint64;
219
205
{
220
206
    JSContext *context;
221
207
    GjsCallbackTrampoline *trampoline;
222
 
    int i, n_args, n_jsargs;
 
208
    int i, n_args, n_jsargs, n_outargs;
223
209
    jsval *jsargs, rval;
 
210
    JSObject *this_object;
224
211
    GITypeInfo ret_type;
225
 
    GArgument return_value;
226
212
    gboolean success = FALSE;
 
213
    gboolean ret_type_is_void;
227
214
 
228
215
    trampoline = data;
229
216
    g_assert(trampoline);
235
222
 
236
223
    g_assert(n_args >= 0);
237
224
 
 
225
    n_outargs = 0;
238
226
    jsargs = (jsval*)g_newa(jsval, n_args);
239
227
    for (i = 0, n_jsargs = 0; i < n_args; i++) {
240
228
        GIArgInfo arg_info;
241
229
        GITypeInfo type_info;
 
230
        GjsParamType param_type;
242
231
 
243
232
        g_callable_info_load_arg(trampoline->info, i, &arg_info);
244
233
        g_arg_info_load_type(&arg_info, &type_info);
247
236
        if (g_type_info_get_tag(&type_info) == GI_TYPE_TAG_VOID)
248
237
            continue;
249
238
 
250
 
        if (!gjs_value_from_g_argument(context,
251
 
                                       &jsargs[n_jsargs++],
252
 
                                       &type_info,
253
 
                                       args[i]))
254
 
            goto out;
 
239
        if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_OUT) {
 
240
            n_outargs++;
 
241
            continue;
 
242
        }
 
243
 
 
244
        if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_INOUT)
 
245
            n_outargs++;
 
246
 
 
247
        param_type = trampoline->param_types[i];
 
248
 
 
249
        switch (param_type) {
 
250
            case PARAM_SKIPPED:
 
251
                continue;
 
252
            case PARAM_ARRAY: {
 
253
                gint array_length_pos = g_type_info_get_array_length(&type_info);
 
254
                GIArgInfo array_length_arg;
 
255
                GITypeInfo arg_type_info;
 
256
                jsval length;
 
257
 
 
258
                g_callable_info_load_arg(trampoline->info, array_length_pos, &array_length_arg);
 
259
                g_arg_info_load_type(&array_length_arg, &arg_type_info);
 
260
                if (!gjs_value_from_g_argument(context, &length,
 
261
                                               &arg_type_info,
 
262
                                               args[array_length_pos], TRUE))
 
263
                    goto out;
 
264
 
 
265
                if (!gjs_value_from_explicit_array(context, &jsargs[n_jsargs++],
 
266
                                                   &type_info, args[i], JSVAL_TO_INT(length)))
 
267
                    goto out;
 
268
                break;
 
269
            }
 
270
            case PARAM_NORMAL:
 
271
                if (!gjs_value_from_g_argument(context,
 
272
                                               &jsargs[n_jsargs++],
 
273
                                               &type_info,
 
274
                                               args[i], FALSE))
 
275
                    goto out;
 
276
                break;
 
277
            default:
 
278
                g_assert_not_reached();
 
279
        }
255
280
    }
256
281
 
 
282
    if (trampoline->is_vfunc)
 
283
        this_object = JSVAL_TO_OBJECT(jsargs[0]);
 
284
    else
 
285
        this_object = NULL;
 
286
 
257
287
    if (!JS_CallFunctionValue(context,
258
 
                              NULL,
 
288
                              this_object,
259
289
                              trampoline->js_function,
260
290
                              n_jsargs,
261
291
                              jsargs,
264
294
    }
265
295
 
266
296
    g_callable_info_load_return_type(trampoline->info, &ret_type);
267
 
 
268
 
    if (!gjs_value_to_g_argument(context,
269
 
                                 rval,
270
 
                                 &ret_type,
271
 
                                 "callback",
272
 
                                 GJS_ARGUMENT_RETURN_VALUE,
273
 
                                 FALSE,
274
 
                                 TRUE,
275
 
                                 &return_value)) {
276
 
        goto out;
 
297
    ret_type_is_void = g_type_info_get_tag (&ret_type) == GI_TYPE_TAG_VOID;
 
298
 
 
299
    if (n_outargs == 0 && !ret_type_is_void) {
 
300
        GIArgument argument;
 
301
 
 
302
        /* non-void return value, no out args. Should
 
303
         * be a single return value. */
 
304
        if (!gjs_value_to_g_argument(context,
 
305
                                     rval,
 
306
                                     &ret_type,
 
307
                                     "callback",
 
308
                                     GJS_ARGUMENT_RETURN_VALUE,
 
309
                                     GI_TRANSFER_NOTHING,
 
310
                                     TRUE,
 
311
                                     &argument))
 
312
            goto out;
 
313
 
 
314
        set_return_ffi_arg_from_giargument(&ret_type,
 
315
                                           result,
 
316
                                           &argument);
 
317
    } else if (n_outargs == 1 && ret_type_is_void) {
 
318
        /* void return value, one out args. Should
 
319
         * be a single return value. */
 
320
        for (i = 0; i < n_args; i++) {
 
321
            GIArgInfo arg_info;
 
322
            GITypeInfo type_info;
 
323
            g_callable_info_load_arg(trampoline->info, i, &arg_info);
 
324
            if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_IN)
 
325
                continue;
 
326
 
 
327
            g_arg_info_load_type(&arg_info, &type_info);
 
328
            if (!gjs_value_to_g_argument(context,
 
329
                                         rval,
 
330
                                         &type_info,
 
331
                                         "callback",
 
332
                                         GJS_ARGUMENT_ARGUMENT,
 
333
                                         GI_TRANSFER_NOTHING,
 
334
                                         TRUE,
 
335
                                         *(gpointer *)args[i]))
 
336
                goto out;
 
337
 
 
338
            break;
 
339
        }
 
340
    } else {
 
341
        jsval elem;
 
342
        gsize elem_idx = 0;
 
343
        /* more than one of a return value or an out argument.
 
344
         * Should be an array of output values. */
 
345
 
 
346
        if (!ret_type_is_void) {
 
347
            GIArgument argument;
 
348
 
 
349
            if (!JS_GetElement(context, JSVAL_TO_OBJECT(rval), elem_idx, &elem))
 
350
                goto out;
 
351
 
 
352
            if (!gjs_value_to_g_argument(context,
 
353
                                         elem,
 
354
                                         &ret_type,
 
355
                                         "callback",
 
356
                                         GJS_ARGUMENT_ARGUMENT,
 
357
                                         GI_TRANSFER_NOTHING,
 
358
                                         TRUE,
 
359
                                         &argument))
 
360
                goto out;
 
361
 
 
362
            set_return_ffi_arg_from_giargument(&ret_type,
 
363
                                               result,
 
364
                                               &argument);
 
365
 
 
366
            elem_idx++;
 
367
        }
 
368
 
 
369
        for (i = 0; i < n_args; i++) {
 
370
            GIArgInfo arg_info;
 
371
            GITypeInfo type_info;
 
372
            g_callable_info_load_arg(trampoline->info, i, &arg_info);
 
373
            if (g_arg_info_get_direction(&arg_info) == GI_DIRECTION_IN)
 
374
                continue;
 
375
 
 
376
            g_arg_info_load_type(&arg_info, &type_info);
 
377
            if (!JS_GetElement(context, JSVAL_TO_OBJECT(rval), elem_idx, &elem))
 
378
                goto out;
 
379
 
 
380
            if (!gjs_value_to_g_argument(context,
 
381
                                         elem,
 
382
                                         &type_info,
 
383
                                         "callback",
 
384
                                         GJS_ARGUMENT_ARGUMENT,
 
385
                                         GI_TRANSFER_NOTHING,
 
386
                                         TRUE,
 
387
                                         *(gpointer *)args[i]))
 
388
                goto out;
 
389
 
 
390
            elem_idx++;
 
391
        }
277
392
    }
278
393
 
279
 
    
280
 
    set_return_ffi_arg_from_giargument(&ret_type, result, &return_value);
281
 
 
282
394
    success = TRUE;
283
395
 
284
396
out:
309
421
    gjs_callback_trampoline_unref(trampoline);
310
422
}
311
423
 
312
 
static GjsCallbackTrampoline*
 
424
GjsCallbackTrampoline*
313
425
gjs_callback_trampoline_new(JSContext      *context,
314
426
                            jsval           function,
315
427
                            GICallableInfo *callable_info,
316
 
                            GIScopeType     scope)
 
428
                            GIScopeType     scope,
 
429
                            gboolean        is_vfunc)
317
430
{
318
431
    GjsCallbackTrampoline *trampoline;
 
432
    int n_args, i;
319
433
 
320
 
    if (function == JSVAL_NULL) {
 
434
    if (JSVAL_IS_NULL(function)) {
321
435
        return NULL;
322
436
    }
323
437
 
329
443
    trampoline->info = callable_info;
330
444
    g_base_info_ref((GIBaseInfo*)trampoline->info);
331
445
    trampoline->js_function = function;
332
 
    JS_AddValueRoot(context, &trampoline->js_function);
 
446
    if (!is_vfunc)
 
447
        JS_AddValueRoot(context, &trampoline->js_function);
 
448
 
 
449
    /* Analyze param types and directions, similarly to init_cached_function_data */
 
450
    n_args = g_callable_info_get_n_args(trampoline->info);
 
451
    trampoline->param_types = g_new0(GjsParamType, n_args);
 
452
 
 
453
    for (i = 0; i < n_args; i++) {
 
454
        GIDirection direction;
 
455
        GIArgInfo arg_info;
 
456
        GITypeInfo type_info;
 
457
        GITypeTag type_tag;
 
458
 
 
459
        if (trampoline->param_types[i] == PARAM_SKIPPED)
 
460
            continue;
 
461
 
 
462
        g_callable_info_load_arg(trampoline->info, i, &arg_info);
 
463
        g_arg_info_load_type(&arg_info, &type_info);
 
464
 
 
465
        direction = g_arg_info_get_direction(&arg_info);
 
466
        type_tag = g_type_info_get_tag(&type_info);
 
467
 
 
468
        if (direction != GI_DIRECTION_IN) {
 
469
            /* INOUT and OUT arguments are handled differently. */
 
470
            continue;
 
471
        }
 
472
 
 
473
        if (type_tag == GI_TYPE_TAG_INTERFACE) {
 
474
            GIBaseInfo* interface_info;
 
475
            GIInfoType interface_type;
 
476
 
 
477
            interface_info = g_type_info_get_interface(&type_info);
 
478
            interface_type = g_base_info_get_type(interface_info);
 
479
            if (interface_type == GI_INFO_TYPE_CALLBACK) {
 
480
                gjs_throw(context, "Callback accepts another callback as a parameter. This is not supported");
 
481
                g_base_info_unref(interface_info);
 
482
                return NULL;
 
483
            }
 
484
            g_base_info_unref(interface_info);
 
485
        } else if (type_tag == GI_TYPE_TAG_ARRAY) {
 
486
            if (g_type_info_get_array_type(&type_info) == GI_ARRAY_TYPE_C) {
 
487
                int array_length_pos = g_type_info_get_array_length(&type_info);
 
488
 
 
489
                if (array_length_pos >= 0 && array_length_pos < n_args) {
 
490
                    GIArgInfo length_arg_info;
 
491
 
 
492
                    g_callable_info_load_arg(trampoline->info, array_length_pos, &length_arg_info);
 
493
                    if (g_arg_info_get_direction(&length_arg_info) != direction) {
 
494
                        gjs_throw(context, "Callback has an array with different-direction length arg, not supported");
 
495
                        return NULL;
 
496
                    }
 
497
 
 
498
                    trampoline->param_types[array_length_pos] = PARAM_SKIPPED;
 
499
                    trampoline->param_types[i] = PARAM_ARRAY;
 
500
                }
 
501
            }
 
502
        }
 
503
    }
 
504
 
333
505
    trampoline->closure = g_callable_info_prepare_closure(callable_info, &trampoline->cif,
334
506
                                                          gjs_callback_closure, trampoline);
335
507
 
336
508
    trampoline->scope = scope;
 
509
    trampoline->is_vfunc = is_vfunc;
337
510
 
338
511
    return trampoline;
339
512
}
436
609
                return_value->v_pointer = (gpointer) value->rv_ffi_arg;
437
610
                break;
438
611
            }
 
612
 
 
613
            g_base_info_unref(interface_info);
439
614
        }
440
615
        break;
441
616
    default:
481
656
    GError *local_error = NULL;
482
657
    gboolean failed, postinvoke_release_failed;
483
658
 
484
 
    GIFunctionInfoFlags flags;
485
659
    gboolean is_method;
486
660
    GITypeInfo return_info;
487
661
    GITypeTag return_tag;
 
662
    GIInfoType info_type;
488
663
    jsval *return_values = NULL;
489
664
    guint8 next_rval = 0; /* index into return_values */
490
665
    GSList *iter;
502
677
        completed_trampolines = NULL;
503
678
    }
504
679
 
505
 
    flags = g_function_info_get_flags(function->info);
506
 
    is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
507
 
    can_throw_gerror = (flags & GI_FUNCTION_THROWS) != 0;
 
680
    info_type = g_base_info_get_type((GIBaseInfo *)function->info);
 
681
 
 
682
    switch (info_type) {
 
683
    case GI_INFO_TYPE_FUNCTION:
 
684
        {
 
685
            GIFunctionInfoFlags flags;
 
686
            flags = g_function_info_get_flags((GIFunctionInfo *)function->info);
 
687
            is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
 
688
            can_throw_gerror = (flags & GI_FUNCTION_THROWS) != 0;
 
689
        }
 
690
        break;
 
691
    case GI_INFO_TYPE_VFUNC:
 
692
        {
 
693
            GIVFuncInfoFlags flags;
 
694
            flags = g_vfunc_info_get_flags ((GIVFuncInfo *)function->info);
 
695
            can_throw_gerror = (flags & GI_VFUNC_THROWS) != 0;
 
696
        }
 
697
        is_method = TRUE;
 
698
      break;
 
699
    case GI_INFO_TYPE_CALLBACK:
 
700
        is_method = TRUE;
 
701
        can_throw_gerror = FALSE;
 
702
        break;
 
703
    default:
 
704
        g_assert_not_reached();
 
705
    }
 
706
 
508
707
    c_argc = function->invoker.cif.nargs;
509
708
    gi_argc = g_callable_info_get_n_args( (GICallableInfo*) function->info);
510
709
 
558
757
            GType gtype;
559
758
 
560
759
            in_arg_cvalues[0].v_pointer = gjs_g_object_from_object(context, obj);
 
760
            if (in_arg_cvalues[0].v_pointer == NULL) {
 
761
                /* priv == NULL (user probably forgot to chain _init).
 
762
                 * Anyway, in this case we've thrown an exception, so just
 
763
                 * make sure we fail. */
 
764
                failed = TRUE;
 
765
                goto release;
 
766
            }
561
767
 
562
768
            gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *)container);
563
769
            if (!g_type_is_a (G_TYPE_FROM_INSTANCE (in_arg_cvalues[0].v_pointer),
636
842
        } else {
637
843
            GArgument *in_value;
638
844
            GITypeInfo ainfo;
639
 
            ParamType param_type;
 
845
            GjsParamType param_type;
640
846
 
641
847
            g_arg_info_load_type(&arg_info, &ainfo);
642
848
 
669
875
                    trampoline = gjs_callback_trampoline_new(context,
670
876
                                                             value,
671
877
                                                             callable_info,
672
 
                                                             scope);
 
878
                                                             scope,
 
879
                                                             FALSE);
673
880
                    closure = trampoline->closure;
674
881
                    g_base_info_unref(callable_info);
675
882
                }
837
1044
                array_length_pos += is_method ? 1 : 0;
838
1045
                arg_failed = !gjs_value_from_g_argument(context, &length,
839
1046
                                                        &arg_type_info,
840
 
                                                        &out_arg_cvalues[array_length_pos]);
 
1047
                                                        &out_arg_cvalues[array_length_pos],
 
1048
                                                        TRUE);
841
1049
                if (!arg_failed) {
842
1050
                    arg_failed = !gjs_value_from_explicit_array(context,
843
1051
                                                                &return_values[next_rval],
854
1062
                    failed = TRUE;
855
1063
            } else {
856
1064
                arg_failed = !gjs_value_from_g_argument(context, &return_values[next_rval],
857
 
                                                        &return_info, &return_gargument);
 
1065
                                                        &return_info, &return_gargument,
 
1066
                                                        TRUE);
858
1067
                /* Free GArgument, the jsval should have ref'd or copied it */
859
1068
                if (!arg_failed &&
860
1069
                    !gjs_g_argument_release(context,
880
1089
        GIDirection direction;
881
1090
        GIArgInfo arg_info;
882
1091
        GITypeInfo arg_type_info;
883
 
        ParamType param_type;
 
1092
        GjsParamType param_type;
884
1093
 
885
1094
        g_callable_info_load_arg( (GICallableInfo*) function->info, gi_arg_pos, &arg_info);
886
1095
        direction = g_arg_info_get_direction(&arg_info);
974
1183
                array_length_pos += is_method ? 1 : 0;
975
1184
                arg_failed = !gjs_value_from_g_argument(context, &array_length,
976
1185
                                                        &array_length_type_info,
977
 
                                                        &out_arg_cvalues[array_length_pos]);
 
1186
                                                        &out_arg_cvalues[array_length_pos],
 
1187
                                                        TRUE);
978
1188
                if (!arg_failed) {
979
1189
                    arg_failed = !gjs_value_from_explicit_array(context,
980
1190
                                                                &return_values[next_rval],
986
1196
                arg_failed = !gjs_value_from_g_argument(context,
987
1197
                                                        &return_values[next_rval],
988
1198
                                                        &arg_type_info,
989
 
                                                        arg);
 
1199
                                                        arg,
 
1200
                                                        TRUE);
990
1201
            }
991
1202
 
992
1203
            if (arg_failed)
1086
1297
    }
1087
1298
}
1088
1299
 
1089
 
#ifdef JSFUN_CONSTRUCTOR
1090
1300
static JSBool
1091
1301
function_call(JSContext *context,
1092
1302
              uintN      js_argc,
1095
1305
    jsval *js_argv = JS_ARGV(context, vp);
1096
1306
    JSObject *object = JS_THIS_OBJECT(context, vp);
1097
1307
    JSObject *callee = JSVAL_TO_OBJECT(JS_CALLEE(context, vp));
1098
 
#else
1099
 
static JSBool
1100
 
function_call(JSContext *context,
1101
 
              JSObject  *object, /* "this" object, not the function object */
1102
 
              uintN      js_argc,
1103
 
              jsval     *js_argv,
1104
 
              jsval     *retval)
1105
 
{
1106
 
    JSObject *callee = JSVAL_TO_OBJECT(JS_ARGV_CALLEE(js_argv));
1107
 
#endif
1108
1308
    JSBool success;
1109
1309
    Function *priv;
 
1310
    jsval retval;
1110
1311
 
1111
1312
    priv = priv_from_js(context, callee);
1112
1313
    gjs_debug_marshal(GJS_DEBUG_GFUNCTION, "Call callee %p priv %p this obj %p %s", callee, priv,
1117
1318
        return JS_TRUE; /* we are the prototype, or have the wrong class */
1118
1319
 
1119
1320
 
1120
 
#ifdef JSFUN_CONSTRUCTOR
1121
 
    {
1122
 
        jsval retval;
1123
 
        success = gjs_invoke_c_function(context, priv, object, js_argc, js_argv, &retval);
1124
 
        if (success)
1125
 
            JS_SET_RVAL(context, vp, retval);
1126
 
    }
1127
 
#else
1128
 
    success = gjs_invoke_c_function(context, priv, object, js_argc, js_argv, retval);
1129
 
#endif
 
1321
    success = gjs_invoke_c_function(context, priv, object, js_argc, js_argv, &retval);
 
1322
    if (success)
 
1323
        JS_SET_RVAL(context, vp, retval);
 
1324
 
1130
1325
    return success;
1131
1326
}
1132
1327
 
1133
 
/* If we set JSCLASS_CONSTRUCT_PROTOTYPE flag, then this is called on
1134
 
 * the prototype in addition to on each instance. When called on the
1135
 
 * prototype, "obj" is the prototype, and "retval" is the prototype
1136
 
 * also, but can be replaced with another object to use instead as the
1137
 
 * prototype. If we don't set JSCLASS_CONSTRUCT_PROTOTYPE we can
1138
 
 * identify the prototype as an object of our class with NULL private
1139
 
 * data.
1140
 
 */
1141
 
#ifdef JSFUN_CONSTRUCTOR
1142
 
static JSBool
1143
 
function_constructor(JSContext *context,
1144
 
                     uintN      argc,
1145
 
                     jsval     *vp)
1146
 
{
1147
 
    JSObject *object;
1148
 
    if (!JS_IsConstructing_PossiblyWithGivenThisObject(context, vp, &object)) {
1149
 
        gjs_throw_constructor_error(context);
1150
 
        return JS_FALSE;
1151
 
    }
1152
 
    if (object == NULL)
1153
 
        object = JS_NewObjectForConstructor(context, vp);
1154
 
#else
1155
 
static JSBool
1156
 
function_constructor(JSContext *context,
1157
 
                     JSObject  *object,
1158
 
                     uintN      argc,
1159
 
                     jsval     *argv,
1160
 
                     jsval     *retval)
1161
 
{
1162
 
#endif
 
1328
GJS_NATIVE_CONSTRUCTOR_DECLARE(function)
 
1329
{
 
1330
    GJS_NATIVE_CONSTRUCTOR_VARIABLES(function)
1163
1331
    Function *priv;
1164
1332
 
 
1333
    GJS_NATIVE_CONSTRUCTOR_PRELUDE(name);
 
1334
 
1165
1335
    priv = g_slice_new0(Function);
1166
1336
 
1167
1337
    GJS_INC_COUNTER(function);
1171
1341
 
1172
1342
    gjs_debug_lifecycle(GJS_DEBUG_GFUNCTION,
1173
1343
                        "function constructor, obj %p priv %p", object, priv);
1174
 
#ifdef JSFUN_CONSTRUCTOR
1175
 
    JS_SET_RVAL(context, vp, OBJECT_TO_JSVAL(object));
1176
 
#endif
 
1344
 
 
1345
    GJS_NATIVE_CONSTRUCTOR_FINISH(name);
1177
1346
 
1178
1347
    return JS_TRUE;
1179
1348
}
1233
1402
    if (priv == NULL) {
1234
1403
        string = "function () {\n}";
1235
1404
        free = FALSE;
1236
 
    } else {
 
1405
    } else if (g_base_info_get_type(priv->info) == GI_INFO_TYPE_FUNCTION) {
1237
1406
        string = g_strdup_printf("function %s(){\n\t/* proxy for native symbol %s(); */\n}",
1238
1407
                                 g_base_info_get_name ((GIBaseInfo *) priv->info),
1239
 
                                 g_function_info_get_symbol (priv->info));
 
1408
                                 g_function_info_get_symbol ((GIFunctionInfo *) priv->info));
 
1409
        free = TRUE;
 
1410
    } else {
 
1411
        string = g_strdup_printf("function %s(){\n\t/* proxy for native symbol */\n}",
 
1412
                                 g_base_info_get_name ((GIBaseInfo *) priv->info));
1240
1413
        free = TRUE;
1241
1414
    }
1242
1415
 
1292
1465
static gboolean
1293
1466
init_cached_function_data (JSContext      *context,
1294
1467
                           Function       *function,
1295
 
                           GIFunctionInfo *info)
 
1468
                           GType           gtype,
 
1469
                           GICallableInfo *info)
1296
1470
{
1297
1471
    guint8 i, n_args, array_length_pos;
1298
1472
    GError *error = NULL;
1299
1473
    GITypeInfo return_type;
1300
 
 
1301
 
    if (!g_function_info_prep_invoker(info, &(function->invoker), &error)) {
1302
 
        gjs_throw_g_error(context, error);
1303
 
        return FALSE;
 
1474
    GIInfoType info_type;
 
1475
 
 
1476
    info_type = g_base_info_get_type((GIBaseInfo *)info);
 
1477
 
 
1478
    if (info_type == GI_INFO_TYPE_FUNCTION) {
 
1479
        if (!g_function_info_prep_invoker((GIFunctionInfo *)info,
 
1480
                                          &(function->invoker),
 
1481
                                          &error)) {
 
1482
            gjs_throw_g_error(context, error);
 
1483
            return FALSE;
 
1484
        }
 
1485
    } else if (info_type == GI_INFO_TYPE_VFUNC) {
 
1486
        gpointer addr;
 
1487
 
 
1488
        addr = g_vfunc_info_get_address((GIVFuncInfo *)info, gtype, &error);
 
1489
        if (error != NULL) {
 
1490
            if (error->code != G_INVOKE_ERROR_SYMBOL_NOT_FOUND)
 
1491
                gjs_throw_g_error(context, error);
 
1492
 
 
1493
            return FALSE;
 
1494
        }
 
1495
 
 
1496
        if (!g_function_invoker_new_for_address(addr, info,
 
1497
                                                &(function->invoker),
 
1498
                                                &error)) {
 
1499
            gjs_throw_g_error(context, error);
 
1500
            return FALSE;
 
1501
        }
1304
1502
    }
1305
1503
 
1306
1504
    g_callable_info_load_return_type((GICallableInfo*)info, &return_type);
1308
1506
        function->js_out_argc += 1;
1309
1507
 
1310
1508
    n_args = g_callable_info_get_n_args((GICallableInfo*) info);
1311
 
    function->param_types = g_new0(ParamType, n_args);
 
1509
    function->param_types = g_new0(GjsParamType, n_args);
1312
1510
 
1313
1511
    array_length_pos = g_type_info_get_array_length(&return_type);
1314
1512
    if (array_length_pos >= 0 && array_length_pos < n_args)
1359
1557
                        gjs_throw(context, "Function %s.%s has a GDestroyNotify but no user_data, not supported",
1360
1558
                                  g_base_info_get_namespace( (GIBaseInfo*) info),
1361
1559
                                  g_base_info_get_name( (GIBaseInfo*) info));
 
1560
                        g_base_info_unref(interface_info);
1362
1561
                        return JS_FALSE;
1363
1562
                    }
1364
1563
                }
1410
1609
 
1411
1610
static JSObject*
1412
1611
function_new(JSContext      *context,
1413
 
             GIFunctionInfo *info)
 
1612
             GType           gtype,
 
1613
             GICallableInfo *info)
1414
1614
{
1415
1615
    JSObject *function;
1416
1616
    JSObject *global;
1439
1639
                                  * none - just name the prototype like
1440
1640
                                  * Math - rarely correct)
1441
1641
                                  */
1442
 
                                 function_constructor,
 
1642
                                 gjs_function_constructor,
1443
1643
                                 /* number of constructor args */
1444
1644
                                 0,
1445
1645
                                 /* props of prototype */
1466
1666
    }
1467
1667
 
1468
1668
    priv = priv_from_js(context, function);
1469
 
    if (!init_cached_function_data(context, priv, info))
 
1669
    if (!init_cached_function_data(context, priv, gtype, (GICallableInfo *)info))
1470
1670
      return NULL;
1471
1671
 
1472
1672
    return function;
1475
1675
JSObject*
1476
1676
gjs_define_function(JSContext      *context,
1477
1677
                    JSObject       *in_object,
1478
 
                    GIFunctionInfo *info)
 
1678
                    GType           gtype,
 
1679
                    GICallableInfo *info)
1479
1680
{
1480
 
    JSObject *function;
 
1681
    JSObject *function = NULL;
 
1682
    GIInfoType info_type;
 
1683
    gchar *name;
 
1684
    gboolean free_name;
 
1685
 
 
1686
    info_type = g_base_info_get_type((GIBaseInfo *)info);
1481
1687
 
1482
1688
    JS_BeginRequest(context);
1483
1689
 
1484
 
    function = function_new(context, info);
 
1690
    function = function_new(context, gtype, info);
1485
1691
    if (function == NULL) {
1486
1692
        gjs_move_exception(context, context);
1487
1693
 
1489
1695
        return NULL;
1490
1696
    }
1491
1697
 
1492
 
    if (!JS_DefineProperty(context, in_object,
1493
 
                           g_base_info_get_name( (GIBaseInfo*) info),
 
1698
    if (info_type == GI_INFO_TYPE_FUNCTION) {
 
1699
        name = (gchar *) g_base_info_get_name((GIBaseInfo*) info);
 
1700
        free_name = FALSE;
 
1701
    } else if (info_type == GI_INFO_TYPE_VFUNC) {
 
1702
        name = g_strdup_printf("vfunc_%s", g_base_info_get_name((GIBaseInfo*) info));
 
1703
        free_name = TRUE;
 
1704
    } else {
 
1705
        g_assert_not_reached ();
 
1706
    }
 
1707
 
 
1708
    if (!JS_DefineProperty(context, in_object, name,
1494
1709
                           OBJECT_TO_JSVAL(function),
1495
1710
                           NULL, NULL,
1496
1711
                           GJS_MODULE_PROP_FLAGS)) {
1500
1715
        return NULL;
1501
1716
    }
1502
1717
 
 
1718
    if (free_name)
 
1719
        g_free(name);
 
1720
 
1503
1721
    JS_EndRequest(context);
1504
1722
    return function;
1505
1723
}
1517
1735
  JSBool result;
1518
1736
 
1519
1737
  memset (&function, 0, sizeof (Function));
1520
 
  if (!init_cached_function_data (context, &function, info))
 
1738
  if (!init_cached_function_data (context, &function, 0, info))
1521
1739
    return JS_FALSE;
1522
1740
 
1523
1741
  result = gjs_invoke_c_function (context, &function, obj, argc, argv, rval);