Skip to content

Commit

Permalink
* allow for value of a declared integer to be a value that has
Browse files Browse the repository at this point in the history
a destructor.  This fixes ticket:937.
  • Loading branch information
Shawn David Pringle, B.Sc. committed Dec 30, 2024
1 parent 5f6c867 commit 793ba70
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 46 deletions.
35 changes: 17 additions & 18 deletions docs/internals.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,14 @@ Euphoria.

==== The Euphoria representation of a Euphoria Object =====

Every Euphoria object is stored as-is. A special unlikely floating point value
Every Euphoria object in the Euphoria backend is stored as-is. A special unlikely floating point value
is used for ##NOVALUE##. ##NOVALUE## signifies that a variable has not been
assigned a value or the end of a sequence.

==== The C Representation of a Euphoria Object =====

Every Euphoria object is either stored as is, or as an encoded pointer. A
Euphoria ##integer## is stored in a 32-bit signed integer. If the number is too
big for a Euphoria ##integer##, it is assigned to a 64-bit double float in a
structure and an encoded pointer to that structure is stored in the said 32-bit
memory space. Sequences are stored in a similar way.
Euphoria ##integer## is often stored in a 32-bit or 64-bit signed integer. If the number is too big for a Euphoria ##integer##, has a fraction part, or has a destructor associated with it; it is assigned to a 64-bit double float in a structure and an encoded pointer to that structure is stored in the said 64 bit or 32-bit memory space. Sequences are stored in a similar way: An encoded pointer is stored, and this pointer points to a sequence structure.

{{{

Expand All @@ -63,15 +60,13 @@ memory space. Sequences are stored in a similar way.
|<-------- integer --------->|
|<--------------------- object ---------------------->|


}}}

The 64-bit system is not documented here. Refer to euphoria.h for detail on the 64-bit version of the scheme outlined above.

Euphoria integers are stored in object variables as-is. An object variable is a
four byte signed integer. Legal integer values for Euphoria integers are
between -1,073,741,824 ( -2^^30^^ ) and +1,073,741,823 ( 2^^30^^-1 ).
Unsigned hexadecimal numbers from C000_0000 to FFFF_FFFF are the negative
integers and numbers from 0000_0000 to 3FFF_FFFF are the positive integers. The
hexadecimal values not used as integers are thus 4000_0000 to BFFF_FFFF. Other
Euphoria integers are stored in object variables as-is. An object variable is a four byte signed integer and is even its own value or an encoded pointer. Legal integer values for Euphoria integers are between -1,073,741,824 ( -2^^30^^ ) and +1,073,741,823 ( 2^^30^^-1 ).
Unsigned hexadecimal numbers from C000_0000 to FFFF_FFFF are the negative integers and numbers from 0000_0000 to 3FFF_FFFF are the positive integers. The hexadecimal values not used as integers are thus 4000_0000 to BFFF_FFFF. Other
values are for encoded pointers. Pointers are always 8 byte aligned. So a
pointer is stored in 29-bits instead of 32 and can fit in a hexadecimal range
0x2000_0000 long. The pointers are encoded in such a way that their encoded values
Expand All @@ -84,11 +79,13 @@ variable and it also signifies the end of a sequence. In C, values of this type
are stored in the 'object' type. The range 4000_0000 to 7FFF_FFFF is unused.

A double structure 'struct d' could indeed contain a value that is legally in
the range of a Euphoria integer. So the encoded pointer to this structure is
the range of a Euphoria integer and has no fraction part. So the encoded pointer to this structure is
recognized by the interpreter as an 'integer' but in this internals document
when we say Euphoria integer we mean it actually is a C integer in the legal
Euphoria integer range.

Objects declared as integer may use encoded pointers to double structures in its representation even after type checking
due to changes made for ticket 937.

=== The C Representations of a Euphoria Sequence and a Euphoria Atom =====

Expand Down Expand Up @@ -182,13 +179,13 @@ in struct s1. To this end, the 64bit implementation of 4.1 has these members in

The macros are imperfect. For example, ##IS_SEQUENCE(NOVALUE)## returns
##TRUE## and ##IS_ATOM_DBL## will return ##TRUE## for integer values as well
as encoded pointers to
'struct d's. This is why there is an order that these tests are made: We test
##IS_ATOM_INT## and if that fails we can use ##IS_ATOM_DBL## and then that will
only be true if we pass an encoded pointer to a double. We must be sure that
something is not ##NOVALUE## before we use ##IS_SEQUENCE## on it.
as encoded pointers to 'struct d's. This is why there is an order that these tests are made:
First, we must either by logic or testing ensure that a value cannot be NOVALUE, and
then we can rely on ##IS_ATOM_INT## to determine that a value is not a pointer to a double structure,
or a sequence structure. Then we may use IS_ATOM_DBL to test that it is a pointer to a double structure.
We must be sure that something is not ##NOVALUE## before we use ##IS_SEQUENCE## on it.

// Often we know foo is not NOVALUE before getting into this://
// Often we know something (foo) is not NOVALUE before getting into this://

{{{
// object foo
Expand All @@ -207,6 +204,8 @@ A sequence is held in a 'struct s1' type and a double is contained in a

=== Type Value Functions and Macros



@[:internals:IS_ATOM_INT|]
==== IS_ATOM_INT
<eucode>
Expand Down
2 changes: 2 additions & 0 deletions include/euphoria.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ object Dor_bits(d_ptr a, d_ptr b);
object Dxor_bits(d_ptr a, d_ptr b);
object not_bits(object a);
object Dxor(object a, object b);
object Dor(object a, object b);
object Xor(object a, object b);
object Date();
cleanup_ptr ChainDeleteRoutine( cleanup_ptr old, cleanup_ptr prev );
cleanup_ptr DeleteRoutine( object e_index );
Expand Down
8 changes: 1 addition & 7 deletions source/be_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1934,7 +1934,7 @@ void do_exec(intptr_t *start_pc)
int end_pos;
int going_up;
object_ptr result_ptr;
object result_val;
object result_val=0;
int cf;
int seqlen;
opcode_type *patch;
Expand Down Expand Up @@ -2772,12 +2772,6 @@ void do_exec(intptr_t *start_pc)
tpc = pc;
a = DoubleToInt(top);
if (IS_ATOM_INT(a)) {
if (UNIQUE(DBL_PTR(top)) && (DBL_PTR(top)->cleanup != 0)) {
tpc = pc - 1; //RTFatalType(pc-1);
RTFatal("Cannot assign value with a destructor to an integer");
}
DeRefDS(top);
*(object_ptr)pc[-1] = a;
BREAK;
}
}
Expand Down
10 changes: 5 additions & 5 deletions source/compile.e
Original file line number Diff line number Diff line change
Expand Up @@ -2988,12 +2988,12 @@ procedure opINTEGER_CHECK()
LeftSym = TRUE
c_stmt("_1 = (object)(DBL_PTR(@)->dbl);\n", sym)
LeftSym = TRUE
c_stmt( "if (UNIQUE(DBL_PTR(@)) && (DBL_PTR(@)->cleanup != 0))\n" &
"RTFatal(\"Cannot assign value with a destructor to an integer\");", {sym, sym})
c_stmt("DeRefDS(@);\n", sym)
c_stmt("@ = _1;\n", sym)
-- The BB_var_type may still be a Dptr structure after an integer check.
c_stmt( "if (!UNIQUE(DBL_PTR(@)) || (DBL_PTR(@)->cleanup == 0)) {\n", {sym, sym})
c_stmt( "DeRefDS(@);\n", {sym})
c_stmt( "@ = _1;\n", {sym})
c_stmt0("}\n")
SetBBType(sym, TYPE_INTEGER, novalue, TYPE_OBJECT, 0 )
c_stmt0("}\n")
end if
pc += 2
end procedure
Expand Down
16 changes: 2 additions & 14 deletions source/emit.e
Original file line number Diff line number Diff line change
Expand Up @@ -220,23 +220,11 @@ function IsInteger(symtab_index sym)

if sym < 1 then
-- probably a forward reference
return 0
return FALSE
end if

mode = SymTab[sym][S_MODE]
if mode = M_NORMAL then
t = SymTab[sym][S_VTYPE]
if t = integer_type then
return TRUE
end if
if t > 0 then
pt = SymTab[t][S_NEXT]
if pt and SymTab[pt][S_VTYPE] = integer_type then
return TRUE -- usertype(integer x)
end if
end if

elsif mode = M_CONSTANT then
if mode = M_CONSTANT then
if integer(SymTab[sym][S_OBJ]) then -- bug fixed: can't allow PLUS1_I op
return TRUE
end if
Expand Down
4 changes: 2 additions & 2 deletions source/parser.e
Original file line number Diff line number Diff line change
Expand Up @@ -3366,7 +3366,7 @@ export function CompileType(symtab_index type_ptr)
return TYPE_OBJECT

elsif type_ptr = integer_type then
return TYPE_INTEGER
return TYPE_ATOM

elsif type_ptr = atom_type then
return TYPE_ATOM
Expand All @@ -3381,7 +3381,7 @@ export function CompileType(symtab_index type_ptr)
-- user defined - look at type of the parameter of the type
t = SymTab[SymTab[type_ptr][S_NEXT]][S_VTYPE]
if t = integer_type then
return TYPE_INTEGER
return TYPE_ATOM
elsif t = atom_type then
return TYPE_ATOM
elsif t = sequence_type then
Expand Down
73 changes: 73 additions & 0 deletions tests/t_937.e
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
include std/io.e
include std/error.e
include std/unittest.e
with trace
trace(1)


type enum boolean T,F=0 end type
type file_number(integer x)
return x >= -1
end type

boolean enable_my_close = F

procedure my_close(integer fh)
if fh > io:STDERR then
-- Closing file
if not enable_my_close then
test_fail("premature file closing")
end if
close(fh)
end if
test_pass("dstor called")
end procedure

procedure do_nothing(integer bool)
end procedure

-- Make sure a user defined type that is integer based can have routine_ids too.
procedure use_integer_with_dtor()
file_number f_debug = open("example.log", "w")
if f_debug =-1 then
f_debug = open("/dev/null", "w")
puts(io:STDERR, "Unable to create log file.")
else
f_debug = delete_routine(f_debug, routine_id("my_close"))
end if
end procedure

enable_my_close = T

-- dtor will be called when this routine exits.
use_integer_with_dtor()


enable_my_close = F
file_number f_debug = open("example.log", "w")
if f_debug =-1 then
f_debug = open("/dev/null", "w")
puts(io:STDERR, "Unable to create log file.")
else
f_debug = delete_routine(f_debug, routine_id("my_close"))
end if

enable_my_close = T
-- dtor will be executed by changing its value to a new one.
f_debug = -1


enable_my_close = F
f_debug = open("example.log", "w")
if f_debug =-1 then
f_debug = open("/dev/null", "w")
puts(io:STDERR, "Unable to create log file.")
else
f_debug = delete_routine(f_debug, routine_id("my_close"))
end if

enable_my_close = T
-- dtor will be executed by changing its value to a new one.
f_debug += 1

test_report()
26 changes: 26 additions & 0 deletions tests/t_autoclose.e
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
include std/unittest.e

type enum boolean
FALSE=0,TRUE
end type

boolean cleanedup = FALSE

procedure cleanup_now(object in_put)
cleanedup = TRUE
end procedure

integer fd = open("t_autoclose.e", "r", 1)

test_pass( "able to assign integers to integer with destructors" )

function wrapper()
return delete_routine(4, routine_id("cleanup_now"))
end function

integer other = wrapper()

other = 3

test_equal("Cleaned up called", TRUE, cleanedup)
test_report()

0 comments on commit 793ba70

Please sign in to comment.