diff --git a/src/code/amd64.c b/src/code/amd64.c index 744fcb75a10d1e5825493cf92edc0192a8c960d3..8ea8b68933cac7fb4571313037da0c785d796716 100644 --- a/src/code/amd64.c +++ b/src/code/amd64.c @@ -3058,6 +3058,92 @@ void ins_f_byte_with_2_args(unsigned int a, INT32 b, INT32 c) ins_f_byte(F_MARK); ins_f_byte_with_2_args(F_EXTERNAL, b, c); return; + + case F_ASSIGN_PRIVATE_TYPED_GLOBAL_AND_POP: + case F_ASSIGN_PRIVATE_TYPED_GLOBAL: + { + LABELS(); + amd64_load_sp_reg(); + + ins_debug_instr_prologue(a-F_OFFSET, b, 0); + + amd64_get_storage( P_REG_RBX, b ); + + /* do not assign anything if this object is destructed. */ + + /* we really only need to redo this check after we have called + some other function. It is sort of hard to know when that + happens while generating the code, however. Simply assigning + the global could in theory actually destruct this object (old + value includes something with a destroy that calls destruct on + this object...) + + Note that nothing crash if we do the assign. We "just" leak the + variable when the storage is eventually free:d. + + The generated code does look sort of silly, however. + */ + mov_mem_reg( fp_reg, OFFSETOF(pike_frame,current_object), ARG1_REG ); + mov_mem_reg( ARG1_REG, OFFSETOF(object,prog), P_REG_RAX ); + test_reg(P_REG_RAX); + jnz(&label_A); + + /* will not return. */ + amd64_call_c_function(object_low_set_index); + + LABEL_A; + /* 1: check type of argument */ + mov_mem8_reg( sp_reg, -sizeof(struct svalue )+OFFSETOF(svalue,tu.t.type), P_REG_RAX); + cmp_reg32_imm( P_REG_RAX, c ); + je( &label_B ); + + /* not the same type. Fall back to use C-function (for code size mainly).. */ + mov_reg_reg( P_REG_RBX, ARG1_REG ); + mov_imm_reg( c, ARG2_REG ); + add_reg_imm_reg( sp_reg, -sizeof(struct svalue), ARG3_REG ); + amd64_call_c_function(assign_to_short_svalue); + /* pop stack if needed. */ + if( a == F_ASSIGN_PRIVATE_GLOBAL_AND_POP ) + { + amd64_add_sp(-1); + /* this will either have assigned 0 or thrown an error. + * if we assigned 0, it was because the argument evaluated as false. + * However, that means that we might possibly have to free it here.. + * + * We do not even know that is has at least two references. + */ + amd64_free_svalue( sp_reg, 0 ); + } + + jmp( &label_E ); /* pop or not. */ + + LABEL_B; + /* at this point: o->storage + off in RBX. */ + if( c >= MIN_REF_TYPE ) + { + mov_mem_reg( P_REG_RBX, 0, P_REG_RAX ); + test_reg(P_REG_RAX); /* old value == NULL? */ + jz(&label_C); + + /* deref. */ + add_mem32_imm( P_REG_RAX, OFFSETOF(pike_string,refs), -1); + jnz(&label_C); + + mov_reg_reg( P_REG_RBX, ARG1_REG ); + mov_imm_reg( c, ARG2_REG ); + amd64_call_c_function(really_free_short_svalue_ptr); + } + LABEL_C; /* old value is gone. Assign new value */ + mov_mem_reg( sp_reg, -8, P_REG_RAX ); + mov_reg_mem( P_REG_RAX, P_REG_RBX, 0 ); + + if( a == F_ASSIGN_PRIVATE_GLOBAL_AND_POP ) + amd64_add_sp( -1 ); + else if( c >= MIN_REF_TYPE ) + add_mem_imm( P_REG_RAX, OFFSETOF(pike_string,refs), 1 ); + LABEL_E; + } + return; case F_PRIVATE_TYPED_GLOBAL: /* b -> off, c -> type */ ins_debug_instr_prologue(a-F_OFFSET, b, c); diff --git a/src/docode.c b/src/docode.c index 8d52eb9a4e5aeccd9393865f2b8aff7b6a37e33e..4022bd796ab4a7c32434bf93f505c90413e8a905 100644 --- a/src/docode.c +++ b/src/docode.c @@ -710,11 +710,14 @@ static void emit_assign_global( int n, int and_pop ) && !(id->identifier_flags & IDENTIFIER_NO_THIS_REF) && !IDENTIFIER_IS_ALIAS(id->identifier_flags) && IDENTIFIER_IS_VARIABLE(id->identifier_flags) - && !ref->inherit_offset - && id->run_time_type == PIKE_T_MIXED ) + && !ref->inherit_offset ) { - emit1((and_pop?F_ASSIGN_PRIVATE_GLOBAL_AND_POP:F_ASSIGN_PRIVATE_GLOBAL), - id->func.offset); + if( id->run_time_type == PIKE_T_MIXED ) + emit1((and_pop?F_ASSIGN_PRIVATE_GLOBAL_AND_POP:F_ASSIGN_PRIVATE_GLOBAL), + id->func.offset); + else + emit2((and_pop?F_ASSIGN_PRIVATE_TYPED_GLOBAL_AND_POP:F_ASSIGN_PRIVATE_TYPED_GLOBAL), + id->func.offset, id->run_time_type); } else { diff --git a/src/interpret_functions.h b/src/interpret_functions.h index 3ac46b71970fffc1d394f07a37b9801d260451a2..994b80790d73aa5b4085b0799d3bedab684053bb 100644 --- a/src/interpret_functions.h +++ b/src/interpret_functions.h @@ -365,7 +365,30 @@ OPCODE1(F_PRIVATE_GLOBAL, "global <private>", I_UPDATE_SP, { print_return_value(); }); -OPCODE2(F_PRIVATE_TYPED_GLOBAL, "global <private>", I_UPDATE_SP, { +OPCODE2(F_ASSIGN_PRIVATE_TYPED_GLOBAL_AND_POP, "assign global <private,typed> and pop", I_UPDATE_SP, { + /* lazy mode. */ + LOCAL_VAR(union anything *tmp); + LOCAL_VAR(struct object *co); + co = Pike_fp->current_object; + if(!co->prog) /* note: generate an error. */ + object_low_set_index(co,0,0); + tmp = (union anything *)(Pike_fp->current_object->storage + Pike_fp->context->storage_offset + arg1); + assign_to_short_svalue( tmp, arg2, Pike_sp-1 ); + pop_stack(); +}); + +OPCODE2(F_ASSIGN_PRIVATE_TYPED_GLOBAL, "assign global <private,typed>", 0, { + LOCAL_VAR(union anything *tmp); + LOCAL_VAR(struct object *co); + co = Pike_fp->current_object; + if(!co->prog) /* note: generate an error. */ + object_low_set_index(co,0,0); + tmp = (union anything *)(Pike_fp->current_object->storage + Pike_fp->context->storage_offset + arg1); + assign_to_short_svalue( tmp, arg2, Pike_sp-1); +}); + + +OPCODE2(F_PRIVATE_TYPED_GLOBAL, "global <private,typed>", I_UPDATE_SP, { LOCAL_VAR(struct object *co); LOCAL_VAR(void *ptr);