name: duk_safe_call proto: | duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, duk_idx_t nargs, duk_idx_t nrets); stack: | [ ... arg1! ...! argN! ] -> [ ... ret1! ...! retN! ] summary: |

Perform a protected pure C function call inside the current value stack frame (the call is not visible on the call stack). nargs topmost values in the current value stack frame are identified as call arguments, and nrets return values are provided after the call returns.

The return value is:

Unlike most Duktape API calls, this call returns zero on success. This allows multiple error codes to be defined later.

Because this call operates on the current value stack frame, stack behavior differs a bit from other call types. Although the target function signature matches Duktape/C functions, value stack and return code policies are different.

The top nargs elements of the stack top are identified as arguments to func establishing a "base index" for the return stack as:

  (duk_get_top() - nargs)
  

When func returns, it indicates with its return value the number of return values it has pushed on top of the stack; multiple or zero return values possible. The stack is then manipulated so that there are exactly nrets values starting at the "base index" established before the call.

Note that since func has full access to the value stack, it may modify the stack below the indended arguments and even pop elements below the "base index" off the stack. Such elements are restored with undefined values before returning, to ensure that the stack is always in a consistent state upon returning.

If an error occurs, the stack will still have nrets values at "base index"; the first of such values is the error, and the remaining values are undefined. If nrets is zero, the error will not be present on the stack (the return stack top will equal the "base index"), so calling this function with nrets as 0 is not very useful.

Example with nargs = 3, nrets = 2, func returns 4. Pipe chars indicate logical boundaries:

        .--- frame bottom
        |
        |     .--- "base index"
        v     v
  [ ... | ... | a b c ]            stack before calling 'func'

  [ ... | ... | a b | x y z w ]    stack after calling 'func', which has
                                   popped one argument and written four
                                   return values (and returned 4)

  [ ... | ... | x y ]              stack after duk_safe_call() returns,
                                   2 (= nrets) first 'func' return values
                                   are left at "base index"
  
Note that func uses caller stack frame, so bottom-based references are dangerous within 'func'.
example: | duk_ret_t my_func(duk_context *ctx) { double a, b, c; a = duk_get_number(ctx, -3); b = duk_get_number(ctx, -2); c = duk_get_number(ctx, -1); /* ignored on purpose */ duk_push_number(ctx, a + b); /* Indicates that there is only one return value. Because the caller * requested two (nrets == 2), Duktape will automatically add an * additional "undefined" result value. */ return 1; } duk_int_t rc; duk_push_int(ctx, 10); duk_push_int(ctx, 11); duk_push_int(ctx, 12); rc = duk_safe_call(ctx, my_func, 3 /*nargs*/, 2 /*nrets*/); if (rc == DUK_EXEC_SUCCESS) { printf("1st return value: %s\n", duk_to_string(ctx, -2)); /* 21 */ printf("2nd return value: %s\n", duk_to_string(ctx, -1)); /* undefined */ } else { printf("error value: %s\n", duk_to_string(ctx, -2)); } duk_pop_2(ctx); tags: - call - protected introduced: 1.0.0