diff --git a/string.c b/string.c index 711918b..2c5c3e9 100644 --- a/string.c +++ b/string.c @@ -406,10 +406,19 @@ str_new(VALUE klass, const char *ptr, long len) return str; } +extern int rb_obj_call_init_if_redefined(VALUE obj, int argc, VALUE *argv); + VALUE rb_str_new(const char *ptr, long len) { - return str_new(rb_cString, ptr, len); + /* str is already initialized by original initialize within str_new() */ + VALUE str = str_new(rb_cString, ptr, len); + + /* speed: call initialize only if it was redefined. See #4893 */ + /* passing str itself as parameter, avoiding need for a temp str */ + rb_obj_call_init_if_redefined((VALUE)str, 1, &str); + + return str; } VALUE diff --git a/vm_method.c b/vm_method.c index 86ff2ee..11f7ece 100644 --- a/vm_method.c +++ b/vm_method.c @@ -258,6 +258,50 @@ method_added(VALUE klass, ID mid) } } +#define FL_CALL_INIT FL_USER18 /* TODO: move to header file */ + +int +rb_set_redefined_flag(VALUE klass, ID mid, int set) +{ +/* current implementation uses class-object-variable (bit-flag FL_USERnn). +Q: why not use of existent "ruby_vm_redefined_flag[]"? +A: It works too, but fails after an undef/remove_method. + Additionally, the vm_redefined_flag is not a per-class but a per-method-flag. +Can be possibly normalized to a later point, after refactoring and +documenting the the vm, especially vm_method.c. The goal would be to have +per-method-flags for any method, and per-class-flags only if absolutely +unavoidable (= avoid global-status, reduce existent global-status to a more +local scope.)*/ + +/* redesign: introduce FL_FAST_CLASS to flag a class for fast +initialization, and test via FL_TEST(CLASS_OF(obj), FL_FAST_CLASS) instead +of klass == rb_cString */ + + if (ruby_running && mid == idInitialize && klass == rb_cString) { + if (set) { + FL_SET(klass, FL_CALL_INIT); + } else { + FL_UNSET(klass, FL_CALL_INIT); + } + return TRUE; /* flag was set or unset */ + } + return FALSE; /* no action taken */ +} + +int +rb_obj_call_init_if_redefined(VALUE obj, int argc, VALUE *argv) +{ +/* use only in fast_classes like String, which call the low level initialize. + Method lookup and call of initialize will be done only, if initialize + was redefined. */ + + if (FL_TEST(CLASS_OF(obj), FL_CALL_INIT)) { + rb_obj_call_init(obj, argc, argv); + return TRUE; + } + return FALSE; /* initialize was not called */ +} + rb_method_entry_t * rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_flag_t noex) { @@ -304,6 +348,9 @@ rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *opts, rb_method_ default: rb_bug("rb_add_method: unsupported method type (%d)\n", type); } + + rb_set_redefined_flag(klass, mid, TRUE); + if (type != VM_METHOD_TYPE_UNDEF) { method_added(klass, mid); } @@ -441,7 +488,7 @@ remove_method(VALUE klass, ID mid) rb_vm_check_redefinition_opt_method(me); rb_clear_cache_for_undef(klass, mid); rb_unlink_method_entry(me); - + rb_set_redefined_flag(klass, mid, FALSE); CALL_METHOD_HOOK(klass, removed, mid); } @@ -628,6 +675,8 @@ rb_undef(VALUE klass, ID id) rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC); + rb_set_redefined_flag(klass, id, FALSE); + CALL_METHOD_HOOK(klass, undefined, id); }