added the #uncopyable attribute to the class definition.

This commit is contained in:
hyunghwan.chung 2019-09-22 15:59:09 +00:00
parent 97f264398d
commit de72bc6b58
8 changed files with 115 additions and 80 deletions

View File

@ -69,6 +69,7 @@ The word class can be followed by attribute list enclosed in parenthesis. e.g.)
* #limited - not instantiable with new.
* #immutable - instantiated object to be read-only.
* #final - disallow subclasses.
* #uncopyable - instantiated object not to be copied.
* #byte, #character, #halfword, #word, #liword, #pointer -
specify the type of a non-pointer object. a non-pointer type can have an additional size
enclosed in parenthesis. e.g.) #character(2)

View File

@ -8,7 +8,7 @@ interface ClassInterface
// the Class object should be a variable-pointer object because
// it needs to accomodate class instance variables.
//
class(#pointer,#limited) Class(Apex) [ClassInterface]
class(#pointer,#limited,#uncopyable) Class(Apex) [ClassInterface]
{
var spec, selfspec, superclass, subclasses, name, modname.
var instvars, classinstvars, classvars, pooldics.
@ -44,7 +44,7 @@ class(#pointer,#limited) Class(Apex) [ClassInterface]
method nsdic { ^self.nsdic }
}
class(#pointer,#limited) Interface(Apex)
class(#pointer,#limited,#uncopyable) Interface(Apex)
{
var name.
var instmthdic, classmthdic, nsup.

View File

@ -1,5 +1,5 @@
class(#pointer,#final,#limited) Process(Object)
class(#pointer,#final,#limited,#uncopyable) Process(Object)
{
var(#get) initialContext, currentContext, id, state.
var sp.
@ -76,7 +76,7 @@ class(#pointer,#final,#limited) Process(Object)
}
}
class Semaphore(Object)
class(#uncopyable) Semaphore(Object)
{
var waiting_head := nil,
waiting_tail := nil.
@ -152,7 +152,7 @@ class Semaphore(Object)
}
}
class Mutex(Semaphore)
class(#uncopyable) Mutex(Semaphore)
{
method(#class) new
{
@ -179,7 +179,7 @@ TODO: how to prohibit wait and signal???
}
class SemaphoreGroup(Object)
class(#uncopyable) SemaphoreGroup(Object)
{
// the first two variables must match those of Semaphore.
var waiting_head := nil,
@ -252,7 +252,7 @@ method(#class,#abstract) xxx. => method(#class) xxx { self subclassResponsibilit
}
}
class SemaphoreHeap(Object)
class(#uncopyable) SemaphoreHeap(Object)
{
var arr, size.
@ -418,7 +418,7 @@ class SemaphoreHeap(Object)
}
}
class(#final,#limited) ProcessScheduler(Object)
class(#final,#limited,#uncopyable) ProcessScheduler(Object)
{
var(#get) active, total_count := 0.
var(#get) runnable_count := 0.

View File

@ -59,7 +59,8 @@ enum class_mod_t
CLASS_FINAL = (1 << 0),
CLASS_LIMITED = (1 << 1),
CLASS_INDEXED = (1 << 2),
CLASS_IMMUTABLE = (1 << 3)
CLASS_IMMUTABLE = (1 << 3),
CLASS_UNCOPYABLE = (1 << 4)
};
enum var_type_t
@ -163,6 +164,7 @@ static struct voca_t
{ 11, { 't','h','i','s','C','o','n','t','e','x','t' } },
{ 11, { 't','h','i','s','P','r','o','c','e','s','s' } },
{ 4, { 't','r','u','e' } },
{ 11, { '#','u','n','c','o','p','y','a','b','l','e' } },
{ 5, { 'u','n','t','i','l' } },
{ 3, { 'v','a','r' } },
{ 8, { 'v','a','r','i','a','b','l','e' } },
@ -233,6 +235,7 @@ enum voca_id_t
VOCA_THIS_CONTEXT,
VOCA_THIS_PROCESS,
VOCA_TRUE,
VOCA_UNCOPYABLE_S,
VOCA_UNTIL,
VOCA_VAR,
VOCA_VARIABLE,
@ -8147,6 +8150,7 @@ static int make_defined_class (moo_t* moo)
flags = 0;
if (cc->flags & CLASS_INDEXED) flags |= MOO_CLASS_SPEC_FLAG_INDEXED;
if (cc->flags & CLASS_IMMUTABLE) flags |= MOO_CLASS_SPEC_FLAG_IMMUTABLE;
if (cc->flags & CLASS_UNCOPYABLE) flags |= MOO_CLASS_SPEC_FLAG_UNCOPYABLE;
if (cc->non_pointer_instsize > 0)
{
@ -8415,6 +8419,16 @@ static int process_class_modifiers (moo_t* moo, moo_ioloc_t* type_loc)
cc->flags |= CLASS_IMMUTABLE;
GET_TOKEN(moo);
}
else if (is_token_symbol(moo, VOCA_UNCOPYABLE_S))
{
if (cc->flags & CLASS_UNCOPYABLE)
{
moo_setsynerr (moo, MOO_SYNERR_MODIFIERDUPL, TOKEN_LOC(moo), TOKEN_NAME(moo));
return -1;
}
cc->flags |= CLASS_UNCOPYABLE;
GET_TOKEN(moo);
}
else if (TOKEN_TYPE(moo) == MOO_IOTOK_COMMA || TOKEN_TYPE(moo) == MOO_IOTOK_EOF || TOKEN_TYPE(moo) == MOO_IOTOK_RPAREN)
{
/* no modifier is present */
@ -9077,7 +9091,6 @@ static int __compile_class_definition (moo_t* moo, int class_type)
while (1);
}
/* TODO: load constants here? */
}
else

View File

@ -124,7 +124,7 @@ static kernel_class_info_t kernel_classes[] =
MOO_CLASS_SELFSPEC_FLAG_LIMITED,
0,
MOO_CLASS_NAMED_INSTVARS,
1,
MOO_CLASS_SPEC_FLAG_INDEXED | MOO_CLASS_SPEC_FLAG_UNCOPYABLE,
MOO_OBJ_TYPE_OOP,
MOO_OFFSETOF(moo_t, _class) },
@ -133,7 +133,7 @@ static kernel_class_info_t kernel_classes[] =
MOO_CLASS_SELFSPEC_FLAG_LIMITED,
0,
MOO_INTERFACE_NAMED_INSTVARS,
1,
MOO_CLASS_SPEC_FLAG_INDEXED | MOO_CLASS_SPEC_FLAG_UNCOPYABLE,
MOO_OBJ_TYPE_OOP,
MOO_OFFSETOF(moo_t, _interface) },
@ -278,7 +278,7 @@ static kernel_class_info_t kernel_classes[] =
MOO_CLASS_SELFSPEC_FLAG_FINAL | MOO_CLASS_SELFSPEC_FLAG_LIMITED,
0,
MOO_PROCESS_NAMED_INSTVARS,
MOO_CLASS_SPEC_FLAG_INDEXED,
MOO_CLASS_SPEC_FLAG_INDEXED | MOO_CLASS_SPEC_FLAG_UNCOPYABLE,
MOO_OBJ_TYPE_OOP,
MOO_OFFSETOF(moo_t, _process) },
@ -287,7 +287,7 @@ static kernel_class_info_t kernel_classes[] =
0,
0,
MOO_SEMAPHORE_NAMED_INSTVARS,
0,
MOO_CLASS_SPEC_FLAG_UNCOPYABLE,
MOO_OBJ_TYPE_OOP,
MOO_OFFSETOF(moo_t, _semaphore) },
@ -296,7 +296,7 @@ static kernel_class_info_t kernel_classes[] =
0,
0,
MOO_SEMAPHORE_GROUP_NAMED_INSTVARS,
0,
MOO_CLASS_SPEC_FLAG_UNCOPYABLE,
MOO_OBJ_TYPE_OOP,
MOO_OFFSETOF(moo_t, _semaphore_group) },
@ -305,7 +305,7 @@ static kernel_class_info_t kernel_classes[] =
MOO_CLASS_SELFSPEC_FLAG_FINAL | MOO_CLASS_SELFSPEC_FLAG_LIMITED,
0,
MOO_PROCESS_SCHEDULER_NAMED_INSTVARS,
0,
MOO_CLASS_SPEC_FLAG_UNCOPYABLE,
MOO_OBJ_TYPE_OOP,
MOO_OFFSETOF(moo_t, _process_scheduler) },
@ -422,11 +422,17 @@ static moo_oow_t move_finalizable_objects (moo_t* moo);
static moo_oop_class_t alloc_kernel_class (moo_t* moo, int class_flags, moo_oow_t num_classvars, moo_oow_t spec)
{
moo_oop_class_t c;
moo_ooi_t cspec;
c = (moo_oop_class_t)moo_allocoopobj(moo, MOO_CLASS_NAMED_INSTVARS + num_classvars);
if (!c) return MOO_NULL;
MOO_OBJ_SET_FLAGS_KERNEL (c, MOO_OBJ_FLAGS_KERNEL_IMMATURE);
cspec = kernel_classes[KCI_CLASS].class_spec_flags;
if (MOO_CLASS_SPEC_IS_IMMUTABLE(cspec)) MOO_OBJ_SET_FLAGS_RDONLY (c, 1); /* just for completeness of code. will never be true as it's not defined in the kernel class info table */
if (MOO_CLASS_SPEC_IS_UNCOPYABLE(cspec)) MOO_OBJ_SET_FLAGS_UNCOPYABLE (c, 1); /* class itself is uncopyable */
MOO_OBJ_SET_CLASS (c, (moo_oop_t)moo->_class);
c->spec = MOO_SMOOI_TO_OOP(spec);
c->selfspec = MOO_SMOOI_TO_OOP(MOO_CLASS_SELFSPEC_MAKE(num_classvars, 0, class_flags));
@ -1120,7 +1126,7 @@ moo_oop_t moo_shallowcopy (moo_t* moo, moo_oop_t oop)
moo_oop_t z;
moo_oow_t total_bytes;
if (MOO_OBJ_GET_FLAGS_TRAILER(oop) || MOO_OBJ_GET_FLAGS_PROC(oop))
if (MOO_OBJ_GET_FLAGS_UNCOPYABLE(oop) || MOO_OBJ_GET_FLAGS_TRAILER(oop))
{
/* TOOD: should i disallow this or return without copying? */
moo_seterrbfmt (moo, MOO_EPERM, "not allowed to copy process or object with trailer");

View File

@ -140,13 +140,13 @@
* For example, on a platform where sizeof(moo_oow_t) is 4,
* the layout of the spec field of a class as an OOP value looks like this:
*
* 31 11 10 9 8 7 6 5 4 3 2 1 0
* 31 12 11 10 9 8 7 6 5 4 3 2 1 0
* |number of named instance variables|indexed-type|flags |oop-tag|
*
* the number of named instance variables is stored in high 23 bits.
* the indexed type takes up bit 3 to bit 8 (assuming MOO_OBJ_TYPE_BITS is 6.
* the number of named instance variables is stored in high 21 bits.
* the indexed type takes up bit 5 to bit 10 (assuming MOO_OBJ_TYPE_BITS is 6.
* MOO_OBJ_TYPE_XXX enumerators are used to represent actual values).
* and the indexability is stored in bit 2.
* and the indexability is stored in the flag bits which span from bit 2 to 4.
*
* The maximum number of named(fixed) instance variables for a class is:
* 2 ^ ((BITS-IN-OOW - MOO_OOP_TAG_BITS_LO) - MOO_OBJ_TYPE_BITS - 1 - 2) - 1
@ -161,36 +161,40 @@
* indexed_type is one of the #moo_obj_type_t enumerators.
*/
#define MOO_CLASS_SPEC_FLAG_BITS (3)
/*
* The MOO_CLASS_SPEC_MAKE() macro creates a class spec value.
* _class->spec = MOO_SMOOI_TO_OOP(MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_CHAR));
*/
#define MOO_CLASS_SPEC_MAKE(named_instvar,flags,indexed_type) ( \
(((moo_oow_t)(named_instvar)) << (MOO_OBJ_FLAGS_TYPE_BITS + 2)) | \
(((moo_oow_t)(indexed_type)) << 2) | (((moo_oow_t)flags) & 3) )
(((moo_oow_t)(named_instvar)) << (MOO_OBJ_FLAGS_TYPE_BITS + MOO_CLASS_SPEC_FLAG_BITS)) | \
(((moo_oow_t)(indexed_type)) << (MOO_CLASS_SPEC_FLAG_BITS)) | (((moo_oow_t)flags) & MOO_LBMASK(moo_oow_t,MOO_CLASS_SPEC_FLAG_BITS)))
/* what is the number of named instance variables?
* MOO_CLASS_SPEC_NAMED_INSTVARS(MOO_OOP_TO_SMOOI(_class->spec))
* ensure to update Class<<specNumInstVars if you change this macro. */
#define MOO_CLASS_SPEC_NAMED_INSTVARS(spec) \
(((moo_oow_t)(spec)) >> (MOO_OBJ_FLAGS_TYPE_BITS + 2))
(((moo_oow_t)(spec)) >> (MOO_OBJ_FLAGS_TYPE_BITS + MOO_CLASS_SPEC_FLAG_BITS))
/* is it a user-indexable class?
* all objects can be indexed with basicAt:.
* this indicates if an object can be instantiated with a dynamic size
* (new: size) and and can be indexed with at:.
*/
#define MOO_CLASS_SPEC_FLAGS(spec) (((moo_oow_t)(spec)) & 3)
#define MOO_CLASS_SPEC_FLAGS(spec) (((moo_oow_t)(spec)) & MOO_LBMASK(moo_oow_t,MOO_CLASS_SPEC_FLAG_BITS))
/* if so, what is the indexing type? character? pointer? etc? */
#define MOO_CLASS_SPEC_INDEXED_TYPE(spec) \
((((moo_oow_t)(spec)) >> 2) & MOO_LBMASK(moo_oow_t, MOO_OBJ_FLAGS_TYPE_BITS))
((((moo_oow_t)(spec)) >> MOO_CLASS_SPEC_FLAG_BITS) & MOO_LBMASK(moo_oow_t, MOO_OBJ_FLAGS_TYPE_BITS))
#define MOO_CLASS_SPEC_FLAG_INDEXED (1 << 0)
#define MOO_CLASS_SPEC_FLAG_IMMUTABLE (1 << 1)
#define MOO_CLASS_SPEC_FLAG_UNCOPYABLE (1 << 2)
#define MOO_CLASS_SPEC_IS_INDEXED(spec) (MOO_CLASS_SPEC_FLAGS(spec) & MOO_CLASS_SPEC_FLAG_INDEXED)
#define MOO_CLASS_SPEC_IS_IMMUTABLE(spec) (MOO_CLASS_SPEC_FLAGS(spec) & MOO_CLASS_SPEC_FLAG_IMMUTABLE)
#define MOO_CLASS_SPEC_IS_UNCOPYABLE(spec) (MOO_CLASS_SPEC_FLAGS(spec) & MOO_CLASS_SPEC_FLAG_UNCOPYABLE)
/* What is the maximum number of named instance variables?
* This limit is set this way because the number must be encoded into
@ -198,7 +202,7 @@
* the number of named instance variables.
*/
#define MOO_MAX_NAMED_INSTVARS \
MOO_BITS_MAX(moo_oow_t, MOO_SMOOI_ABS_BITS - (MOO_OBJ_FLAGS_TYPE_BITS + 2))
MOO_BITS_MAX(moo_oow_t, MOO_SMOOI_ABS_BITS - (MOO_OBJ_FLAGS_TYPE_BITS + MOO_CLASS_SPEC_FLAG_BITS))
/* Given the number of named instance variables, what is the maximum number
* of indexed instance variables? The number of indexed instance variables
@ -209,7 +213,6 @@
*/
#define MOO_MAX_INDEXED_INSTVARS(named_instvar) (MOO_OBJ_SIZE_MAX - named_instvar)
/*
* self-specification of a class
* | classinstvars | classvars | flags |

View File

@ -301,6 +301,7 @@ typedef enum moo_gcfin_t moo_gcfin_t;
#define MOO_OBJ_FLAGS_GCFIN_BITS 4
#define MOO_OBJ_FLAGS_TRAILER_BITS 1
#define MOO_OBJ_FLAGS_HASH_BITS 2
#define MOO_OBJ_FLAGS_UNCOPYABLE_BITS 1
#define MOO_OBJ_FLAGS_TYPE_SHIFT (MOO_OBJ_FLAGS_UNIT_BITS + MOO_OBJ_FLAGS_UNIT_SHIFT)
#define MOO_OBJ_FLAGS_UNIT_SHIFT (MOO_OBJ_FLAGS_EXTRA_BITS + MOO_OBJ_FLAGS_EXTRA_SHIFT)
@ -312,7 +313,8 @@ typedef enum moo_gcfin_t moo_gcfin_t;
#define MOO_OBJ_FLAGS_RDONLY_SHIFT (MOO_OBJ_FLAGS_GCFIN_BITS + MOO_OBJ_FLAGS_GCFIN_SHIFT)
#define MOO_OBJ_FLAGS_GCFIN_SHIFT (MOO_OBJ_FLAGS_TRAILER_BITS + MOO_OBJ_FLAGS_TRAILER_SHIFT)
#define MOO_OBJ_FLAGS_TRAILER_SHIFT (MOO_OBJ_FLAGS_HASH_BITS + MOO_OBJ_FLAGS_HASH_SHIFT)
#define MOO_OBJ_FLAGS_HASH_SHIFT (0)
#define MOO_OBJ_FLAGS_HASH_SHIFT (MOO_OBJ_FLAGS_UNCOPYABLE_BITS + MOO_OBJ_FLAGS_UNCOPYABLE_SHIFT)
#define MOO_OBJ_FLAGS_UNCOPYABLE_SHIFT (0)
#define MOO_OBJ_GET_FLAGS_TYPE(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_TYPE_SHIFT, MOO_OBJ_FLAGS_TYPE_BITS)
#define MOO_OBJ_GET_FLAGS_UNIT(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_UNIT_SHIFT, MOO_OBJ_FLAGS_UNIT_BITS)
@ -325,6 +327,7 @@ typedef enum moo_gcfin_t moo_gcfin_t;
#define MOO_OBJ_GET_FLAGS_GCFIN(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_GCFIN_SHIFT, MOO_OBJ_FLAGS_GCFIN_BITS)
#define MOO_OBJ_GET_FLAGS_TRAILER(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_TRAILER_SHIFT, MOO_OBJ_FLAGS_TRAILER_BITS)
#define MOO_OBJ_GET_FLAGS_HASH(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_HASH_SHIFT, MOO_OBJ_FLAGS_HASH_BITS)
#define MOO_OBJ_GET_FLAGS_UNCOPYABLE(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_UNCOPYABLE_SHIFT, MOO_OBJ_FLAGS_UNCOPYABLE_BITS)
#define MOO_OBJ_SET_FLAGS_TYPE(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_TYPE_SHIFT, MOO_OBJ_FLAGS_TYPE_BITS, v)
#define MOO_OBJ_SET_FLAGS_UNIT(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_UNIT_SHIFT, MOO_OBJ_FLAGS_UNIT_BITS, v)
@ -337,6 +340,7 @@ typedef enum moo_gcfin_t moo_gcfin_t;
#define MOO_OBJ_SET_FLAGS_GCFIN(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_GCFIN_SHIFT, MOO_OBJ_FLAGS_GCFIN_BITS, v)
#define MOO_OBJ_SET_FLAGS_TRAILER(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_TRAILER_SHIFT, MOO_OBJ_FLAGS_TRAILER_BITS, v)
#define MOO_OBJ_SET_FLAGS_HASH(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_HASH_SHIFT, MOO_OBJ_FLAGS_HASH_BITS, v)
#define MOO_OBJ_SET_FLAGS_UNCOPYABLE(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_UNCOPYABLE_SHIFT, MOO_OBJ_FLAGS_UNCOPYABLE_BITS, v)
#define MOO_OBJ_GET_SIZE(oop) ((oop)->_size)
#define MOO_OBJ_GET_CLASS(oop) ((moo_oop_class_t)((oop)->_class))
@ -369,9 +373,9 @@ typedef enum moo_gcfin_t moo_gcfin_t;
(((moo_oow_t)(_h)) << MOO_OBJ_FLAGS_HASH_SHIFT) \
)
#define MOO_OBJ_FLAGS_KERNEL_USER 0
#define MOO_OBJ_FLAGS_KERNEL_IMMATURE 1
#define MOO_OBJ_FLAGS_KERNEL_MATURE 2
#define MOO_OBJ_FLAGS_KERNEL_USER 0 /* not a kernel object */
#define MOO_OBJ_FLAGS_KERNEL_IMMATURE 1 /* incomplete kernel object. defined in gc.c for bootstrapping. but no complete class definition has been read */
#define MOO_OBJ_FLAGS_KERNEL_MATURE 2 /* kernel object with its full class defintion read in */
#define MOO_OBJ_FLAGS_HASH_UNUSED 0 /* the hash method has never been invoked */
#define MOO_OBJ_FLAGS_HASH_CALLED 1 /* the hash method has been invoked for this object */

View File

@ -322,8 +322,11 @@ moo_oop_t moo_instantiate (moo_t* moo, moo_oop_class_t _class, const void* vptr,
if (oop)
{
moo_ooi_t spec;
MOO_OBJ_SET_CLASS (oop, (moo_oop_t)_class);
if (MOO_CLASS_SPEC_IS_IMMUTABLE(MOO_OOP_TO_SMOOI(_class->spec))) MOO_OBJ_SET_FLAGS_RDONLY (oop, 1);
spec = MOO_OOP_TO_SMOOI(_class->spec);
if (MOO_CLASS_SPEC_IS_IMMUTABLE(spec)) MOO_OBJ_SET_FLAGS_RDONLY (oop, 1);
if (MOO_CLASS_SPEC_IS_UNCOPYABLE(spec)) MOO_OBJ_SET_FLAGS_UNCOPYABLE (oop, 1);
}
moo_popvolats (moo, tmp_count);
return oop;
@ -381,9 +384,14 @@ moo_oop_t moo_instantiatewithtrailer (moo_t* moo, moo_oop_class_t _class, moo_oo
if (oop)
{
moo_ooi_t spec;
MOO_OBJ_SET_CLASS (oop, _class);
if (MOO_CLASS_SPEC_IS_IMMUTABLE(MOO_OOP_TO_SMOOI(_class->spec))) MOO_OBJ_SET_FLAGS_RDONLY (oop, 1);
spec = MOO_OOP_TO_SMOOI(_class->spec);
if (MOO_CLASS_SPEC_IS_IMMUTABLE(spec)) MOO_OBJ_SET_FLAGS_RDONLY (oop, 1);
/* the object with a trailer is always uncopyable */
/*if (MOO_CLASS_SPEC_IS_UNCOPYABLE(spec)) */MOO_OBJ_SET_FLAGS_UNCOPYABLE (oop, 1);
}
moo_popvolats (moo, tmp_count);
return oop;
}