Github User Fetcher 1.0.0
C Application with Server and GUI
Loading...
Searching...
No Matches
duk_js_var.c File Reference
#include "duk_internal.h"

Go to the source code of this file.

Data Structures

struct  duk__id_lookup_result
 

Functions

DUK_LOCAL void duk__inc_data_inner_refcounts (duk_hthread *thr, duk_hcompiledfunction *f)
 
DUK_INTERNAL void duk_js_push_closure (duk_hthread *thr, duk_hcompiledfunction *fun_temp, duk_hobject *outer_var_env, duk_hobject *outer_lex_env, duk_bool_t add_auto_proto)
 
DUK_INTERNAL duk_hobjectduk_create_activation_environment_record (duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom)
 
DUK_INTERNAL void duk_js_init_activation_environment_records_delayed (duk_hthread *thr, duk_activation *act)
 
DUK_INTERNAL void duk_js_close_environment_record (duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase)
 
DUK_LOCAL duk_bool_t duk__getid_open_decl_env_regs (duk_hthread *thr, duk_hstring *name, duk_hobject *env, duk__id_lookup_result *out)
 
DUK_LOCAL duk_bool_t duk__getid_activation_regs (duk_hthread *thr, duk_hstring *name, duk_activation *act, duk__id_lookup_result *out)
 
DUK_LOCAL duk_bool_t duk__get_identifier_reference (duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_activation *act, duk_bool_t parents, duk__id_lookup_result *out)
 
DUK_LOCAL duk_bool_t duk__getvar_helper (duk_hthread *thr, duk_hobject *env, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag)
 
DUK_INTERNAL duk_bool_t duk_js_getvar_envrec (duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag)
 
DUK_INTERNAL duk_bool_t duk_js_getvar_activation (duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag)
 
DUK_LOCAL void duk__putvar_helper (duk_hthread *thr, duk_hobject *env, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict)
 
DUK_INTERNAL void duk_js_putvar_envrec (duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict)
 
DUK_INTERNAL void duk_js_putvar_activation (duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict)
 
DUK_LOCAL duk_bool_t duk__delvar_helper (duk_hthread *thr, duk_hobject *env, duk_activation *act, duk_hstring *name)
 
DUK_INTERNAL duk_bool_t duk_js_delvar_activation (duk_hthread *thr, duk_activation *act, duk_hstring *name)
 
DUK_LOCAL duk_bool_t duk__declvar_helper (duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl)
 
DUK_INTERNAL duk_bool_t duk_js_declvar_activation (duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl)
 

Variables

DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist []
 

Function Documentation

◆ duk__declvar_helper()

DUK_LOCAL duk_bool_t duk__declvar_helper ( duk_hthread * thr,
duk_hobject * env,
duk_hstring * name,
duk_tval * val,
duk_small_int_t prop_flags,
duk_bool_t is_func_decl )

Definition at line 1560 of file duktape-1.8.0/src-separate/duk_js_var.c.

1565 {
1566 duk_context *ctx = (duk_context *) thr;
1567 duk_hobject *holder;
1568 duk_bool_t parents;
1570 duk_tval *tv;
1571
1572 DUK_DDD(DUK_DDDPRINT("declvar: thr=%p, env=%p, name=%!O, val=%!T, prop_flags=0x%08lx, is_func_decl=%ld "
1573 "(env -> %!iO)",
1574 (void *) thr, (void *) env, (duk_heaphdr *) name,
1575 (duk_tval *) val, (unsigned long) prop_flags,
1576 (unsigned int) is_func_decl, (duk_heaphdr *) env));
1577
1578 DUK_ASSERT(thr != NULL);
1579 DUK_ASSERT(env != NULL);
1580 DUK_ASSERT(name != NULL);
1581 DUK_ASSERT(val != NULL);
1582
1583 /* Note: in strict mode the compiler should reject explicit
1584 * declaration of 'eval' or 'arguments'. However, internal
1585 * bytecode may declare 'arguments' in the function prologue.
1586 * We don't bother checking (or asserting) for these now.
1587 */
1588
1589 /* Note: val is a stable duk_tval pointer. The caller makes
1590 * a value copy into its stack frame, so 'tv_val' is not subject
1591 * to side effects here.
1592 */
1593
1594 /*
1595 * Check whether already declared.
1596 *
1597 * We need to check whether the binding exists in the environment
1598 * without walking its parents. However, we still need to check
1599 * register-bound identifiers and the prototype chain of an object
1600 * environment target object.
1601 */
1602
1603 parents = 0; /* just check 'env' */
1604 if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) {
1605 duk_int_t e_idx;
1606 duk_int_t h_idx;
1607 duk_small_int_t flags;
1608
1609 /*
1610 * Variable already declared, ignore re-declaration.
1611 * The only exception is the updated behavior of E5.1 for
1612 * global function declarations, E5.1 Section 10.5, step 5.e.
1613 * This behavior does not apply to global variable declarations.
1614 */
1615
1616 if (!(is_func_decl && env == thr->builtins[DUK_BIDX_GLOBAL_ENV])) {
1617 DUK_DDD(DUK_DDDPRINT("re-declare a binding, ignoring"));
1618 return 1; /* 1 -> needs a PUTVAR */
1619 }
1620
1621 /*
1622 * Special behavior in E5.1.
1623 *
1624 * Note that even though parents == 0, the conflicting property
1625 * may be an inherited property (currently our global object's
1626 * prototype is Object.prototype). Step 5.e first operates on
1627 * the existing property (which is potentially in an ancestor)
1628 * and then defines a new property in the global object (and
1629 * never modifies the ancestor).
1630 *
1631 * Also note that this logic would become even more complicated
1632 * if the conflicting property might be a virtual one. Object
1633 * prototype has no virtual properties, though.
1634 *
1635 * XXX: this is now very awkward, rework.
1636 */
1637
1638 DUK_DDD(DUK_DDDPRINT("re-declare a function binding in global object, "
1639 "updated E5.1 processing"));
1640
1641 DUK_ASSERT(ref.holder != NULL);
1642 holder = ref.holder;
1643
1644 /* holder will be set to the target object, not the actual object
1645 * where the property was found (see duk__get_identifier_reference()).
1646 */
1648 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(holder)); /* global object doesn't have array part */
1649
1650 /* XXX: use a helper for prototype traversal; no loop check here */
1651 /* must be found: was found earlier, and cannot be inherited */
1652 for (;;) {
1653 DUK_ASSERT(holder != NULL);
1654 duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx);
1655 if (e_idx >= 0) {
1656 break;
1657 }
1658 /* SCANBUILD: NULL pointer dereference, doesn't actually trigger,
1659 * asserted above.
1660 */
1661 holder = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, holder);
1662 }
1663 DUK_ASSERT(holder != NULL);
1664 DUK_ASSERT(e_idx >= 0);
1665 /* SCANBUILD: scan-build produces a NULL pointer dereference warning
1666 * below; it never actually triggers because holder is actually never
1667 * NULL.
1668 */
1669
1670 /* ref.holder is global object, holder is the object with the
1671 * conflicting property.
1672 */
1673
1674 flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, holder, e_idx);
1675 if (!(flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
1676 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
1677 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
1678 "accessor -> reject"));
1679 goto fail_existing_attributes;
1680 }
1681 if (!((flags & DUK_PROPDESC_FLAG_WRITABLE) &&
1682 (flags & DUK_PROPDESC_FLAG_ENUMERABLE))) {
1683 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
1684 "plain property which is not writable and "
1685 "enumerable -> reject"));
1686 goto fail_existing_attributes;
1687 }
1688
1689 DUK_DDD(DUK_DDDPRINT("existing property is not configurable but "
1690 "is plain, enumerable, and writable -> "
1691 "allow redeclaration"));
1692 }
1693
1694 if (holder == ref.holder) {
1695 /* XXX: if duk_hobject_define_property_internal() was updated
1696 * to handle a pre-existing accessor property, this would be
1697 * a simple call (like for the ancestor case).
1698 */
1699 DUK_DDD(DUK_DDDPRINT("redefine, offending property in global object itself"));
1700
1701 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
1702 duk_hobject *tmp;
1703
1704 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, holder, e_idx);
1705 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, holder, e_idx, NULL);
1707 DUK_UNREF(tmp);
1708 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, holder, e_idx);
1709 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, holder, e_idx, NULL);
1711 DUK_UNREF(tmp);
1712 } else {
1713 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
1715 }
1716
1717 /* Here val would be potentially invalid if we didn't make
1718 * a value copy at the caller.
1719 */
1720
1721 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
1722 DUK_TVAL_SET_TVAL(tv, val);
1723 DUK_TVAL_INCREF(thr, tv);
1724 DUK_HOBJECT_E_SET_FLAGS(thr->heap, holder, e_idx, prop_flags);
1725
1726 DUK_DDD(DUK_DDDPRINT("updated global binding, final result: "
1727 "value -> %!T, prop_flags=0x%08lx",
1728 (duk_tval *) DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx),
1729 (unsigned long) prop_flags));
1730 } else {
1731 DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor"));
1732
1733 DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]);
1734 duk_push_tval(ctx, val);
1735 duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags);
1736 }
1737
1738 return 0;
1739 }
1740
1741 /*
1742 * Not found (in registers or record objects). Declare
1743 * to current variable environment.
1744 */
1745
1746 /*
1747 * Get holder object
1748 */
1749
1750 if (DUK_HOBJECT_IS_DECENV(env)) {
1751 holder = env;
1752 } else {
1754
1756 DUK_ASSERT(tv != NULL);
1758 holder = DUK_TVAL_GET_OBJECT(tv);
1759 DUK_ASSERT(holder != NULL);
1760 }
1761
1762 /*
1763 * Define new property
1764 *
1765 * Note: this may fail if the holder is not extensible.
1766 */
1767
1768 /* XXX: this is awkward as we use an internal method which doesn't handle
1769 * extensibility etc correctly. Basically we'd want to do a [[DefineOwnProperty]]
1770 * or Object.defineProperty() here.
1771 */
1772
1773 if (!DUK_HOBJECT_HAS_EXTENSIBLE(holder)) {
1774 goto fail_not_extensible;
1775 }
1776
1777 duk_push_hobject(ctx, holder);
1778 duk_push_hstring(ctx, name);
1779 duk_push_tval(ctx, val);
1780 duk_xdef_prop(ctx, -3, prop_flags); /* [holder name val] -> [holder] */
1781 duk_pop(ctx);
1782
1783 return 0;
1784
1785 fail_existing_attributes:
1786 fail_not_extensible:
1787 DUK_ERROR_TYPE(thr, "declaration failed");
1788 return 0;
1789}
duk_int_fast32_t duk_int_t
duk_small_int_t duk_bool_t
#define DUK_TVAL_SET_TVAL(v, x)
#define DUK_HOBJECT_DECREF_ALLOWNULL(thr, h)
#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)
#define DUK_HOBJECT_GET_PROTOTYPE(heap, h)
#define DUK_ERROR_TYPE(thr, msg)
#define DUK_TVAL_GET_OBJECT(tv)
#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, h, i)
#define DUK_TVAL_IS_OBJECT(tv)
#define DUK_HOBJECT_IS_OBJENV(h)
#define DUK_HTHREAD_STRING_INT_TARGET(thr)
#define DUK_TVAL_INCREF(thr, tv)
#define DUK_HOBJECT_E_GET_VALUE_SETTER(heap, h, i)
#define DUK_PROPDESC_FLAG_ACCESSOR
DUK_INTERNAL_DECL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx)
DUK_INTERNAL_DECL duk_tval * duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key)
#define DUK_HOBJECT_CLASS_GLOBAL
#define DUK_PROPDESC_FLAG_CONFIGURABLE
#define DUK_HOBJECT_E_SET_VALUE_SETTER(heap, h, i, v)
DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv)
#define DUK_HOBJECT_E_SET_FLAGS(heap, h, i, f)
#define DUK_HOBJECT_IS_DECENV(h)
#define DUK_PROPDESC_FLAG_WRITABLE
DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags)
#define DUK_PROPDESC_FLAG_ENUMERABLE
#define DUK_HOBJECT_E_SET_VALUE_GETTER(heap, h, i, v)
DUK_EXTERNAL void duk_pop(duk_context *ctx)
DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h)
#define DUK_TVAL_SET_UNDEFINED_UPDREF
#define DUK_HOBJECT_GET_CLASS_NUMBER(h)
#define DUK_HOBJECT_E_GET_FLAGS(heap, h, i)
#define DUK_HOBJECT_E_GET_VALUE_GETTER(heap, h, i)
DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h)
#define DUK_HOBJECT_HAS_EXTENSIBLE(h)
DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_index, duk_small_uint_t desc_flags)
DUK_LOCAL duk_bool_t duk__get_identifier_reference(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_activation *act, duk_bool_t parents, duk__id_lookup_result *out)
#define NULL
Definition gmacros.h:924
const char * name
Definition lsqlite3.c:2154

References duk_hthread::builtins, duk__get_identifier_reference(), DUK_ASSERT, DUK_BIDX_GLOBAL, DUK_BIDX_GLOBAL_ENV, DUK_DDD, DUK_DDDPRINT, DUK_ERROR_TYPE, DUK_HOBJECT_CLASS_GLOBAL, DUK_HOBJECT_DECREF_ALLOWNULL, duk_hobject_define_property_internal(), DUK_HOBJECT_E_GET_FLAGS, DUK_HOBJECT_E_GET_VALUE_GETTER, DUK_HOBJECT_E_GET_VALUE_SETTER, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR, DUK_HOBJECT_E_SET_FLAGS, DUK_HOBJECT_E_SET_VALUE_GETTER, DUK_HOBJECT_E_SET_VALUE_SETTER, duk_hobject_find_existing_entry(), duk_hobject_find_existing_entry_tval_ptr(), DUK_HOBJECT_GET_CLASS_NUMBER, DUK_HOBJECT_GET_PROTOTYPE, DUK_HOBJECT_HAS_EXOTIC_ARRAY, DUK_HOBJECT_HAS_EXTENSIBLE, DUK_HOBJECT_IS_DECENV, DUK_HOBJECT_IS_OBJENV, DUK_HTHREAD_STRING_INT_TARGET, duk_pop(), DUK_PROPDESC_FLAG_ACCESSOR, DUK_PROPDESC_FLAG_CONFIGURABLE, DUK_PROPDESC_FLAG_ENUMERABLE, DUK_PROPDESC_FLAG_WRITABLE, duk_push_hobject(), duk_push_hstring(), duk_push_tval(), DUK_TVAL_GET_OBJECT, DUK_TVAL_INCREF, DUK_TVAL_IS_OBJECT, DUK_TVAL_SET_TVAL, DUK_TVAL_SET_UNDEFINED_UPDREF, DUK_UNREF, duk_xdef_prop(), duk_hthread::heap, duk__id_lookup_result::holder, name, and NULL.

Referenced by duk_js_declvar_activation().

◆ duk__delvar_helper()

DUK_LOCAL duk_bool_t duk__delvar_helper ( duk_hthread * thr,
duk_hobject * env,
duk_activation * act,
duk_hstring * name )

Definition at line 1446 of file duktape-1.8.0/src-separate/duk_js_var.c.

1449 {
1451 duk_bool_t parents;
1452
1453 DUK_DDD(DUK_DDDPRINT("delvar: thr=%p, env=%p, act=%p, name=%!O "
1454 "(env -> %!dO)",
1455 (void *) thr, (void *) env, (void *) act,
1456 (duk_heaphdr *) name, (duk_heaphdr *) env));
1457
1458 DUK_ASSERT(thr != NULL);
1459 DUK_ASSERT(name != NULL);
1460 /* env and act may be NULL */
1461
1463
1464 parents = 1; /* follow parent chain */
1465
1466 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
1467 if (ref.value && !(ref.attrs & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
1468 /* Identifier found in registers (always non-deletable)
1469 * or declarative environment record and non-configurable.
1470 */
1471 return 0;
1472 }
1473 DUK_ASSERT(ref.holder != NULL);
1474
1475 return duk_hobject_delprop_raw(thr, ref.holder, name, 0);
1476 }
1477
1478 /*
1479 * Not found (even in global object).
1480 *
1481 * In non-strict mode this is a silent SUCCESS (!), see E5 Section 11.4.1,
1482 * step 3.b. In strict mode this case is a compile time SyntaxError so
1483 * we should not come here.
1484 */
1485
1486 DUK_DDD(DUK_DDDPRINT("identifier to be deleted not found: name=%!O "
1487 "(treated as silent success)",
1488 (duk_heaphdr *) name));
1489 return 1;
1490}
#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h)
DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags)

References duk__id_lookup_result::attrs, duk__get_identifier_reference(), DUK_ASSERT, DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR, DUK_DDD, DUK_DDDPRINT, duk_hobject_delprop_raw(), DUK_PROPDESC_FLAG_CONFIGURABLE, duk__id_lookup_result::holder, name, NULL, and duk__id_lookup_result::value.

Referenced by duk_js_delvar_activation().

◆ duk__get_identifier_reference()

DUK_LOCAL duk_bool_t duk__get_identifier_reference ( duk_hthread * thr,
duk_hobject * env,
duk_hstring * name,
duk_activation * act,
duk_bool_t parents,
duk__id_lookup_result * out )

Definition at line 895 of file duktape-1.8.0/src-separate/duk_js_var.c.

900 {
901 duk_tval *tv;
902 duk_tval *tv_target;
903 duk_tval tv_name;
904 duk_uint_t sanity;
905
906 DUK_ASSERT(thr != NULL);
907 DUK_ASSERT(env != NULL || act != NULL);
908 DUK_ASSERT(name != NULL);
909 DUK_ASSERT(out != NULL);
910
911 DUK_ASSERT(!env || DUK_HOBJECT_IS_ENV(env));
913
914 /*
915 * Conceptually, we look for the identifier binding by starting from
916 * 'env' and following to chain of environment records (represented
917 * by the prototype chain).
918 *
919 * If 'env' is NULL, the current activation does not yet have an
920 * allocated declarative environment record; this should be treated
921 * exactly as if the environment record existed but had no bindings
922 * other than register bindings.
923 *
924 * Note: we assume that with the DUK_HOBJECT_FLAG_NEWENV cleared
925 * the environment will always be initialized immediately; hence
926 * a NULL 'env' should only happen with the flag set. This is the
927 * case for: (1) function calls, and (2) strict, direct eval calls.
928 */
929
930 if (env == NULL && act != NULL) {
931 duk_hobject *func;
932
933 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> "
934 "delayed env case, look up activation regs first"));
935
936 /*
937 * Try registers
938 */
939
940 if (duk__getid_activation_regs(thr, name, act, out)) {
941 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
942 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
943 "(found from register bindings when env=NULL)",
944 (duk_heaphdr *) name, (duk_tval *) out->value,
945 (long) out->attrs, (duk_tval *) out->this_binding,
946 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
947 return 1;
948 }
949
950 DUK_DDD(DUK_DDDPRINT("not found in current activation regs"));
951
952 /*
953 * Not found in registers, proceed to the parent record.
954 * Here we need to determine what the parent would be,
955 * if 'env' was not NULL (i.e. same logic as when initializing
956 * the record).
957 *
958 * Note that environment initialization is only deferred when
959 * DUK_HOBJECT_HAS_NEWENV is set, and this only happens for:
960 * - Function code
961 * - Strict eval code
962 *
963 * We only need to check _Lexenv here; _Varenv exists only if it
964 * differs from _Lexenv (and thus _Lexenv will also be present).
965 */
966
967 if (!parents) {
968 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
969 "(not found from register bindings when env=NULL)"));
970 goto fail_not_found;
971 }
972
973 func = DUK_ACT_GET_FUNC(act);
974 DUK_ASSERT(func != NULL);
976
978 if (tv) {
980 env = DUK_TVAL_GET_OBJECT(tv);
981 } else {
983 env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
984 }
985
986 DUK_DDD(DUK_DDDPRINT("continue lookup from env: %!iO",
987 (duk_heaphdr *) env));
988 }
989
990 /*
991 * Prototype walking starting from 'env'.
992 *
993 * ('act' is not needed anywhere here.)
994 */
995
997 while (env != NULL) {
999 duk_int_t attrs;
1000
1001 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO",
1002 (duk_heaphdr *) name,
1003 (void *) env,
1004 (duk_heaphdr *) env));
1005
1006 DUK_ASSERT(env != NULL);
1009
1012 if (cl == DUK_HOBJECT_CLASS_DECENV) {
1013 /*
1014 * Declarative environment record.
1015 *
1016 * Identifiers can never be stored in ancestors and are
1017 * always plain values, so we can use an internal helper
1018 * and access the value directly with an duk_tval ptr.
1019 *
1020 * A closed environment is only indicated by it missing
1021 * the "book-keeping" properties required for accessing
1022 * register-bound variables.
1023 */
1024
1026 /* already closed */
1027 goto skip_regs;
1028 }
1029
1030 if (duk__getid_open_decl_env_regs(thr, name, env, out)) {
1031 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
1032 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
1033 "(declarative environment record, scope open, found in regs)",
1034 (duk_heaphdr *) name, (duk_tval *) out->value,
1035 (long) out->attrs, (duk_tval *) out->this_binding,
1036 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
1037 return 1;
1038 }
1039 skip_regs:
1040
1042 if (tv) {
1043 out->value = tv;
1044 out->attrs = attrs;
1045 out->this_binding = NULL; /* implicit this value always undefined for
1046 * declarative environment records.
1047 */
1048 out->env = env;
1049 out->holder = env;
1050
1051 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
1052 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
1053 "(declarative environment record, found in properties)",
1054 (duk_heaphdr *) name, (duk_tval *) out->value,
1055 (long) out->attrs, (duk_tval *) out->this_binding,
1056 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
1057 return 1;
1058 }
1059 } else {
1060 /*
1061 * Object environment record.
1062 *
1063 * Binding (target) object is an external, uncontrolled object.
1064 * Identifier may be bound in an ancestor property, and may be
1065 * an accessor. Target can also be a Proxy which we must support
1066 * here.
1067 */
1068
1069 /* XXX: we could save space by using _Target OR _This. If _Target, assume
1070 * this binding is undefined. If _This, assumes this binding is _This, and
1071 * target is also _This. One property would then be enough.
1072 */
1073
1074 duk_hobject *target;
1075 duk_bool_t found;
1076
1078
1080 DUK_ASSERT(tv_target != NULL);
1081 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
1082 target = DUK_TVAL_GET_OBJECT(tv_target);
1083 DUK_ASSERT(target != NULL);
1084
1085 /* Target may be a Proxy or property may be an accessor, so we must
1086 * use an actual, Proxy-aware hasprop check here.
1087 *
1088 * out->holder is NOT set to the actual duk_hobject where the
1089 * property is found, but rather the object binding target object.
1090 */
1091
1092 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) {
1093 DUK_ASSERT(name != NULL);
1094 DUK_TVAL_SET_STRING(&tv_name, name);
1095
1096 found = duk_hobject_hasprop(thr, tv_target, &tv_name);
1097 } else {
1098 /* XXX: duk_hobject_hasprop() would be correct for
1099 * non-Proxy objects too, but it is about ~20-25%
1100 * slower at present so separate code paths for
1101 * Proxy and non-Proxy now.
1102 */
1103 found = duk_hobject_hasprop_raw(thr, target, name);
1104 }
1105
1106 if (found) {
1107 out->value = NULL; /* can't get value, may be accessor */
1108 out->attrs = 0; /* irrelevant when out->value == NULL */
1110 out->this_binding = tv; /* may be NULL */
1111 out->env = env;
1112 out->holder = target;
1113
1114 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
1115 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
1116 "(object environment record)",
1117 (duk_heaphdr *) name, (duk_tval *) out->value,
1118 (long) out->attrs, (duk_tval *) out->this_binding,
1119 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
1120 return 1;
1121 }
1122 }
1123
1124 if (!parents) {
1125 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
1126 "(not found from first traversed env)"));
1127 goto fail_not_found;
1128 }
1129
1130 if (sanity-- == 0) {
1132 }
1133 env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env);
1134 };
1135
1136 /*
1137 * Not found (even in global object)
1138 */
1139
1140 fail_not_found:
1141 return 0;
1142}
duk_uint_fast32_t duk_uint_t
#define DUK_ERROR_RANGE(thr, msg)
#define DUK_HTHREAD_STRING_INT_VARENV(thr)
#define DUK_HTHREAD_STRING_INT_LEXENV(thr)
#define DUK_HOBJECT_IS_ENV(h)
DUK_INTERNAL_DECL duk_tval * duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs)
#define DUK_HOBJECT_HAS_ARRAY_PART(h)
#define DUK_HOBJECT_CLASS_OBJENV
#define DUK_STR_PROTOTYPE_CHAIN_LIMIT
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key)
#define DUK_HTHREAD_STRING_INT_THIS(thr)
#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY
DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key)
#define DUK_HOBJECT_CLASS_DECENV
#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)
#define DUK_HOBJECT_HAS_NEWENV(h)
#define DUK_ACT_GET_FUNC(act)
#define DUK_HOBJECT_HAS_ENVRECCLOSED(h)
#define DUK_TVAL_SET_STRING(tv, hptr)
DUK_LOCAL duk_bool_t duk__getid_activation_regs(duk_hthread *thr, duk_hstring *name, duk_activation *act, duk__id_lookup_result *out)
DUK_LOCAL duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr, duk_hstring *name, duk_hobject *env, duk__id_lookup_result *out)
duk_hobject * builtins[DUK_NUM_BUILTINS]

References duk__id_lookup_result::attrs, duk_hthread::builtins, duk__getid_activation_regs(), duk__getid_open_decl_env_regs(), DUK_ACT_GET_FUNC, DUK_ASSERT, DUK_BIDX_GLOBAL_ENV, DUK_DDD, DUK_DDDPRINT, DUK_ERROR_RANGE, DUK_HOBJECT_CLASS_DECENV, DUK_HOBJECT_CLASS_OBJENV, duk_hobject_find_existing_entry_tval_ptr(), duk_hobject_find_existing_entry_tval_ptr_and_attrs(), DUK_HOBJECT_GET_CLASS_NUMBER, DUK_HOBJECT_GET_PROTOTYPE, DUK_HOBJECT_HAS_ARRAY_PART, DUK_HOBJECT_HAS_ENVRECCLOSED, DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ, DUK_HOBJECT_HAS_NEWENV, duk_hobject_hasprop(), duk_hobject_hasprop_raw(), DUK_HOBJECT_IS_ENV, DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY, DUK_HTHREAD_STRING_INT_LEXENV, DUK_HTHREAD_STRING_INT_TARGET, DUK_HTHREAD_STRING_INT_THIS, DUK_HTHREAD_STRING_INT_VARENV, DUK_STR_PROTOTYPE_CHAIN_LIMIT, DUK_TVAL_GET_OBJECT, DUK_TVAL_IS_OBJECT, DUK_TVAL_SET_STRING, duk__id_lookup_result::env, duk_hthread::heap, duk__id_lookup_result::holder, name, NULL, duk__id_lookup_result::this_binding, and duk__id_lookup_result::value.

Referenced by duk__declvar_helper(), duk__delvar_helper(), duk__getvar_helper(), and duk__putvar_helper().

◆ duk__getid_activation_regs()

DUK_LOCAL duk_bool_t duk__getid_activation_regs ( duk_hthread * thr,
duk_hstring * name,
duk_activation * act,
duk__id_lookup_result * out )

Definition at line 839 of file duktape-1.8.0/src-separate/duk_js_var.c.

842 {
843 duk_tval *tv;
844 duk_hobject *func;
845 duk_hobject *varmap;
846 duk_size_t reg_rel;
847 duk_size_t idx;
848
849 DUK_ASSERT(thr != NULL);
850 DUK_ASSERT(name != NULL);
851 DUK_ASSERT(act != NULL);
852 DUK_ASSERT(out != NULL);
853
854 func = DUK_ACT_GET_FUNC(act);
855 DUK_ASSERT(func != NULL);
857
859 return 0;
860 }
861
863 if (!tv) {
864 return 0;
865 }
867 varmap = DUK_TVAL_GET_OBJECT(tv);
868 DUK_ASSERT(varmap != NULL);
869
871 if (!tv) {
872 return 0;
873 }
875 reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
876 DUK_ASSERT_DISABLE(reg_rel >= 0);
877 DUK_ASSERT(reg_rel < ((duk_hcompiledfunction *) func)->nregs);
878
879 idx = act->idx_bottom + reg_rel;
880 DUK_ASSERT(idx >= act->idx_bottom);
881 tv = thr->valstack + idx;
882
883 out->value = tv;
884 out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
885 out->this_binding = NULL; /* implicit this value always undefined for
886 * declarative environment records.
887 */
888 out->env = NULL;
889 out->holder = NULL;
890
891 return 1;
892}
#define DUK_TVAL_IS_NUMBER(tv)
#define DUK_HOBJECT_IS_COMPILEDFUNCTION(h)
#define DUK_ASSERT_DISABLE(x)
#define DUK_HTHREAD_STRING_INT_VARMAP(thr)
#define DUK_TVAL_GET_NUMBER(tv)

References duk__id_lookup_result::attrs, DUK_ACT_GET_FUNC, DUK_ASSERT, DUK_ASSERT_DISABLE, duk_hobject_find_existing_entry_tval_ptr(), DUK_HOBJECT_HAS_NEWENV, DUK_HOBJECT_IS_COMPILEDFUNCTION, DUK_HTHREAD_STRING_INT_VARMAP, DUK_PROPDESC_FLAGS_W, DUK_TVAL_GET_NUMBER, DUK_TVAL_GET_OBJECT, DUK_TVAL_IS_NUMBER, DUK_TVAL_IS_OBJECT, duk__id_lookup_result::env, duk_hthread::heap, duk__id_lookup_result::holder, duk_activation::idx_bottom, name, NULL, duk__id_lookup_result::this_binding, duk_hthread::valstack, and duk__id_lookup_result::value.

Referenced by duk__get_identifier_reference().

◆ duk__getid_open_decl_env_regs()

DUK_LOCAL duk_bool_t duk__getid_open_decl_env_regs ( duk_hthread * thr,
duk_hstring * name,
duk_hobject * env,
duk__id_lookup_result * out )

Definition at line 754 of file duktape-1.8.0/src-separate/duk_js_var.c.

757 {
758 duk_hthread *env_thr;
759 duk_hobject *env_func;
760 duk_size_t env_regbase;
761 duk_hobject *varmap;
762 duk_tval *tv;
763 duk_size_t reg_rel;
764 duk_size_t idx;
765
766 DUK_ASSERT(thr != NULL);
767 DUK_ASSERT(name != NULL);
768 DUK_ASSERT(env != NULL);
769 DUK_ASSERT(out != NULL);
770
772
774 if (!tv) {
775 /* env is closed, should be missing _Callee, _Thread, _Regbase */
779 return 0;
780 }
781
785 env_func = DUK_TVAL_GET_OBJECT(tv);
786 DUK_ASSERT(env_func != NULL);
787
789 if (!tv) {
790 return 0;
791 }
793 varmap = DUK_TVAL_GET_OBJECT(tv);
794 DUK_ASSERT(varmap != NULL);
795
797 if (!tv) {
798 return 0;
799 }
801 reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
802 DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */
803 DUK_ASSERT(reg_rel < ((duk_hcompiledfunction *) env_func)->nregs);
804
806 DUK_ASSERT(tv != NULL);
810 env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
811 DUK_ASSERT(env_thr != NULL);
812
813 /* Note: env_thr != thr is quite possible and normal, so careful
814 * with what thread is used for valstack lookup.
815 */
816
818 DUK_ASSERT(tv != NULL);
820 env_regbase = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
821
822 idx = env_regbase + reg_rel;
823 tv = env_thr->valstack + idx;
824 DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end); /* XXX: more accurate? */
825
826 out->value = tv;
827 out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
828 out->this_binding = NULL; /* implicit this value always undefined for
829 * declarative environment records.
830 */
831 out->env = env;
832 out->holder = NULL;
833
834 return 1;
835}
#define DUK_HTHREAD_STRING_INT_REGBASE(thr)
#define DUK_HTHREAD_STRING_INT_THREAD(thr)
#define DUK_HOBJECT_IS_THREAD(h)
#define DUK_HTHREAD_STRING_INT_CALLEE(thr)

References duk__id_lookup_result::attrs, DUK_ASSERT, DUK_ASSERT_DISABLE, duk_hobject_find_existing_entry_tval_ptr(), DUK_HOBJECT_IS_COMPILEDFUNCTION, DUK_HOBJECT_IS_DECENV, DUK_HOBJECT_IS_THREAD, DUK_HTHREAD_STRING_INT_CALLEE, DUK_HTHREAD_STRING_INT_REGBASE, DUK_HTHREAD_STRING_INT_THREAD, DUK_HTHREAD_STRING_INT_VARMAP, DUK_PROPDESC_FLAGS_W, DUK_TVAL_GET_NUMBER, DUK_TVAL_GET_OBJECT, DUK_TVAL_IS_NUMBER, DUK_TVAL_IS_OBJECT, duk__id_lookup_result::env, duk_hthread::heap, duk__id_lookup_result::holder, name, NULL, duk__id_lookup_result::this_binding, duk_hthread::valstack, and duk__id_lookup_result::value.

Referenced by duk__get_identifier_reference().

◆ duk__getvar_helper()

DUK_LOCAL duk_bool_t duk__getvar_helper ( duk_hthread * thr,
duk_hobject * env,
duk_activation * act,
duk_hstring * name,
duk_bool_t throw_flag )

Definition at line 1215 of file duktape-1.8.0/src-separate/duk_js_var.c.

1219 {
1220 duk_context *ctx = (duk_context *) thr;
1222 duk_tval tv_tmp_obj;
1223 duk_tval tv_tmp_key;
1224 duk_bool_t parents;
1225
1226 DUK_DDD(DUK_DDDPRINT("getvar: thr=%p, env=%p, act=%p, name=%!O "
1227 "(env -> %!dO)",
1228 (void *) thr, (void *) env, (void *) act,
1229 (duk_heaphdr *) name, (duk_heaphdr *) env));
1230
1231 DUK_ASSERT(thr != NULL);
1232 DUK_ASSERT(name != NULL);
1233 /* env and act may be NULL */
1234
1237
1238 parents = 1; /* follow parent chain */
1239 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
1240 if (ref.value) {
1241 DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
1242 duk_push_tval(ctx, ref.value);
1243 duk_push_undefined(ctx);
1244 } else {
1245 DUK_ASSERT(ref.holder != NULL);
1246
1247 /* Note: getprop may invoke any getter and invalidate any
1248 * duk_tval pointers, so this must be done first.
1249 */
1250
1251 if (ref.this_binding) {
1252 duk_push_tval(ctx, ref.this_binding);
1253 } else {
1254 duk_push_undefined(ctx);
1255 }
1256
1257 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
1258 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
1259 (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */
1260
1261 /* ref.value, ref.this.binding invalidated here by getprop call */
1262
1263 duk_insert(ctx, -2); /* [this value] -> [value this] */
1264 }
1265
1266 return 1;
1267 } else {
1268 if (throw_flag) {
1270 "identifier '%s' undefined",
1271 (const char *) DUK_HSTRING_GET_DATA(name));
1272 }
1273
1274 return 0;
1275 }
1276}
#define DUK_HSTRING_GET_DATA(x)
#define DUK_TVAL_SET_OBJECT(tv, hptr)
DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key)
DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_index)
DUK_EXTERNAL void duk_push_undefined(duk_context *ctx)
#define DUK_ERROR_FMT1(thr, err, fmt, arg1)
#define DUK_ERR_REFERENCE_ERROR

References duk__get_identifier_reference(), DUK_ASSERT, DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR, DUK_DDD, DUK_DDDPRINT, DUK_ERR_REFERENCE_ERROR, DUK_ERROR_FMT1, duk_hobject_getprop(), DUK_HSTRING_GET_DATA, duk_insert(), duk_push_tval(), duk_push_undefined(), DUK_TVAL_SET_OBJECT, DUK_TVAL_SET_STRING, duk__id_lookup_result::holder, name, NULL, duk__id_lookup_result::this_binding, and duk__id_lookup_result::value.

Referenced by duk_js_getvar_activation(), and duk_js_getvar_envrec().

◆ duk__inc_data_inner_refcounts()

DUK_LOCAL void duk__inc_data_inner_refcounts ( duk_hthread * thr,
duk_hcompiledfunction * f )

Definition at line 73 of file duktape-1.8.0/src-separate/duk_js_var.c.

73 {
74 duk_tval *tv, *tv_end;
75 duk_hobject **funcs, **funcs_end;
76
77 /* If function creation fails due to out-of-memory, the data buffer
78 * pointer may be NULL in some cases. That's actually possible for
79 * GC code, but shouldn't be possible here because the incomplete
80 * function will be unwound from the value stack and never instantiated.
81 */
83 DUK_UNREF(thr);
84
87 while (tv < tv_end) {
88 DUK_TVAL_INCREF(thr, tv);
89 tv++;
90 }
91
93 funcs_end = DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(thr->heap, f);
94 while (funcs < funcs_end) {
96 funcs++;
97 }
98}
#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE(heap, h)
#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE(heap, h)
#define DUK_HCOMPILEDFUNCTION_GET_FUNCS_END(heap, h)
#define DUK_HEAPHDR_INCREF(thr, h)
#define DUK_HCOMPILEDFUNCTION_GET_DATA(heap, h)
#define DUK_HCOMPILEDFUNCTION_GET_CONSTS_END(heap, h)
static const luaL_Reg funcs[]

References DUK_ASSERT, DUK_HCOMPILEDFUNCTION_GET_CONSTS_BASE, DUK_HCOMPILEDFUNCTION_GET_CONSTS_END, DUK_HCOMPILEDFUNCTION_GET_DATA, DUK_HCOMPILEDFUNCTION_GET_FUNCS_BASE, DUK_HCOMPILEDFUNCTION_GET_FUNCS_END, DUK_HEAPHDR_INCREF, DUK_TVAL_INCREF, DUK_UNREF, funcs, duk_hthread::heap, and NULL.

Referenced by duk_js_push_closure().

◆ duk__putvar_helper()

DUK_LOCAL void duk__putvar_helper ( duk_hthread * thr,
duk_hobject * env,
duk_activation * act,
duk_hstring * name,
duk_tval * val,
duk_bool_t strict )

Definition at line 1311 of file duktape-1.8.0/src-separate/duk_js_var.c.

1316 {
1318 duk_tval tv_tmp_obj;
1319 duk_tval tv_tmp_key;
1320 duk_bool_t parents;
1321
1322 DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld "
1323 "(env -> %!dO, val -> %!T)",
1324 (void *) thr, (void *) env, (void *) act,
1325 (duk_heaphdr *) name, (void *) val, (long) strict,
1326 (duk_heaphdr *) env, (duk_tval *) val));
1327
1328 DUK_ASSERT(thr != NULL);
1329 DUK_ASSERT(name != NULL);
1330 DUK_ASSERT(val != NULL);
1331 /* env and act may be NULL */
1332
1336
1337 /*
1338 * In strict mode E5 protects 'eval' and 'arguments' from being
1339 * assigned to (or even declared anywhere). Attempt to do so
1340 * should result in a compile time SyntaxError. See the internal
1341 * design documentation for details.
1342 *
1343 * Thus, we should never come here, run-time, for strict code,
1344 * and name 'eval' or 'arguments'.
1345 */
1346
1347 DUK_ASSERT(!strict ||
1348 (name != DUK_HTHREAD_STRING_EVAL(thr) &&
1350
1351 /*
1352 * Lookup variable and update in-place if found.
1353 */
1354
1355 parents = 1; /* follow parent chain */
1356
1357 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
1358 if (ref.value && (ref.attrs & DUK_PROPDESC_FLAG_WRITABLE)) {
1359 /* Update duk_tval in-place if pointer provided and the
1360 * property is writable. If the property is not writable
1361 * (immutable binding), use duk_hobject_putprop() which
1362 * will respect mutability.
1363 */
1364 duk_tval *tv_val;
1365
1366 DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
1367
1368 tv_val = ref.value;
1369 DUK_ASSERT(tv_val != NULL);
1370 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */
1371
1372 /* ref.value and ref.this_binding invalidated here */
1373 } else {
1374 DUK_ASSERT(ref.holder != NULL);
1375
1376 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
1377 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
1378 (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict);
1379
1380 /* ref.value and ref.this_binding invalidated here */
1381 }
1382
1383 return;
1384 }
1385
1386 /*
1387 * Not found: write to global object (non-strict) or ReferenceError
1388 * (strict); see E5 Section 8.7.2, step 3.
1389 */
1390
1391 if (strict) {
1392 DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error"));
1393 DUK_ERROR(thr, DUK_ERR_REFERENCE_ERROR, "identifier not defined");
1394 }
1395
1396 DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global"));
1397
1398 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]);
1399 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
1400 (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0); /* 0 = no throw */
1401
1402 /* NB: 'val' may be invalidated here because put_value may realloc valstack,
1403 * caller beware.
1404 */
1405}
#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv)
#define DUK_TVAL_SET_TVAL_UPDREF
#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)
#define DUK_HTHREAD_STRING_EVAL(thr)
#define DUK_ERROR(thr, err, msg)
DUK_INTERNAL_DECL duk_bool_t duk_hobject_putprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_tval *tv_val, duk_bool_t throw_flag)

References duk__id_lookup_result::attrs, duk_hthread::builtins, duk__get_identifier_reference(), DUK_ASSERT, DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR, DUK_ASSERT_REFCOUNT_NONZERO_TVAL, DUK_BIDX_GLOBAL, DUK_DDD, DUK_DDDPRINT, DUK_ERR_REFERENCE_ERROR, DUK_ERROR, duk_hobject_putprop(), DUK_HTHREAD_STRING_EVAL, DUK_HTHREAD_STRING_LC_ARGUMENTS, DUK_PROPDESC_FLAG_WRITABLE, DUK_TVAL_SET_OBJECT, DUK_TVAL_SET_STRING, DUK_TVAL_SET_TVAL_UPDREF, duk__id_lookup_result::holder, name, NULL, duk__id_lookup_result::this_binding, and duk__id_lookup_result::value.

Referenced by duk_js_putvar_activation(), and duk_js_putvar_envrec().

◆ duk_create_activation_environment_record()

DUK_INTERNAL duk_hobject * duk_create_activation_environment_record ( duk_hthread * thr,
duk_hobject * func,
duk_size_t idx_bottom )

Definition at line 486 of file duktape-1.8.0/src-separate/duk_js_var.c.

488 {
489 duk_context *ctx = (duk_context *) thr;
490 duk_hobject *env;
491 duk_hobject *parent;
492 duk_tval *tv;
493
494 DUK_ASSERT(thr != NULL);
495 DUK_ASSERT(func != NULL);
496
498 if (tv) {
501 parent = DUK_TVAL_GET_OBJECT(tv);
502 } else {
503 parent = thr->builtins[DUK_BIDX_GLOBAL_ENV];
504 }
505
506 (void) duk_push_object_helper(ctx,
509 -1); /* no prototype, updated below */
510 env = duk_require_hobject(ctx, -1);
511 DUK_ASSERT(env != NULL);
512 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent); /* parent env is the prototype */
513
514 /* open scope information, for compiled functions only */
515
517 duk_push_hthread(ctx, thr);
519 duk_push_hobject(ctx, func);
521 duk_push_size_t(ctx, idx_bottom);
523 }
524
525 return env;
526}
#define DUK_STRIDX_INT_CALLEE
#define DUK_STRIDX_INT_REGBASE
DUK_INTERNAL_DECL duk_hobject * duk_require_hobject(duk_context *ctx, duk_idx_t index)
#define duk_xdef_prop_stridx_wec(ctx, obj_index, stridx)
#define DUK_STRIDX_INT_THREAD
#define duk_push_size_t(ctx, val)
#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, p)
#define DUK_HOBJECT_CLASS_AS_FLAGS(v)
#define duk_push_hthread(ctx, h)
#define DUK_HOBJECT_FLAG_EXTENSIBLE
DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx)

References duk_hthread::builtins, DUK_ASSERT, DUK_BIDX_GLOBAL_ENV, DUK_HOBJECT_CLASS_AS_FLAGS, DUK_HOBJECT_CLASS_DECENV, duk_hobject_find_existing_entry_tval_ptr(), DUK_HOBJECT_FLAG_EXTENSIBLE, DUK_HOBJECT_IS_COMPILEDFUNCTION, DUK_HOBJECT_IS_ENV, DUK_HOBJECT_SET_PROTOTYPE_UPDREF, DUK_HTHREAD_STRING_INT_LEXENV, duk_push_hobject(), duk_push_hthread, duk_push_object_helper(), duk_push_size_t, duk_require_hobject(), DUK_STRIDX_INT_CALLEE, DUK_STRIDX_INT_REGBASE, DUK_STRIDX_INT_THREAD, DUK_TVAL_GET_OBJECT, DUK_TVAL_IS_OBJECT, duk_xdef_prop_stridx_wec, duk_hthread::heap, and NULL.

Referenced by duk_js_init_activation_environment_records_delayed().

◆ duk_js_close_environment_record()

DUK_INTERNAL void duk_js_close_environment_record ( duk_hthread * thr,
duk_hobject * env,
duk_hobject * func,
duk_size_t regbase )

Definition at line 588 of file duktape-1.8.0/src-separate/duk_js_var.c.

588 {
589 duk_context *ctx = (duk_context *) thr;
591
592 DUK_ASSERT(thr != NULL);
593 DUK_ASSERT(env != NULL);
594 /* func is NULL for lightfuncs */
595
597 DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, "
598 "or already closed: %!iO",
599 (duk_heaphdr *) env));
600 return;
601 }
602
603 DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld",
604 (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase));
605
606 duk_push_hobject(ctx, env);
607
608 /* assertions: env must be closed in the same thread as where it runs */
609#ifdef DUK_USE_ASSERTIONS
610 {
611 /* [... env] */
612
614 DUK_ASSERT(duk_is_object(ctx, -1));
615 DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func);
616 }
617 duk_pop(ctx);
618
620 DUK_ASSERT(duk_is_object(ctx, -1));
621 DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr);
622 }
623 duk_pop(ctx);
624
626 DUK_ASSERT(duk_is_number(ctx, -1));
627 DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase);
628 }
629 duk_pop(ctx);
630
631 /* [... env] */
632 }
633#endif
634
635 if (func != NULL && DUK_HOBJECT_IS_COMPILEDFUNCTION(func)) {
636 duk_hobject *varmap;
637 duk_hstring *key;
638 duk_tval *tv;
639 duk_uint_t regnum;
640
641 /* XXX: additional conditions when to close variables? we don't want to do it
642 * unless the environment may have "escaped" (referenced in a function closure).
643 * With delayed environments, the existence is probably good enough of a check.
644 */
645
646 /* XXX: any way to detect faster whether something needs to be closed?
647 * We now look up _Callee and then skip the rest.
648 */
649
650 /* Note: we rely on the _Varmap having a bunch of nice properties, like:
651 * - being compacted and unmodified during this process
652 * - not containing an array part
653 * - having correct value types
654 */
655
656 /* [... env] */
657
659 DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case"));
660 duk_pop(ctx);
661 goto skip_varmap;
662 }
663
664 /* [... env callee] */
665
667 DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties"));
668 duk_pop_2(ctx);
669 goto skip_varmap;
670 }
671 varmap = duk_require_hobject(ctx, -1);
672 DUK_ASSERT(varmap != NULL);
673
674 DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap));
675
676 /* [... env callee varmap] */
677
678 DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap)));
679
680 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
681 key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
682 DUK_ASSERT(key != NULL); /* assume keys are compacted */
683
684 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */
685
686 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i);
687 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */
688 regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
689 DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */
690 DUK_ASSERT(regnum < ((duk_hcompiledfunction *) func)->nregs); /* regnum is sane */
691 DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack);
692 DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top);
693
694 /* XXX: slightly awkward */
695 duk_push_hstring(ctx, key);
696 duk_push_tval(ctx, thr->valstack + regbase + regnum);
697 DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T",
698 (const char *) duk_require_string(ctx, -2),
699 (long) regnum,
700 (duk_tval *) duk_get_tval(ctx, -1)));
701
702 /* [... env callee varmap key val] */
703
704 /* if property already exists, overwrites silently */
705 duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */
706 }
707
708 duk_pop_2(ctx);
709
710 /* [... env] */
711 }
712
713 skip_varmap:
714
715 /* [... env] */
716
720
721 duk_pop(ctx);
722
724
725 DUK_DDD(DUK_DDDPRINT("environment record after being closed: %!O",
726 (duk_heaphdr *) env));
727}
duk_uint32_t duk_uint_fast32_t
DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx)
DUK_EXTERNAL void duk_pop_2(duk_context *ctx)
DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx)
DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t index)
#define DUK_HOBJECT_GET_ENEXT(h)
#define DUK_HOBJECT_E_GET_KEY(heap, h, i)
#define DUK_PROPDESC_FLAGS_WE
DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t index)
DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t index)
#define DUK_STRIDX_INT_VARMAP
#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)
#define DUK_HOBJECT_SET_ENVRECCLOSED(h)
DUK_INTERNAL_DECL duk_hobject * duk_get_hobject(duk_context *ctx, duk_idx_t index)
DUK_EXTERNAL const char * duk_require_string(duk_context *ctx, duk_idx_t index)
DUK_INTERNAL_DECL duk_tval * duk_get_tval(duk_context *ctx, duk_idx_t index)

References DUK_ASSERT, DUK_ASSERT_DISABLE, DUK_DDD, DUK_DDDPRINT, duk_del_prop_stridx(), duk_get_hobject(), duk_get_number(), duk_get_prop_stridx(), duk_get_tval(), DUK_HOBJECT_E_GET_KEY, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR, DUK_HOBJECT_E_SLOT_IS_ACCESSOR, DUK_HOBJECT_GET_ENEXT, DUK_HOBJECT_HAS_ENVRECCLOSED, DUK_HOBJECT_IS_COMPILEDFUNCTION, DUK_HOBJECT_IS_DECENV, DUK_HOBJECT_SET_ENVRECCLOSED, duk_is_number(), duk_is_object(), duk_pop(), duk_pop_2(), DUK_PROPDESC_FLAGS_WE, duk_push_hobject(), duk_push_hstring(), duk_push_tval(), duk_require_hobject(), duk_require_string(), DUK_STRIDX_INT_CALLEE, DUK_STRIDX_INT_REGBASE, DUK_STRIDX_INT_THREAD, DUK_STRIDX_INT_VARMAP, DUK_TVAL_GET_NUMBER, DUK_TVAL_IS_NUMBER, duk_xdef_prop(), duk_hthread::heap, NULL, and duk_hthread::valstack.

◆ duk_js_declvar_activation()

DUK_INTERNAL duk_bool_t duk_js_declvar_activation ( duk_hthread * thr,
duk_activation * act,
duk_hstring * name,
duk_tval * val,
duk_small_int_t prop_flags,
duk_bool_t is_func_decl )

Definition at line 1792 of file duktape-1.8.0/src-separate/duk_js_var.c.

1797 {
1798 duk_hobject *env;
1799 duk_tval tv_val_copy;
1800 duk_size_t act_off;
1801
1802 DUK_ASSERT(act != NULL);
1803 act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack);
1804
1805 /*
1806 * Make a value copy of the input val. This ensures that
1807 * side effects cannot invalidate the pointer.
1808 */
1809
1810 DUK_TVAL_SET_TVAL(&tv_val_copy, val);
1811 val = &tv_val_copy;
1812
1813 /*
1814 * Delayed env creation check
1815 */
1816
1817 if (!act->var_env) {
1818 DUK_ASSERT(act->lex_env == NULL);
1820 act = (duk_activation *) ((duk_uint8_t *) thr->callstack + act_off);
1821 }
1822 DUK_ASSERT(act->lex_env != NULL);
1823 DUK_ASSERT(act->var_env != NULL);
1824
1825 env = act->var_env;
1826 DUK_ASSERT(env != NULL);
1828
1829 return duk__declvar_helper(thr, env, name, val, prop_flags, is_func_decl);
1830}
DUK_INTERNAL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act)
DUK_LOCAL duk_bool_t duk__declvar_helper(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl)

References duk_hthread::callstack, duk__declvar_helper(), DUK_ASSERT, DUK_HOBJECT_IS_ENV, duk_js_init_activation_environment_records_delayed(), DUK_TVAL_SET_TVAL, duk_activation::lex_env, name, NULL, and duk_activation::var_env.

◆ duk_js_delvar_activation()

DUK_INTERNAL duk_bool_t duk_js_delvar_activation ( duk_hthread * thr,
duk_activation * act,
duk_hstring * name )

Definition at line 1502 of file duktape-1.8.0/src-separate/duk_js_var.c.

1504 {
1505 DUK_ASSERT(act != NULL);
1506 return duk__delvar_helper(thr, act->lex_env, act, name);
1507}
DUK_LOCAL duk_bool_t duk__delvar_helper(duk_hthread *thr, duk_hobject *env, duk_activation *act, duk_hstring *name)

References duk__delvar_helper(), DUK_ASSERT, duk_activation::lex_env, name, and NULL.

◆ duk_js_getvar_activation()

DUK_INTERNAL duk_bool_t duk_js_getvar_activation ( duk_hthread * thr,
duk_activation * act,
duk_hstring * name,
duk_bool_t throw_flag )

Definition at line 1287 of file duktape-1.8.0/src-separate/duk_js_var.c.

1290 {
1291 DUK_ASSERT(act != NULL);
1292 return duk__getvar_helper(thr, act->lex_env, act, name, throw_flag);
1293}
DUK_LOCAL duk_bool_t duk__getvar_helper(duk_hthread *thr, duk_hobject *env, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag)

References duk__getvar_helper(), DUK_ASSERT, duk_activation::lex_env, name, and NULL.

◆ duk_js_getvar_envrec()

DUK_INTERNAL duk_bool_t duk_js_getvar_envrec ( duk_hthread * thr,
duk_hobject * env,
duk_hstring * name,
duk_bool_t throw_flag )

Definition at line 1279 of file duktape-1.8.0/src-separate/duk_js_var.c.

1282 {
1283 return duk__getvar_helper(thr, env, NULL, name, throw_flag);
1284}

References duk__getvar_helper(), name, and NULL.

◆ duk_js_init_activation_environment_records_delayed()

DUK_INTERNAL void duk_js_init_activation_environment_records_delayed ( duk_hthread * thr,
duk_activation * act )

Definition at line 529 of file duktape-1.8.0/src-separate/duk_js_var.c.

530 {
531 duk_context *ctx = (duk_context *) thr;
532 duk_hobject *func;
533 duk_hobject *env;
534 duk_size_t act_off;
535
536 DUK_ASSERT(act != NULL);
537 act_off = (duk_size_t) ((duk_uint8_t *) act - (duk_uint8_t *) thr->callstack);
538 func = DUK_ACT_GET_FUNC(act);
539 DUK_ASSERT(func != NULL);
540 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUND(func)); /* bound functions are never in act 'func' */
541
542 /*
543 * Delayed initialization only occurs for 'NEWENV' functions.
544 */
545
547 DUK_ASSERT(act->lex_env == NULL);
548 DUK_ASSERT(act->var_env == NULL);
549
551 DUK_ASSERT(env != NULL);
552 act = (duk_activation *) ((duk_uint8_t *) thr->callstack + act_off);
553
554 DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env));
555#ifdef DUK_USE_DDDPRINT
556 {
557 duk_hobject *p = env;
558 while (p) {
559 DUK_DDD(DUK_DDDPRINT(" -> %!ipO", (duk_heaphdr *) p));
560 p = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, p);
561 }
562 }
563#endif
564
565 act->lex_env = env;
566 act->var_env = env;
567 DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (here 2 times) */
568 DUK_HOBJECT_INCREF(thr, env);
569
570 duk_pop(ctx);
571}
#define DUK_HOBJECT_HAS_BOUND(h)
#define DUK_HOBJECT_INCREF(thr, h)
DUK_INTERNAL duk_hobject * duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom)

References duk_hthread::callstack, DUK_ACT_GET_FUNC, DUK_ASSERT, duk_create_activation_environment_record(), DUK_DDD, DUK_DDDPRINT, DUK_HOBJECT_GET_PROTOTYPE, DUK_HOBJECT_HAS_BOUND, DUK_HOBJECT_HAS_NEWENV, DUK_HOBJECT_INCREF, duk_pop(), duk_hthread::heap, duk_activation::idx_bottom, duk_activation::lex_env, NULL, and duk_activation::var_env.

Referenced by duk_js_declvar_activation().

◆ duk_js_push_closure()

DUK_INTERNAL void duk_js_push_closure ( duk_hthread * thr,
duk_hcompiledfunction * fun_temp,
duk_hobject * outer_var_env,
duk_hobject * outer_lex_env,
duk_bool_t add_auto_proto )

Definition at line 118 of file duktape-1.8.0/src-separate/duk_js_var.c.

122 {
123 duk_context *ctx = (duk_context *) thr;
124 duk_hcompiledfunction *fun_clos;
126 duk_uint_t len_value;
127
128 DUK_ASSERT(fun_temp != NULL);
132 DUK_ASSERT(outer_var_env != NULL);
133 DUK_ASSERT(outer_lex_env != NULL);
134 DUK_UNREF(len_value);
135
137 duk_push_hobject(ctx, &fun_temp->obj); /* -> [ ... closure template ] */
138
139 fun_clos = (duk_hcompiledfunction *) duk_get_hcompiledfunction(ctx, -2);
140 DUK_ASSERT(fun_clos != NULL);
145
149
150 /* Note: all references inside 'data' need to get their refcounts
151 * upped too. This is the case because refcounts are decreased
152 * through every function referencing 'data' independently.
153 */
154
156 duk__inc_data_inner_refcounts(thr, fun_temp);
157
158 fun_clos->nregs = fun_temp->nregs;
159 fun_clos->nargs = fun_temp->nargs;
160#if defined(DUK_USE_DEBUGGER_SUPPORT)
161 fun_clos->start_line = fun_temp->start_line;
162 fun_clos->end_line = fun_temp->end_line;
163#endif
164
168
169 /* XXX: could also copy from template, but there's no way to have any
170 * other value here now (used code has no access to the template).
171 */
173
174 /*
175 * Init/assert flags, copying them where appropriate. Some flags
176 * (like NEWENV) are processed separately below.
177 */
178
179 /* XXX: copy flags using a mask */
180
182 DUK_HOBJECT_SET_CONSTRUCTABLE(&fun_clos->obj); /* Note: not set in template (has no "prototype") */
188 /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */
189 if (DUK_HOBJECT_HAS_STRICT(&fun_temp->obj)) {
190 DUK_HOBJECT_SET_STRICT(&fun_clos->obj);
191 }
192 if (DUK_HOBJECT_HAS_NOTAIL(&fun_temp->obj)) {
193 DUK_HOBJECT_SET_NOTAIL(&fun_clos->obj);
194 }
195 /* DUK_HOBJECT_FLAG_NEWENV: handled below */
196 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
197 /* Although NAMEBINDING is not directly needed for using
198 * function instances, it's needed by bytecode dump/load
199 * so copy it too.
200 */
202 }
203 if (DUK_HOBJECT_HAS_CREATEARGS(&fun_temp->obj)) {
205 }
209
210 /*
211 * Setup environment record properties based on the template and
212 * its flags.
213 *
214 * If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment
215 * records represent identifiers "outside" the function; the
216 * "inner" environment records are created on demand. Otherwise,
217 * the environment records are those that will be directly used
218 * (e.g. for declarations).
219 *
220 * _Lexenv is always set; _Varenv defaults to _Lexenv if missing,
221 * so _Varenv is only set if _Lexenv != _Varenv.
222 *
223 * This is relatively complex, see doc/identifier-handling.rst.
224 */
225
226 if (DUK_HOBJECT_HAS_NEWENV(&fun_temp->obj)) {
227 DUK_HOBJECT_SET_NEWENV(&fun_clos->obj);
228
229 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj)) {
231
232 /*
233 * Named function expression, name needs to be bound
234 * in an intermediate environment record. The "outer"
235 * lexical/variable environment will thus be:
236 *
237 * a) { funcname: <func>, __prototype: outer_lex_env }
238 * b) { funcname: <func>, __prototype: <globalenv> } (if outer_lex_env missing)
239 */
240
241 DUK_ASSERT(duk_has_prop_stridx(ctx, -1, DUK_STRIDX_NAME)); /* required if NAMEBINDING set */
242
243 if (outer_lex_env) {
244 proto = outer_lex_env;
245 } else {
247 }
248
249 /* -> [ ... closure template env ] */
253 proto);
254
255 /* It's important that duk_xdef_prop() is a 'raw define' so that any
256 * properties in an ancestor are never an issue (they should never be
257 * e.g. non-writable, but just in case).
258 */
259 duk_get_prop_stridx(ctx, -2, DUK_STRIDX_NAME); /* -> [ ... closure template env funcname ] */
260 duk_dup(ctx, -4); /* -> [ ... closure template env funcname closure ] */
261 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
262 /* env[funcname] = closure */
263
264 /* [ ... closure template env ] */
265
267 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
268 * will be ignored anyway
269 */
270
271 /* [ ... closure template ] */
272 } else {
273 /*
274 * Other cases (function declaration, anonymous function expression,
275 * strict direct eval code). The "outer" environment will be whatever
276 * the caller gave us.
277 */
278
279 duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
281 /* since closure has NEWENV, never define DUK_STRIDX_INT_VARENV, as it
282 * will be ignored anyway
283 */
284
285 /* [ ... closure template ] */
286 }
287 } else {
288 /*
289 * Function gets no new environment when called. This is the
290 * case for global code, indirect eval code, and non-strict
291 * direct eval code. There is no direct correspondence to the
292 * E5 specification, as global/eval code is not exposed as a
293 * function.
294 */
295
297
298 duk_push_hobject(ctx, outer_lex_env); /* -> [ ... closure template env ] */
300
301 if (outer_var_env != outer_lex_env) {
302 duk_push_hobject(ctx, outer_var_env); /* -> [ ... closure template env ] */
304 }
305 }
306#ifdef DUK_USE_DDDPRINT
309 DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipT, lexenv -> %!ipT",
310 (duk_tval *) duk_get_tval(ctx, -2),
311 (duk_tval *) duk_get_tval(ctx, -1)));
312 duk_pop_2(ctx);
313#endif
314
315 /*
316 * Copy some internal properties directly
317 *
318 * The properties will be writable and configurable, but not enumerable.
319 */
320
321 /* [ ... closure template ] */
322
323 DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT",
324 (duk_tval *) duk_get_tval(ctx, -2),
325 (duk_tval *) duk_get_tval(ctx, -1)));
326
327 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
329 if (duk_get_prop_stridx(ctx, -1, stridx)) {
330 /* [ ... closure template val ] */
331 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx));
333 } else {
334 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx));
335 duk_pop(ctx);
336 }
337 }
338
339 /*
340 * "length" maps to number of formals (E5 Section 13.2) for function
341 * declarations/expressions (non-bound functions). Note that 'nargs'
342 * is NOT necessarily equal to the number of arguments.
343 */
344
345 /* [ ... closure template ] */
346
347 len_value = 0;
348
349 /* XXX: use helper for size optimization */
351 /* [ ... closure template formals ] */
353 DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_UINT_MAX); /* formal arg limits */
354 len_value = (duk_uint_t) duk_get_length(ctx, -1);
355 } else {
356 /* XXX: what to do if _Formals is not empty but compiler has
357 * optimized it away -- read length from an explicit property
358 * then?
359 */
360 }
361 duk_pop(ctx);
362
363 duk_push_uint(ctx, len_value); /* [ ... closure template len_value ] */
365
366 /*
367 * "prototype" is, by default, a fresh object with the "constructor"
368 * property.
369 *
370 * Note that this creates a circular reference for every function
371 * instance (closure) which prevents refcount-based collection of
372 * function instances.
373 *
374 * XXX: Try to avoid creating the default prototype object, because
375 * many functions are not used as constructors and the default
376 * prototype is unnecessary. Perhaps it could be created on-demand
377 * when it is first accessed?
378 */
379
380 /* [ ... closure template ] */
381
382 if (add_auto_proto) {
383 duk_push_object(ctx); /* -> [ ... closure template newobj ] */
384 duk_dup(ctx, -3); /* -> [ ... closure template newobj closure ] */
385 duk_xdef_prop_stridx(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
386 duk_compact(ctx, -1); /* compact the prototype */
387 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
388 }
389
390 /*
391 * "arguments" and "caller" must be mapped to throwers for strict
392 * mode and bound functions (E5 Section 15.3.5).
393 *
394 * XXX: This is expensive to have for every strict function instance.
395 * Try to implement as virtual properties or on-demand created properties.
396 */
397
398 /* [ ... closure template ] */
399
400 if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
403 } else {
404#ifdef DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
405 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value"));
406 duk_push_null(ctx);
408#else
409 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used"));
410#endif
411 }
412
413 /*
414 * "name" is a non-standard property found in at least V8, Rhino, smjs.
415 * For Rhino and smjs it is non-writable, non-enumerable, and non-configurable;
416 * for V8 it is writable, non-enumerable, non-configurable. It is also defined
417 * for an anonymous function expression in which case the value is an empty string.
418 * We could also leave name 'undefined' for anonymous functions but that would
419 * differ from behavior of other engines, so use an empty string.
420 *
421 * XXX: make optional? costs something per function.
422 */
423
424 /* [ ... closure template ] */
425
426 if (duk_get_prop_stridx(ctx, -1, DUK_STRIDX_NAME)) {
427 /* [ ... closure template name ] */
428 DUK_ASSERT(duk_is_string(ctx, -1));
429 } else {
430 /* [ ... closure template undefined ] */
431 duk_pop(ctx);
433 }
434 duk_xdef_prop_stridx(ctx, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template ] */
435
436 /*
437 * Compact the closure, in most cases no properties will be added later.
438 * Also, without this the closures end up having unused property slots
439 * (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used).
440 * A better future solution would be to allocate the closure directly
441 * to correct size (and setup the properties directly without going
442 * through the API).
443 */
444
445 duk_compact(ctx, -2);
446
447 /*
448 * Some assertions (E5 Section 13.2).
449 */
450
455 DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE) != 0);
456 DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_NAME) != 0); /* non-standard */
461
462 /*
463 * Finish
464 */
465
466 /* [ ... closure template ] */
467
468 DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT",
469 (duk_tval *) duk_get_tval(ctx, -1),
470 (duk_tval *) duk_get_tval(ctx, -2)));
471
472 duk_pop(ctx);
473
474 /* [ ... closure ] */
475}
const char * proto
Definition civetweb.c:18378
unsigned int duk_small_uint_t
#define DUK_HCOMPILEDFUNCTION_SET_FUNCS(heap, h, v)
DUK_INTERNAL_DECL duk_idx_t duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto)
#define DUK_HCOMPILEDFUNCTION_SET_BYTECODE(heap, h, v)
#define DUK_HBUFFER_INCREF(thr, h)
#define DUK_STRIDX_INT_FORMALS
#define DUK_STRIDX_LC_ARGUMENTS
DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_index)
#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)
DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t index)
#define DUK_HOBJECT_SET_CREATEARGS(h)
#define DUK_HOBJECT_HAS_CREATEARGS(h)
DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx)
#define DUK_BIDX_FUNCTION_PROTOTYPE
#define DUK_PROPDESC_FLAGS_NONE
DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_int_t stridx)
#define DUK_HOBJECT_CLASS_FUNCTION
#define DUK_STRIDX_CONSTRUCTOR
#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h)
#define DUK_HCOMPILEDFUNCTION_SET_DATA(heap, h, v)
DUK_EXTERNAL void duk_push_null(duk_context *ctx)
#define DUK_HOBJECT_SET_NOTAIL(h)
#define DUK_HOBJECT_SET_STRICT(h)
#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)
#define DUK_STRIDX_INT_LEXENV
DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx)
#define DUK_STRIDX_EMPTY_STRING
DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_index)
#define DUK_HOBJECT_HAS_NATIVEFUNCTION(h)
DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val)
#define DUK_HOBJECT_HAS_THREAD(h)
#define DUK_HCOMPILEDFUNCTION_GET_FUNCS(heap, h)
DUK_INTERNAL_DECL duk_hcompiledfunction * duk_get_hcompiledfunction(duk_context *ctx, duk_idx_t index)
#define DUK_HOBJECT_SET_CONSTRUCTABLE(h)
#define DUK_PROPDESC_FLAGS_WC
DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags)
#define DUK_STRIDX_INT_VARENV
DUK_INTERNAL_DECL duk_idx_t duk_push_compiledfunction(duk_context *ctx)
#define DUK_HOBJECT_SET_NAMEBINDING(h)
DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_index, duk_small_int_t stridx, duk_small_uint_t desc_flags)
DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t index)
#define DUK_HOBJECT_HAS_STRICT(h)
#define DUK_HCOMPILEDFUNCTION_GET_BYTECODE(heap, h)
#define DUK_HOBJECT_HAS_NOTAIL(h)
#define DUK_HOBJECT_SET_NEWENV(h)
#define DUK_HOBJECT_HAS_COMPILEDFUNCTION(h)
#define DUK_HOBJECT_HAS_NAMEBINDING(h)
DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[]
DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompiledfunction *f)

References duk_hthread::builtins, duk__closure_copy_proplist, duk__inc_data_inner_refcounts(), DUK_ASSERT, DUK_BIDX_FUNCTION_PROTOTYPE, DUK_BIDX_GLOBAL_ENV, duk_compact(), DUK_DDD, DUK_DDDPRINT, duk_dup(), duk_get_hcompiledfunction(), duk_get_length(), duk_get_prop_stridx(), duk_get_tval(), duk_has_prop_stridx(), DUK_HBUFFER_INCREF, DUK_HCOMPILEDFUNCTION_GET_BYTECODE, DUK_HCOMPILEDFUNCTION_GET_DATA, DUK_HCOMPILEDFUNCTION_GET_FUNCS, DUK_HCOMPILEDFUNCTION_SET_BYTECODE, DUK_HCOMPILEDFUNCTION_SET_DATA, DUK_HCOMPILEDFUNCTION_SET_FUNCS, DUK_HOBJECT_CLASS_AS_FLAGS, DUK_HOBJECT_CLASS_DECENV, DUK_HOBJECT_CLASS_FUNCTION, DUK_HOBJECT_FLAG_EXTENSIBLE, DUK_HOBJECT_GET_CLASS_NUMBER, DUK_HOBJECT_GET_PROTOTYPE, DUK_HOBJECT_HAS_BOUND, DUK_HOBJECT_HAS_COMPILEDFUNCTION, DUK_HOBJECT_HAS_CONSTRUCTABLE, DUK_HOBJECT_HAS_CREATEARGS, DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS, DUK_HOBJECT_HAS_EXOTIC_ARRAY, DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ, DUK_HOBJECT_HAS_EXTENSIBLE, DUK_HOBJECT_HAS_NAMEBINDING, DUK_HOBJECT_HAS_NATIVEFUNCTION, DUK_HOBJECT_HAS_NEWENV, DUK_HOBJECT_HAS_NOTAIL, DUK_HOBJECT_HAS_STRICT, DUK_HOBJECT_HAS_THREAD, DUK_HOBJECT_IS_COMPILEDFUNCTION, DUK_HOBJECT_SET_CONSTRUCTABLE, DUK_HOBJECT_SET_CREATEARGS, DUK_HOBJECT_SET_NAMEBINDING, DUK_HOBJECT_SET_NEWENV, DUK_HOBJECT_SET_NOTAIL, DUK_HOBJECT_SET_PROTOTYPE_UPDREF, DUK_HOBJECT_SET_STRICT, duk_is_string(), duk_pop(), duk_pop_2(), DUK_PROPDESC_FLAGS_NONE, DUK_PROPDESC_FLAGS_W, DUK_PROPDESC_FLAGS_WC, duk_push_compiledfunction(), duk_push_hobject(), duk_push_hstring_stridx(), duk_push_null(), duk_push_object(), duk_push_object_helper_proto(), duk_push_uint(), DUK_STRIDX_CALLER, DUK_STRIDX_CONSTRUCTOR, DUK_STRIDX_EMPTY_STRING, DUK_STRIDX_INT_FORMALS, DUK_STRIDX_INT_LEXENV, DUK_STRIDX_INT_VARENV, DUK_STRIDX_LC_ARGUMENTS, DUK_STRIDX_LENGTH, DUK_STRIDX_NAME, DUK_STRIDX_PROTOTYPE, DUK_UINT_MAX, DUK_UNREF, duk_xdef_prop(), duk_xdef_prop_stridx(), duk_xdef_prop_stridx_thrower(), duk_hthread::heap, duk_hcompiledfunction::nargs, duk_hcompiledfunction::nregs, NULL, duk_hcompiledfunction::obj, and proto.

◆ duk_js_putvar_activation()

DUK_INTERNAL void duk_js_putvar_activation ( duk_hthread * thr,
duk_activation * act,
duk_hstring * name,
duk_tval * val,
duk_bool_t strict )

Definition at line 1417 of file duktape-1.8.0/src-separate/duk_js_var.c.

1421 {
1422 DUK_ASSERT(act != NULL);
1423 duk__putvar_helper(thr, act->lex_env, act, name, val, strict);
1424}
DUK_LOCAL void duk__putvar_helper(duk_hthread *thr, duk_hobject *env, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict)

References duk__putvar_helper(), DUK_ASSERT, duk_activation::lex_env, name, and NULL.

◆ duk_js_putvar_envrec()

DUK_INTERNAL void duk_js_putvar_envrec ( duk_hthread * thr,
duk_hobject * env,
duk_hstring * name,
duk_tval * val,
duk_bool_t strict )

Definition at line 1408 of file duktape-1.8.0/src-separate/duk_js_var.c.

1412 {
1413 duk__putvar_helper(thr, env, NULL, name, val, strict);
1414}

References duk__putvar_helper(), name, and NULL.

Variable Documentation

◆ duk__closure_copy_proplist

DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[]