/* * Heap compiled function (ECMAScript function) representation. * * There is a single data buffer containing the ECMAScript function's * bytecode, constants, and inner functions. */ #if !defined(DUK_HCOMPFUNC_H_INCLUDED) #define DUK_HCOMPFUNC_H_INCLUDED /* * Field accessor macros */ /* XXX: casts could be improved, especially for GET/SET DATA */ #if defined(DUK_USE_HEAPPTR16) #define DUK_HCOMPFUNC_GET_DATA(heap,h) \ ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16)) #define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \ (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ } while (0) #define DUK_HCOMPFUNC_GET_FUNCS(heap,h) \ ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16))) #define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \ (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ } while (0) #define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) \ ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16))) #define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \ (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ } while (0) #define DUK_HCOMPFUNC_GET_LEXENV(heap,h) \ ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->lex_env16))) #define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \ (h)->lex_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ } while (0) #define DUK_HCOMPFUNC_GET_VARENV(heap,h) \ ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->var_env16))) #define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \ (h)->var_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \ } while (0) #else #define DUK_HCOMPFUNC_GET_DATA(heap,h) ((duk_hbuffer_fixed *) (void *) (h)->data) #define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \ (h)->data = (duk_hbuffer *) (v); \ } while (0) #define DUK_HCOMPFUNC_GET_FUNCS(heap,h) ((h)->funcs) #define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \ (h)->funcs = (v); \ } while (0) #define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) ((h)->bytecode) #define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \ (h)->bytecode = (v); \ } while (0) #define DUK_HCOMPFUNC_GET_LEXENV(heap,h) ((h)->lex_env) #define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \ (h)->lex_env = (v); \ } while (0) #define DUK_HCOMPFUNC_GET_VARENV(heap,h) ((h)->var_env) #define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \ (h)->var_env = (v); \ } while (0) #endif /* * Accessor macros for function specific data areas */ /* Note: assumes 'data' is always a fixed buffer */ #define DUK_HCOMPFUNC_GET_BUFFER_BASE(heap,h) \ DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) #define DUK_HCOMPFUNC_GET_CONSTS_BASE(heap,h) \ ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_BUFFER_BASE((heap), (h))) #define DUK_HCOMPFUNC_GET_FUNCS_BASE(heap,h) \ DUK_HCOMPFUNC_GET_FUNCS((heap), (h)) #define DUK_HCOMPFUNC_GET_CODE_BASE(heap,h) \ DUK_HCOMPFUNC_GET_BYTECODE((heap), (h)) #define DUK_HCOMPFUNC_GET_CONSTS_END(heap,h) \ ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_FUNCS((heap), (h))) #define DUK_HCOMPFUNC_GET_FUNCS_END(heap,h) \ ((duk_hobject **) (void *) DUK_HCOMPFUNC_GET_BYTECODE((heap), (h))) /* XXX: double evaluation of DUK_HCOMPFUNC_GET_DATA() */ #define DUK_HCOMPFUNC_GET_CODE_END(heap,h) \ ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) + \ DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA((heap), h)))) #define DUK_HCOMPFUNC_GET_CONSTS_SIZE(heap,h) \ ( \ (duk_size_t) \ ( \ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_END((heap), (h))) - \ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_BASE((heap), (h))) \ ) \ ) #define DUK_HCOMPFUNC_GET_FUNCS_SIZE(heap,h) \ ( \ (duk_size_t) \ ( \ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_END((heap), (h))) - \ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_BASE((heap), (h))) \ ) \ ) #define DUK_HCOMPFUNC_GET_CODE_SIZE(heap,h) \ ( \ (duk_size_t) \ ( \ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_END((heap),(h))) - \ ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_BASE((heap),(h))) \ ) \ ) #define DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap,h) \ ((duk_size_t) (DUK_HCOMPFUNC_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval))) #define DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap,h) \ ((duk_size_t) (DUK_HCOMPFUNC_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *))) #define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h) \ ((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t))) /* * Validity assert */ #define DUK_ASSERT_HCOMPFUNC_VALID(h) do { \ DUK_ASSERT((h) != NULL); \ } while (0) /* * Main struct */ struct duk_hcompfunc { /* shared object part */ duk_hobject obj; /* * Pointers to function data area for faster access. Function * data is a buffer shared between all closures of the same * "template" function. The data buffer is always fixed (non- * dynamic, hence stable), with a layout as follows: * * constants (duk_tval) * inner functions (duk_hobject *) * bytecode (duk_instr_t) * * Note: bytecode end address can be computed from 'data' buffer * size. It is not strictly necessary functionally, assuming * bytecode never jumps outside its allocated area. However, * it's a safety/robustness feature for avoiding the chance of * executing random data as bytecode due to a compiler error. * * Note: values in the data buffer must be incref'd (they will * be decref'd on release) for every compiledfunction referring * to the 'data' element. */ /* Data area, fixed allocation, stable data ptrs. */ #if defined(DUK_USE_HEAPPTR16) duk_uint16_t data16; #else duk_hbuffer *data; #endif /* No need for constants pointer (= same as data). * * When using 16-bit packing alignment to 4 is nice. 'funcs' will be * 4-byte aligned because 'constants' are duk_tvals. For now the * inner function pointers are not compressed, so that 'bytecode' will * also be 4-byte aligned. */ #if defined(DUK_USE_HEAPPTR16) duk_uint16_t funcs16; duk_uint16_t bytecode16; #else duk_hobject **funcs; duk_instr_t *bytecode; #endif /* Lexenv: lexical environment of closure, NULL for templates. * Varenv: variable environment of closure, NULL for templates. */ #if defined(DUK_USE_HEAPPTR16) duk_uint16_t lex_env16; duk_uint16_t var_env16; #else duk_hobject *lex_env; duk_hobject *var_env; #endif /* * 'nregs' registers are allocated on function entry, at most 'nargs' * are initialized to arguments, and the rest to undefined. Arguments * above 'nregs' are not mapped to registers. All registers in the * active stack range must be initialized because they are GC reachable. * 'nargs' is needed so that if the function is given more than 'nargs' * arguments, the additional arguments do not 'clobber' registers * beyond 'nregs' which must be consistently initialized to undefined. * * Usually there is no need to know which registers are mapped to * local variables. Registers may be allocated to variable in any * way (even including gaps). However, a register-variable mapping * must be the same for the duration of the function execution and * the register cannot be used for anything else. * * When looking up variables by name, the '_Varmap' map is used. * When an activation closes, registers mapped to arguments are * copied into the environment record based on the same map. The * reverse map (from register to variable) is not currently needed * at run time, except for debugging, so it is not maintained. */ duk_uint16_t nregs; /* regs to allocate */ duk_uint16_t nargs; /* number of arguments allocated to regs */ /* * Additional control information is placed into the object itself * as internal properties to avoid unnecessary fields for the * majority of functions. The compiler tries to omit internal * control fields when possible. * * Function templates: * * { * name: "func", // declaration, named function expressions * fileName: * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 }, * _Formals: [ "arg1", "arg2" ], * _Source: "function func(arg1, arg2) { ... }", * _Pc2line: , * } * * Function instances: * * { * length: 2, * prototype: { constructor: }, * caller: , * arguments: , * name: "func", // declaration, named function expressions * fileName: * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 }, * _Formals: [ "arg1", "arg2" ], * _Source: "function func(arg1, arg2) { ... }", * _Pc2line: , * } * * More detailed description of these properties can be found * in the documentation. */ #if defined(DUK_USE_DEBUGGER_SUPPORT) /* Line number range for function. Needed during debugging to * determine active breakpoints. */ duk_uint32_t start_line; duk_uint32_t end_line; #endif }; #endif /* DUK_HCOMPFUNC_H_INCLUDED */