diff --git a/include/mruby.h b/include/mruby.h index 8904ae334..06635b79e 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1014,6 +1014,13 @@ struct mrb_kwargs */ MRB_API mrb_int mrb_get_args(mrb_state *mrb, mrb_args_format format, ...); +/** + * Array version of mrb_get_args() + * + * @param ptr Array of void*, in the same order as the varargs version. + */ +MRB_API mrb_int mrb_get_args_a(mrb_state *mrb, mrb_args_format format, void** ptr); + MRB_INLINE mrb_sym mrb_get_mid(mrb_state *mrb) /* get method symbol */ { diff --git a/include/mruby/gc.h b/include/mruby/gc.h index 9f4ceec4d..ba56cefd7 100644 --- a/include/mruby/gc.h +++ b/include/mruby/gc.h @@ -48,7 +48,8 @@ typedef struct mrb_heap_page { struct mrb_heap_page *free_next; struct mrb_heap_page *free_prev; mrb_bool old:1; - void *objects[]; + /* Flexible array members area a C99 feature, not C++ compatible */ + /* void* objects[]; */ } mrb_heap_page; #ifdef _MSC_VER diff --git a/src/class.c b/src/class.c index b668ae55f..14be8ca9d 100644 --- a/src/class.c +++ b/src/class.c @@ -890,51 +890,14 @@ mrb_block_given_p(mrb_state *mrb) return !mrb_nil_p(b); } -/* - retrieve arguments from mrb_state. +#define GET_ARG(_type) (ptr ? ((_type)(*ptr++)) : va_arg(ap, _type)) - mrb_get_args(mrb, format, ...) - - returns number of arguments parsed. - - format specifiers: - - string mruby type C type note - ---------------------------------------------------------------------------------------------- - o: Object [mrb_value] - C: Class/Module [mrb_value] when ! follows, the value may be nil - S: String [mrb_value] when ! follows, the value may be nil - A: Array [mrb_value] when ! follows, the value may be nil - H: Hash [mrb_value] when ! follows, the value may be nil - s: String [const char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil - z: String [const char*] NUL terminated string; z! gives NULL for nil - a: Array [const mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil - c: Class/Module [strcut RClass*] c! gives NULL for nil - f: Integer/Float [mrb_float] - i: Integer/Float [mrb_int] - b: boolean [mrb_bool] - n: String/Symbol [mrb_sym] - d: data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified; when ! follows, the value may be nil - &: block [mrb_value] &! raises exception if no block given - *: rest argument [const mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack - |: optional Following arguments are optional - ?: optional given [mrb_bool] true if preceding argument (optional) is given - ':': keyword args [mrb_kwargs const] Get keyword arguments - - format modifiers: - - string note - ---------------------------------------------------------------------------------------------- - !: Switch to the alternate mode; The behaviour changes depending on the specifier - +: Request a not frozen object; However, except nil value - */ -MRB_API mrb_int -mrb_get_args(mrb_state *mrb, const char *format, ...) +static mrb_int +get_args_v(mrb_state *mrb, mrb_args_format format, void** ptr, va_list ap) { const char *fmt = format; char c; mrb_int i = 0; - va_list ap; mrb_callinfo *ci = mrb->c->ci; mrb_int argc = ci->n; const mrb_value *argv = ci->stack+1; @@ -946,8 +909,6 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_bool reqkarg = FALSE; int argc_min = 0, argc_max = 0; - va_start(ap, format); - while ((c = *fmt++)) { switch (c) { case '|': @@ -1071,7 +1032,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_value *p; - p = va_arg(ap, mrb_value*); + p = GET_ARG(mrb_value*); if (pickarg) { if (!(altmode && mrb_nil_p(*pickarg))) { switch (c) { @@ -1089,7 +1050,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { struct RClass **p; - p = va_arg(ap, struct RClass**); + p = GET_ARG(struct RClass**); if (pickarg) { if (altmode && mrb_nil_p(*pickarg)) { *p = NULL; @@ -1106,8 +1067,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) const char **ps = 0; mrb_int *pl = 0; - ps = va_arg(ap, const char**); - pl = va_arg(ap, mrb_int*); + ps = GET_ARG(const char**); + pl = GET_ARG(mrb_int*); if (needmodify) goto bad_needmodify; if (pickarg) { if (altmode && mrb_nil_p(*pickarg)) { @@ -1126,7 +1087,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { const char **ps; - ps = va_arg(ap, const char**); + ps = GET_ARG(const char**); if (needmodify) goto bad_needmodify; if (pickarg) { if (altmode && mrb_nil_p(*pickarg)) { @@ -1145,8 +1106,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) const mrb_value **pb; mrb_int *pl; - pb = va_arg(ap, const mrb_value**); - pl = va_arg(ap, mrb_int*); + pb = GET_ARG(const mrb_value**); + pl = GET_ARG(mrb_int*); if (needmodify) goto bad_needmodify; if (pickarg) { if (altmode && mrb_nil_p(*pickarg)) { @@ -1167,7 +1128,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_float *p; - p = va_arg(ap, mrb_float*); + p = GET_ARG(mrb_float*); if (pickarg) { *p = mrb_as_float(mrb, *pickarg); } @@ -1178,7 +1139,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_int *p; - p = va_arg(ap, mrb_int*); + p = GET_ARG(mrb_int*); if (pickarg) { *p = mrb_as_int(mrb, *pickarg); } @@ -1186,7 +1147,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) break; case 'b': { - mrb_bool *boolp = va_arg(ap, mrb_bool*); + mrb_bool *boolp = GET_ARG(mrb_bool*); if (pickarg) { *boolp = mrb_test(*pickarg); @@ -1197,7 +1158,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_sym *symp; - symp = va_arg(ap, mrb_sym*); + symp = GET_ARG(mrb_sym*); if (pickarg) { *symp = to_sym(mrb, *pickarg); } @@ -1208,8 +1169,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) void** datap; struct mrb_data_type const* type; - datap = va_arg(ap, void**); - type = va_arg(ap, struct mrb_data_type const*); + datap = GET_ARG(void**); + type = GET_ARG(struct mrb_data_type const*); if (pickarg) { if (altmode && mrb_nil_p(*pickarg)) { *datap = 0; @@ -1225,7 +1186,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_value *p, *bp; - p = va_arg(ap, mrb_value*); + p = GET_ARG(mrb_value*); bp = ci->stack + mrb_ci_bidx(ci); if (altmode && mrb_nil_p(*bp)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); @@ -1241,7 +1202,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) { mrb_bool *p; - p = va_arg(ap, mrb_bool*); + p = GET_ARG(mrb_bool*); *p = pickarg ? TRUE : FALSE; } break; @@ -1252,8 +1213,8 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) mrb_int *pl; mrb_bool nocopy = (altmode || !argv_on_stack) ? TRUE : FALSE; - var = va_arg(ap, const mrb_value**); - pl = va_arg(ap, mrb_int*); + var = GET_ARG(const mrb_value**); + pl = GET_ARG(mrb_int*); if (argc > i) { *pl = argc-i; if (*pl > 0) { @@ -1278,7 +1239,7 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) case ':': { mrb_value ksrc = mrb_hash_p(kdict) ? mrb_hash_dup(mrb, kdict) : mrb_hash_new(mrb); - const mrb_kwargs *kwargs = va_arg(ap, const mrb_kwargs*); + const mrb_kwargs *kwargs = GET_ARG(const mrb_kwargs*); mrb_value *rest; if (kwargs == NULL) { @@ -1341,10 +1302,64 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } finish: - va_end(ap); return i; } +/* + retrieve arguments from mrb_state. + + mrb_get_args(mrb, format, ...) + + returns number of arguments parsed. + + format specifiers: + + string mruby type C type note + ---------------------------------------------------------------------------------------------- + o: Object [mrb_value] + C: Class/Module [mrb_value] when ! follows, the value may be nil + S: String [mrb_value] when ! follows, the value may be nil + A: Array [mrb_value] when ! follows, the value may be nil + H: Hash [mrb_value] when ! follows, the value may be nil + s: String [const char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil + z: String [const char*] NUL terminated string; z! gives NULL for nil + a: Array [const mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil + c: Class/Module [strcut RClass*] c! gives NULL for nil + f: Integer/Float [mrb_float] + i: Integer/Float [mrb_int] + b: boolean [mrb_bool] + n: String/Symbol [mrb_sym] + d: data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified; when ! follows, the value may be nil + &: block [mrb_value] &! raises exception if no block given + *: rest argument [const mrb_value*,mrb_int] The rest of the arguments as an array; *! avoid copy of the stack + |: optional Following arguments are optional + ?: optional given [mrb_bool] true if preceding argument (optional) is given + ':': keyword args [mrb_kwargs const] Get keyword arguments + + format modifiers: + + string note + ---------------------------------------------------------------------------------------------- + !: Switch to the alternate mode; The behaviour changes depending on the specifier + +: Request a not frozen object; However, except nil value + */ +MRB_API mrb_int +mrb_get_args(mrb_state *mrb, mrb_args_format format, ...) +{ + va_list ap; + va_start(ap, format); + mrb_int rc = get_args_v(mrb, format, NULL, ap); + va_end(ap); + return rc; +} + +MRB_API mrb_int +mrb_get_args_a(mrb_state *mrb, mrb_args_format format, void** args) +{ + va_list ap; + return get_args_v(mrb, format, args, ap); +} + static struct RClass* boot_defclass(mrb_state *mrb, struct RClass *super) { diff --git a/src/gc.c b/src/gc.c index 610929d90..16ac8841b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -215,7 +215,11 @@ mrb_static_assert(MRB_GC_RED <= GC_COLOR_MASK); #define other_white_part(s) ((s)->current_white_part ^ GC_WHITES) #define is_dead(s, o) (((o)->color & other_white_part(s) & GC_WHITES) || (o)->tt == MRB_TT_FREE) -#define objects(p) ((RVALUE *)p->objects) +/* We have removed `objects[]` from `mrb_heap_page` since it was not C++ + * compatible. Using array index to get pointer after structure instead. */ + +/* #define objects(p) ((RVALUE *)p->objects) */ +#define objects(p) ((RVALUE *)&p[1]) mrb_noreturn void mrb_raise_nomemory(mrb_state *mrb);