|
|
|
/*
|
|
|
|
* Duktape built-ins
|
|
|
|
*
|
|
|
|
* Size optimization note: it might seem that vararg multipurpose functions
|
|
|
|
* like fin(), enc(), and dec() are not very size optimal, but using a single
|
|
|
|
* user-visible Ecmascript function saves a lot of run-time footprint; each
|
|
|
|
* Function instance takes >100 bytes. Using a shared native helper and a
|
|
|
|
* 'magic' value won't save much if there are multiple Function instances
|
|
|
|
* anyway.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "duk_internal.h"
|
|
|
|
|
|
|
|
#if defined(DUK_USE_DUKTAPE_BUILTIN)
|
|
|
|
|
|
|
|
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
|
|
|
|
duk_inspect_value(ctx, -1);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
|
|
|
|
duk_int_t level;
|
|
|
|
|
|
|
|
level = duk_to_int(ctx, 0);
|
|
|
|
duk_inspect_callstack_entry(ctx, level);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
|
|
|
|
duk_hthread *thr = (duk_hthread *) ctx;
|
|
|
|
duk_small_uint_t flags;
|
|
|
|
|
|
|
|
flags = (duk_small_uint_t) duk_get_uint(ctx, 0);
|
|
|
|
duk_heap_mark_and_sweep(thr->heap, flags);
|
|
|
|
|
|
|
|
/* XXX: Not sure what the best return value would be in the API.
|
|
|
|
* Return true for now.
|
|
|
|
*/
|
|
|
|
duk_push_true(ctx);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(DUK_USE_FINALIZER_SUPPORT)
|
|
|
|
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
|
|
|
|
(void) duk_require_hobject(ctx, 0);
|
|
|
|
if (duk_get_top(ctx) >= 2) {
|
|
|
|
/* Set: currently a finalizer is disabled by setting it to
|
|
|
|
* undefined; this does not remove the property at the moment.
|
|
|
|
* The value could be type checked to be either a function
|
|
|
|
* or something else; if something else, the property could
|
Use DUK_HOBJECT_FLAG_HAVE_FINALIZER for checks
One bottleneck in refzero and mark-and-sweep handling is checking whether an
object has an own or inherited _Finalizer property. This check walked the
prototype chain and did a property lookup for every object. Because a
finalizer is usually not present, the prototype chain would almost always be
walked to completion.
Improve this behavior by:
* Adding a DUK_HOBJECT_FLAG_HAVE_FINALIZER flag. The flag is set when the
object has an own _Finalizer property with a callable value, and cleared
otherwise. The flag is *only* set by duk_set_finalizer(), so any other
means of changing the internal _Finalizer property will leave the flag out
of sync (which causes a finalizer run to be skipped).
* Adding duk_hobject_has_finalizer_fast() which checks for finalizer existence
by walking the prototype chain, but only checking the flag, not the property
table.
* Use the fast finalizer check in refzero and mark-and-sweep.
Out-of sync cases:
* If the flag is set but there is no actual finalizer, the object will go
through finalizer processing when garbage collecting. This is harmless:
the finalizer call will fail and the object will be garbage collected, but
with some potential delay (especially for mark-and-sweep).
* If the flag is cleared but there is an actual finalizer, the finalizer will
be ignored.
Related changes:
* When duk_dump_function() is called, zero DUK_HOBJECT_FLAG_HAVE_FINALIZER on
serialization, so it won't be set when the function is loaded back. If this
is not done, the loaded function will (harmlessly) go through finalizer
processing when garbage collected.
* Update debugger artificial properties to include "have_finalizer" flag.
Other changes:
* A few DUK_UNLIKELY() attributes for prototype sanity limits which are
almost never hit.
8 years ago
|
|
|
* be deleted. Must use duk_set_finalizer() to keep
|
|
|
|
* DUK_HOBJECT_FLAG_HAVE_FINALIZER in sync.
|
|
|
|
*/
|
|
|
|
duk_set_top(ctx, 2);
|
Use DUK_HOBJECT_FLAG_HAVE_FINALIZER for checks
One bottleneck in refzero and mark-and-sweep handling is checking whether an
object has an own or inherited _Finalizer property. This check walked the
prototype chain and did a property lookup for every object. Because a
finalizer is usually not present, the prototype chain would almost always be
walked to completion.
Improve this behavior by:
* Adding a DUK_HOBJECT_FLAG_HAVE_FINALIZER flag. The flag is set when the
object has an own _Finalizer property with a callable value, and cleared
otherwise. The flag is *only* set by duk_set_finalizer(), so any other
means of changing the internal _Finalizer property will leave the flag out
of sync (which causes a finalizer run to be skipped).
* Adding duk_hobject_has_finalizer_fast() which checks for finalizer existence
by walking the prototype chain, but only checking the flag, not the property
table.
* Use the fast finalizer check in refzero and mark-and-sweep.
Out-of sync cases:
* If the flag is set but there is no actual finalizer, the object will go
through finalizer processing when garbage collecting. This is harmless:
the finalizer call will fail and the object will be garbage collected, but
with some potential delay (especially for mark-and-sweep).
* If the flag is cleared but there is an actual finalizer, the finalizer will
be ignored.
Related changes:
* When duk_dump_function() is called, zero DUK_HOBJECT_FLAG_HAVE_FINALIZER on
serialization, so it won't be set when the function is loaded back. If this
is not done, the loaded function will (harmlessly) go through finalizer
processing when garbage collected.
* Update debugger artificial properties to include "have_finalizer" flag.
Other changes:
* A few DUK_UNLIKELY() attributes for prototype sanity limits which are
almost never hit.
8 years ago
|
|
|
duk_set_finalizer(ctx, 0);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
/* Get. */
|
|
|
|
DUK_ASSERT(duk_get_top(ctx) == 1);
|
Use DUK_HOBJECT_FLAG_HAVE_FINALIZER for checks
One bottleneck in refzero and mark-and-sweep handling is checking whether an
object has an own or inherited _Finalizer property. This check walked the
prototype chain and did a property lookup for every object. Because a
finalizer is usually not present, the prototype chain would almost always be
walked to completion.
Improve this behavior by:
* Adding a DUK_HOBJECT_FLAG_HAVE_FINALIZER flag. The flag is set when the
object has an own _Finalizer property with a callable value, and cleared
otherwise. The flag is *only* set by duk_set_finalizer(), so any other
means of changing the internal _Finalizer property will leave the flag out
of sync (which causes a finalizer run to be skipped).
* Adding duk_hobject_has_finalizer_fast() which checks for finalizer existence
by walking the prototype chain, but only checking the flag, not the property
table.
* Use the fast finalizer check in refzero and mark-and-sweep.
Out-of sync cases:
* If the flag is set but there is no actual finalizer, the object will go
through finalizer processing when garbage collecting. This is harmless:
the finalizer call will fail and the object will be garbage collected, but
with some potential delay (especially for mark-and-sweep).
* If the flag is cleared but there is an actual finalizer, the finalizer will
be ignored.
Related changes:
* When duk_dump_function() is called, zero DUK_HOBJECT_FLAG_HAVE_FINALIZER on
serialization, so it won't be set when the function is loaded back. If this
is not done, the loaded function will (harmlessly) go through finalizer
processing when garbage collected.
* Update debugger artificial properties to include "have_finalizer" flag.
Other changes:
* A few DUK_UNLIKELY() attributes for prototype sanity limits which are
almost never hit.
8 years ago
|
|
|
duk_get_finalizer(ctx, 0);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* DUK_USE_FINALIZER_SUPPORT */
|
|
|
|
|
|
|
|
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
|
|
|
|
duk_hthread *thr = (duk_hthread *) ctx;
|
|
|
|
duk_hstring *h_str;
|
|
|
|
|
|
|
|
DUK_UNREF(thr);
|
|
|
|
|
|
|
|
/* Vararg function: must be careful to check/require arguments.
|
|
|
|
* The JSON helpers accept invalid indices and treat them like
|
|
|
|
* non-existent optional parameters.
|
|
|
|
*/
|
|
|
|
|
|
|
|
h_str = duk_require_hstring(ctx, 0); /* Could reject symbols, but no point: won't match comparisons. */
|
|
|
|
duk_require_valid_index(ctx, 1);
|
|
|
|
|
|
|
|
if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
|
|
|
|
duk_set_top(ctx, 2);
|
|
|
|
duk_hex_encode(ctx, 1);
|
|
|
|
DUK_ASSERT_TOP(ctx, 2);
|
|
|
|
} else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
|
|
|
|
duk_set_top(ctx, 2);
|
|
|
|
duk_base64_encode(ctx, 1);
|
|
|
|
DUK_ASSERT_TOP(ctx, 2);
|
|
|
|
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
|
|
|
|
} else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
|
|
|
|
duk_bi_json_stringify_helper(ctx,
|
|
|
|
1 /*idx_value*/,
|
|
|
|
2 /*idx_replacer*/,
|
|
|
|
3 /*idx_space*/,
|
|
|
|
DUK_JSON_FLAG_EXT_CUSTOM |
|
|
|
|
DUK_JSON_FLAG_ASCII_ONLY |
|
|
|
|
DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
|
|
|
|
#endif
|
|
|
|
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
|
|
|
|
} else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
|
|
|
|
duk_bi_json_stringify_helper(ctx,
|
|
|
|
1 /*idx_value*/,
|
|
|
|
2 /*idx_replacer*/,
|
|
|
|
3 /*idx_space*/,
|
|
|
|
DUK_JSON_FLAG_EXT_COMPATIBLE |
|
|
|
|
DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
|
|
|
|
duk_hthread *thr = (duk_hthread *) ctx;
|
|
|
|
duk_hstring *h_str;
|
|
|
|
|
|
|
|
DUK_UNREF(thr);
|
|
|
|
|
|
|
|
/* Vararg function: must be careful to check/require arguments.
|
|
|
|
* The JSON helpers accept invalid indices and treat them like
|
|
|
|
* non-existent optional parameters.
|
|
|
|
*/
|
|
|
|
|
|
|
|
h_str = duk_require_hstring(ctx, 0); /* Could reject symbols, but no point: won't match comparisons */
|
|
|
|
duk_require_valid_index(ctx, 1);
|
|
|
|
|
|
|
|
if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
|
|
|
|
duk_set_top(ctx, 2);
|
|
|
|
duk_hex_decode(ctx, 1);
|
|
|
|
DUK_ASSERT_TOP(ctx, 2);
|
|
|
|
} else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
|
|
|
|
duk_set_top(ctx, 2);
|
|
|
|
duk_base64_decode(ctx, 1);
|
|
|
|
DUK_ASSERT_TOP(ctx, 2);
|
|
|
|
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
|
|
|
|
} else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
|
|
|
|
duk_bi_json_parse_helper(ctx,
|
|
|
|
1 /*idx_value*/,
|
|
|
|
2 /*idx_replacer*/,
|
|
|
|
DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
|
|
|
|
#endif
|
|
|
|
#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
|
|
|
|
} else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
|
|
|
|
duk_bi_json_parse_helper(ctx,
|
|
|
|
1 /*idx_value*/,
|
|
|
|
2 /*idx_replacer*/,
|
|
|
|
DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
DUK_DCERROR_TYPE_INVALID_ARGS(thr);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compact an object
|
|
|
|
*/
|
|
|
|
|
|
|
|
DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) {
|
|
|
|
DUK_ASSERT_TOP(ctx, 1);
|
|
|
|
duk_compact(ctx, 0);
|
|
|
|
return 1; /* return the argument object */
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* DUK_USE_DUKTAPE_BUILTIN */
|