DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) { #if defined(DUK_USE_EXPLICIT_NULL_INIT) DUK_HOBJECT_SET_PROPS(heap, obj, NULL); #endif /* XXX: macro? sets both heaphdr and object flags */ obj->hdr.h_flags = hobject_flags; DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT); /* also goes into flags */ #if defined(DUK_USE_HEAPPTR16) /* Zero encoded pointer is required to match NULL */ DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL); #if defined(DUK_USE_DOUBLE_LINKED_HEAP) DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL); #endif #endif DUK_ASSERT_HEAPHDR_LINKS(heap, &obj->hdr); DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr); /* * obj->props is intentionally left as NULL, and duk_hobject_props.c must deal * with this properly. This is intentional: empty objects consume a minimum * amount of memory. Further, an initial allocation might fail and cause * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet. */ }
DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) { duk_context *ctx; duk_hobject *h1; #if defined(DUK_USE_ROM_GLOBAL_CLONE) duk_hobject *h2; duk_uint8_t *props; duk_size_t alloc_size; #endif ctx = (duk_context *) thr; /* XXX: refactor into internal helper, duk_clone_hobject() */ #if defined(DUK_USE_ROM_GLOBAL_INHERIT) /* Inherit from ROM-based global object: less RAM usage, less transparent. */ duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), DUK_BIDX_GLOBAL); h1 = duk_get_hobject(ctx, -1); DUK_ASSERT(h1 != NULL); #elif defined(DUK_USE_ROM_GLOBAL_CLONE) /* Clone the properties of the ROM-based global object to create a * fully RAM-based global object. Uses more memory than the inherit * model but more compliant. */ duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL), DUK_BIDX_OBJECT_PROTOTYPE); h1 = duk_get_hobject(ctx, -1); DUK_ASSERT(h1 != NULL); h2 = thr->builtins[DUK_BIDX_GLOBAL]; DUK_ASSERT(h2 != NULL); /* Copy the property table verbatim; this handles attributes etc. * For ROM objects it's not necessary (or possible) to update * refcounts so leave them as is. */ alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2); DUK_ASSERT(alloc_size > 0); props = DUK_ALLOC(thr->heap, alloc_size); if (!props) { DUK_ERROR_ALLOC_FAILED(thr); return; } DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL); DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size); /* XXX: keep property attributes or tweak them here? * Properties will now be non-configurable even when they're * normally configurable for the global object. */ DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL); DUK_HOBJECT_SET_PROPS(thr->heap, h1, props); DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2)); DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2)); DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2)); DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2)); #else #error internal error in defines #endif duk_hobject_compact_props(thr, h1); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL); DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref */ thr->builtins[DUK_BIDX_GLOBAL] = h1; DUK_HOBJECT_INCREF(thr, h1); DUK_D(DUK_DPRINT("duplicated global object: %!O", h1)); /* Create a fresh object environment for the global scope. This is * needed so that the global scope points to the newly created RAM-based * global object. */ duk_push_object_helper(ctx, DUK_HOBJECT_FLAG_EXTENSIBLE | DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV), -1); /* no prototype */ h1 = duk_get_hobject(ctx, -1); DUK_ASSERT(h1 != NULL); duk_dup(ctx, -2); duk_dup(ctx, -1); /* -> [ ... new_global new_globalenv new_global new_global ] */ duk_xdef_prop_stridx(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE); duk_xdef_prop_stridx(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */ duk_hobject_compact_props(thr, h1); DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL); DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref */ thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1; DUK_HOBJECT_INCREF(thr, h1); DUK_D(DUK_DPRINT("duplicated global env: %!O", h1)); duk_pop_2(ctx); }