blob: c2791d7013ef3e25853673eb7a4e704926e1da93 [file] [log] [blame]
/*
* Copyright (C) Igor Sysoev
* Copyright (C) NGINX, Inc.
*/
#ifndef _NJS_FUNCTION_H_INCLUDED_
#define _NJS_FUNCTION_H_INCLUDED_
struct njs_function_lambda_s {
njs_index_t *closures;
uint32_t nclosures;
uint32_t nlocal;
njs_declaration_t *declarations;
uint32_t ndeclarations;
njs_index_t self;
uint32_t nargs;
uint8_t ctor; /* 1 bit */
uint8_t rest_parameters; /* 1 bit */
u_char *start;
};
/* The frame size must be aligned to njs_value_t. */
#define NJS_NATIVE_FRAME_SIZE \
njs_align_size(sizeof(njs_native_frame_t), sizeof(njs_value_t))
/* The frame size must be aligned to njs_value_t. */
#define NJS_FRAME_SIZE \
njs_align_size(sizeof(njs_frame_t), sizeof(njs_value_t))
#define NJS_FRAME_SPARE_SIZE (4 * 1024)
struct njs_native_frame_s {
u_char *free;
u_char *pc;
njs_function_t *function;
njs_native_frame_t *previous;
njs_value_t *arguments;
njs_object_t *arguments_object;
njs_value_t *arguments_offset;
njs_value_t **local;
uint32_t size;
uint32_t free_size;
njs_value_t *retval;
uint32_t nargs;
uint8_t native; /* 1 bit */
/* Function is called as constructor with "new" keyword. */
uint8_t ctor; /* 1 bit */
/* Skip the Function.call() and Function.apply() methods frames. */
uint8_t skip; /* 1 bit */
};
typedef struct njs_exception_s njs_exception_t;
struct njs_exception_s {
njs_exception_t *next;
u_char *catch;
};
struct njs_frame_s {
njs_native_frame_t native;
njs_exception_t exception;
njs_frame_t *previous_active_frame;
};
njs_function_t *njs_function_alloc(njs_vm_t *vm, njs_function_lambda_t *lambda,
njs_bool_t async);
njs_function_t *njs_function_value_copy(njs_vm_t *vm, njs_value_t *value);
njs_int_t njs_function_name_set(njs_vm_t *vm, njs_function_t *function,
njs_value_t *name, const char *prefix);
njs_function_t *njs_function_copy(njs_vm_t *vm, njs_function_t *function);
njs_int_t njs_function_arguments_object_init(njs_vm_t *vm,
njs_native_frame_t *frame);
njs_int_t njs_function_rest_parameters_init(njs_vm_t *vm,
njs_native_frame_t *frame);
njs_int_t njs_function_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop,
njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
njs_int_t njs_function_constructor(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused);
njs_int_t njs_function_instance_length(njs_vm_t *vm, njs_object_prop_t *prop,
njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
njs_int_t njs_eval_function(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused);
njs_int_t njs_function_native_frame(njs_vm_t *vm, njs_function_t *function,
const njs_value_t *this, const njs_value_t *args, njs_uint_t nargs,
njs_bool_t ctor);
njs_int_t njs_function_lambda_frame(njs_vm_t *vm, njs_function_t *function,
const njs_value_t *this, const njs_value_t *args, njs_uint_t nargs,
njs_bool_t ctor);
njs_int_t njs_function_call2(njs_vm_t *vm, njs_function_t *function,
const njs_value_t *this, const njs_value_t *args,
njs_uint_t nargs, njs_value_t *retval, njs_bool_t ctor);
njs_int_t njs_function_lambda_call(njs_vm_t *vm, void *promise_cap);
njs_int_t njs_function_native_call(njs_vm_t *vm);
njs_native_frame_t *njs_function_frame_alloc(njs_vm_t *vm, size_t size);
void njs_function_frame_free(njs_vm_t *vm, njs_native_frame_t *frame);
njs_int_t njs_function_frame_save(njs_vm_t *vm, njs_frame_t *native,
u_char *pc);
njs_object_type_t njs_function_object_type(njs_vm_t *vm,
njs_function_t *function);
njs_int_t njs_function_capture_closure(njs_vm_t *vm, njs_function_t *function,
njs_function_lambda_t *lambda);
njs_int_t njs_function_capture_global_closures(njs_vm_t *vm,
njs_function_t *function);
njs_int_t njs_function_frame_invoke(njs_vm_t *vm, njs_value_t *retval);
njs_inline njs_function_lambda_t *
njs_function_lambda_alloc(njs_vm_t *vm, uint8_t ctor)
{
njs_function_lambda_t *lambda;
lambda = njs_mp_zalloc(vm->mem_pool, sizeof(njs_function_lambda_t));
if (njs_fast_path(lambda != NULL)) {
lambda->ctor = ctor;
}
return lambda;
}
njs_inline njs_int_t
njs_function_frame(njs_vm_t *vm, njs_function_t *function,
const njs_value_t *this, const njs_value_t *args, njs_uint_t nargs,
njs_bool_t ctor)
{
if (function->native) {
return njs_function_native_frame(vm, function, this, args, nargs, ctor);
} else {
return njs_function_lambda_frame(vm, function, this, args, nargs, ctor);
}
}
njs_inline njs_native_frame_t *
njs_function_previous_frame(njs_native_frame_t *frame)
{
njs_native_frame_t *previous;
do {
previous = frame->previous;
frame = previous;
} while (frame->skip);
return frame;
}
njs_inline njs_int_t
njs_function_call(njs_vm_t *vm, njs_function_t *function,
const njs_value_t *this, const njs_value_t *args,
njs_uint_t nargs, njs_value_t *retval)
{
return njs_function_call2(vm, function, this, args, nargs, retval, 0);
}
njs_inline njs_int_t
njs_function_apply(njs_vm_t *vm, njs_function_t *function,
const njs_value_t *args, njs_uint_t nargs, njs_value_t *retval)
{
return njs_function_call2(vm, function, &args[0], &args[1], nargs - 1,
retval, 0);
}
njs_inline njs_bool_t
njs_native_function_same(const njs_function_t *f1, const njs_function_t *f2)
{
return f1->u.native == f2->u.native && f1->magic8 == f2->magic8;
}
njs_inline njs_value_t **
njs_function_closures(const njs_function_t *func)
{
return (njs_value_t **) ((u_char *) func + sizeof(njs_function_t));
}
njs_inline size_t
njs_function_frame_size(njs_native_frame_t *frame)
{
size_t size;
uintptr_t start;
start = (uintptr_t) ((u_char *) frame + NJS_FRAME_SIZE);
size = ((uintptr_t) frame->arguments - start) / sizeof(njs_value_t *);
return NJS_FRAME_SIZE + (size * sizeof(njs_value_t *))
+ (size * sizeof(njs_value_t));
}
njs_inline size_t
njs_function_frame_args_count(njs_native_frame_t *frame)
{
uintptr_t start;
start = (uintptr_t) ((u_char *) frame + NJS_FRAME_SIZE);
return ((uintptr_t) frame->local - start) / sizeof(njs_value_t *);
}
njs_inline njs_value_t *
njs_function_frame_values(njs_native_frame_t *frame, njs_value_t **end)
{
size_t count;
uintptr_t start;
start = (uintptr_t) ((u_char *) frame + NJS_FRAME_SIZE);
count = ((uintptr_t) frame->arguments - start) / sizeof(njs_value_t *);
*end = frame->arguments + count;
return frame->arguments;
}
extern const njs_object_type_init_t njs_function_type_init;
extern const njs_object_init_t njs_function_instance_init;
extern const njs_object_init_t njs_arrow_instance_init;
extern const njs_object_init_t njs_arguments_object_instance_init;
#endif /* _NJS_FUNCTION_H_INCLUDED_ */