1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #ifndef _NJS_FUNCTION_H_INCLUDED_
8 #define _NJS_FUNCTION_H_INCLUDED_
9 
10 
11 struct njs_function_lambda_s {
12     njs_index_t                    *closures;
13     uint32_t                       nclosures;
14     uint32_t                       nlocal;
15     uint32_t                       temp;
16 
17     njs_declaration_t              *declarations;
18     uint32_t                       ndeclarations;
19 
20     njs_index_t                    self;
21 
22     uint32_t                       nargs;
23 
24     uint8_t                        ctor;              /* 1 bit */
25     uint8_t                        rest_parameters;   /* 1 bit */
26 
27     u_char                         *start;
28 };
29 
30 
31 /* The frame size must be aligned to njs_value_t. */
32 #define NJS_NATIVE_FRAME_SIZE                                                 \
33     njs_align_size(sizeof(njs_native_frame_t), sizeof(njs_value_t))
34 
35 /* The frame size must be aligned to njs_value_t. */
36 #define NJS_FRAME_SIZE                                                        \
37     njs_align_size(sizeof(njs_frame_t), sizeof(njs_value_t))
38 
39 #define NJS_FRAME_SPARE_SIZE       (4 * 1024)
40 
41 
42 struct njs_native_frame_s {
43     u_char                         *free;
44     u_char                         *pc;
45 
46     njs_function_t                 *function;
47     njs_native_frame_t             *previous;
48 
49     njs_value_t                    *arguments;
50     njs_object_t                   *arguments_object;
51     njs_value_t                    *arguments_offset;
52     njs_value_t                    **local;
53     njs_value_t                    **temp;
54 
55     uint32_t                       size;
56     uint32_t                       free_size;
57 
58     njs_value_t                    *retval;
59 
60     uint32_t                       nargs;
61 
62     uint8_t                        native;            /* 1 bit  */
63     /* Function is called as constructor with "new" keyword. */
64     uint8_t                        ctor;              /* 1 bit  */
65 
66     /* Skip the Function.call() and Function.apply() methods frames. */
67     uint8_t                        skip;              /* 1 bit  */
68 };
69 
70 
71 typedef struct njs_exception_s     njs_exception_t;
72 
73 struct njs_exception_s {
74     njs_exception_t                *next;
75     u_char                         *catch;
76 };
77 
78 
79 struct njs_frame_s {
80     njs_native_frame_t             native;
81 
82     njs_exception_t                exception;
83 
84     njs_frame_t                    *previous_active_frame;
85 };
86 
87 
88 njs_function_t *njs_function_alloc(njs_vm_t *vm, njs_function_lambda_t *lambda,
89     njs_bool_t async);
90 njs_function_t *njs_function_value_copy(njs_vm_t *vm, njs_value_t *value);
91 njs_int_t njs_function_name_set(njs_vm_t *vm, njs_function_t *function,
92     njs_value_t *name, const char *prefix);
93 njs_function_t *njs_function_copy(njs_vm_t *vm, njs_function_t *function);
94 njs_int_t njs_function_arguments_object_init(njs_vm_t *vm,
95     njs_native_frame_t *frame);
96 njs_int_t njs_function_rest_parameters_init(njs_vm_t *vm,
97     njs_native_frame_t *frame);
98 njs_int_t njs_function_prototype_create(njs_vm_t *vm, njs_object_prop_t *prop,
99     njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
100 njs_int_t njs_function_constructor(njs_vm_t *vm, njs_value_t *args,
101     njs_uint_t nargs, njs_index_t unused);
102 njs_int_t njs_function_instance_length(njs_vm_t *vm, njs_object_prop_t *prop,
103     njs_value_t *value, njs_value_t *setval, njs_value_t *retval);
104 njs_int_t njs_eval_function(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
105     njs_index_t unused);
106 njs_int_t njs_function_native_frame(njs_vm_t *vm, njs_function_t *function,
107     const njs_value_t *this, const njs_value_t *args, njs_uint_t nargs,
108     njs_bool_t ctor);
109 njs_int_t njs_function_lambda_frame(njs_vm_t *vm, njs_function_t *function,
110     const njs_value_t *this, const njs_value_t *args, njs_uint_t nargs,
111     njs_bool_t ctor);
112 njs_int_t njs_function_call2(njs_vm_t *vm, njs_function_t *function,
113     const njs_value_t *this, const njs_value_t *args,
114     njs_uint_t nargs, njs_value_t *retval, njs_bool_t ctor);
115 njs_int_t njs_function_lambda_call(njs_vm_t *vm);
116 njs_int_t njs_function_native_call(njs_vm_t *vm);
117 njs_native_frame_t *njs_function_frame_alloc(njs_vm_t *vm, size_t size);
118 void njs_function_frame_free(njs_vm_t *vm, njs_native_frame_t *frame);
119 njs_int_t njs_function_frame_save(njs_vm_t *vm, njs_frame_t *native,
120     u_char *pc);
121 njs_object_type_t njs_function_object_type(njs_vm_t *vm,
122     njs_function_t *function);
123 njs_int_t njs_function_capture_closure(njs_vm_t *vm, njs_function_t *function,
124      njs_function_lambda_t *lambda);
125 njs_int_t njs_function_capture_global_closures(njs_vm_t *vm,
126     njs_function_t *function);
127 njs_int_t njs_function_frame_invoke(njs_vm_t *vm, njs_value_t *retval);
128 
129 
130 njs_inline njs_function_lambda_t *
njs_function_lambda_alloc(njs_vm_t * vm,uint8_t ctor)131 njs_function_lambda_alloc(njs_vm_t *vm, uint8_t ctor)
132 {
133     njs_function_lambda_t  *lambda;
134 
135     lambda = njs_mp_zalloc(vm->mem_pool, sizeof(njs_function_lambda_t));
136 
137     if (njs_fast_path(lambda != NULL)) {
138         lambda->ctor = ctor;
139     }
140 
141     return lambda;
142 }
143 
144 
145 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)146 njs_function_frame(njs_vm_t *vm, njs_function_t *function,
147     const njs_value_t *this, const njs_value_t *args, njs_uint_t nargs,
148     njs_bool_t ctor)
149 {
150     if (function->native) {
151         return njs_function_native_frame(vm, function, this, args, nargs, ctor);
152 
153     } else {
154         return njs_function_lambda_frame(vm, function, this, args, nargs, ctor);
155     }
156 }
157 
158 
159 njs_inline njs_native_frame_t *
njs_function_previous_frame(njs_native_frame_t * frame)160 njs_function_previous_frame(njs_native_frame_t *frame)
161 {
162     njs_native_frame_t  *previous;
163 
164     do {
165         previous = frame->previous;
166         frame = previous;
167 
168     } while (frame->skip);
169 
170     return frame;
171 }
172 
173 
174 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)175 njs_function_call(njs_vm_t *vm, njs_function_t *function,
176     const njs_value_t *this, const njs_value_t *args,
177     njs_uint_t nargs, njs_value_t *retval)
178 {
179     return njs_function_call2(vm, function, this, args, nargs, retval, 0);
180 }
181 
182 
183 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)184 njs_function_apply(njs_vm_t *vm, njs_function_t *function,
185     const njs_value_t *args, njs_uint_t nargs, njs_value_t *retval)
186 {
187     return njs_function_call2(vm, function, &args[0], &args[1], nargs - 1,
188                               retval, 0);
189 }
190 
191 
192 njs_inline njs_bool_t
njs_native_function_same(const njs_function_t * f1,const njs_function_t * f2)193 njs_native_function_same(const njs_function_t *f1, const njs_function_t *f2)
194 {
195     return f1->u.native == f2->u.native && f1->magic8 == f2->magic8;
196 }
197 
198 
199 njs_inline njs_value_t **
njs_function_closures(const njs_function_t * func)200 njs_function_closures(const njs_function_t *func)
201 {
202     return (njs_value_t **) ((u_char *) func + sizeof(njs_function_t));
203 }
204 
205 
206 njs_inline size_t
njs_function_frame_size(njs_native_frame_t * frame)207 njs_function_frame_size(njs_native_frame_t *frame)
208 {
209     size_t     size;
210     uintptr_t  start;
211 
212     start = (uintptr_t) ((u_char *) frame + NJS_FRAME_SIZE);
213     size = ((uintptr_t) frame->arguments - start) / sizeof(njs_value_t *);
214 
215     return NJS_FRAME_SIZE + (size * sizeof(njs_value_t *))
216                           + (size * sizeof(njs_value_t));
217 }
218 
219 
220 njs_inline size_t
njs_function_frame_args_count(njs_native_frame_t * frame)221 njs_function_frame_args_count(njs_native_frame_t *frame)
222 {
223     uintptr_t  start;
224 
225     start = (uintptr_t) ((u_char *) frame + NJS_FRAME_SIZE);
226 
227     return ((uintptr_t) frame->local - start) / sizeof(njs_value_t *);
228 }
229 
230 
231 njs_inline size_t
njs_function_frame_value_count(njs_native_frame_t * frame)232 njs_function_frame_value_count(njs_native_frame_t *frame)
233 {
234     uintptr_t  start;
235 
236     start = (uintptr_t) ((u_char *) frame + NJS_FRAME_SIZE);
237 
238     return ((uintptr_t) frame->temp - start) / sizeof(njs_value_t *);
239 }
240 
241 
242 njs_inline njs_value_t *
njs_function_frame_values(njs_native_frame_t * frame,njs_value_t ** end)243 njs_function_frame_values(njs_native_frame_t *frame, njs_value_t **end)
244 {
245     size_t     count;
246     uintptr_t  start;
247 
248     start = (uintptr_t) ((u_char *) frame + NJS_FRAME_SIZE);
249     count = ((uintptr_t) frame->arguments - start) / sizeof(njs_value_t *);
250 
251     *end = frame->arguments + count;
252 
253     return frame->arguments;
254 }
255 
256 
257 extern const njs_object_type_init_t  njs_function_type_init;
258 extern const njs_object_init_t  njs_function_instance_init;
259 extern const njs_object_init_t  njs_arrow_instance_init;
260 extern const njs_object_init_t  njs_arguments_object_instance_init;
261 
262 #endif /* _NJS_FUNCTION_H_INCLUDED_ */
263