diff options
-rw-r--r-- | Zend/Zend.dsp | 2 | ||||
-rw-r--r-- | Zend/ZendTS.dsp | 2 | ||||
-rw-r--r-- | Zend/zend_API.c | 6 | ||||
-rw-r--r-- | Zend/zend_API.h | 2 | ||||
-rw-r--r-- | Zend/zend_alloc.c | 37 | ||||
-rw-r--r-- | Zend/zend_compile.c | 6 | ||||
-rw-r--r-- | Zend/zend_execute.c | 8 | ||||
-rw-r--r-- | Zend/zend_execute_API.c | 4 | ||||
-rw-r--r-- | Zend/zend_fast_cache.h | 110 | ||||
-rw-r--r-- | Zend/zend_globals.h | 6 | ||||
-rw-r--r-- | Zend/zend_opcode.c | 2 | ||||
-rw-r--r-- | Zend/zend_operators.c | 6 | ||||
-rw-r--r-- | Zend/zend_variables.c | 4 | ||||
-rw-r--r-- | Zend/zend_zval_alloc.h | 74 |
14 files changed, 157 insertions, 112 deletions
diff --git a/Zend/Zend.dsp b/Zend/Zend.dsp index e30c62f75f..6f177558b4 100644 --- a/Zend/Zend.dsp +++ b/Zend/Zend.dsp @@ -270,7 +270,7 @@ SOURCE=.\zend_variables.h # End Source File
# Begin Source File
-SOURCE=.\zend_zval_alloc.h
+SOURCE=.\zend_fast_cache.h
# End Source File
# End Group
# Begin Group "Parsers"
diff --git a/Zend/ZendTS.dsp b/Zend/ZendTS.dsp index 6fcb29d9b6..1cdc46ffde 100644 --- a/Zend/ZendTS.dsp +++ b/Zend/ZendTS.dsp @@ -274,7 +274,7 @@ SOURCE=.\zend_variables.h # End Source File
# Begin Source File
-SOURCE=.\zend_zval_alloc.h
+SOURCE=.\zend_fast_cache.h
# End Source File
# End Group
# Begin Group "Parsers"
diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 9f8d4bba81..0224154868 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -188,7 +188,8 @@ ZEND_API void wrong_param_count() ZEND_API inline int array_init(zval *arg) { - arg->value.ht = (HashTable *) emalloc(sizeof(HashTable)); + ALLOC_HASHTABLE(arg->value.ht); + if (!arg->value.ht || zend_hash_init(arg->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0)) { zend_error(E_CORE_ERROR, "Cannot allocate memory for array"); return FAILURE; @@ -206,7 +207,8 @@ ZEND_API inline int object_init_ex(zval *arg, zend_class_entry *class_type) zend_hash_apply(&class_type->default_properties, (int (*)(void *)) zval_update_constant); class_type->constants_updated = 1; } - arg->value.obj.properties = (HashTable *) emalloc(sizeof(HashTable)); + + ALLOC_HASHTABLE(arg->value.obj.properties); zend_hash_init(arg->value.obj.properties, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(arg->value.obj.properties, &class_type->default_properties, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *)); arg->type = IS_OBJECT; diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 46054a8fd7..c1eadf23f8 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -23,7 +23,7 @@ #include "modules.h" #include "zend_list.h" -#include "zend_zval_alloc.h" +#include "zend_fast_cache.h" #define ZEND_NAMED_FUNCTION(name) void name(INTERNAL_FUNCTION_PARAMETERS) diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index d778d6fd6c..174305c48e 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -23,7 +23,7 @@ #include "zend.h" #include "zend_alloc.h" #include "zend_globals.h" -#include "zend_zval_alloc.h" +#include "zend_fast_cache.h" #ifdef HAVE_SIGNAL_H # include <signal.h> #endif @@ -106,7 +106,6 @@ ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) zend_mem_header *p; ALS_FETCH(); - if (!ZEND_DISABLE_MEMORY_CACHE && (size < MAX_CACHED_MEMORY) && (AG(cache_count)[size] > 0)) { p = AG(cache)[size][--AG(cache_count)[size]]; #if ZEND_DEBUG @@ -321,7 +320,6 @@ ZEND_API int zend_set_memory_limit(unsigned int memory_limit) ZEND_API void start_memory_manager(ALS_D) { AG(phead) = AG(head) = NULL; - AG(zval_list_head) = NULL; #if MEMORY_LIMIT AG(memory_limit)=1<<30; /* rediculous limit, effectively no limit */ @@ -331,9 +329,10 @@ ZEND_API void start_memory_manager(ALS_D) #if ZEND_DEBUG memset(AG(cache_stats), 0, sizeof(AG(cache_stats))); - memset(AG(zval_cache_stats), 0, sizeof(AG(zval_cache_stats))); + memset(AG(fast_cache_stats), 0, sizeof(AG(fast_cache_stats))); #endif + memset(AG(fast_cache_list_head), 0, sizeof(AG(fast_cache_list_head))); memset(AG(cache_count),0,MAX_CACHED_MEMORY*sizeof(unsigned char)); } @@ -341,19 +340,23 @@ ZEND_API void start_memory_manager(ALS_D) ZEND_API void shutdown_memory_manager(int silent, int clean_cache) { zend_mem_header *p, *t; + int fci; #if ZEND_DEBUG int had_leaks=0; #endif - zend_zval_list_entry *zval_list_entry, *next_zval_list_entry; + zend_fast_cache_list_entry *fast_cache_list_entry, *next_fast_cache_list_entry; ALS_FETCH(); - zval_list_entry = AG(zval_list_head); - while (zval_list_entry) { - next_zval_list_entry = zval_list_entry->next; - efree(zval_list_entry); - zval_list_entry = next_zval_list_entry; + + for (fci=0; fci<MAX_FAST_CACHE_TYPES; fci++) { + fast_cache_list_entry = AG(fast_cache_list_head)[fci]; + while (fast_cache_list_entry) { + next_fast_cache_list_entry = fast_cache_list_entry->next; + efree(fast_cache_list_entry); + fast_cache_list_entry = next_fast_cache_list_entry; + } + AG(fast_cache_list_head)[fci] = NULL; } - AG(zval_list_head) = NULL; p=AG(head); t=AG(head); @@ -409,14 +412,18 @@ ZEND_API void shutdown_memory_manager(int silent, int clean_cache) } fprintf(stderr, "Memory cache statistics\n" "-----------------------\n\n" - "[zval, %2d]\t\t%d / %d (%.2f%%)\n", + "[zval, %2d]\t\t%d / %d (%.2f%%)\n" + "[hash, %2d]\t\t%d / %d (%.2f%%)\n", sizeof(zval), - AG(zval_cache_stats)[1], AG(zval_cache_stats)[0]+AG(zval_cache_stats)[1], - ((double) AG(zval_cache_stats)[1] / (AG(zval_cache_stats)[0]+AG(zval_cache_stats)[1]))*100); + AG(fast_cache_stats)[ZVAL_CACHE_LIST][1], AG(fast_cache_stats)[ZVAL_CACHE_LIST][0]+AG(fast_cache_stats)[ZVAL_CACHE_LIST][1], + ((double) AG(fast_cache_stats)[ZVAL_CACHE_LIST][1] / (AG(fast_cache_stats)[ZVAL_CACHE_LIST][0]+AG(fast_cache_stats)[ZVAL_CACHE_LIST][1]))*100, + sizeof(HashTable), + AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][1], AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][0]+AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][1], + ((double) AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][1] / (AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][0]+AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][1]))*100); for (i=0; i<MAX_CACHED_MEMORY; i+=2) { - fprintf(stderr, "[%2d, %2d]\t\t", i+1, i+2); + fprintf(stderr, "[%2d, %2d]\t\t", i, i+1); for (j=0; j<2; j++) { fprintf(stderr, "%d / %d (%.2f%%)\t\t", AG(cache_stats)[i+j][1], AG(cache_stats)[i+j][0]+AG(cache_stats)[i+j][1], diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 64872a1d0d..91afbc80c3 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -25,7 +25,7 @@ #include "zend_API.h" #include "zend_variables.h" #include "zend_operators.h" -#include "zend_zval_alloc.h" +#include "zend_fast_cache.h" ZEND_API zend_op_array *(*zend_compile_files)(int mark_as_ref CLS_DC, int file_count, ...); @@ -1006,7 +1006,7 @@ static void function_add_ref(zend_function *function) HashTable *static_variables = op_array->static_variables; zval *tmp_zval; - op_array->static_variables = (HashTable *) emalloc(sizeof(HashTable)); + ALLOC_HASHTABLE(op_array->static_variables); zend_hash_init(op_array->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(op_array->static_variables, static_variables, (void (*)(void *)) zval_add_ref, (void *) &tmp_zval, sizeof(zval *)); } @@ -1817,7 +1817,7 @@ void do_fetch_global_or_static_variable(znode *varname, znode *static_assignment convert_to_string(&varname->u.constant); *tmp = static_assignment->u.constant; if (!CG(active_op_array)->static_variables) { - CG(active_op_array)->static_variables = (HashTable *) emalloc(sizeof(HashTable)); + ALLOC_HASHTABLE(CG(active_op_array)->static_variables); zend_hash_init(CG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0); } zend_hash_update_ptr(CG(active_op_array)->static_variables, varname->u.constant.value.str.val, varname->u.constant.value.str.len+1, tmp, sizeof(zval *), NULL); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index eb23e33826..2087252d17 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -30,7 +30,7 @@ #include "zend_operators.h" #include "zend_constants.h" #include "zend_extensions.h" -#include "zend_zval_alloc.h" +#include "zend_fast_cache.h" #if defined(HAVE_ALLOCA) && defined(HAVE_ALLOCA_H) # include <alloca.h> @@ -481,7 +481,7 @@ static inline void zend_fetch_var_address(znode *result, znode *op1, znode *op2, break; case ZEND_FETCH_STATIC: if (!EG(active_op_array)->static_variables) { - EG(active_op_array)->static_variables = (HashTable *) emalloc(sizeof(HashTable)); + ALLOC_HASHTABLE(EG(active_op_array)->static_variables); zend_hash_init(EG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0); } target_symbol_table = EG(active_op_array)->static_variables; @@ -1526,7 +1526,7 @@ do_fcall_common: /*printf("Cache hit! Reusing %x\n", symtable_cache[symtable_cache_ptr]);*/ function_state.function_symbol_table = *(EG(symtable_cache_ptr)--); } else { - function_state.function_symbol_table = (HashTable *) emalloc(sizeof(HashTable)); + ALLOC_HASHTABLE(function_state.function_symbol_table); zend_hash_init(function_state.function_symbol_table, 0, NULL, ZVAL_PTR_DTOR, 0); /*printf("Cache miss! Initialized %x\n", function_state.function_symbol_table);*/ } @@ -1561,7 +1561,7 @@ do_fcall_common: EG(return_value_ptr_ptr)=original_return_value; if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) { zend_hash_destroy(function_state.function_symbol_table); - efree(function_state.function_symbol_table); + FREE_HASHTABLE(function_state.function_symbol_table); } else { *(++EG(symtable_cache_ptr)) = function_state.function_symbol_table; zend_hash_clean(*EG(symtable_cache_ptr)); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 4be74a6472..88662d3b1e 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -370,7 +370,7 @@ int call_user_function_ex(HashTable *function_table, zval *object, zval *functio *retval_ptr_ptr = NULL; if (function_state.function->type == ZEND_USER_FUNCTION) { calling_symbol_table = EG(active_symbol_table); - EG(active_symbol_table) = (HashTable *) emalloc(sizeof(HashTable)); + ALLOC_HASHTABLE(EG(active_symbol_table)); zend_hash_init(EG(active_symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0); if (object) { zval *dummy, **this_ptr; @@ -388,7 +388,7 @@ int call_user_function_ex(HashTable *function_table, zval *object, zval *functio original_opline_ptr = EG(opline_ptr); zend_execute(EG(active_op_array) ELS_CC); zend_hash_destroy(EG(active_symbol_table)); - efree(EG(active_symbol_table)); + FREE_HASHTABLE(EG(active_symbol_table)); EG(active_symbol_table) = calling_symbol_table; EG(active_op_array) = original_op_array; EG(return_value_ptr_ptr)=original_return_value; diff --git a/Zend/zend_fast_cache.h b/Zend/zend_fast_cache.h new file mode 100644 index 0000000000..865fb23c51 --- /dev/null +++ b/Zend/zend_fast_cache.h @@ -0,0 +1,110 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) 1998, 1999 Andi Gutmans, Zeev Suraski | + +----------------------------------------------------------------------+ + | This source file is subject to version 0.91 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.zend.com/license/0_91.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Andi Gutmans <andi@zend.com> | + | Zeev Suraski <zeev@zend.com> | + +----------------------------------------------------------------------+ +*/ + + +#ifndef _ZEND_FAST_CACHE_H +#define _ZEND_FAST_CACHE_H + +#define ZEND_ENABLE_FAST_CACHE 1 + +#define MAX_FAST_CACHE_TYPES 4 + +#if ZEND_ENABLE_FAST_CACHE + +#define ZVAL_CACHE_LIST 0 +#define HASHTABLE_CACHE_LIST 1 + +#include "zend_globals.h" +#include "zend_globals_macros.h" +#include "zend_alloc.h" + +typedef struct _zend_fast_cache_list_entry { + struct _zend_fast_cache_list_entry *next; +} zend_fast_cache_list_entry; + +#if ZEND_DEBUG +# define RECORD_ZVAL_CACHE_HIT(fc_type) AG(fast_cache_stats)[fc_type][1]++; +# define RECORD_ZVAL_CACHE_MISS(fc_type) AG(fast_cache_stats)[fc_type][0]++; +#else +# define RECORD_ZVAL_CACHE_HIT(fc_type) +# define RECORD_ZVAL_CACHE_MISS(fc_type) +#endif + +#ifndef ZTS +extern zend_alloc_globals alloc_globals; +#endif + +#define ZEND_FAST_ALLOC(p, type, fc_type) \ + { \ + ALS_FETCH(); \ + \ + if (((p) = (type *) AG(fast_cache_list_head)[fc_type])) { \ + AG(fast_cache_list_head)[fc_type] = ((zend_fast_cache_list_entry *) AG(fast_cache_list_head)[fc_type])->next; \ + RECORD_ZVAL_CACHE_HIT(fc_type); \ + } else { \ + (p) = (type *) emalloc(sizeof(type)); \ + RECORD_ZVAL_CACHE_MISS(fc_type); \ + } \ + } + + +#define ZEND_FAST_FREE(p, fc_type) \ + { \ + ALS_FETCH(); \ + \ + ((zend_fast_cache_list_entry *) (p))->next = AG(fast_cache_list_head)[fc_type]; \ + AG(fast_cache_list_head)[fc_type] = (zend_fast_cache_list_entry *) (p); \ + } + + +#else /* !ZEND_ENABLE_FAST_CACHE */ + +#define ZEND_FAST_ALLOC(p, type, fc_type) \ + (p) = (type *) emalloc(sizeof(type)) + +#define ZEND_FAST_FREE(p, fc_type) \ + efree(p) + +#endif /* ZEND_ENABLE_FAST_CACHE */ + + + + +/* fast cache for zval's */ +#define ALLOC_ZVAL(z) \ + ZEND_FAST_ALLOC(z, zval, ZVAL_CACHE_LIST) + +#define FREE_ZVAL(z) \ + ZEND_FAST_FREE(z, ZVAL_CACHE_LIST) + +/* fast cache for HashTable's */ +#define ALLOC_HASHTABLE(b) \ + ZEND_FAST_ALLOC(b, HashTable, HASHTABLE_CACHE_LIST) + +#define FREE_HASHTABLE(ht) \ + ZEND_FAST_FREE(ht, HASHTABLE_CACHE_LIST) + +#endif /* _ZEND_FAST_CACHE_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + */ diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index da0719f286..8ae06f263c 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -30,6 +30,7 @@ #include "zend_ptr_stack.h" #include "zend_hash.h" #include "zend_llist.h" +#include "zend_fast_cache.h" /* Define ZTS if you want a thread-safe Zend */ /*#undef ZTS*/ @@ -173,18 +174,17 @@ struct _zend_executor_globals { }; - struct _zend_alloc_globals { zend_mem_header *head; /* standard list */ zend_mem_header *phead; /* persistent list */ void *cache[MAX_CACHED_MEMORY][MAX_CACHED_ENTRIES]; unsigned char cache_count[MAX_CACHED_MEMORY]; - void *zval_list_head; + void *fast_cache_list_head[MAX_FAST_CACHE_TYPES]; #if ZEND_DEBUG /* for performance tuning */ int cache_stats[MAX_CACHED_MEMORY][2]; - int zval_cache_stats[2]; + int fast_cache_stats[MAX_FAST_CACHE_TYPES][2]; #endif #if MEMORY_LIMIT unsigned int memory_limit; diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 77632df91c..3f40aad847 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -155,7 +155,7 @@ ZEND_API void destroy_op_array(zend_op_array *op_array) if (op_array->static_variables) { zend_hash_destroy(op_array->static_variables); - efree(op_array->static_variables); + FREE_HASHTABLE(op_array->static_variables); } if (--(*op_array->refcount)>0) { diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index 894d929d00..11064c0087 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -29,7 +29,7 @@ #include "zend_variables.h" #include "zend_globals.h" #include "zend_list.h" -#include "zend_zval_alloc.h" +#include "zend_fast_cache.h" #if WITH_BCMATH #include "functions/number.h" @@ -348,13 +348,13 @@ static void convert_scalar_to_array(zval *op, int type) switch (type) { case IS_ARRAY: - op->value.ht = (HashTable *) emalloc(sizeof(HashTable)); + ALLOC_HASHTABLE(op->value.ht); zend_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_index_update(op->value.ht, 0, (void *) &entry, sizeof(zval *), NULL); op->type = IS_ARRAY; break; case IS_OBJECT: - op->value.obj.properties = (HashTable *) emalloc(sizeof(HashTable)); + ALLOC_HASHTABLE(op->value.obj.properties); zend_hash_init(op->value.obj.properties, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_update(op->value.obj.properties, "scalar", sizeof("scalar"), (void *) &entry, sizeof(zval *), NULL); op->value.obj.ce = &zend_standard_class_def; diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c index e415aa4e9b..c0fee24ee6 100644 --- a/Zend/zend_variables.c +++ b/Zend/zend_variables.c @@ -66,13 +66,13 @@ ZEND_API int _zval_dtor(zval *zvalue ZEND_FILE_LINE_DC) if (zvalue->value.ht && (zvalue->value.ht != &EG(symbol_table))) { zend_hash_destroy(zvalue->value.ht); - efree_rel(zvalue->value.ht); + FREE_HASHTABLE(zvalue->value.ht); } } break; case IS_OBJECT: zend_hash_destroy(zvalue->value.obj.properties); - efree_rel(zvalue->value.obj.properties); + FREE_HASHTABLE(zvalue->value.obj.properties); break; case IS_RESOURCE: /* destroy resource */ diff --git a/Zend/zend_zval_alloc.h b/Zend/zend_zval_alloc.h deleted file mode 100644 index b78488b844..0000000000 --- a/Zend/zend_zval_alloc.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend Engine | - +----------------------------------------------------------------------+ - | Copyright (c) 1998, 1999 Andi Gutmans, Zeev Suraski | - +----------------------------------------------------------------------+ - | This source file is subject to version 0.91 of the Zend license, | - | that is bundled with this package in the file LICENSE, and is | - | available at through the world-wide-web at | - | http://www.zend.com/license/0_91.txt. | - | If you did not receive a copy of the Zend license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@zend.com so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Andi Gutmans <andi@zend.com> | - | Zeev Suraski <zeev@zend.com> | - +----------------------------------------------------------------------+ -*/ - - -#ifndef _ZVAL_ALLOC_H -#define _ZVAL_ALLOC_H - -#include "zend_globals.h" -#include "zend_globals_macros.h" -#include "zend_alloc.h" - -typedef struct _zend_zval_list_entry { - struct _zend_zval_list_entry *next; -} zend_zval_list_entry; - -#if ZEND_DEBUG -# define RECORD_ZVAL_CACHE_HIT() AG(zval_cache_stats)[1]++; -# define RECORD_ZVAL_CACHE_MISS() AG(zval_cache_stats)[0]++; -#else -# define RECORD_ZVAL_CACHE_HIT() -# define RECORD_ZVAL_CACHE_MISS() -#endif - -#ifndef ZTS -extern zend_alloc_globals alloc_globals; -#endif - -#define ALLOC_ZVAL(z) \ - { \ - ALS_FETCH(); \ - \ - if (((z) = (void *) AG(zval_list_head))) { \ - AG(zval_list_head) = ((zend_zval_list_entry *) AG(zval_list_head))->next; \ - RECORD_ZVAL_CACHE_HIT(); \ - } else { \ - (z) = emalloc(sizeof(zval)); \ - RECORD_ZVAL_CACHE_MISS(); \ - } \ - } - - -#define FREE_ZVAL(z) \ - { \ - ALS_FETCH(); \ - \ - ((zend_zval_list_entry *) (z))->next = AG(zval_list_head); \ - AG(zval_list_head) = (zend_zval_list_entry *) (z); \ - } - - -#endif - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - */ |