mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-07-15 16:58:34 +00:00
Enhance aot feature flags emit and load (#3048)
- Emit SIMD/ref-types/bulk-memory flags into AOT file only when the features are really used in wasm file - Remove unused tail-call flag and stringref flag - Add memoy64 flag and dynamic-linking flag - Change WASM_FEATURE_THREADS to WASM_FEATURE_MULTI_THREAD
This commit is contained in:
parent
4f0551ac25
commit
7c812ece9a
|
@ -481,7 +481,7 @@ check_feature_flags(char *error_buf, uint32 error_buf_size,
|
|||
#endif
|
||||
|
||||
#if WASM_ENABLE_THREAD_MGR == 0
|
||||
if (feature_flags & WASM_FEATURE_THREADS) {
|
||||
if (feature_flags & WASM_FEATURE_MULTI_THREAD) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"thread is not enabled in this build");
|
||||
return false;
|
||||
|
@ -496,14 +496,6 @@ check_feature_flags(char *error_buf, uint32 error_buf_size,
|
|||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_TAIL_CALL == 0
|
||||
if (feature_flags & WASM_FEATURE_TAIL_CALL) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"tail call is not enabled in this build");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_GC == 0
|
||||
if (feature_flags & WASM_FEATURE_GARBAGE_COLLECTION) {
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
|
@ -1186,8 +1178,12 @@ load_init_expr(const uint8 **p_buf, const uint8 *buf_end, AOTModule *module,
|
|||
case INIT_EXPR_TYPE_GET_GLOBAL:
|
||||
read_uint32(buf, buf_end, expr->u.global_index);
|
||||
break;
|
||||
#if WASM_ENABLE_GC != 0 || WASM_ENABLE_REF_TYPES != 0
|
||||
/* INIT_EXPR_TYPE_FUNCREF_CONST can be used when
|
||||
both reference types and GC are disabled */
|
||||
case INIT_EXPR_TYPE_FUNCREF_CONST:
|
||||
read_uint32(buf, buf_end, expr->u.ref_index);
|
||||
break;
|
||||
#if WASM_ENABLE_GC != 0 || WASM_ENABLE_REF_TYPES != 0
|
||||
case INIT_EXPR_TYPE_REFNULL_CONST:
|
||||
read_uint32(buf, buf_end, expr->u.ref_index);
|
||||
break;
|
||||
|
|
|
@ -25,16 +25,16 @@ extern "C" {
|
|||
/* Wasm feature supported, mainly used by AOTTargetInfo now */
|
||||
#define WASM_FEATURE_SIMD_128BIT (1 << 0)
|
||||
#define WASM_FEATURE_BULK_MEMORY (1 << 1)
|
||||
#define WASM_FEATURE_THREADS (1 << 2)
|
||||
#define WASM_FEATURE_MULTI_THREAD (1 << 2)
|
||||
#define WASM_FEATURE_REF_TYPES (1 << 3)
|
||||
#define WASM_FEATURE_TAIL_CALL (1 << 4)
|
||||
#define WASM_FEATURE_GARBAGE_COLLECTION (1 << 4)
|
||||
#define WASM_FEATURE_EXCEPTION_HANDLING (1 << 5)
|
||||
#define WASM_FEATURE_GARBAGE_COLLECTION (1 << 6)
|
||||
#define WASM_FEATURE_COMPONENT_MODEL (1 << 7)
|
||||
#define WASM_FEATURE_MULTIPLE_MEMORY (1 << 8)
|
||||
#define WASM_FEATURE_RELAXED_SIMD (1 << 9)
|
||||
#define WASM_FEATURE_FLEXIBLE_VECTORS (1 << 10)
|
||||
#define WASM_FEATURE_STRING_REF (1 << 11)
|
||||
#define WASM_FEATURE_MEMORY64 (1 << 6)
|
||||
#define WASM_FEATURE_MULTI_MEMORY (1 << 7)
|
||||
#define WASM_FEATURE_DYNAMIC_LINKING (1 << 8)
|
||||
#define WASM_FEATURE_COMPONENT_MODEL (1 << 9)
|
||||
#define WASM_FEATURE_RELAXED_SIMD (1 << 10)
|
||||
#define WASM_FEATURE_FLEXIBLE_VECTORS (1 << 11)
|
||||
|
||||
typedef enum AOTSectionType {
|
||||
AOT_SECTION_TYPE_TARGET_INFO = 0,
|
||||
|
|
|
@ -4389,14 +4389,11 @@ aot_obj_data_create(AOTCompContext *comp_ctx)
|
|||
obj_data->target_info.feature_flags |= WASM_FEATURE_BULK_MEMORY;
|
||||
}
|
||||
if (comp_ctx->enable_thread_mgr) {
|
||||
obj_data->target_info.feature_flags |= WASM_FEATURE_THREADS;
|
||||
obj_data->target_info.feature_flags |= WASM_FEATURE_MULTI_THREAD;
|
||||
}
|
||||
if (comp_ctx->enable_ref_types) {
|
||||
obj_data->target_info.feature_flags |= WASM_FEATURE_REF_TYPES;
|
||||
}
|
||||
if (comp_ctx->enable_tail_call) {
|
||||
obj_data->target_info.feature_flags |= WASM_FEATURE_TAIL_CALL;
|
||||
}
|
||||
if (comp_ctx->enable_gc) {
|
||||
obj_data->target_info.feature_flags |= WASM_FEATURE_GARBAGE_COLLECTION;
|
||||
}
|
||||
|
|
|
@ -3075,17 +3075,25 @@ aot_create_comp_context(const AOTCompData *comp_data, aot_comp_option_t option)
|
|||
LLVMDisposeMessage(triple);
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
WASMModule *wasm_module = (WASMModule *)comp_data->wasm_module;
|
||||
|
||||
/* Return error if SIMD is disabled by command line but SIMD instructions
|
||||
* are used */
|
||||
if (!option->enable_simd
|
||||
&& ((WASMModule *)comp_data->wasm_module)->is_simd_used) {
|
||||
if (!option->enable_simd && wasm_module->is_simd_used) {
|
||||
aot_set_last_error("SIMD is disabled by --disable-simd but SIMD "
|
||||
"instructions are used in this module");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!((WASMModule *)comp_data->wasm_module)->is_simd_used) {
|
||||
option->enable_simd = false;
|
||||
/* Disable features when they are not actually used */
|
||||
if (!wasm_module->is_simd_used) {
|
||||
option->enable_simd = comp_ctx->enable_simd = false;
|
||||
}
|
||||
if (!wasm_module->is_ref_types_used) {
|
||||
option->enable_ref_types = comp_ctx->enable_ref_types = false;
|
||||
}
|
||||
if (!wasm_module->is_bulk_memory_used) {
|
||||
option->enable_bulk_memory = comp_ctx->enable_bulk_memory = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -980,6 +980,8 @@ struct WASMModule {
|
|||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
bool is_simd_used;
|
||||
bool is_ref_types_used;
|
||||
bool is_bulk_memory_used;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -854,6 +854,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
|
|||
0, &cur_value, error_buf,
|
||||
error_buf_size))
|
||||
goto fail;
|
||||
#endif
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
@ -896,6 +899,9 @@ load_init_expr(WASMModule *module, const uint8 **p_buf, const uint8 *buf_end,
|
|||
error_buf_size))
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
@ -1619,6 +1625,13 @@ resolve_func_type(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
|
|||
type->quick_aot_entry = wasm_native_lookup_quick_aot_entry(type);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
for (i = 0; i < type->param_count + type->result_count; i++) {
|
||||
if (type->types[i] == VALUE_TYPE_V128)
|
||||
module->is_simd_used = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Calculate the minimal type index of the type equal to this type */
|
||||
type->min_type_idx_normalized = type_idx;
|
||||
for (i = 0; i < type_idx; i++) {
|
||||
|
@ -1994,6 +2007,16 @@ load_type_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
|||
type->quick_aot_entry = wasm_native_lookup_quick_aot_entry(type);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
for (j = 0; j < type->param_count + type->result_count; j++) {
|
||||
if (type->types[j] == VALUE_TYPE_V128)
|
||||
module->is_simd_used = true;
|
||||
else if (type->types[j] == VALUE_TYPE_FUNCREF
|
||||
|| type->types[j] == VALUE_TYPE_EXTERNREF)
|
||||
module->is_ref_types_used = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If there is already a same type created, use it instead */
|
||||
for (j = 0; j < i; j++) {
|
||||
if (wasm_type_equal(type, module->types[j], module->types, i)) {
|
||||
|
@ -2627,6 +2650,10 @@ load_table_import(const uint8 **p_buf, const uint8 *buf_end,
|
|||
table->flags = declare_max_size_flag;
|
||||
table->max_size = declare_max_size;
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
if (table->elem_type == VALUE_TYPE_EXTERNREF)
|
||||
parent_module->is_ref_types_used = true;
|
||||
#endif
|
||||
(void)parent_module;
|
||||
return true;
|
||||
fail:
|
||||
|
@ -2868,6 +2895,12 @@ load_global_import(const uint8 **p_buf, const uint8 *buf_end,
|
|||
global->type = declare_type;
|
||||
global->is_mutable = (declare_mutable == 1);
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
if (global->type == VALUE_TYPE_V128)
|
||||
parent_module->is_simd_used = true;
|
||||
else if (global->type == VALUE_TYPE_EXTERNREF)
|
||||
parent_module->is_ref_types_used = true;
|
||||
#endif
|
||||
(void)parent_module;
|
||||
(void)ret;
|
||||
return true;
|
||||
|
@ -2955,6 +2988,11 @@ load_table(const uint8 **p_buf, const uint8 *buf_end, WASMModule *module,
|
|||
|
||||
adjust_table_max_size(table->init_size, table->flags, &table->max_size);
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
if (table->elem_type == VALUE_TYPE_EXTERNREF)
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
|
||||
*p_buf = p;
|
||||
return true;
|
||||
fail:
|
||||
|
@ -3095,13 +3133,15 @@ load_import_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
|||
read_leb_uint32(p, p_end, u32);
|
||||
module->import_table_count++;
|
||||
|
||||
#if WASM_ENABLE_REF_TYPES == 0 && WASM_ENABLE_GC == 0
|
||||
if (module->import_table_count > 1) {
|
||||
#if WASM_ENABLE_REF_TYPES == 0 && WASM_ENABLE_GC == 0
|
||||
set_error_buf(error_buf, error_buf_size,
|
||||
"multiple tables");
|
||||
return false;
|
||||
}
|
||||
#elif WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case IMPORT_KIND_MEMORY: /* import memory */
|
||||
|
@ -3510,6 +3550,13 @@ load_function_section(const uint8 *buf, const uint8 *buf_end,
|
|||
for (k = 0; k < sub_local_count; k++) {
|
||||
func->local_types[local_type_index++] = type;
|
||||
}
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
if (type == VALUE_TYPE_V128)
|
||||
module->is_simd_used = true;
|
||||
else if (type == VALUE_TYPE_FUNCREF
|
||||
|| type == VALUE_TYPE_EXTERNREF)
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bh_assert(local_type_index == func->local_count);
|
||||
|
@ -3573,13 +3620,15 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
|||
WASMTable *table;
|
||||
|
||||
read_leb_uint32(p, p_end, table_count);
|
||||
#if WASM_ENABLE_REF_TYPES == 0 && WASM_ENABLE_GC == 0
|
||||
if (module->import_table_count + table_count > 1) {
|
||||
#if WASM_ENABLE_REF_TYPES == 0 && WASM_ENABLE_GC == 0
|
||||
/* a total of one table is allowed */
|
||||
set_error_buf(error_buf, error_buf_size, "multiple tables");
|
||||
return false;
|
||||
}
|
||||
#elif WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (table_count) {
|
||||
module->table_count = table_count;
|
||||
|
@ -3643,6 +3692,11 @@ load_table_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
|||
}
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_GC != 0 */
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
if (table->elem_type == VALUE_TYPE_EXTERNREF)
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3741,6 +3795,14 @@ load_global_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
|
|||
mutable = read_uint8(p);
|
||||
#endif /* end of WASM_ENABLE_GC */
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
if (global->type == VALUE_TYPE_V128)
|
||||
module->is_simd_used = true;
|
||||
else if (global->type == VALUE_TYPE_FUNCREF
|
||||
|| global->type == VALUE_TYPE_EXTERNREF)
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
|
||||
if (!check_mutability(mutable, error_buf, error_buf_size)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -4302,6 +4364,11 @@ load_table_segment_section(const uint8 *buf, const uint8 *buf_end,
|
|||
error_buf, error_buf_size))
|
||||
return false;
|
||||
#endif /* WASM_ENABLE_REF_TYPES != 0 */
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
if (table_segment->elem_type == VALUE_TYPE_EXTERNREF)
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4358,6 +4425,9 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end,
|
|||
switch (mem_flag) {
|
||||
case 0x01:
|
||||
is_passive = true;
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_bulk_memory_used = true;
|
||||
#endif
|
||||
break;
|
||||
case 0x00:
|
||||
/* no memory index, treat index as 0 */
|
||||
|
@ -4366,6 +4436,9 @@ load_data_segment_section(const uint8 *buf, const uint8 *buf_end,
|
|||
case 0x02:
|
||||
/* read following memory index */
|
||||
read_leb_uint32(p, p_end, mem_index);
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_bulk_memory_used = true;
|
||||
#endif
|
||||
check_mem_index:
|
||||
if (mem_index
|
||||
>= module->import_memory_count + module->memory_count) {
|
||||
|
@ -4451,6 +4524,9 @@ load_datacount_section(const uint8 *buf, const uint8 *buf_end,
|
|||
return false;
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_bulk_memory_used = true;
|
||||
#endif
|
||||
LOG_VERBOSE("Load datacount section success.\n");
|
||||
return true;
|
||||
fail:
|
||||
|
@ -10184,6 +10260,13 @@ re_scan:
|
|||
* the single return value. */
|
||||
block_type.is_value_type = true;
|
||||
block_type.u.value_type.type = value_type;
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
if (value_type == VALUE_TYPE_V128)
|
||||
module->is_simd_used = true;
|
||||
else if (value_type == VALUE_TYPE_FUNCREF
|
||||
|| value_type == VALUE_TYPE_EXTERNREF)
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
#if WASM_ENABLE_GC != 0
|
||||
if (value_type != VALUE_TYPE_VOID) {
|
||||
p_org = p;
|
||||
|
@ -11274,6 +11357,9 @@ re_scan:
|
|||
#endif
|
||||
PUSH_REF(type);
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
(void)vec_len;
|
||||
break;
|
||||
}
|
||||
|
@ -11325,6 +11411,9 @@ re_scan:
|
|||
POP_I32();
|
||||
}
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case WASM_OP_REF_NULL:
|
||||
|
@ -11365,6 +11454,10 @@ re_scan:
|
|||
PUSH_OFFSET_TYPE(ref_type);
|
||||
#endif
|
||||
PUSH_TYPE(ref_type);
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case WASM_OP_REF_IS_NULL:
|
||||
|
@ -11416,6 +11509,10 @@ re_scan:
|
|||
}
|
||||
#endif
|
||||
PUSH_I32();
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case WASM_OP_REF_FUNC:
|
||||
|
@ -11483,6 +11580,10 @@ re_scan:
|
|||
false, type_idx);
|
||||
PUSH_REF(wasm_ref_type.ref_type);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */
|
||||
|
@ -13426,6 +13527,9 @@ re_scan:
|
|||
POP_I32();
|
||||
#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
|
||||
func->has_memory_operations = true;
|
||||
#endif
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_bulk_memory_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
@ -13446,6 +13550,9 @@ re_scan:
|
|||
|
||||
#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
|
||||
func->has_memory_operations = true;
|
||||
#endif
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_bulk_memory_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
@ -13465,6 +13572,9 @@ re_scan:
|
|||
POP_I32();
|
||||
#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
|
||||
func->has_memory_operations = true;
|
||||
#endif
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_bulk_memory_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
@ -13483,6 +13593,9 @@ re_scan:
|
|||
POP_I32();
|
||||
#if WASM_ENABLE_JIT != 0 || WASM_ENABLE_WAMR_COMPILER != 0
|
||||
func->has_memory_operations = true;
|
||||
#endif
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_bulk_memory_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
@ -13553,6 +13666,10 @@ re_scan:
|
|||
POP_I32();
|
||||
POP_I32();
|
||||
POP_I32();
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case WASM_OP_ELEM_DROP:
|
||||
|
@ -13565,6 +13682,10 @@ re_scan:
|
|||
#if WASM_ENABLE_FAST_INTERP != 0
|
||||
emit_uint32(loader_ctx, table_seg_idx);
|
||||
#endif
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case WASM_OP_TABLE_COPY:
|
||||
|
@ -13618,6 +13739,10 @@ re_scan:
|
|||
POP_I32();
|
||||
POP_I32();
|
||||
POP_I32();
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case WASM_OP_TABLE_SIZE:
|
||||
|
@ -13634,6 +13759,10 @@ re_scan:
|
|||
#endif
|
||||
|
||||
PUSH_I32();
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case WASM_OP_TABLE_GROW:
|
||||
|
@ -13687,6 +13816,10 @@ re_scan:
|
|||
PUSH_I32();
|
||||
else
|
||||
POP_I32();
|
||||
|
||||
#if WASM_ENABLE_WAMR_COMPILER != 0
|
||||
module->is_ref_types_used = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#endif /* end of WASM_ENABLE_REF_TYPES != 0 || WASM_ENABLE_GC != 0 */
|
||||
|
|
Loading…
Reference in New Issue
Block a user