/* * Swap an entry from a higher level dictionary into a base dictionary. * elt[0] is the key, elt[1] is the current value in the Level 2 dictionary * (*pdict2). */ static int swap_entry(i_ctx_t *i_ctx_p, ref elt[2], ref * pdict, ref * pdict2) { ref *pvalue; #ifdef PACIFY_VALGRIND ref old_value = { 0 }; /* current value in *pdict */ #else ref old_value; /* current value in *pdict */ #endif int found = dict_find(pdict, &elt[0], &pvalue); switch (found) { default: /* <0, error */ /* * The only possible error here is a dictfull error, which is * harmless. */ /* fall through */ case 0: /* missing */ make_null(&old_value); break; case 1: /* present */ old_value = *pvalue; } /* * Temporarily flag the dictionaries as local, so that we don't * get invalidaccess errors. (We know that they are both * referenced from systemdict, so they are allowed to reference * local objects even if they are global.) */ { uint space2 = r_space(pdict2); int code; r_set_space(pdict2, avm_local); idict_put(pdict2, &elt[0], &old_value); if (r_has_type(&elt[1], t_null)) { code = idict_undef(pdict, &elt[0]); if (code == gs_error_undefined && r_has_type(&old_value, t_null) ) code = 0; } else { uint space = r_space(pdict); r_set_space(pdict, avm_local); code = idict_put(pdict, &elt[0], &elt[1]); r_set_space(pdict, space); } r_set_space(pdict2, space2); return code; } }
/* * This forces a "put" even if the object is not writable, and (if the * object is systemdict or the save level is 0) even if the value is in * local VM. It is meant to be used only for replacing the value of * FontDirectory in systemdict when switching between local and global VM, * and a few similar applications. After initialization, this operator * should no longer be accessible by name. */ static int zforceput(i_ctx_t *i_ctx_p) { os_ptr op = osp; os_ptr op1 = op - 1; os_ptr op2 = op - 2; int code; switch (r_type(op2)) { case t_array: check_int_ltu(*op1, r_size(op2)); if (r_space(op2) > r_space(op)) { if (imemory_save_level(iimemory)) return_error(e_invalidaccess); } { ref *eltp = op2->value.refs + (uint) op1->value.intval; ref_assign_old(op2, eltp, op, "put"); } break; case t_dictionary: if (op2->value.pdict == systemdict->value.pdict || !imemory_save_level(iimemory) ) { uint space = r_space(op2); r_set_space(op2, avm_local); code = idict_put(op2, op1, op); r_set_space(op2, space); } else code = idict_put(op2, op1, op); if (code < 0) return code; break; default: return_error(e_typecheck); } pop(3); return 0; }
/* initialize the dictionaries that hold operator definitions. */ int obj_init(i_ctx_t **pi_ctx_p, gs_dual_memory_t *idmem) { int level = gs_op_language_level(); ref system_dict; i_ctx_t *i_ctx_p; int code; /* * Create systemdict. The context machinery requires that * we do this before initializing the interpreter. */ code = dict_alloc(idmem->space_global, (level >= 3 ? SYSTEMDICT_LL3_SIZE : level >= 2 ? SYSTEMDICT_LEVEL2_SIZE : SYSTEMDICT_SIZE), &system_dict); if (code < 0) return code; /* Initialize the interpreter. */ code = gs_interp_init(pi_ctx_p, &system_dict, idmem); if (code < 0) return code; i_ctx_p = *pi_ctx_p; { #define icount countof(initial_dictionaries) ref idicts[icount]; int i; const op_def *const *tptr; min_dstack_size = MIN_DSTACK_SIZE; refset_null(idicts, icount); /* Put systemdict on the dictionary stack. */ if (level >= 2) { dsp += 2; /* * For the moment, let globaldict be an alias for systemdict. */ dsp[-1] = system_dict; min_dstack_size++; } else { ++dsp; } *dsp = system_dict; /* Create dictionaries which are to be homes for operators. */ for (tptr = op_defs_all; *tptr != 0; tptr++) { const op_def *def; for (def = *tptr; def->oname != 0; def++) if (op_def_is_begin_dict(def)) { if (make_initial_dict(i_ctx_p, def->oname, idicts) == 0) return_error(e_VMerror); } } /* Set up the initial dstack. */ for (i = 0; i < countof(initial_dstack); i++) { const char *dname = initial_dstack[i]; ++dsp; if (!strcmp(dname, "userdict")) dstack_userdict_index = dsp - dsbot; ref_assign(dsp, make_initial_dict(i_ctx_p, dname, idicts)); } /* Enter names of referenced initial dictionaries into systemdict. */ initial_enter_name("systemdict", systemdict); for (i = 0; i < icount; i++) { ref *idict = &idicts[i]; if (!r_has_type(idict, t_null)) { /* * Note that we enter the dictionary in systemdict * even if it is in local VM. There is a special * provision in the garbage collector for this: * see ivmspace.h for more information. * In order to do this, we must temporarily * identify systemdict as local, so that the * store check in dict_put won't fail. */ uint save_space = r_space(systemdict); r_set_space(systemdict, avm_local); code = initial_enter_name(initial_dictionaries[i].name, idict); r_set_space(systemdict, save_space); if (code < 0) return code; } } #undef icount } gs_interp_reset(i_ctx_p); { ref vnull, vtrue, vfalse; make_null(&vnull); make_true(&vtrue); make_false(&vfalse); if ((code = initial_enter_name("null", &vnull)) < 0 || (code = initial_enter_name("true", &vtrue)) < 0 || (code = initial_enter_name("false", &vfalse)) < 0 ) return code; } /* Create the error name table */ { int n = countof(gs_error_names) - 1; int i; ref era; code = ialloc_ref_array(&era, a_readonly, n, "ErrorNames"); if (code < 0) return code; for (i = 0; i < n; i++) if ((code = name_enter_string(imemory, (const char *)gs_error_names[i], era.value.refs + i)) < 0) return code; return initial_enter_name("ErrorNames", &era); } }
/* Resize a dictionary. */ int dict_resize(ref * pdref, uint new_size, dict_stack_t *pds) { dict *pdict = pdref->value.pdict; gs_ref_memory_t *mem = dict_memory(pdict); uint new_mask = imemory_new_mask(mem); ushort orig_attrs = r_type_attrs(&pdict->values) & (a_all | a_executable); dict dnew; ref drto; int code; if (new_size < d_length(pdict)) { if (!mem->gs_lib_ctx->dict_auto_expand) return_error(gs_error_dictfull); new_size = d_length(pdict); } make_tav(&drto, t_dictionary, r_space(pdref) | a_all | new_mask, pdict, &dnew); dnew.memory = pdict->memory; if ((code = dict_create_contents(new_size, &drto, dict_is_packed(pdict))) < 0) return code; /* * We must suppress the store check, in case we are expanding * systemdict or another global dictionary that is allowed * to reference local objects. */ r_set_space(&drto, avm_local); /* * If we are expanding a permanent dictionary, we must make sure that * dict_put doesn't think this is a second definition for any * single-definition names. This in turn requires that * dstack_dict_is_permanent must be true for the second ("to") * argument of dict_copy_elements, which requires temporarily * setting *pdref = drto. */ if (CAN_SET_PVALUE_CACHE(pds, pdref, mem)) { ref drfrom; drfrom = *pdref; *pdref = drto; dict_copy_elements(&drfrom, pdref, COPY_FOR_RESIZE, pds); *pdref = drfrom; } else { dict_copy_elements(pdref, &drto, 0, pds); } /* Save or free the old dictionary. */ if (ref_must_save_in(mem, &pdict->values)) ref_do_save_in(mem, pdref, &pdict->values, "dict_resize(values)"); else gs_free_ref_array(mem, &pdict->values, "dict_resize(old values)"); if (ref_must_save_in(mem, &pdict->keys)) ref_do_save_in(mem, pdref, &pdict->keys, "dict_resize(keys)"); else gs_free_ref_array(mem, &pdict->keys, "dict_resize(old keys)"); ref_assign(&pdict->keys, &dnew.keys); ref_assign(&pdict->values, &dnew.values); r_store_attrs(&pdict->values, a_all | a_executable, orig_attrs); ref_save_in(dict_memory(pdict), pdref, &pdict->maxlength, "dict_resize(maxlength)"); d_set_maxlength(pdict, new_size); if (pds) dstack_set_top(pds); /* just in case this is the top dict */ return 0; }