static sdlPtr make_persistent_sdl(sdlPtr sdl)
{
	sdlPtr psdl = NULL;
	HashTable ptr_map;
	HashTable bp_types, bp_encoders;
	zend_string *key;

	zend_hash_init(&bp_types, 0, NULL, NULL, 0);
	zend_hash_init(&bp_encoders, 0, NULL, NULL, 0);
	zend_hash_init(&ptr_map, 0, NULL, NULL, 0);

	psdl = malloc(sizeof(*sdl));
	memset(psdl, 0, sizeof(*sdl));

	if (sdl->source) {
		psdl->source = strdup(sdl->source);
	}
	if (sdl->target_ns) {
		psdl->target_ns = strdup(sdl->target_ns);
	}

	if (sdl->groups) {
		sdlTypePtr tmp;
		sdlTypePtr ptype;

		psdl->groups = malloc(sizeof(HashTable));
		zend_hash_init(psdl->groups, zend_hash_num_elements(sdl->groups), NULL, delete_type_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->groups, key, tmp) {
			ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
			if (key) {
				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(psdl->groups, ZSTR_VAL(key), ZSTR_LEN(key), ptype);
			} else {
				zend_hash_next_index_insert_ptr(psdl->groups, ptype);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), ptype);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->types) {
		sdlTypePtr tmp;
		sdlTypePtr ptype;

		psdl->types = malloc(sizeof(HashTable));
		zend_hash_init(psdl->types, zend_hash_num_elements(sdl->types), NULL, delete_type_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->types, key, tmp) {
			ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
			if (key) {
				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(psdl->types, ZSTR_VAL(key), ZSTR_LEN(key), ptype);
			} else {
				zend_hash_next_index_insert_ptr(psdl->types, ptype);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), ptype);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->elements) {
		sdlTypePtr tmp;
		sdlTypePtr ptype;

		psdl->elements = malloc(sizeof(HashTable));
		zend_hash_init(psdl->elements, zend_hash_num_elements(sdl->elements), NULL, delete_type_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->elements, key, tmp) {
			ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
			if (key) {
				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(psdl->elements, ZSTR_VAL(key), ZSTR_LEN(key), ptype);
			} else {
				zend_hash_next_index_insert_ptr(psdl->elements, ptype);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), ptype);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->encoders) {
		encodePtr tmp;
		encodePtr penc;

		psdl->encoders = malloc(sizeof(HashTable));
		zend_hash_init(psdl->encoders, zend_hash_num_elements(sdl->encoders), NULL, delete_encoder_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->encoders, key, tmp) {
			penc = make_persistent_sdl_encoder(tmp, &ptr_map, &bp_types, &bp_encoders);
			if (key) {
				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(psdl->encoders, ZSTR_VAL(key), ZSTR_LEN(key), penc);
			} else {
				zend_hash_next_index_insert_ptr(psdl->encoders, penc);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), penc);
		} ZEND_HASH_FOREACH_END();
	}

	/* do backpatching here */
	if (zend_hash_num_elements(&bp_types)) {
		sdlTypePtr *tmp, ptype = NULL;

		ZEND_HASH_FOREACH_PTR(&bp_types, tmp) {
			if ((ptype = zend_hash_str_find_ptr(&ptr_map, (char*)tmp, sizeof(*tmp))) == NULL) {
				assert(0);
			}
			*tmp = ptype;
		} ZEND_HASH_FOREACH_END();
	}
	if (zend_hash_num_elements(&bp_encoders)) {
		encodePtr *tmp, penc = NULL;

		ZEND_HASH_FOREACH_PTR(&bp_encoders, tmp) {
			if ((penc = zend_hash_str_find_ptr(&ptr_map, (char*)tmp, sizeof(*tmp))) == NULL) {
				assert(0);
			}
			*tmp = penc;
		} ZEND_HASH_FOREACH_END();
	}


	if (sdl->bindings) {
		sdlBindingPtr tmp;
		sdlBindingPtr pbind;

		psdl->bindings = malloc(sizeof(HashTable));
		zend_hash_init(psdl->bindings, zend_hash_num_elements(sdl->bindings), NULL, delete_binding_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->bindings, key, tmp) {
			pbind = make_persistent_sdl_binding(tmp, &ptr_map);
			if (key) {
				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(psdl->bindings, ZSTR_VAL(key), ZSTR_LEN(key), pbind);
			} else {
				zend_hash_next_index_insert_ptr(psdl->bindings, pbind);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), pbind);
		} ZEND_HASH_FOREACH_END();
	}

	zend_hash_init(&psdl->functions, zend_hash_num_elements(&sdl->functions), NULL, delete_function_persistent, 1);
	if (zend_hash_num_elements(&sdl->functions)) {
		sdlFunctionPtr tmp;
		sdlFunctionPtr pfunc;

		ZEND_HASH_FOREACH_STR_KEY_PTR(&sdl->functions, key, tmp) {
			pfunc = make_persistent_sdl_function(tmp, &ptr_map);
			if (key) {
				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(&psdl->functions, ZSTR_VAL(key), ZSTR_LEN(key), pfunc);
			} else {
				zend_hash_next_index_insert_ptr(&psdl->functions, pfunc);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), pfunc);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->requests) {
		zval *zv;
		sdlFunctionPtr tmp;
		sdlFunctionPtr preq;

		psdl->requests = malloc(sizeof(HashTable));
		zend_hash_init(psdl->requests, zend_hash_num_elements(sdl->requests), NULL, NULL, 1);

		ZEND_HASH_FOREACH_STR_KEY_VAL(sdl->requests, key, zv) {
			tmp = Z_PTR_P(zv);
			if ((preq = zend_hash_str_find_ptr(&ptr_map, (char*)&tmp, sizeof(tmp))) == NULL) {
				assert(0);
			}
			Z_PTR_P(zv) = preq;
			if (key) {
				/* We have to duplicate key emalloc->malloc */
				zend_hash_str_add_ptr(psdl->requests, ZSTR_VAL(key), ZSTR_LEN(key), preq);
			}
		} ZEND_HASH_FOREACH_END();
	}

	zend_hash_destroy(&ptr_map);
	zend_hash_destroy(&bp_encoders);
	zend_hash_destroy(&bp_types);

	return psdl;
}
static sdlPtr make_persistent_sdl(sdlPtr sdl)
{
	sdlPtr psdl = NULL;
	HashTable ptr_map;
	HashTable bp_types, bp_encoders;
	zend_string *key;

	zend_hash_init(&bp_types, 0, NULL, NULL, 0);
	zend_hash_init(&bp_encoders, 0, NULL, NULL, 0);
	zend_hash_init(&ptr_map, 0, NULL, NULL, 0);

	psdl = malloc(sizeof(*sdl));
	memset(psdl, 0, sizeof(*sdl));

	if (sdl->source) {
		psdl->source = strdup(sdl->source);
	}
	if (sdl->target_ns) {
		psdl->target_ns = strdup(sdl->target_ns);
	}

	if (sdl->groups) {
		sdlTypePtr tmp;
		sdlTypePtr ptype;

		psdl->groups = malloc(sizeof(HashTable));
		zend_hash_init(psdl->groups, zend_hash_num_elements(sdl->groups), NULL, delete_type_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->groups, key, tmp) {
			ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
			if (key) {
				 
				zend_hash_str_add_ptr(psdl->groups, ZSTR_VAL(key), ZSTR_LEN(key), ptype);
			} else {
				zend_hash_next_index_insert_ptr(psdl->groups, ptype);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), ptype);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->types) {
		sdlTypePtr tmp;
		sdlTypePtr ptype;

		psdl->types = malloc(sizeof(HashTable));
		zend_hash_init(psdl->types, zend_hash_num_elements(sdl->types), NULL, delete_type_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->types, key, tmp) {
			ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
			if (key) {
				 
				zend_hash_str_add_ptr(psdl->types, ZSTR_VAL(key), ZSTR_LEN(key), ptype);
			} else {
				zend_hash_next_index_insert_ptr(psdl->types, ptype);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), ptype);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->elements) {
		sdlTypePtr tmp;
		sdlTypePtr ptype;

		psdl->elements = malloc(sizeof(HashTable));
		zend_hash_init(psdl->elements, zend_hash_num_elements(sdl->elements), NULL, delete_type_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->elements, key, tmp) {
			ptype = make_persistent_sdl_type(tmp, &ptr_map, &bp_types, &bp_encoders);
			if (key) {
				 
				zend_hash_str_add_ptr(psdl->elements, ZSTR_VAL(key), ZSTR_LEN(key), ptype);
			} else {
				zend_hash_next_index_insert_ptr(psdl->elements, ptype);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), ptype);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->encoders) {
		encodePtr tmp;
		encodePtr penc;

		psdl->encoders = malloc(sizeof(HashTable));
		zend_hash_init(psdl->encoders, zend_hash_num_elements(sdl->encoders), NULL, delete_encoder_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->encoders, key, tmp) {
			penc = make_persistent_sdl_encoder(tmp, &ptr_map, &bp_types, &bp_encoders);
			if (key) {
				 
				zend_hash_str_add_ptr(psdl->encoders, ZSTR_VAL(key), ZSTR_LEN(key), penc);
			} else {
				zend_hash_next_index_insert_ptr(psdl->encoders, penc);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), penc);
		} ZEND_HASH_FOREACH_END();
	}

	 
	if (zend_hash_num_elements(&bp_types)) {
		sdlTypePtr *tmp, ptype = NULL;

		ZEND_HASH_FOREACH_PTR(&bp_types, tmp) {
			if ((ptype = zend_hash_str_find_ptr(&ptr_map, (char*)tmp, sizeof(*tmp))) == NULL) {
				assert(0);
			}
			*tmp = ptype;
		} ZEND_HASH_FOREACH_END();
	}
	if (zend_hash_num_elements(&bp_encoders)) {
		encodePtr *tmp, penc = NULL;

		ZEND_HASH_FOREACH_PTR(&bp_encoders, tmp) {
			if ((penc = zend_hash_str_find_ptr(&ptr_map, (char*)tmp, sizeof(*tmp))) == NULL) {
				assert(0);
			}
			*tmp = penc;
		} ZEND_HASH_FOREACH_END();
	}


	if (sdl->bindings) {
		sdlBindingPtr tmp;
		sdlBindingPtr pbind;

		psdl->bindings = malloc(sizeof(HashTable));
		zend_hash_init(psdl->bindings, zend_hash_num_elements(sdl->bindings), NULL, delete_binding_persistent, 1);

		ZEND_HASH_FOREACH_STR_KEY_PTR(sdl->bindings, key, tmp) {
			pbind = make_persistent_sdl_binding(tmp, &ptr_map);
			if (key) {
				 
				zend_hash_str_add_ptr(psdl->bindings, ZSTR_VAL(key), ZSTR_LEN(key), pbind);
			} else {
				zend_hash_next_index_insert_ptr(psdl->bindings, pbind);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), pbind);
		} ZEND_HASH_FOREACH_END();
	}

	zend_hash_init(&psdl->functions, zend_hash_num_elements(&sdl->functions), NULL, delete_function_persistent, 1);
	if (zend_hash_num_elements(&sdl->functions)) {
		sdlFunctionPtr tmp;
		sdlFunctionPtr pfunc;

		ZEND_HASH_FOREACH_STR_KEY_PTR(&sdl->functions, key, tmp) {
			pfunc = make_persistent_sdl_function(tmp, &ptr_map);
			if (key) {
				 
				zend_hash_str_add_ptr(&psdl->functions, ZSTR_VAL(key), ZSTR_LEN(key), pfunc);
			} else {
				zend_hash_next_index_insert_ptr(&psdl->functions, pfunc);
			}
			zend_hash_str_add_ptr(&ptr_map, (char*)&tmp, sizeof(tmp), pfunc);
		} ZEND_HASH_FOREACH_END();
	}

	if (sdl->requests) {
		zval *zv;
		sdlFunctionPtr tmp;
		sdlFunctionPtr preq;

		psdl->requests = malloc(sizeof(HashTable));
		zend_hash_init(psdl->requests, zend_hash_num_elements(sdl->requests), NULL, NULL, 1);

		ZEND_HASH_FOREACH_STR_KEY_VAL(sdl->requests, key, zv) {
			tmp = Z_PTR_P(zv);
			if ((preq = zend_hash_str_find_ptr(&ptr_map, (char*)&tmp, sizeof(tmp))) == NULL) {
				assert(0);
			}
			Z_PTR_P(zv) = preq;
			if (key) {
				 
				zend_hash_str_add_ptr(psdl->requests, ZSTR_VAL(key), ZSTR_LEN(key), preq);
			}
		} ZEND_HASH_FOREACH_END();
	}

	zend_hash_destroy(&ptr_map);
	zend_hash_destroy(&bp_encoders);
	zend_hash_destroy(&bp_types);

	return psdl;
}