How to work with lightfuncs
When a normal native function is created using
duk_push_c_function() two heap allocations are needed:
A Function object is created to represent the function in ECMAScript code. The function is represented by an internal
duk_hnatfuncstructure which is a subtype of the generic
duk_hobjectpart of the structure provides a property table allocated separately.
duk_hnatfuncpart of the structure points to the Duktape/C function to be called when ECMAScript code invokes the function, and stores various function parameters like the argument count and a "magic" value.
A property table is allocated to hold e.g. the
.lengthproperty. Built-in functions also have a
In very low memory environments the memory cost of this representation adds up when multiplied for e.g. 100 functions.
The lightfunc type provides a very lightweight alternative to representing function objects. A lightfunc represents a native function using just a tagged value (
duk_tval) with no heap allocations, thus taking no more space than representing e.g. a boolean value. In concrete terms:
When a packed
duk_tvalis used on 32-bit platforms, lightfuncs take 8 bytes: 2 bytes for the type tag, 4 bytes for the native function pointer, and 2 bytes for flags. The flags field (16 bits) stores the function argument count (nargs),
.lengthfield, and an 8-bit magic value.
duk_tvalis used, lightfuncs typically take 16 bytes. The fields are logically the same, but laid out differently.
Because there are no heap allocations related to lightfuncs, there are some limitations, with the most important being:
Lightfuncs cannot hold properties because they don't have a property table.
As a result, lightfuncs cannot have a manually set
.nameproperty. They do, however, have a virtual
.nameproperty which appears in tracebacks etc.
Lightfuncs also cannot hold a
.prototypeproperty. They can still be used as constructors, but the default instance created will always inherit from Object.prototype. The native function can overwrite the prototype explicitly, or return a "replacement value". See How to write a native constructor function.
Example of a lightfunc name:
duk> Math.cos.name = "light_08067ce4_0511"
The name is autogenerated and includes the native function pointer (here 08067ce4) and the 16-bit flags field (here 0x0511).
See also: http://duktape.org/guide.html#type-lightfunc.
Lightfuncs can only be created from C code as:
/* http://duktape.org/api.html#duk_push_c_lightfunc */ duk_push_c_lightfunc(ctx, my_adder, 2 /*nargs*/, 2 /*length*/, 0 /*magic*/);
length fields will have the same value. The magic field can be ignored and set to zero if the native function doesn't need it.
Making built-in functions lightfuncs
The ECMAScript built-in functions
Array.prototype.join, etc are all by default ordinary Function objects and consume a significant amount of memory (more than 20kB on a 32-bit low memory target).
To save memory, you can enable the following option:
When enabled, built-in functions will be converted to lightfuncs during their initialization. A few built-in functions cannot be safely converted to lightfuncs; they will remain normal Functions.
The downside of this option is that the converted built-ins will have a less useful
.name, for example.