diff --git a/moo/kernel/Apex.moo b/moo/kernel/Apex.moo index faead9c..0c0b6ec 100644 --- a/moo/kernel/Apex.moo +++ b/moo/kernel/Apex.moo @@ -529,3 +529,7 @@ extend Error method(#primitive) asString. } + +class SmallPointer(Object) +{ +} diff --git a/moo/lib/exec.c b/moo/lib/exec.c index 591e49a..d6f431d 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -1031,7 +1031,12 @@ static moo_oop_method_t find_method (moo_t* moo, moo_oop_t receiver, const moo_o do { mthdic = ((moo_oop_class_t)c)->mthdic[dic_no]; - MOO_ASSERT (moo, (moo_oop_t)mthdic != moo->_nil); + + /* if a kernel class is not defined in the bootstrapping code, + * the method dictionary is still nil. the initial kernel classes + * must all be defined properly */ + MOO_ASSERT (moo, (moo_oop_t)mthdic != moo->_nil); + MOO_ASSERT (moo, MOO_CLASSOF(moo, mthdic) == moo->_method_dictionary); ass = (moo_oop_association_t)moo_lookupdic (moo, mthdic, message); @@ -1320,11 +1325,14 @@ static moo_pfrc_t _equal_objects (moo_t* moo, moo_ooi_t nargs) rtag = MOO_OOP_GET_TAG(rcv); if (rtag != MOO_OOP_GET_TAG(arg)) return 0; - switch (MOO_OOP_GET_TAG(rcv)) + switch (rtag) { case MOO_OOP_TAG_SMOOI: return MOO_OOP_TO_SMOOI(rcv) == MOO_OOP_TO_SMOOI(arg)? 1: 0; + case MOO_OOP_TAG_SMPTR: + return MOO_OOP_TO_SMPTR(rcv) == MOO_OOP_TO_SMPTR(arg)? 1: 0; + case MOO_OOP_TAG_CHAR: return MOO_OOP_TO_CHAR(rcv) == MOO_OOP_TO_CHAR(arg)? 1: 0; @@ -1688,6 +1696,10 @@ static moo_pfrc_t pf_hash (moo_t* moo, moo_ooi_t nargs) hv = MOO_OOP_TO_SMOOI(rcv); break; + case MOO_OOP_TAG_SMPTR: + hv = (moo_oow_t)MOO_OOP_TO_SMPTR(rcv); + break; + case MOO_OOP_TAG_CHAR: hv = MOO_OOP_TO_CHAR(rcv); break; @@ -2828,7 +2840,9 @@ static moo_pfrc_t pf_smooi_as_error (moo_t* moo, moo_ooi_t nargs) if (!MOO_OOP_IS_SMOOI(rcv)) return MOO_PF_FAILURE; ec = MOO_OOP_TO_SMOOI(rcv); - if (ec < 0) ec = 0; + if (ec < MOO_ERROR_MIN) ec = MOO_ERROR_MIN; + else if (ec > MOO_ERROR_MAX) ec = MOO_ERROR_MAX; + MOO_STACK_SETRET (moo, nargs, MOO_ERROR_TO_OOP(ec)); return MOO_PF_SUCCESS; } @@ -2844,7 +2858,7 @@ static moo_pfrc_t pf_error_as_character (moo_t* moo, moo_ooi_t nargs) if (!MOO_OOP_IS_ERROR(rcv)) return MOO_PF_FAILURE; ec = MOO_OOP_TO_ERROR(rcv); - MOO_ASSERT (moo, MOO_IN_SMOOI_RANGE(ec)); + MOO_ASSERT (moo, ec >= MOO_CHAR_MIN && ec <= MOO_CHAR_MAX); MOO_STACK_SETRET (moo, nargs, MOO_CHAR_TO_OOP(ec)); return MOO_PF_SUCCESS; } diff --git a/moo/lib/gc.c b/moo/lib/gc.c index 4e94034..286bbce 100644 --- a/moo/lib/gc.c +++ b/moo/lib/gc.c @@ -115,6 +115,7 @@ static kernel_class_info_t kernel_classes[] = { 20, { 'L','a','r','g','e','P','o','s','i','t','i','v','e','I','n','t','e','g','e','r' }, MOO_OFFSETOF(moo_t, _large_positive_integer) }, { 20, { 'L','a','r','g','e','N','e','g','a','t','i','v','e','I','n','t','e','g','e','r' }, MOO_OFFSETOF(moo_t, _large_negative_integer) }, + { 12, { 'S','m','a','l','l','P','o','i','n','t','e','r' }, MOO_OFFSETOF(moo_t, _small_pointer) }, { 6, { 'S','y','s','t','e','m' }, MOO_OFFSETOF(moo_t, _system) }, }; @@ -205,6 +206,7 @@ static int ignite_1 (moo_t* moo) moo->_large_positive_integer = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_LIWORD)); moo->_large_negative_integer = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 1, MOO_OBJ_TYPE_LIWORD)); + moo->_small_pointer = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP)); moo->_system = alloc_kernel_class (moo, 0, MOO_CLASS_SPEC_MAKE(0, 0, MOO_OBJ_TYPE_OOP)); if (!moo->_apex || !moo->_undefined_object || @@ -222,7 +224,8 @@ static int ignite_1 (moo_t* moo) !moo->_true_class || !moo->_false_class || !moo->_character || !moo->_small_integer || - !moo->_large_positive_integer || !moo->_large_negative_integer || !moo->_system) return -1; + !moo->_large_positive_integer || !moo->_large_negative_integer || + !moo->_small_pointer || !moo->_system) return -1; MOO_OBJ_SET_CLASS (moo->_nil, (moo_oop_t)moo->_undefined_object); return 0; diff --git a/moo/lib/logfmt.c b/moo/lib/logfmt.c index 4cf96f8..0ac8b6b 100644 --- a/moo/lib/logfmt.c +++ b/moo/lib/logfmt.c @@ -312,6 +312,10 @@ static void print_object (moo_t* moo, moo_oow_t mask, moo_oop_t oop) { moo_logbfmt (moo, mask, "%zd", MOO_OOP_TO_SMOOI(oop)); } + else if (MOO_OOP_IS_SMPTR(oop)) + { + moo_logbfmt (moo, mask, "%p", MOO_OOP_TO_SMPTR(oop)); + } else if (MOO_OOP_IS_CHAR(oop)) { moo_logbfmt (moo, mask, "$%.1C", MOO_OOP_TO_CHAR(oop)); diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index 1b242e9..7f9c420 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -125,9 +125,9 @@ * and the indexability is stored in bit 2. * * The maximum number of named(fixed) instance variables for a class is: - * 2 ^ ((BITS-IN-OOW - MOO_OOP_TAG_BITS) - MOO_OBJ_TYPE_BITS - 1) - 1 + * 2 ^ ((BITS-IN-OOW - MOO_OOP_TAG_BITS_LO) - MOO_OBJ_TYPE_BITS - 1) - 1 * - * MOO_OOP_TAG_BITS are decremented from the number of bits in OOW because + * MOO_OOP_TAG_BITS_LO are decremented from the number of bits in OOW because * the spec field is always encoded as a small integer. * * The number of named instance variables can be greater than 0 if the @@ -171,7 +171,7 @@ */ /* #define MOO_MAX_NAMED_INSTVARS \ - MOO_BITS_MAX(moo_oow_t, MOO_OOW_BITS - MOO_OOP_TAG_BITS - (MOO_OBJ_FLAGS_TYPE_BITS + 1) - 1) + MOO_BITS_MAX(moo_oow_t, MOO_OOW_BITS - MOO_OOP_TAG_BITS_LO - (MOO_OBJ_FLAGS_TYPE_BITS + 1) - 1) */ #define MOO_MAX_NAMED_INSTVARS \ MOO_BITS_MAX(moo_oow_t, MOO_SMOOI_ABS_BITS - (MOO_OBJ_FLAGS_TYPE_BITS + 1)) @@ -187,14 +187,14 @@ /* #define MOO_CLASS_SELFSPEC_MAKE(class_var,classinst_var) \ - (((moo_oow_t)class_var) << ((MOO_OOW_BITS - MOO_OOP_TAG_BITS) / 2)) | ((moo_oow_t)classinst_var) + (((moo_oow_t)class_var) << ((MOO_OOW_BITS - MOO_OOP_TAG_BITS_LO) / 2)) | ((moo_oow_t)classinst_var) */ #define MOO_CLASS_SELFSPEC_MAKE(class_var,classinst_var) \ (((moo_oow_t)class_var) << (MOO_SMOOI_BITS / 2)) | ((moo_oow_t)classinst_var) /* -#define MOO_CLASS_SELFSPEC_CLASSVAR(spec) ((moo_oow_t)spec >> ((MOO_OOW_BITS - MOO_OOP_TAG_BITS) / 2)) -#define MOO_CLASS_SELFSPEC_CLASSINSTVAR(spec) (((moo_oow_t)spec) & MOO_LBMASK(moo_oow_t, (MOO_OOW_BITS - MOO_OOP_TAG_BITS) / 2)) +#define MOO_CLASS_SELFSPEC_CLASSVAR(spec) ((moo_oow_t)spec >> ((MOO_OOW_BITS - MOO_OOP_TAG_BITS_LO) / 2)) +#define MOO_CLASS_SELFSPEC_CLASSINSTVAR(spec) (((moo_oow_t)spec) & MOO_LBMASK(moo_oow_t, (MOO_OOW_BITS - MOO_OOP_TAG_BITS_LO) / 2)) */ #define MOO_CLASS_SELFSPEC_CLASSVAR(spec) ((moo_oow_t)spec >> (MOO_SMOOI_BITS / 2)) #define MOO_CLASS_SELFSPEC_CLASSINSTVAR(spec) (((moo_oow_t)spec) & MOO_LBMASK(moo_oow_t, (MOO_SMOOI_BITS / 2))) @@ -204,8 +204,8 @@ * a small-integer */ /* -#define MOO_MAX_CLASSVARS MOO_BITS_MAX(moo_oow_t, (MOO_OOW_BITS - MOO_OOP_TAG_BITS - 1) / 2) -#define MOO_MAX_CLASSINSTVARS MOO_BITS_MAX(moo_oow_t, (MOO_OOW_BITS - MOO_OOP_TAG_BITS - 1) / 2) +#define MOO_MAX_CLASSVARS MOO_BITS_MAX(moo_oow_t, (MOO_OOW_BITS - MOO_OOP_TAG_BITS_LO - 1) / 2) +#define MOO_MAX_CLASSINSTVARS MOO_BITS_MAX(moo_oow_t, (MOO_OOW_BITS - MOO_OOP_TAG_BITS_LO - 1) / 2) */ #define MOO_MAX_CLASSVARS MOO_BITS_MAX(moo_oow_t, MOO_SMOOI_ABS_BITS / 2) #define MOO_MAX_CLASSINSTVARS MOO_BITS_MAX(moo_oow_t, MOO_SMOOI_ABS_BITS / 2) diff --git a/moo/lib/moo.c b/moo/lib/moo.c index b16037c..5fc6bd1 100644 --- a/moo/lib/moo.c +++ b/moo/lib/moo.c @@ -111,6 +111,7 @@ int moo_init (moo_t* moo, moo_mmgr_t* mmgr, moo_oow_t heapsz, const moo_vmprim_t fill_bigint_tables (moo); moo->tagged_classes[MOO_OOP_TAG_SMOOI] = &moo->_small_integer; + moo->tagged_classes[MOO_OOP_TAG_SMPTR] = &moo->_small_pointer; moo->tagged_classes[MOO_OOP_TAG_CHAR] = &moo->_character; moo->tagged_classes[MOO_OOP_TAG_ERROR] = &moo->_error_class; diff --git a/moo/lib/moo.h b/moo/lib/moo.h index 1710956..5c5d9c1 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -194,50 +194,83 @@ typedef enum moo_method_type_t moo_method_type_t; * This scheme works because the object allocators aligns the object size to * a multiple of sizeof(moo_oop_t). This way, the 2 least-significant bits * of a real OOP are always 0s. + * + * With 2 bits, i can encode only 3 special types except object pointers. + * Since I need more than 3 special types, I extend the tag bits up to 4 bits + * to represent a special data type that doesn't require a range as wide + * as a small integer. A unicode character, for instance, only requires 21 + * bits at most. An error doesn't need to be as diverse as a small integer. */ -#define MOO_OOP_TAG_BITS 2 -#define MOO_OOP_TAG_SMOOI 1 -#define MOO_OOP_TAG_CHAR 2 -#define MOO_OOP_TAG_ERROR 3 +#define MOO_OOP_TAG_BITS_LO 2 +#define MOO_OOP_TAG_BITS_HI 2 + +#define MOO_OOP_TAG_SMOOI 1 /* 01 */ +#define MOO_OOP_TAG_SMPTR 2 /* 10 */ +#define MOO_OOP_TAG_EXTENDED 3 /* 11 - internal use only */ +#define MOO_OOP_TAG_CHAR 3 /* 0011 */ +#define MOO_OOP_TAG_ERROR 7 /* 0111 */ +#define MOO_OOP_TAG_HANDLE 11 /* 1011 */ +#define MOO_OOP_TAG_RESERVED1 15 /* 1111 */ + +#define MOO_OOP_GET_TAG_LO(oop) (((moo_oow_t)oop) & MOO_LBMASK(moo_oow_t, MOO_OOP_TAG_BITS_LO)) +#define MOO_OOP_GET_TAG_LOHI(oop) (((moo_oow_t)oop) & MOO_LBMASK(moo_oow_t, MOO_OOP_TAG_BITS_LO + MOO_OOP_TAG_BITS_HI)) +#define MOO_OOP_GET_TAG(oop) (MOO_OOP_GET_TAG_LO(oop) == MOO_OOP_TAG_EXTENDED? MOO_OOP_GET_TAG_LOHI(oop): MOO_OOP_GET_TAG_LO(oop)) + +#define MOO_OOP_IS_NUMERIC(oop) (MOO_OOP_GET_TAG_LO(oop) != 0) +#define MOO_OOP_IS_POINTER(oop) (MOO_OOP_GET_TAG_LO(oop) == 0) + +#define MOO_OOP_IS_SMOOI(oop) (MOO_OOP_GET_TAG_LO(oop) == MOO_OOP_TAG_SMOOI) +#define MOO_OOP_IS_SMPTR(oop) (MOO_OOP_GET_TAG_LO(oop) == MOO_OOP_TAG_SMPTR) + +#define MOO_SMOOI_TO_OOP(num) ((moo_oop_t)((((moo_ooi_t)(num)) << MOO_OOP_TAG_BITS_LO) | MOO_OOP_TAG_SMOOI)) +#define MOO_OOP_TO_SMOOI(oop) (((moo_ooi_t)oop) >> MOO_OOP_TAG_BITS_LO) +/* +#define MOO_SMPTR_TO_OOP(num) ((moo_oop_t)((((moo_ooi_t)(num)) << MOO_OOP_TAG_BITS_LO) | MOO_OOP_TAG_SMPTR)) +#define MOO_OOP_TO_SMPTR(oop) (((moo_ooi_t)oop) >> MOO_OOP_TAG_BITS_LO) +*/ +#define MOO_SMPTR_TO_OOP(ptr) ((moo_oop_t)(((moo_oow_t)ptr) | MOO_OOP_TAG_SMPTR)) +#define MOO_OOP_TO_SMPTR(oop) ((void*)(((moo_oow_t)oop) & ~MOO_LBMASK(moo_oow_t, MOO_OOP_TAG_BITS_LO))) -#define MOO_OOP_GET_TAG(oop) (((moo_oow_t)oop) & MOO_LBMASK(moo_oow_t, MOO_OOP_TAG_BITS)) -#define MOO_OOP_IS_NUMERIC(oop) (MOO_OOP_GET_TAG(oop) != 0) -#define MOO_OOP_IS_POINTER(oop) (MOO_OOP_GET_TAG(oop) == 0) -#define MOO_OOP_IS_SMOOI(oop) (MOO_OOP_GET_TAG(oop) == MOO_OOP_TAG_SMOOI) #define MOO_OOP_IS_CHAR(oop) (MOO_OOP_GET_TAG(oop) == MOO_OOP_TAG_CHAR) #define MOO_OOP_IS_ERROR(oop) (MOO_OOP_GET_TAG(oop) == MOO_OOP_TAG_ERROR) +#define MOO_OOP_IS_HANDLE(oop) (MOO_OOP_GET_TAG(oop) == MOO_OOP_TAG_HANDLE) -#define MOO_SMOOI_TO_OOP(num) ((moo_oop_t)((((moo_ooi_t)(num)) << MOO_OOP_TAG_BITS) | MOO_OOP_TAG_SMOOI)) -#define MOO_OOP_TO_SMOOI(oop) (((moo_ooi_t)oop) >> MOO_OOP_TAG_BITS) -#define MOO_CHAR_TO_OOP(num) ((moo_oop_t)((((moo_oow_t)(num)) << MOO_OOP_TAG_BITS) | MOO_OOP_TAG_CHAR)) -#define MOO_OOP_TO_CHAR(oop) (((moo_oow_t)oop) >> MOO_OOP_TAG_BITS) -#define MOO_ERROR_TO_OOP(num) ((moo_oop_t)((((moo_oow_t)(num)) << MOO_OOP_TAG_BITS) | MOO_OOP_TAG_ERROR)) -#define MOO_OOP_TO_ERROR(oop) (((moo_oow_t)oop) >> MOO_OOP_TAG_BITS) +#define MOO_OOP_TO_CHAR(oop) (((moo_oow_t)oop) >> (MOO_OOP_TAG_BITS_LO + MOO_OOP_TAG_BITS_LO)) +#define MOO_CHAR_TO_OOP(num) ((moo_oop_t)((((moo_oow_t)(num)) << (MOO_OOP_TAG_BITS_LO + MOO_OOP_TAG_BITS_LO)) | MOO_OOP_TAG_CHAR)) +#define MOO_OOP_TO_ERROR(oop) (((moo_oow_t)oop) >> (MOO_OOP_TAG_BITS_LO + MOO_OOP_TAG_BITS_LO)) +#define MOO_ERROR_TO_OOP(num) ((moo_oop_t)((((moo_oow_t)(num)) << (MOO_OOP_TAG_BITS_LO + MOO_OOP_TAG_BITS_LO)) | MOO_OOP_TAG_ERROR)) +#define MOO_OOP_TO_HANDLE(oop) (((moo_oow_t)oop) >> (MOO_OOP_TAG_BITS_LO + MOO_OOP_TAG_BITS_LO)) +#define MOO_HANDLE_TO_OOP(num) ((moo_oop_t)((((moo_oow_t)(num)) << (MOO_OOP_TAG_BITS_LO + MOO_OOP_TAG_BITS_LO)) | MOO_OOP_TAG_ERROR)) + +/* -------------------------------- */ /* SMOOI takes up 62 bits on a 64-bit architecture and 30 bits * on a 32-bit architecture. The absolute value takes up 61 bits and 29 bits * respectively for the sign bit. */ -#define MOO_SMOOI_BITS (MOO_OOI_BITS - MOO_OOP_TAG_BITS) +#define MOO_SMOOI_BITS (MOO_OOI_BITS - MOO_OOP_TAG_BITS_LO) #define MOO_SMOOI_ABS_BITS (MOO_SMOOI_BITS - 1) -#define MOO_SMOOI_MAX ((moo_ooi_t)(~((moo_oow_t)0) >> (MOO_OOP_TAG_BITS + 1))) +#define MOO_SMOOI_MAX ((moo_ooi_t)(~((moo_oow_t)0) >> (MOO_OOP_TAG_BITS_LO + 1))) /* Sacrificing 1 bit pattern for a negative SMOOI makes * implementation a lot eaisier in many aspects. */ /*#define MOO_SMOOI_MIN (-MOO_SMOOI_MAX - 1)*/ #define MOO_SMOOI_MIN (-MOO_SMOOI_MAX) #define MOO_IN_SMOOI_RANGE(ooi) ((ooi) >= MOO_SMOOI_MIN && (ooi) <= MOO_SMOOI_MAX) +/* SMPTR is a special value which has been devised to encode an address value + * whose low MOO_OOP_TAG_BITS_LO bits are 0. its class is SmallPointer. A pointer + * returned by most of system functions would be aligned to the pointer size. + * you can use the followings macros when converting such a pointer without loss. */ +#define MOO_IN_SMPTR_RANGE(ptr) ((((moo_oow_t)ptr) & MOO_LBMASK(moo_oow_t, MOO_OOP_TAG_BITS_LO)) == 0) -/* SMPTR is a special SMOOI value which has been devised to - * encode an address value whose low MOO_OOP_TAG_BITS bits are 0. - * its class is still SmallInteger. A pointer returned by most of - * system functions would be aligned to the pointer size. - * you can use tthe followings macros when storing such a pointer - * in a small integer without loss. */ -#define MOO_IN_SMPTR_RANGE(ptr) ((((moo_oow_t)ptr) & MOO_LBMASK(moo_oow_t, MOO_OOP_TAG_BITS)) == 0) -#define MOO_SMPTR_TO_OOP(ptr) ((moo_oop_t)(((moo_oow_t)ptr) | MOO_OOP_TAG_SMOOI)) -#define MOO_OOP_TO_SMPTR(oop) ((void*)(((moo_oow_t)oop) & ~MOO_LBMASK(moo_oow_t, MOO_OOP_TAG_BITS))) +#define MOO_CHAR_BITS (MOO_OOI_BITS - MOO_OOP_TAG_BITS_LO - MOO_OOP_TAG_BITS_HI) +#define MOO_CHAR_MIN 0 +#define MOO_CHAR_MAX (~((moo_oow_t)0) >> (MOO_OOP_TAG_BITS_LO + MOO_OOP_TAG_BITS_HI)) + +#define MOO_ERROR_BITS (MOO_OOI_BITS - MOO_OOP_TAG_BITS_LO - MOO_OOP_TAG_BITS_HI) +#define MOO_ERROR_MIN 0 +#define MOO_ERROR_MAX (~((moo_oow_t)0) >> (MOO_OOP_TAG_BITS_LO + MOO_OOP_TAG_BITS_HI)) /* TODO: There are untested code where a small integer is converted to moo_oow_t. * for example, the spec making macro treats the number as moo_oow_t instead of moo_ooi_t. @@ -1003,6 +1036,7 @@ struct moo_t moo_oop_class_t _large_positive_integer; /* LargePositiveInteger */ moo_oop_class_t _large_negative_integer; /* LargeNegativeInteger */ + moo_oop_class_t _small_pointer; moo_oop_class_t _system; /* ============================================================= * END KERNEL CLASSES @@ -1011,7 +1045,11 @@ struct moo_t /* ============================================================= * KEY SYSTEM DICTIONARIES * ============================================================= */ - moo_oop_class_t* tagged_classes[4]; + /* 2 tag bits(lo) + 2 extended tag bits(hi). not all slots are used + * because the 2 high extended bits are used only if the low tag bits + * are 3 */ + moo_oop_class_t* tagged_classes[16]; + moo_oop_set_t symtab; /* system-wide symbol table. instance of SymbolSet */ moo_oop_set_t sysdic; /* system dictionary. instance of SystemDictionary */ moo_oop_process_scheduler_t processor; /* instance of ProcessScheduler */