static void setup_argv(struct Parrot_Interp *interpreter, int argc, char ** argv) { INTVAL i; PMC *userargv; if (Interp_flags_TEST(interpreter, PARROT_DEBUG_FLAG)) { PIO_eprintf(interpreter, "*** Parrot VM: Setting up ARGV array in P5. Current argc: %d ***\n", argc); } userargv = pmc_new_noinit(interpreter, enum_class_SArray); /* immediately anchor pmc to root set */ interpreter->pmc_reg.registers[5] = userargv; VTABLE_set_pmc_keyed_int(interpreter, interpreter->iglobals, (INTVAL)IGLOBALS_ARGV_LIST, userargv); VTABLE_init(interpreter, userargv); VTABLE_set_integer_native(interpreter, userargv, argc); for (i = 0; i < argc; i++) { /* Run through argv, adding everything to @ARGS. */ STRING *arg = string_make(interpreter, argv[i], strlen(argv[i]), 0, PObj_external_FLAG, 0); if (Interp_flags_TEST(interpreter, PARROT_DEBUG_FLAG)) { PIO_eprintf(interpreter, "\t%vd: %s\n", i, argv[i]); } VTABLE_push_string(interpreter, userargv, arg); } }
/* can't really use xsubpp here... */ extern XS(blizkost_callable_trampoline) { #ifdef dVAR dVAR; #endif dXSARGS; PMC *callable; blizkost_nexus *nexus; int i; PMC *args, *posret, *namret; blizkost_get_bound_pmc(my_perl, &nexus, (SV *)cv, &callable); if (nexus->dying) exit_fatal(1, "Attempted reentry of Parrot code during global destruction"); PERL_UNUSED_VAR(ax); SP -= items; PUTBACK; args = Parrot_pmc_new_init_int(nexus->parrot_interp, enum_class_ResizablePMCArray, items); for (i = 0; i < items; i++) { SV *svarg = ST(i); PMC *pmcarg = blizkost_wrap_sv(nexus, svarg); VTABLE_set_pmc_keyed_int(nexus->parrot_interp, args, i, pmcarg); } Parrot_pcc_invoke_sub_from_c_args(nexus->parrot_interp, callable, "Pf->PsPsn", args, &posret, &namret); blizkost_slurpy_to_stack(nexus, posret, namret); SPAGAIN; }
PARROT_EXPORT void Parrot_set_executable_name(PARROT_INTERP, Parrot_String name) { PMC * const name_pmc = pmc_new(interp, enum_class_String); VTABLE_set_string_native(interp, name_pmc, name); VTABLE_set_pmc_keyed_int(interp, interp->iglobals, IGLOBALS_EXECUTABLE, name_pmc); }
/* Sets up a very simple attribute meta-object. Just supports having a * name, and even uses the P6str representation to store it, so that's * really all that it supports. */ PMC * SixModelObject_setup_knowhow_attribute(PARROT_INTERP, PMC *sc, PMC *knowhow) { PMC *old_ctx, *cappy, *meth, *knowhow_attr, *how; /* Create a new KnowHOWAttribute type using P6str repr.. */ meth = STABLE(knowhow)->find_method(interp, knowhow, Parrot_str_new_constant(interp, "new_type"), NO_HINT); old_ctx = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)); cappy = Parrot_pmc_new(interp, enum_class_CallContext); VTABLE_push_pmc(interp, cappy, knowhow); VTABLE_set_string_keyed_str(interp, cappy, name_str, Parrot_str_new_constant(interp, "KnowHOWAttribute")); VTABLE_set_string_keyed_str(interp, cappy, repr_str, Parrot_str_new_constant(interp, "P6str")); Parrot_pcc_invoke_from_sig_object(interp, meth, cappy); cappy = Parrot_pcc_get_signature(interp, CURRENT_CONTEXT(interp)); Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx); knowhow_attr = VTABLE_get_pmc_keyed_int(interp, cappy, 0); how = STABLE(knowhow_attr)->HOW; /* Add new method. */ meth = STABLE(how)->find_method(interp, how, Parrot_str_new_constant(interp, "add_method"), NO_HINT); cappy = Parrot_pmc_new(interp, enum_class_CallContext); VTABLE_push_pmc(interp, cappy, how); VTABLE_push_pmc(interp, cappy, knowhow_attr); VTABLE_push_string(interp, cappy, Parrot_str_new_constant(interp, "new")); VTABLE_push_pmc(interp, cappy, wrap_c(interp, F2DPTR(attr_new))); Parrot_pcc_invoke_from_sig_object(interp, meth, cappy); Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx); /* Add name method. */ cappy = Parrot_pmc_new(interp, enum_class_CallContext); VTABLE_push_pmc(interp, cappy, how); VTABLE_push_pmc(interp, cappy, knowhow_attr); VTABLE_push_string(interp, cappy, name_str); VTABLE_push_pmc(interp, cappy, wrap_c(interp, F2DPTR(attr_name))); Parrot_pcc_invoke_from_sig_object(interp, meth, cappy); Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx); /* Compose. */ meth = STABLE(knowhow)->find_method(interp, how, Parrot_str_new_constant(interp, "compose"), NO_HINT); cappy = Parrot_pmc_new(interp, enum_class_CallContext); VTABLE_push_pmc(interp, cappy, how); VTABLE_push_pmc(interp, cappy, knowhow_attr); Parrot_pcc_invoke_from_sig_object(interp, meth, cappy); Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), old_ctx); /* Associate the created object with the intial core serialization * context. */ VTABLE_set_pmc_keyed_int(interp, sc, 2, knowhow_attr); SC_PMC(knowhow_attr) = sc; STABLE(knowhow_attr)->sc = sc; return knowhow_attr; }
/* Takes an STable and adds it to this SC's root set, and installs a * reposession entry. */ void SC_repossess_stable(PARROT_INTERP, PMC *target_sc, PMC *orig_sc, PMC *st_pmc) { PMC *rep_indexes, *rep_scs; /* Add to root set. */ PMC *stables; INTVAL new_slot; GETATTR_SerializationContext_root_stables(interp, target_sc, stables); new_slot = VTABLE_elements(interp, stables); VTABLE_set_pmc_keyed_int(interp, stables, new_slot, st_pmc); /* Add repossession entry. */ GETATTR_SerializationContext_rep_indexes(interp, target_sc, rep_indexes); GETATTR_SerializationContext_rep_scs(interp, target_sc, rep_scs); VTABLE_push_integer(interp, rep_indexes, (new_slot << 1) | 1); VTABLE_push_pmc(interp, rep_scs, orig_sc); }
/* This function gets shared with perl6.ops for the perl6_parcel_from_rpa op. */ PMC * Rakudo_binding_parcel_from_rpa(PARROT_INTERP, PMC *rpa, PMC *fill) { PMC *type = Rakudo_types_parcel_get(); PMC *parcel = REPR(type)->allocate(interp, STABLE(type)); VTABLE_set_attr_keyed(interp, parcel, type, STORAGE_str, rpa); if (!PMC_IS_NULL(fill)) { INTVAL elems = VTABLE_elements(interp, rpa); INTVAL i; for (i = 0; i < elems; i++) { if (PMC_IS_NULL(VTABLE_get_pmc_keyed_int(interp, rpa, i))) VTABLE_set_pmc_keyed_int(interp, rpa, i, fill); } } return parcel; }
static void parrot_set_config_hash_interpreter(PARROT_INTERP) { ASSERT_ARGS(parrot_set_config_hash_interpreter) PMC *iglobals = interp->iglobals; PMC *config_hash = NULL; if (parrot_config_size_stored > 1) { STRING * const config_string = Parrot_str_new_init(interp, (const char *)parrot_config_stored, parrot_config_size_stored, Parrot_default_encoding_ptr, PObj_external_FLAG|PObj_constant_FLAG); config_hash = Parrot_thaw(interp, config_string); } else { config_hash = Parrot_pmc_new(interp, enum_class_Hash); } VTABLE_set_pmc_keyed_int(interp, iglobals, (INTVAL) IGLOBALS_CONFIG_HASH, config_hash); }
/* Bootstraps the KnowHOW. This is were things "bottom out" in the meta-model * so it's a tad loopy. Basically, we create a KnowHOW type object. We then * create an instance from that and add a bunch of methods to it. Returns the * bootstrapped object. */ PMC * SixModelObject_bootstrap_knowhow(PARROT_INTERP, PMC *sc) { /* Create our KnowHOW type object. Note we don't have a HOW just yet, so * pass in null. */ REPROps *REPR = REPR_get_by_name(interp, Parrot_str_new_constant(interp, "KnowHOWREPR")); PMC *knowhow_pmc = REPR->type_object_for(interp, PMCNULL); /* We create a KnowHOW instance that can describe itself. This means * .HOW.HOW.HOW.HOW etc will always return that, which closes the model * up. Also pull out its underlying struct. */ PMC *knowhow_how_pmc = REPR->allocate(interp, NULL); KnowHOWREPRInstance *knowhow_how = (KnowHOWREPRInstance *)PMC_data(knowhow_how_pmc); /* Need to give the knowhow_how a twiddled STable with a different * dispatcher, so things bottom out. */ PMC *st_copy = create_stable(interp, REPR, knowhow_how_pmc); STABLE_STRUCT(st_copy)->WHAT = knowhow_pmc; STABLE_STRUCT(st_copy)->find_method = bottom_find_method; knowhow_how->common.stable = st_copy; /* Add various methods to the KnowHOW's HOW. */ knowhow_how->body.methods = Parrot_pmc_new(interp, enum_class_Hash); knowhow_how->body.attributes = Parrot_pmc_new(interp, enum_class_ResizablePMCArray); VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods, Parrot_str_new_constant(interp, "new_type"), wrap_c(interp, F2DPTR(new_type))); VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods, Parrot_str_new_constant(interp, "find_method"), wrap_c(interp, F2DPTR(find_method))); VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods, Parrot_str_new_constant(interp, "add_method"), wrap_c(interp, F2DPTR(add_method))); VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods, Parrot_str_new_constant(interp, "add_attribute"), wrap_c(interp, F2DPTR(add_attribute))); VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods, Parrot_str_new_constant(interp, "compose"), wrap_c(interp, F2DPTR(compose))); VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods, Parrot_str_new_constant(interp, "parents"), wrap_c(interp, F2DPTR(parents))); VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods, Parrot_str_new_constant(interp, "attributes"), wrap_c(interp, F2DPTR(attributes))); VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods, Parrot_str_new_constant(interp, "methods"), wrap_c(interp, F2DPTR(methods))); VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods, Parrot_str_new_constant(interp, "mro"), wrap_c(interp, F2DPTR(mro))); VTABLE_set_pmc_keyed_str(interp, knowhow_how->body.methods, Parrot_str_new_constant(interp, "name"), wrap_c(interp, F2DPTR(name))); /* Set name KnowHOW for the KnowHOW's HOW. */ knowhow_how->body.name = Parrot_str_new_constant(interp, "KnowHOW"); /* Set this built up HOW as the KnowHOW's HOW. */ STABLE(knowhow_pmc)->HOW = knowhow_how_pmc; /* Give it an authoritative method cache. */ STABLE(knowhow_pmc)->method_cache = knowhow_how->body.methods; STABLE(knowhow_pmc)->mode_flags = METHOD_CACHE_AUTHORITATIVE; /* Set up some string constants that the methods here use. */ repr_str = Parrot_str_new_constant(interp, "repr"); name_str = Parrot_str_new_constant(interp, "name"); empty_str = Parrot_str_new_constant(interp, ""); p6opaque_str = Parrot_str_new_constant(interp, "P6opaque"); /* Associate the created objects with the intial core serialization * context. */ VTABLE_set_pmc_keyed_int(interp, sc, 0, knowhow_pmc); SC_PMC(knowhow_pmc) = sc; VTABLE_set_pmc_keyed_int(interp, sc, 1, knowhow_how_pmc); SC_PMC(knowhow_how_pmc) = sc; STABLE(knowhow_pmc)->sc = sc; STABLE(knowhow_how_pmc)->sc = sc; return knowhow_pmc; }
void parrot_init_library_paths(PARROT_INTERP) { ASSERT_ARGS(parrot_init_library_paths) PMC *paths; STRING *entry; STRING *versionlib = NULL; STRING *builddir = NULL; PMC * const iglobals = interp->iglobals; PMC * const config_hash = VTABLE_get_pmc_keyed_int(interp, iglobals, (INTVAL)IGLOBALS_CONFIG_HASH); /* create the lib_paths array */ PMC * const lib_paths = Parrot_pmc_new_init_int(interp, enum_class_FixedPMCArray, PARROT_LIB_PATH_SIZE); VTABLE_set_pmc_keyed_int(interp, iglobals, IGLOBALS_LIB_PATHS, lib_paths); if (VTABLE_elements(interp, config_hash)) { STRING * const libkey = CONST_STRING(interp, "libdir"); STRING * const verkey = CONST_STRING(interp, "versiondir"); STRING * const builddirkey = CONST_STRING(interp, "build_dir"); STRING * const installed = CONST_STRING(interp, "installed"); versionlib = VTABLE_get_string_keyed_str(interp, config_hash, libkey); entry = VTABLE_get_string_keyed_str(interp, config_hash, verkey); versionlib = Parrot_str_concat(interp, versionlib, entry); if (!VTABLE_get_integer_keyed_str(interp, config_hash, installed)) builddir = VTABLE_get_string_keyed_str(interp, config_hash, builddirkey); } /* each is an array of strings */ /* define include paths */ paths = Parrot_pmc_new(interp, enum_class_ResizableStringArray); VTABLE_set_pmc_keyed_int(interp, lib_paths, PARROT_LIB_PATH_INCLUDE, paths); { /* EXPERIMENTAL: add include path from environment */ const char *envvar = Parrot_getenv(interp, Parrot_str_new_constant(interp, "PARROT_INCLUDE")); if (envvar != NULL && envvar[0]) { entry = Parrot_str_new(interp, envvar, 0); VTABLE_push_string(interp, paths, entry); } } if (!STRING_IS_NULL(builddir)) { entry = Parrot_str_concat(interp, builddir, CONST_STRING(interp, "/")); VTABLE_push_string(interp, paths, entry); entry = Parrot_str_concat(interp, builddir, CONST_STRING(interp, "/runtime/parrot/include/")); VTABLE_push_string(interp, paths, entry); } entry = CONST_STRING(interp, "./"); VTABLE_push_string(interp, paths, entry); if (!STRING_IS_NULL(versionlib)) { entry = Parrot_str_concat(interp, versionlib, CONST_STRING(interp, "/include/")); VTABLE_push_string(interp, paths, entry); } /* define library paths */ paths = Parrot_pmc_new(interp, enum_class_ResizableStringArray); VTABLE_set_pmc_keyed_int(interp, lib_paths, PARROT_LIB_PATH_LIBRARY, paths); { /* EXPERIMENTAL: add library path from environment */ const char *envvar = Parrot_getenv(interp, Parrot_str_new_constant(interp, "PARROT_LIBRARY")); if (envvar != NULL && envvar[0]) { entry = Parrot_str_new(interp, envvar, 0); VTABLE_push_string(interp, paths, entry); } } if (!STRING_IS_NULL(builddir)) { entry = Parrot_str_concat(interp, builddir, CONST_STRING(interp, "/runtime/parrot/library/")); VTABLE_push_string(interp, paths, entry); } entry = CONST_STRING(interp, "./"); VTABLE_push_string(interp, paths, entry); if (!STRING_IS_NULL(versionlib)) { entry = Parrot_str_concat(interp, versionlib, CONST_STRING(interp, "/library/")); VTABLE_push_string(interp, paths, entry); } /* define languages paths */ paths = Parrot_pmc_new(interp, enum_class_ResizableStringArray); VTABLE_set_pmc_keyed_int(interp, lib_paths, PARROT_LIB_PATH_LANG, paths); if (!STRING_IS_NULL(builddir)) { entry = Parrot_str_concat(interp, builddir, CONST_STRING(interp, "/runtime/parrot/languages/")); VTABLE_push_string(interp, paths, entry); } entry = CONST_STRING(interp, "./"); VTABLE_push_string(interp, paths, entry); if (!STRING_IS_NULL(versionlib)) { entry = Parrot_str_concat(interp, versionlib, CONST_STRING(interp, "/languages/")); VTABLE_push_string(interp, paths, entry); } /* define dynext paths */ paths = Parrot_pmc_new(interp, enum_class_ResizableStringArray); VTABLE_set_pmc_keyed_int(interp, lib_paths, PARROT_LIB_PATH_DYNEXT, paths); if (!STRING_IS_NULL(builddir)) { entry = Parrot_str_concat(interp, builddir, CONST_STRING(interp, "/runtime/parrot/dynext/")); VTABLE_push_string(interp, paths, entry); } entry = CONST_STRING(interp, "dynext/"); VTABLE_push_string(interp, paths, entry); if (!STRING_IS_NULL(versionlib)) { entry = Parrot_str_concat(interp, versionlib, CONST_STRING(interp, "/dynext/")); VTABLE_push_string(interp, paths, entry); } /* shared exts */ paths = Parrot_pmc_new(interp, enum_class_ResizableStringArray); VTABLE_set_pmc_keyed_int(interp, lib_paths, PARROT_LIB_DYN_EXTS, paths); /* no CONST_STRING here - the c2str.pl preprocessor needs "real strs" */ entry = Parrot_str_new_constant(interp, PARROT_LOAD_EXT); VTABLE_push_string(interp, paths, entry); /* OS/X has .dylib and .bundle */ if (!STREQ(PARROT_LOAD_EXT, PARROT_SHARE_EXT)) { entry = Parrot_str_new_constant(interp, PARROT_SHARE_EXT); VTABLE_push_string(interp, paths, entry); } #ifdef PARROT_PLATFORM_LIB_PATH_INIT_HOOK PARROT_PLATFORM_LIB_PATH_INIT_HOOK(interp, lib_paths); #endif }
/* Adds a code ref to an SC. */ void SC_set_code(PARROT_INTERP, PMC *sc, INTVAL idx, PMC *code) { PMC *codes; GETATTR_SerializationContext_root_codes(interp, sc, codes); VTABLE_set_pmc_keyed_int(interp, codes, idx, code); }
void parrot_init_library_paths(PARROT_INTERP) { ASSERT_ARGS(parrot_init_library_paths) PMC *paths; STRING *entry; PMC * const iglobals = interp->iglobals; /* create the lib_paths array */ PMC * const lib_paths = Parrot_pmc_new_init_int(interp, enum_class_FixedPMCArray, PARROT_LIB_PATH_SIZE); VTABLE_set_pmc_keyed_int(interp, iglobals, IGLOBALS_LIB_PATHS, lib_paths); /* each is an array of strings */ /* define include paths */ paths = Parrot_pmc_new(interp, enum_class_ResizableStringArray); VTABLE_set_pmc_keyed_int(interp, lib_paths, PARROT_LIB_PATH_INCLUDE, paths); { /* EXPERIMENTAL: add include path from environment */ STRING *envvar = Parrot_getenv(interp, CONST_STRING(interp, "PARROT_INCLUDE")); Parrot_warn_experimental(interp, "PARROT_INCLUDE environment variable is experimental"); if (!STRING_IS_NULL(envvar) && !STRING_IS_EMPTY(envvar)) VTABLE_push_string(interp, paths, envvar); } entry = CONST_STRING(interp, "./"); VTABLE_push_string(interp, paths, entry); /* define library paths */ paths = Parrot_pmc_new(interp, enum_class_ResizableStringArray); VTABLE_set_pmc_keyed_int(interp, lib_paths, PARROT_LIB_PATH_LIBRARY, paths); { /* EXPERIMENTAL: add library path from environment */ STRING *envvar = Parrot_getenv(interp, CONST_STRING(interp, "PARROT_LIBRARY")); Parrot_warn_experimental(interp, "PARROT_LIBRARY environment variable is experimental"); if (!STRING_IS_NULL(envvar) && !STRING_IS_EMPTY(envvar)) VTABLE_push_string(interp, paths, envvar); } entry = CONST_STRING(interp, "./"); VTABLE_push_string(interp, paths, entry); /* define languages paths */ paths = Parrot_pmc_new(interp, enum_class_ResizableStringArray); VTABLE_set_pmc_keyed_int(interp, lib_paths, PARROT_LIB_PATH_LANG, paths); entry = CONST_STRING(interp, "./"); VTABLE_push_string(interp, paths, entry); /* define dynext paths */ paths = Parrot_pmc_new(interp, enum_class_ResizableStringArray); VTABLE_set_pmc_keyed_int(interp, lib_paths, PARROT_LIB_PATH_DYNEXT, paths); entry = CONST_STRING(interp, "dynext/"); VTABLE_push_string(interp, paths, entry); /* shared exts */ paths = Parrot_pmc_new(interp, enum_class_ResizableStringArray); VTABLE_set_pmc_keyed_int(interp, lib_paths, PARROT_LIB_DYN_EXTS, paths); /* no CONST_STRING here - the c2str.pl preprocessor needs "real strs" */ entry = Parrot_str_new_constant(interp, PARROT_LOAD_EXT); VTABLE_push_string(interp, paths, entry); /* OS/X has .dylib and .bundle */ if (!STREQ(PARROT_LOAD_EXT, PARROT_SHARE_EXT)) { entry = Parrot_str_new_constant(interp, PARROT_SHARE_EXT); VTABLE_push_string(interp, paths, entry); } #ifdef PARROT_PLATFORM_LIB_PATH_INIT_HOOK PARROT_PLATFORM_LIB_PATH_INIT_HOOK(interp, lib_paths); #endif }
PARROT_CANNOT_RETURN_NULL PMC * Parrot_oo_clone_object(PARROT_INTERP, ARGIN(PMC *pmc), ARGMOD_NULLOK(PMC *dest)) { ASSERT_ARGS(Parrot_oo_clone_object) Parrot_Object_attributes *obj = PARROT_OBJECT(pmc); Parrot_Object_attributes *cloned_guts; Parrot_Class_attributes *_class; PMC *cloned; INTVAL num_classes; INTVAL i, num_attrs; if (!PMC_IS_NULL(dest)) { cloned = dest; } else { cloned = Parrot_pmc_new_noinit(interp, enum_class_Object); } _class = PARROT_CLASS(obj->_class); PARROT_ASSERT(_class); num_classes = VTABLE_elements(interp, _class->all_parents); /* Set custom GC mark and destroy on the object. */ PObj_custom_mark_SET(cloned); PObj_custom_destroy_SET(cloned); /* Flag that it is an object */ PObj_is_object_SET(cloned); /* Now clone attributes list.class. */ cloned_guts = (Parrot_Object_attributes *) PMC_data(cloned); cloned_guts->_class = obj->_class; cloned_guts->attrib_store = VTABLE_clone(interp, obj->attrib_store); num_attrs = VTABLE_elements(interp, cloned_guts->attrib_store); for (i = 0; i < num_attrs; ++i) { PMC * const to_clone = VTABLE_get_pmc_keyed_int(interp, cloned_guts->attrib_store, i); if (!PMC_IS_NULL(to_clone)) { VTABLE_set_pmc_keyed_int(interp, cloned_guts->attrib_store, i, VTABLE_clone(interp, to_clone)); } } /* Some of the attributes may have been the PMCs providing storage for any * PMCs we inherited from; also need to clone those. */ if (CLASS_has_alien_parents_TEST(obj->_class)) { int j; /* Locate any PMC parents. */ for (j = 0; j < num_classes; ++j) { PMC * const cur_class = VTABLE_get_pmc_keyed_int(interp, _class->all_parents, j); if (cur_class->vtable->base_type == enum_class_PMCProxy) { /* Clone this PMC too. */ STRING * const proxy = CONST_STRING(interp, "proxy"); VTABLE_set_attr_keyed(interp, cloned, cur_class, proxy, VTABLE_clone(interp, VTABLE_get_attr_keyed(interp, cloned, cur_class, proxy))); } } } /* And we have ourselves a clone. */ return cloned; }