4 * Size optimization note: it might seem that vararg multipurpose functions
5 * like fin(), enc(), and dec() are not very size optimal, but using a single
6 * user-visible Ecmascript function saves a lot of run-time footprint; each
7 * Function instance takes >100 bytes. Using a shared native helper and a
8 * 'magic' value won't save much if there are multiple Function instances
12 #include "duk_internal.h"
14 /* Raw helper to extract internal information / statistics about a value.
15 * The return values are version specific and must not expose anything
16 * that would lead to security issues (e.g. exposing compiled function
17 * 'data' buffer might be an issue). Currently only counts and sizes and
18 * such are given so there should not be a security impact.
20 DUK_INTERNAL duk_ret_t
duk_bi_duktape_object_info(duk_context
*ctx
) {
21 duk_hthread
*thr
= (duk_hthread
*) ctx
;
29 duk_push_array(ctx
); /* -> [ val arr ] */
31 /* type tag (public) */
32 duk_push_int(ctx
, duk_get_type(ctx
, 0));
35 tv
= duk_get_tval(ctx
, 0);
36 DUK_ASSERT(tv
!= NULL
); /* because arg count is 1 */
37 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv
)) {
38 h
= DUK_TVAL_GET_HEAPHDR(tv
);
39 duk_push_pointer(ctx
, (void *) h
);
41 /* internal type tag */
42 duk_push_int(ctx
, (duk_int_t
) DUK_TVAL_GET_TAG(tv
));
45 DUK_ASSERT(h
!= NULL
);
48 #ifdef DUK_USE_REFERENCE_COUNTING
49 duk_push_size_t(ctx
, DUK_HEAPHDR_GET_REFCOUNT(h
));
51 duk_push_undefined(ctx
);
54 /* heaphdr size and additional allocation size, followed by
55 * type specific stuff (with varying value count)
57 switch ((duk_small_int_t
) DUK_HEAPHDR_GET_TYPE(h
)) {
58 case DUK_HTYPE_STRING
: {
59 duk_hstring
*h_str
= (duk_hstring
*) h
;
60 duk_push_uint(ctx
, (duk_uint_t
) (sizeof(duk_hstring
) + DUK_HSTRING_GET_BYTELEN(h_str
) + 1));
63 case DUK_HTYPE_OBJECT
: {
64 duk_hobject
*h_obj
= (duk_hobject
*) h
;
65 duk_small_uint_t hdr_size
;
66 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj
)) {
67 hdr_size
= (duk_small_uint_t
) sizeof(duk_hcompiledfunction
);
68 } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h_obj
)) {
69 hdr_size
= (duk_small_uint_t
) sizeof(duk_hnativefunction
);
70 } else if (DUK_HOBJECT_IS_THREAD(h_obj
)) {
71 hdr_size
= (duk_small_uint_t
) sizeof(duk_hthread
);
72 #if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
73 } else if (DUK_HOBJECT_IS_BUFFEROBJECT(h_obj
)) {
74 hdr_size
= (duk_small_uint_t
) sizeof(duk_hbufferobject
);
77 hdr_size
= (duk_small_uint_t
) sizeof(duk_hobject
);
79 duk_push_uint(ctx
, (duk_uint_t
) hdr_size
);
80 duk_push_uint(ctx
, (duk_uint_t
) DUK_HOBJECT_P_ALLOC_SIZE(h_obj
));
81 duk_push_uint(ctx
, (duk_uint_t
) DUK_HOBJECT_GET_ESIZE(h_obj
));
82 /* Note: e_next indicates the number of gc-reachable entries
83 * in the entry part, and also indicates the index where the
84 * next new property would be inserted. It does *not* indicate
85 * the number of non-NULL keys present in the object. That
86 * value could be counted separately but requires a pass through
89 duk_push_uint(ctx
, (duk_uint_t
) DUK_HOBJECT_GET_ENEXT(h_obj
));
90 duk_push_uint(ctx
, (duk_uint_t
) DUK_HOBJECT_GET_ASIZE(h_obj
));
91 duk_push_uint(ctx
, (duk_uint_t
) DUK_HOBJECT_GET_HSIZE(h_obj
));
92 if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h_obj
)) {
93 duk_hbuffer
*h_data
= (duk_hbuffer
*) DUK_HCOMPILEDFUNCTION_GET_DATA(thr
->heap
, (duk_hcompiledfunction
*) h_obj
);
95 duk_push_uint(ctx
, (duk_uint_t
) DUK_HBUFFER_GET_SIZE(h_data
));
97 duk_push_uint(ctx
, 0);
102 case DUK_HTYPE_BUFFER
: {
103 duk_hbuffer
*h_buf
= (duk_hbuffer
*) h
;
104 if (DUK_HBUFFER_HAS_DYNAMIC(h_buf
)) {
105 if (DUK_HBUFFER_HAS_EXTERNAL(h_buf
)) {
106 duk_push_uint(ctx
, (duk_uint_t
) (sizeof(duk_hbuffer_external
)));
108 /* When alloc_size == 0 the second allocation may not
111 duk_push_uint(ctx
, (duk_uint_t
) (sizeof(duk_hbuffer_dynamic
)));
113 duk_push_uint(ctx
, (duk_uint_t
) (DUK_HBUFFER_GET_SIZE(h_buf
)));
115 duk_push_uint(ctx
, (duk_uint_t
) (sizeof(duk_hbuffer_fixed
) + DUK_HBUFFER_GET_SIZE(h_buf
) + 1));
123 /* set values into ret array */
124 /* XXX: primitive to make array from valstack slice */
125 n
= duk_get_top(ctx
);
126 for (i
= 2; i
< n
; i
++) {
128 duk_put_prop_index(ctx
, 1, i
- 2);
134 DUK_INTERNAL duk_ret_t
duk_bi_duktape_object_act(duk_context
*ctx
) {
135 duk_hthread
*thr
= (duk_hthread
*) ctx
;
137 duk_uint_fast32_t pc
;
138 duk_uint_fast32_t line
;
141 /* -1 = top callstack entry, callstack[callstack_top - 1]
142 * -callstack_top = bottom callstack entry, callstack[0]
144 level
= duk_to_int(ctx
, 0);
145 if (level
>= 0 || -level
> (duk_int_t
) thr
->callstack_top
) {
148 DUK_ASSERT(level
>= -((duk_int_t
) thr
->callstack_top
) && level
<= -1);
149 act
= thr
->callstack
+ thr
->callstack_top
+ level
;
151 duk_push_object(ctx
);
153 duk_push_tval(ctx
, &act
->tv_func
);
155 /* Relevant PC is just before current one because PC is
156 * post-incremented. This should match what error augment
159 pc
= duk_hthread_get_act_prev_pc(thr
, act
);
160 duk_push_uint(ctx
, (duk_uint_t
) pc
);
162 #if defined(DUK_USE_PC2LINE)
163 line
= duk_hobject_pc2line_query(ctx
, -2, pc
);
167 duk_push_uint(ctx
, (duk_uint_t
) line
);
169 /* Providing access to e.g. act->lex_env would be dangerous: these
170 * internal structures must never be accessible to the application.
171 * Duktape relies on them having consistent data, and this consistency
172 * is only asserted for, not checked for.
175 /* [ level obj func pc line ] */
177 /* XXX: version specific array format instead? */
178 duk_xdef_prop_stridx_wec(ctx
, -4, DUK_STRIDX_LINE_NUMBER
);
179 duk_xdef_prop_stridx_wec(ctx
, -3, DUK_STRIDX_PC
);
180 duk_xdef_prop_stridx_wec(ctx
, -2, DUK_STRIDX_LC_FUNCTION
);
184 DUK_INTERNAL duk_ret_t
duk_bi_duktape_object_gc(duk_context
*ctx
) {
185 #ifdef DUK_USE_MARK_AND_SWEEP
186 duk_hthread
*thr
= (duk_hthread
*) ctx
;
187 duk_small_uint_t flags
;
190 flags
= (duk_small_uint_t
) duk_get_uint(ctx
, 0);
191 rc
= duk_heap_mark_and_sweep(thr
->heap
, flags
);
193 /* XXX: Not sure what the best return value would be in the API.
194 * Return a boolean for now. Note that rc == 0 is success (true).
196 duk_push_boolean(ctx
, !rc
);
204 DUK_INTERNAL duk_ret_t
duk_bi_duktape_object_fin(duk_context
*ctx
) {
205 (void) duk_require_hobject(ctx
, 0);
206 if (duk_get_top(ctx
) >= 2) {
207 /* Set: currently a finalizer is disabled by setting it to
208 * undefined; this does not remove the property at the moment.
209 * The value could be type checked to be either a function
210 * or something else; if something else, the property could
214 (void) duk_put_prop_stridx(ctx
, 0, DUK_STRIDX_INT_FINALIZER
);
218 DUK_ASSERT(duk_get_top(ctx
) == 1);
219 duk_get_prop_stridx(ctx
, 0, DUK_STRIDX_INT_FINALIZER
);
224 DUK_INTERNAL duk_ret_t
duk_bi_duktape_object_enc(duk_context
*ctx
) {
225 duk_hthread
*thr
= (duk_hthread
*) ctx
;
230 /* Vararg function: must be careful to check/require arguments.
231 * The JSON helpers accept invalid indices and treat them like
232 * non-existent optional parameters.
235 h_str
= duk_require_hstring(ctx
, 0);
236 duk_require_valid_index(ctx
, 1);
238 if (h_str
== DUK_HTHREAD_STRING_HEX(thr
)) {
240 duk_hex_encode(ctx
, 1);
241 DUK_ASSERT_TOP(ctx
, 2);
242 } else if (h_str
== DUK_HTHREAD_STRING_BASE64(thr
)) {
244 duk_base64_encode(ctx
, 1);
245 DUK_ASSERT_TOP(ctx
, 2);
247 } else if (h_str
== DUK_HTHREAD_STRING_JX(thr
)) {
248 duk_bi_json_stringify_helper(ctx
,
252 DUK_JSON_FLAG_EXT_CUSTOM
|
253 DUK_JSON_FLAG_ASCII_ONLY
|
254 DUK_JSON_FLAG_AVOID_KEY_QUOTES
/*flags*/);
257 } else if (h_str
== DUK_HTHREAD_STRING_JC(thr
)) {
258 duk_bi_json_stringify_helper(ctx
,
262 DUK_JSON_FLAG_EXT_COMPATIBLE
|
263 DUK_JSON_FLAG_ASCII_ONLY
/*flags*/);
266 return DUK_RET_TYPE_ERROR
;
271 DUK_INTERNAL duk_ret_t
duk_bi_duktape_object_dec(duk_context
*ctx
) {
272 duk_hthread
*thr
= (duk_hthread
*) ctx
;
277 /* Vararg function: must be careful to check/require arguments.
278 * The JSON helpers accept invalid indices and treat them like
279 * non-existent optional parameters.
282 h_str
= duk_require_hstring(ctx
, 0);
283 duk_require_valid_index(ctx
, 1);
285 if (h_str
== DUK_HTHREAD_STRING_HEX(thr
)) {
287 duk_hex_decode(ctx
, 1);
288 DUK_ASSERT_TOP(ctx
, 2);
289 } else if (h_str
== DUK_HTHREAD_STRING_BASE64(thr
)) {
291 duk_base64_decode(ctx
, 1);
292 DUK_ASSERT_TOP(ctx
, 2);
294 } else if (h_str
== DUK_HTHREAD_STRING_JX(thr
)) {
295 duk_bi_json_parse_helper(ctx
,
298 DUK_JSON_FLAG_EXT_CUSTOM
/*flags*/);
301 } else if (h_str
== DUK_HTHREAD_STRING_JC(thr
)) {
302 duk_bi_json_parse_helper(ctx
,
305 DUK_JSON_FLAG_EXT_COMPATIBLE
/*flags*/);
308 return DUK_RET_TYPE_ERROR
;
317 DUK_INTERNAL duk_ret_t
duk_bi_duktape_object_compact(duk_context
*ctx
) {
318 DUK_ASSERT_TOP(ctx
, 1);
320 return 1; /* return the argument object */