From 4cca8bac6bbdab02eba11e6527f793f2e9a5e75d Mon Sep 17 00:00:00 2001 From: Tomasz Dąbrowski Date: Wed, 16 Nov 2016 17:43:55 +0100 Subject: inline structures data type for mruby (MRB_TT_INLINE) (fix #3237) Inline structures have no instance variables, no finalizer, and offer as much space as possible in RBASIC object. This means 24 bytes on 64-bit platforms and 12 bytes on 32-bit platforms. mruby-inline-struct gem is only provided for testing. --- mrbgems/mruby-inline-struct/test/inline.c | 83 +++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 mrbgems/mruby-inline-struct/test/inline.c (limited to 'mrbgems/mruby-inline-struct/test/inline.c') diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c new file mode 100644 index 000000000..903c08aca --- /dev/null +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +static mrb_value +inline_test_initialize(mrb_state *mrb, mrb_value self) +{ + char *string = mrb_inline_ptr(self); + mrb_int size = mrb_inline_size(); + mrb_value object; + mrb_get_args(mrb, "o", &object); + + if (mrb_float_p(object)) + { + snprintf(string, size, "float(%.3f)", mrb_float(object)); + } + else if (mrb_fixnum_p(object)) + { + snprintf(string, size, "fixnum(%d)", mrb_fixnum(object)); + } + else if (mrb_string_p(object)) + { + snprintf(string, size, "string(%s)", mrb_string_value_cstr(mrb, &object)); + } + + string[size - 1] = 0; // force NULL at the end + return self; +} + +static mrb_value +inline_test_to_s(mrb_state *mrb, mrb_value self) +{ + return mrb_str_new_cstr(mrb, mrb_inline_ptr(self)); +} + +static mrb_value +inline_test_length(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(mrb_inline_size()); +} + +static mrb_value +inline_test_test_receive(mrb_state *mrb, mrb_value self) +{ + mrb_value object; + mrb_get_args(mrb, "o", &object); + if (mrb_obj_class(mrb, object) != mrb_class_get(mrb, "InlineStructTest")) + { + mrb_raisef(mrb, E_TYPE_ERROR, "Expected InlineStructTest"); + } + return mrb_bool_value(((char*)mrb_inline_ptr(object))[0] == 's'); +} + +static mrb_value +inline_test_test_receive_direct(mrb_state *mrb, mrb_value self) +{ + char *ptr; + mrb_get_args(mrb, "I", &ptr); + return mrb_bool_value(ptr[0] == 's'); +} + +static mrb_value +inline_test_mutate(mrb_state *mrb, mrb_value self) +{ + char *ptr = mrb_inline_ptr(self); + memcpy(ptr, "mutate", 6); + return mrb_nil_value(); +} + +void mrb_mruby_inline_struct_gem_test(mrb_state *mrb) +{ + struct RClass *cls; + + cls = mrb_define_class(mrb, "InlineStructTest", mrb->object_class); + MRB_SET_INSTANCE_TT(cls, MRB_TT_INLINE); + mrb_define_method(mrb, cls, "initialize", inline_test_initialize, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, cls, "to_s", inline_test_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, cls, "mutate", inline_test_mutate, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "length", inline_test_length, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "test_receive", inline_test_test_receive, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, cls, "test_receive_direct", inline_test_test_receive_direct, MRB_ARGS_REQ(1)); +} -- cgit v1.2.3 From 8438792d27bac2a236d5eef9824d36f815c0472f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 17 Nov 2016 17:12:11 +0900 Subject: renamed "inline" to "istruct" to represent inline struct; ref #3251 --- include/mruby/inline.h | 47 ------------------------------- include/mruby/istruct.h | 47 +++++++++++++++++++++++++++++++ include/mruby/value.h | 2 +- mrbgems/mruby-inline-struct/test/inline.c | 40 +++++++++++++------------- src/class.c | 6 ++-- src/etc.c | 2 +- src/kernel.c | 6 ++-- src/object.c | 4 +-- 8 files changed, 77 insertions(+), 77 deletions(-) delete mode 100644 include/mruby/inline.h create mode 100644 include/mruby/istruct.h (limited to 'mrbgems/mruby-inline-struct/test/inline.c') diff --git a/include/mruby/inline.h b/include/mruby/inline.h deleted file mode 100644 index e773aa118..000000000 --- a/include/mruby/inline.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -** mruby/inline.h - Inline structures -** -** See Copyright Notice in mruby.h -*/ - -#ifndef MRUBY_INLINE_H -#define MRUBY_INLINE_H - -#include "common.h" -#include - -/** - * Inline structures that fit in RVALUE - * - * They cannot have finalizer, and cannot have instance variables. - */ -MRB_BEGIN_DECL - -#define INLINE_DATA_SIZE (sizeof(void*) * 3) - -struct RInline { - MRB_OBJECT_HEADER; - char inline_data[INLINE_DATA_SIZE]; -}; - -#define RINLINE(obj) ((struct RInline*)(mrb_ptr(obj))) -#define INLINE_PTR(obj) (RINLINE(obj)->inline_data) - -MRB_INLINE mrb_int mrb_inline_size() -{ - return INLINE_DATA_SIZE; -} - -MRB_INLINE void* mrb_inline_ptr(mrb_value object) -{ - return INLINE_PTR(object); -} - -MRB_INLINE void mrb_inline_copy(mrb_value dest, mrb_value src) -{ - memcpy(INLINE_PTR(dest), INLINE_PTR(src), INLINE_DATA_SIZE); -} - -MRB_END_DECL - -#endif /* MRUBY_INLINE_H */ diff --git a/include/mruby/istruct.h b/include/mruby/istruct.h new file mode 100644 index 000000000..293a13788 --- /dev/null +++ b/include/mruby/istruct.h @@ -0,0 +1,47 @@ +/* +** mruby/instruct.h - Inline structures +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_ISTRUCT_H +#define MRUBY_ISTRUCT_H + +#include "common.h" +#include + +/** + * Inline structures that fit in RVALUE + * + * They cannot have finalizer, and cannot have instance variables. + */ +MRB_BEGIN_DECL + +#define ISTRUCT_DATA_SIZE (sizeof(void*) * 3) + +struct RIstruct { + MRB_OBJECT_HEADER; + char inline_data[ISTRUCT_DATA_SIZE]; +}; + +#define RISTRUCT(obj) ((struct RIstruct*)(mrb_ptr(obj))) +#define ISTRUCT_PTR(obj) (RISTRUCT(obj)->inline_data) + +MRB_INLINE mrb_int mrb_istruct_size() +{ + return ISTRUCT_DATA_SIZE; +} + +MRB_INLINE void* mrb_istruct_ptr(mrb_value object) +{ + return ISTRUCT_PTR(object); +} + +MRB_INLINE void mrb_istruct_copy(mrb_value dest, mrb_value src) +{ + memcpy(ISTRUCT_PTR(dest), ISTRUCT_PTR(src), ISTRUCT_DATA_SIZE); +} + +MRB_END_DECL + +#endif /* MRUBY_ISTRUCT_H */ diff --git a/include/mruby/value.h b/include/mruby/value.h index eb3f931e1..6b29ab273 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -116,7 +116,7 @@ enum mrb_vtype { MRB_TT_ENV, /* 20 */ MRB_TT_DATA, /* 21 */ MRB_TT_FIBER, /* 22 */ - MRB_TT_INLINE, /* 23 */ + MRB_TT_ISTRUCT, /* 23 */ MRB_TT_MAXDEFINE /* 24 */ }; diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c index 903c08aca..49ef31d00 100644 --- a/mrbgems/mruby-inline-struct/test/inline.c +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -1,13 +1,13 @@ #include #include #include -#include +#include static mrb_value -inline_test_initialize(mrb_state *mrb, mrb_value self) +istruct_test_initialize(mrb_state *mrb, mrb_value self) { - char *string = mrb_inline_ptr(self); - mrb_int size = mrb_inline_size(); + char *string = mrb_istruct_ptr(self); + mrb_int size = mrb_istruct_size(); mrb_value object; mrb_get_args(mrb, "o", &object); @@ -29,19 +29,19 @@ inline_test_initialize(mrb_state *mrb, mrb_value self) } static mrb_value -inline_test_to_s(mrb_state *mrb, mrb_value self) +istruct_test_to_s(mrb_state *mrb, mrb_value self) { - return mrb_str_new_cstr(mrb, mrb_inline_ptr(self)); + return mrb_str_new_cstr(mrb, mrb_istruct_ptr(self)); } static mrb_value -inline_test_length(mrb_state *mrb, mrb_value self) +istruct_test_length(mrb_state *mrb, mrb_value self) { - return mrb_fixnum_value(mrb_inline_size()); + return mrb_fixnum_value(mrb_istruct_size()); } static mrb_value -inline_test_test_receive(mrb_state *mrb, mrb_value self) +istruct_test_test_receive(mrb_state *mrb, mrb_value self) { mrb_value object; mrb_get_args(mrb, "o", &object); @@ -49,11 +49,11 @@ inline_test_test_receive(mrb_state *mrb, mrb_value self) { mrb_raisef(mrb, E_TYPE_ERROR, "Expected InlineStructTest"); } - return mrb_bool_value(((char*)mrb_inline_ptr(object))[0] == 's'); + return mrb_bool_value(((char*)mrb_istruct_ptr(object))[0] == 's'); } static mrb_value -inline_test_test_receive_direct(mrb_state *mrb, mrb_value self) +istruct_test_test_receive_direct(mrb_state *mrb, mrb_value self) { char *ptr; mrb_get_args(mrb, "I", &ptr); @@ -61,9 +61,9 @@ inline_test_test_receive_direct(mrb_state *mrb, mrb_value self) } static mrb_value -inline_test_mutate(mrb_state *mrb, mrb_value self) +istruct_test_mutate(mrb_state *mrb, mrb_value self) { - char *ptr = mrb_inline_ptr(self); + char *ptr = mrb_istruct_ptr(self); memcpy(ptr, "mutate", 6); return mrb_nil_value(); } @@ -73,11 +73,11 @@ void mrb_mruby_inline_struct_gem_test(mrb_state *mrb) struct RClass *cls; cls = mrb_define_class(mrb, "InlineStructTest", mrb->object_class); - MRB_SET_INSTANCE_TT(cls, MRB_TT_INLINE); - mrb_define_method(mrb, cls, "initialize", inline_test_initialize, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, cls, "to_s", inline_test_to_s, MRB_ARGS_NONE()); - mrb_define_method(mrb, cls, "mutate", inline_test_mutate, MRB_ARGS_NONE()); - mrb_define_class_method(mrb, cls, "length", inline_test_length, MRB_ARGS_NONE()); - mrb_define_class_method(mrb, cls, "test_receive", inline_test_test_receive, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, cls, "test_receive_direct", inline_test_test_receive_direct, MRB_ARGS_REQ(1)); + MRB_SET_INSTANCE_TT(cls, MRB_TT_ISTRUCT); + mrb_define_method(mrb, cls, "initialize", istruct_test_initialize, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, cls, "to_s", istruct_test_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, cls, "mutate", istruct_test_mutate, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "length", istruct_test_length, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "test_receive", istruct_test_test_receive, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, cls, "test_receive_direct", istruct_test_test_receive_direct, MRB_ARGS_REQ(1)); } diff --git a/src/class.c b/src/class.c index 53354d02a..d02253c57 100644 --- a/src/class.c +++ b/src/class.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal) @@ -712,11 +712,11 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, void**); if (i < argc) { ss = ARGV[arg_i]; - if (mrb_type(ss) != MRB_TT_INLINE) + if (mrb_type(ss) != MRB_TT_ISTRUCT) { mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss); } - *p = mrb_inline_ptr(ss); + *p = mrb_istruct_ptr(ss); arg_i++; i++; } diff --git a/src/etc.c b/src/etc.c index c89549da6..e0810d589 100644 --- a/src/etc.c +++ b/src/etc.c @@ -139,7 +139,7 @@ mrb_obj_id(mrb_value obj) case MRB_TT_EXCEPTION: case MRB_TT_FILE: case MRB_TT_DATA: - case MRB_TT_INLINE: + case MRB_TT_ISTRUCT: default: return MakeID(mrb_ptr(obj)); } diff --git a/src/kernel.c b/src/kernel.c index 4a4b6b414..8b1ef80a0 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include typedef enum { NOEX_PUBLIC = 0x00, @@ -302,8 +302,8 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj) case MRB_TT_EXCEPTION: mrb_iv_copy(mrb, dest, obj); break; - case MRB_TT_INLINE: - mrb_inline_copy(dest, obj); + case MRB_TT_ISTRUCT: + mrb_istruct_copy(dest, obj); break; default: diff --git a/src/object.c b/src/object.c index af66d93d0..392432b0f 100644 --- a/src/object.c +++ b/src/object.c @@ -348,7 +348,7 @@ mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const { mrb_value v; - if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_INLINE) return val; + if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_ISTRUCT) return val; v = convert_type(mrb, val, tname, method, FALSE); if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value(); return v; @@ -390,7 +390,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) enum mrb_vtype xt; xt = mrb_type(x); - if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_INLINE)) { + if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_ISTRUCT)) { while (type->type < MRB_TT_MAXDEFINE) { if (type->type == t) { const char *etype; -- cgit v1.2.3 From 1af9e363f28810e46e263cd13da918cdf779d71d Mon Sep 17 00:00:00 2001 From: Tomasz Dąbrowski Date: Tue, 22 Nov 2016 13:19:05 +0100 Subject: Fixes for compiling mruby as C++ --- include/mruby.h | 16 ++++++++++++++++ include/mruby/boxing_nan.h | 2 +- mrbgems/mruby-inline-struct/test/inline.c | 6 +++--- mrbgems/mruby-objectspace/src/mruby_objectspace.c | 2 +- mrbgems/mruby-sprintf/src/sprintf.c | 12 ++++++------ src/backtrace.c | 4 ++-- src/string.c | 2 +- 7 files changed, 30 insertions(+), 14 deletions(-) (limited to 'mrbgems/mruby-inline-struct/test/inline.c') diff --git a/include/mruby.h b/include/mruby.h index e6eaf7f27..d40dce6d9 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -28,10 +28,26 @@ #ifndef MRUBY_H #define MRUBY_H +#ifdef __cplusplus +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS +#define __STDC_FORMAT_MACROS +#endif + #include #include #include +#ifdef __cplusplus +#ifndef SIZE_MAX +#ifdef __SIZE_MAX__ +#define SIZE_MAX __SIZE_MAX__ +#else +#define SIZE_MAX std::numeric_limits::max() +#endif +#endif +#endif + #ifdef MRB_DEBUG #include #define mrb_assert(p) assert(p) diff --git a/include/mruby/boxing_nan.h b/include/mruby/boxing_nan.h index 154150ece..052164ffc 100644 --- a/include/mruby/boxing_nan.h +++ b/include/mruby/boxing_nan.h @@ -53,7 +53,7 @@ typedef struct mrb_value { #define mrb_float_pool(mrb,f) mrb_float_value(mrb,f) #define mrb_tt(o) ((enum mrb_vtype)(((o).value.ttt & 0xfc000)>>14)-1) -#define mrb_type(o) ((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT) +#define mrb_type(o) (enum mrb_vtype)((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT) #define mrb_ptr(o) ((void*)((((uintptr_t)0x3fffffffffff)&((uintptr_t)((o).value.p)))<<2)) #define mrb_float(o) (o).f #define mrb_cptr(o) mrb_ptr(o) diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c index 49ef31d00..772248e9b 100644 --- a/mrbgems/mruby-inline-struct/test/inline.c +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -6,7 +6,7 @@ static mrb_value istruct_test_initialize(mrb_state *mrb, mrb_value self) { - char *string = mrb_istruct_ptr(self); + char *string = (char*)mrb_istruct_ptr(self); mrb_int size = mrb_istruct_size(); mrb_value object; mrb_get_args(mrb, "o", &object); @@ -31,7 +31,7 @@ istruct_test_initialize(mrb_state *mrb, mrb_value self) static mrb_value istruct_test_to_s(mrb_state *mrb, mrb_value self) { - return mrb_str_new_cstr(mrb, mrb_istruct_ptr(self)); + return mrb_str_new_cstr(mrb, (const char*)mrb_istruct_ptr(self)); } static mrb_value @@ -63,7 +63,7 @@ istruct_test_test_receive_direct(mrb_state *mrb, mrb_value self) static mrb_value istruct_test_mutate(mrb_state *mrb, mrb_value self) { - char *ptr = mrb_istruct_ptr(self); + char *ptr = (char*)mrb_istruct_ptr(self); memcpy(ptr, "mutate", 6); return mrb_nil_value(); } diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c index d5cd4f5a1..d0a8effd0 100644 --- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c +++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c @@ -49,7 +49,7 @@ static mrb_value os_count_objects(mrb_state *mrb, mrb_value self) { struct os_count_struct obj_count = { 0 }; - enum mrb_vtype i; + mrb_int i; mrb_value hash; if (mrb_get_args(mrb, "|H", &hash) == 0) { diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index ccee23bd2..696d0939f 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -844,13 +844,13 @@ retry: strncpy(nbuf, RSTRING_PTR(val), sizeof(nbuf)); break; case 8: - snprintf(nbuf, sizeof(nbuf), "%"MRB_PRIo, v); + snprintf(nbuf, sizeof(nbuf), "%" MRB_PRIo, v); break; case 10: - snprintf(nbuf, sizeof(nbuf), "%"MRB_PRId, v); + snprintf(nbuf, sizeof(nbuf), "%" MRB_PRId, v); break; case 16: - snprintf(nbuf, sizeof(nbuf), "%"MRB_PRIx, v); + snprintf(nbuf, sizeof(nbuf), "%" MRB_PRIx, v); break; } s = nbuf; @@ -865,13 +865,13 @@ retry: strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-1); break; case 8: - snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRIo, v); + snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIo, v); break; case 10: - snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRId, v); + snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRId, v); break; case 16: - snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRIx, v); + snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIx, v); break; } if (v < 0) { diff --git a/src/backtrace.c b/src/backtrace.c index 11082b705..285af562f 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -160,7 +160,7 @@ static void output_backtrace_i(mrb_state *mrb, struct backtrace_location_raw *loc_raw, void *data) { struct backtrace_location loc; - struct output_backtrace_args *args = data; + struct output_backtrace_args *args = (struct output_backtrace_args *)data; loc.i = loc_raw->i; loc.lineno = loc_raw->lineno; @@ -338,7 +338,7 @@ save_backtrace_i(mrb_state *mrb, else { new_n_allocated = mrb->backtrace.n_allocated * 2; } - mrb->backtrace.entries = + mrb->backtrace.entries = (mrb_backtrace_entry *) mrb_realloc(mrb, mrb->backtrace.entries, sizeof(mrb_backtrace_entry) * new_n_allocated); diff --git a/src/string.c b/src/string.c index f8ab9478f..5e490bf03 100644 --- a/src/string.c +++ b/src/string.c @@ -361,7 +361,7 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n) return 0; } else if (m == 1) { - const unsigned char *ys = memchr(y, *x, n); + const unsigned char *ys = (const unsigned char *)memchr(y, *x, n); if (ys) return ys - y; -- cgit v1.2.3 From a630c4f413f6af764e68210430e8b61a435d38d7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 Nov 2016 22:10:54 +0900 Subject: use MRB_PRId instead of %d for mrb_int --- mrbgems/mruby-inline-struct/test/inline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mrbgems/mruby-inline-struct/test/inline.c') diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c index 772248e9b..0baaab617 100644 --- a/mrbgems/mruby-inline-struct/test/inline.c +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -17,7 +17,7 @@ istruct_test_initialize(mrb_state *mrb, mrb_value self) } else if (mrb_fixnum_p(object)) { - snprintf(string, size, "fixnum(%d)", mrb_fixnum(object)); + snprintf(string, size, "fixnum(%" MRB_PRId ")", mrb_fixnum(object)); } else if (mrb_string_p(object)) { -- cgit v1.2.3