1 /*
2  *  Heap compiled function (Ecmascript function) representation.
3  *
4  *  There is a single data buffer containing the Ecmascript function's
5  *  bytecode, constants, and inner functions.
6  */
7 
8 #ifndef DUK_HCOMPILEDFUNCTION_H_INCLUDED
9 #define DUK_HCOMPILEDFUNCTION_H_INCLUDED
10 
11 /*
12  *  Field accessor macros
13  */
14 
15 /* XXX: casts could be improved, especially for GET/SET DATA */
16 
17 #if defined(DUK_USE_HEAPPTR16)
18 #define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
19 	((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16))
20 #define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
21 		(h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
22 	} while (0)
23 #define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h)  \
24 	((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16)))
25 #define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v)  do { \
26 		(h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
27 	} while (0)
28 #define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h)  \
29 	((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16)))
30 #define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v)  do { \
31 		(h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
32 	} while (0)
33 #else
34 #define DUK_HCOMPILEDFUNCTION_GET_DATA(heap,h) \
35 	((duk_hbuffer_fixed *) (void *) (h)->data)
36 #define DUK_HCOMPILEDFUNCTION_SET_DATA(heap,h,v) do { \
37 		(h)->data = (duk_hbuffer *) (v); \
38 	} while (0)
39 #define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap,h)  \
40 	((h)->funcs)
41 #define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap,h,v)  do { \
42 		(h)->funcs = (v); \
43 	} while (0)
44 #define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap,h)  \
45 	((h)->bytecode)
46 #define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap,h,v)  do { \
47 		(h)->bytecode = (v); \
48 	} while (0)
49 #endif
50 
51 /*
52  *  Accessor macros for function specific data areas
53  */
54 
55 /* Note: assumes 'data' is always a fixed buffer */
56 #define DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE(heap,h)  \
57 	DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h)))
58 
59 #define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap,h)  \
60 	((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_BUFFER_BASE((heap), (h)))
61 
62 #define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap,h)  \
63 	DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h))
64 
65 #define DUK_HCOMPILEDFUNCTION_GET_CODE_BASE(heap,h)  \
66 	DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h))
67 
68 #define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap,h)  \
69 	((duk_tval *) (void *) DUK_HCOMPILEDFUNCTION_GET_FUNCS((heap), (h)))
70 
71 #define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap,h)  \
72 	((duk_hobject **) (void *) DUK_HCOMPILEDFUNCTION_GET_BYTECODE((heap), (h)))
73 
74 /* XXX: double evaluation of DUK_HCOMPILEDFUNCTION_GET_DATA() */
75 #define DUK_HCOMPILEDFUNCTION_GET_CODE_END(heap,h)  \
76 	((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPILEDFUNCTION_GET_DATA((heap), (h))) + \
77 	                DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPILEDFUNCTION_GET_DATA((heap), h))))
78 
79 #define DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE(heap,h)  \
80 	( \
81 	 (duk_size_t) \
82 	 ( \
83 	   ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_END((heap), (h))) - \
84 	   ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE((heap), (h))) \
85 	 ) \
86 	)
87 
88 #define DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE(heap,h)  \
89 	( \
90 	 (duk_size_t) \
91 	 ( \
92 	   ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_END((heap), (h))) - \
93 	   ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE((heap), (h))) \
94 	 ) \
95 	)
96 
97 #define DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE(heap,h)  \
98 	( \
99 	 (duk_size_t) \
100 	 ( \
101 	   ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_END((heap),(h))) - \
102 	   ((const duk_uint8_t *) DUK_HCOMPILEDFUNCTION_GET_CODE_BASE((heap),(h))) \
103 	 ) \
104 	)
105 
106 #define DUK_HCOMPILEDFUNCTION_GET_CONSTS_COUNT(heap,h)  \
107 	((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
108 
109 #define DUK_HCOMPILEDFUNCTION_GET_FUNCS_COUNT(heap,h)  \
110 	((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
111 
112 #define DUK_HCOMPILEDFUNCTION_GET_CODE_COUNT(heap,h)  \
113 	((duk_size_t) (DUK_HCOMPILEDFUNCTION_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
114 
115 
116 /*
117  *  Main struct
118  */
119 
120 struct duk_hcompiledfunction {
121 	/* shared object part */
122 	duk_hobject obj;
123 
124 	/*
125 	 *  Pointers to function data area for faster access.  Function
126 	 *  data is a buffer shared between all closures of the same
127 	 *  "template" function.  The data buffer is always fixed (non-
128 	 *  dynamic, hence stable), with a layout as follows:
129 	 *
130 	 *    constants (duk_tval)
131 	 *    inner functions (duk_hobject *)
132 	 *    bytecode (duk_instr_t)
133 	 *
134 	 *  Note: bytecode end address can be computed from 'data' buffer
135 	 *  size.  It is not strictly necessary functionally, assuming
136 	 *  bytecode never jumps outside its allocated area.  However,
137 	 *  it's a safety/robustness feature for avoiding the chance of
138 	 *  executing random data as bytecode due to a compiler error.
139 	 *
140 	 *  Note: values in the data buffer must be incref'd (they will
141 	 *  be decref'd on release) for every compiledfunction referring
142 	 *  to the 'data' element.
143 	 */
144 
145 	/* Data area, fixed allocation, stable data ptrs. */
146 #if defined(DUK_USE_HEAPPTR16)
147 	duk_uint16_t data16;
148 #else
149 	duk_hbuffer *data;
150 #endif
151 
152 	/* No need for constants pointer (= same as data).
153 	 *
154 	 * When using 16-bit packing alignment to 4 is nice.  'funcs' will be
155 	 * 4-byte aligned because 'constants' are duk_tvals.  For now the
156 	 * inner function pointers are not compressed, so that 'bytecode' will
157 	 * also be 4-byte aligned.
158 	 */
159 #if defined(DUK_USE_HEAPPTR16)
160 	duk_uint16_t funcs16;
161 	duk_uint16_t bytecode16;
162 #else
163 	duk_hobject **funcs;
164 	duk_instr_t *bytecode;
165 #endif
166 
167 	/*
168 	 *  'nregs' registers are allocated on function entry, at most 'nargs'
169 	 *  are initialized to arguments, and the rest to undefined.  Arguments
170 	 *  above 'nregs' are not mapped to registers.  All registers in the
171 	 *  active stack range must be initialized because they are GC reachable.
172 	 *  'nargs' is needed so that if the function is given more than 'nargs'
173 	 *  arguments, the additional arguments do not 'clobber' registers
174 	 *  beyond 'nregs' which must be consistently initialized to undefined.
175 	 *
176 	 *  Usually there is no need to know which registers are mapped to
177 	 *  local variables.  Registers may be allocated to variable in any
178 	 *  way (even including gaps).  However, a register-variable mapping
179 	 *  must be the same for the duration of the function execution and
180 	 *  the register cannot be used for anything else.
181 	 *
182 	 *  When looking up variables by name, the '_Varmap' map is used.
183 	 *  When an activation closes, registers mapped to arguments are
184 	 *  copied into the environment record based on the same map.  The
185 	 *  reverse map (from register to variable) is not currently needed
186 	 *  at run time, except for debugging, so it is not maintained.
187 	 */
188 
189 	duk_uint16_t nregs;                /* regs to allocate */
190 	duk_uint16_t nargs;                /* number of arguments allocated to regs */
191 
192 	/*
193 	 *  Additional control information is placed into the object itself
194 	 *  as internal properties to avoid unnecessary fields for the
195 	 *  majority of functions.  The compiler tries to omit internal
196 	 *  control fields when possible.
197 	 *
198 	 *  Function templates:
199 	 *
200 	 *    {
201 	 *      name: "func",    // declaration, named function expressions
202 	 *      fileName: <debug info for creating nice errors>
203 	 *      _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
204 	 *      _Formals: [ "arg1", "arg2" ],
205 	 *      _Source: "function func(arg1, arg2) { ... }",
206 	 *      _Pc2line: <debug info for pc-to-line mapping>,
207 	 *    }
208 	 *
209 	 *  Function instances:
210 	 *
211 	 *    {
212 	 *      length: 2,
213 	 *      prototype: { constructor: <func> },
214 	 *      caller: <thrower>,
215 	 *      arguments: <thrower>,
216 	 *      name: "func",    // declaration, named function expressions
217 	 *      fileName: <debug info for creating nice errors>
218 	 *      _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
219 	 *      _Formals: [ "arg1", "arg2" ],
220 	 *      _Source: "function func(arg1, arg2) { ... }",
221 	 *      _Pc2line: <debug info for pc-to-line mapping>,
222 	 *      _Varenv: <variable environment of closure>,
223 	 *      _Lexenv: <lexical environment of closure (if differs from _Varenv)>
224 	 *    }
225 	 *
226 	 *  More detailed description of these properties can be found
227 	 *  in the documentation.
228 	 */
229 
230 #if defined(DUK_USE_DEBUGGER_SUPPORT)
231 	/* Line number range for function.  Needed during debugging to
232 	 * determine active breakpoints.
233 	 */
234 	duk_uint32_t start_line;
235 	duk_uint32_t end_line;
236 #endif
237 };
238 
239 #endif  /* DUK_HCOMPILEDFUNCTION_H_INCLUDED */
240