Commit 231886f6 authored by Chris Fallin's avatar Chris Fallin

Ruby C extension speedup: don't re-intern constant string needlessly.

Also fixed lines with > 80 char length.
parent a8b38c59
...@@ -34,8 +34,6 @@ ...@@ -34,8 +34,6 @@
// Common utilities. // Common utilities.
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
const char* kDescriptorInstanceVar = "descriptor";
static const char* get_str(VALUE str) { static const char* get_str(VALUE str) {
Check_Type(str, T_STRING); Check_Type(str, T_STRING);
return RSTRING_PTR(str); return RSTRING_PTR(str);
...@@ -1590,9 +1588,9 @@ VALUE Builder_add_message(VALUE _self, VALUE name) { ...@@ -1590,9 +1588,9 @@ VALUE Builder_add_message(VALUE _self, VALUE name) {
* call-seq: * call-seq:
* Builder.add_enum(name, &block) * Builder.add_enum(name, &block)
* *
* Creates a new, empty enum descriptor with the given name, and invokes the block in * Creates a new, empty enum descriptor with the given name, and invokes the
* the context of an EnumBuilderContext on that descriptor. The block can then * block in the context of an EnumBuilderContext on that descriptor. The block
* call EnumBuilderContext#add_value to define the enum values. * can then call EnumBuilderContext#add_value to define the enum values.
* *
* This is the recommended, idiomatic way to build enum definitions. * This is the recommended, idiomatic way to build enum definitions.
*/ */
......
...@@ -644,7 +644,8 @@ static bool env_error_func(void* ud, const upb_status* status) { ...@@ -644,7 +644,8 @@ static bool env_error_func(void* ud, const upb_status* status) {
// Free the env -- rb_raise will longjmp up the stack past the encode/decode // Free the env -- rb_raise will longjmp up the stack past the encode/decode
// function so it would not otherwise have been freed. // function so it would not otherwise have been freed.
stackenv_uninit(se); stackenv_uninit(se);
rb_raise(rb_eRuntimeError, se->ruby_error_template, upb_status_errmsg(status)); rb_raise(rb_eRuntimeError, se->ruby_error_template,
upb_status_errmsg(status));
// Never reached: rb_raise() always longjmp()s up the stack, past all of our // Never reached: rb_raise() always longjmp()s up the stack, past all of our
// code, back to Ruby. // code, back to Ruby.
return false; return false;
...@@ -673,7 +674,7 @@ static void stackenv_uninit(stackenv* se) { ...@@ -673,7 +674,7 @@ static void stackenv_uninit(stackenv* se) {
* and returns a message object with the corresponding field values. * and returns a message object with the corresponding field values.
*/ */
VALUE Message_decode(VALUE klass, VALUE data) { VALUE Message_decode(VALUE klass, VALUE data) {
VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar); VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
Descriptor* desc = ruby_to_Descriptor(descriptor); Descriptor* desc = ruby_to_Descriptor(descriptor);
VALUE msgklass = Descriptor_msgclass(descriptor); VALUE msgklass = Descriptor_msgclass(descriptor);
...@@ -711,7 +712,7 @@ VALUE Message_decode(VALUE klass, VALUE data) { ...@@ -711,7 +712,7 @@ VALUE Message_decode(VALUE klass, VALUE data) {
* and returns a message object with the corresponding field values. * and returns a message object with the corresponding field values.
*/ */
VALUE Message_decode_json(VALUE klass, VALUE data) { VALUE Message_decode_json(VALUE klass, VALUE data) {
VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar); VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
Descriptor* desc = ruby_to_Descriptor(descriptor); Descriptor* desc = ruby_to_Descriptor(descriptor);
VALUE msgklass = Descriptor_msgclass(descriptor); VALUE msgklass = Descriptor_msgclass(descriptor);
...@@ -846,7 +847,7 @@ static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink, ...@@ -846,7 +847,7 @@ static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink,
if (submsg == Qnil) return; if (submsg == Qnil) return;
upb_sink subsink; upb_sink subsink;
VALUE descriptor = rb_iv_get(submsg, kDescriptorInstanceVar); VALUE descriptor = rb_ivar_get(submsg, descriptor_instancevar_interned);
Descriptor* subdesc = ruby_to_Descriptor(descriptor); Descriptor* subdesc = ruby_to_Descriptor(descriptor);
upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink); upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink);
...@@ -968,7 +969,8 @@ static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink, ...@@ -968,7 +969,8 @@ static void putmap(VALUE map, const upb_fielddef *f, upb_sink *sink,
VALUE value = Map_iter_value(&it); VALUE value = Map_iter_value(&it);
upb_sink entry_sink; upb_sink entry_sink;
upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG), &entry_sink); upb_sink_startsubmsg(&subsink, getsel(f, UPB_HANDLER_STARTSUBMSG),
&entry_sink);
upb_sink_startmsg(&entry_sink); upb_sink_startmsg(&entry_sink);
put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink); put_ruby_value(key, key_field, Qnil, depth + 1, &entry_sink);
...@@ -1098,7 +1100,7 @@ static const upb_handlers* msgdef_json_serialize_handlers(Descriptor* desc) { ...@@ -1098,7 +1100,7 @@ static const upb_handlers* msgdef_json_serialize_handlers(Descriptor* desc) {
* wire format. * wire format.
*/ */
VALUE Message_encode(VALUE klass, VALUE msg_rb) { VALUE Message_encode(VALUE klass, VALUE msg_rb) {
VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar); VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
Descriptor* desc = ruby_to_Descriptor(descriptor); Descriptor* desc = ruby_to_Descriptor(descriptor);
stringsink sink; stringsink sink;
...@@ -1129,7 +1131,7 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) { ...@@ -1129,7 +1131,7 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) {
* Encodes the given message object into its serialized JSON representation. * Encodes the given message object into its serialized JSON representation.
*/ */
VALUE Message_encode_json(VALUE klass, VALUE msg_rb) { VALUE Message_encode_json(VALUE klass, VALUE msg_rb) {
VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar); VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
Descriptor* desc = ruby_to_Descriptor(descriptor); Descriptor* desc = ruby_to_Descriptor(descriptor);
stringsink sink; stringsink sink;
......
...@@ -53,7 +53,7 @@ rb_data_type_t Message_type = { ...@@ -53,7 +53,7 @@ rb_data_type_t Message_type = {
}; };
VALUE Message_alloc(VALUE klass) { VALUE Message_alloc(VALUE klass) {
VALUE descriptor = rb_iv_get(klass, kDescriptorInstanceVar); VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned);
Descriptor* desc = ruby_to_Descriptor(descriptor); Descriptor* desc = ruby_to_Descriptor(descriptor);
MessageHeader* msg = (MessageHeader*)ALLOC_N( MessageHeader* msg = (MessageHeader*)ALLOC_N(
uint8_t, sizeof(MessageHeader) + desc->layout->size); uint8_t, sizeof(MessageHeader) + desc->layout->size);
...@@ -63,7 +63,7 @@ VALUE Message_alloc(VALUE klass) { ...@@ -63,7 +63,7 @@ VALUE Message_alloc(VALUE klass) {
// a collection happens during object creation in layout_init(). // a collection happens during object creation in layout_init().
VALUE ret = TypedData_Wrap_Struct(klass, &Message_type, msg); VALUE ret = TypedData_Wrap_Struct(klass, &Message_type, msg);
msg->descriptor = desc; msg->descriptor = desc;
rb_iv_set(ret, kDescriptorInstanceVar, descriptor); rb_ivar_set(ret, descriptor_instancevar_interned, descriptor);
layout_init(desc->layout, Message_data(msg)); layout_init(desc->layout, Message_data(msg));
...@@ -341,7 +341,8 @@ VALUE Message_to_h(VALUE _self) { ...@@ -341,7 +341,8 @@ VALUE Message_to_h(VALUE _self) {
!upb_msg_field_done(&it); !upb_msg_field_done(&it);
upb_msg_field_next(&it)) { upb_msg_field_next(&it)) {
const upb_fielddef* field = upb_msg_iter_field(&it); const upb_fielddef* field = upb_msg_iter_field(&it);
VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self), field); VALUE msg_value = layout_get(self->descriptor->layout, Message_data(self),
field);
VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field))); VALUE msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) {
msg_value = RepeatedField_to_ary(msg_value); msg_value = RepeatedField_to_ary(msg_value);
...@@ -400,7 +401,7 @@ VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) { ...@@ -400,7 +401,7 @@ VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
* message class's type. * message class's type.
*/ */
VALUE Message_descriptor(VALUE klass) { VALUE Message_descriptor(VALUE klass) {
return rb_iv_get(klass, kDescriptorInstanceVar); return rb_ivar_get(klass, descriptor_instancevar_interned);
} }
VALUE build_class_from_descriptor(Descriptor* desc) { VALUE build_class_from_descriptor(Descriptor* desc) {
...@@ -421,11 +422,13 @@ VALUE build_class_from_descriptor(Descriptor* desc) { ...@@ -421,11 +422,13 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
// their own toplevel constant class name. // their own toplevel constant class name.
rb_intern("Message"), rb_intern("Message"),
rb_cObject); rb_cObject);
rb_iv_set(klass, kDescriptorInstanceVar, get_def_obj(desc->msgdef)); rb_ivar_set(klass, descriptor_instancevar_interned,
get_def_obj(desc->msgdef));
rb_define_alloc_func(klass, Message_alloc); rb_define_alloc_func(klass, Message_alloc);
rb_require("google/protobuf/message_exts"); rb_require("google/protobuf/message_exts");
rb_include_module(klass, rb_eval_string("Google::Protobuf::MessageExts")); rb_include_module(klass, rb_eval_string("Google::Protobuf::MessageExts"));
rb_extend_object(klass, rb_eval_string("Google::Protobuf::MessageExts::ClassMethods")); rb_extend_object(
klass, rb_eval_string("Google::Protobuf::MessageExts::ClassMethods"));
rb_define_method(klass, "method_missing", rb_define_method(klass, "method_missing",
Message_method_missing, -1); Message_method_missing, -1);
...@@ -458,7 +461,7 @@ VALUE build_class_from_descriptor(Descriptor* desc) { ...@@ -458,7 +461,7 @@ VALUE build_class_from_descriptor(Descriptor* desc) {
*/ */
VALUE enum_lookup(VALUE self, VALUE number) { VALUE enum_lookup(VALUE self, VALUE number) {
int32_t num = NUM2INT(number); int32_t num = NUM2INT(number);
VALUE desc = rb_iv_get(self, kDescriptorInstanceVar); VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc); EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
const char* name = upb_enumdef_iton(enumdesc->enumdef, num); const char* name = upb_enumdef_iton(enumdesc->enumdef, num);
...@@ -478,7 +481,7 @@ VALUE enum_lookup(VALUE self, VALUE number) { ...@@ -478,7 +481,7 @@ VALUE enum_lookup(VALUE self, VALUE number) {
*/ */
VALUE enum_resolve(VALUE self, VALUE sym) { VALUE enum_resolve(VALUE self, VALUE sym) {
const char* name = rb_id2name(SYM2ID(sym)); const char* name = rb_id2name(SYM2ID(sym));
VALUE desc = rb_iv_get(self, kDescriptorInstanceVar); VALUE desc = rb_ivar_get(self, descriptor_instancevar_interned);
EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc); EnumDescriptor* enumdesc = ruby_to_EnumDescriptor(desc);
int32_t num = 0; int32_t num = 0;
...@@ -498,7 +501,7 @@ VALUE enum_resolve(VALUE self, VALUE sym) { ...@@ -498,7 +501,7 @@ VALUE enum_resolve(VALUE self, VALUE sym) {
* EnumDescriptor corresponding to this enum type. * EnumDescriptor corresponding to this enum type.
*/ */
VALUE enum_descriptor(VALUE self) { VALUE enum_descriptor(VALUE self) {
return rb_iv_get(self, kDescriptorInstanceVar); return rb_ivar_get(self, descriptor_instancevar_interned);
} }
VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) { VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
...@@ -523,7 +526,8 @@ VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) { ...@@ -523,7 +526,8 @@ VALUE build_module_from_enumdesc(EnumDescriptor* enumdesc) {
rb_define_singleton_method(mod, "lookup", enum_lookup, 1); rb_define_singleton_method(mod, "lookup", enum_lookup, 1);
rb_define_singleton_method(mod, "resolve", enum_resolve, 1); rb_define_singleton_method(mod, "resolve", enum_resolve, 1);
rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0); rb_define_singleton_method(mod, "descriptor", enum_descriptor, 0);
rb_iv_set(mod, kDescriptorInstanceVar, get_def_obj(enumdesc->enumdef)); rb_ivar_set(mod, descriptor_instancevar_interned,
get_def_obj(enumdesc->enumdef));
return mod; return mod;
} }
......
...@@ -64,6 +64,15 @@ rb_encoding* kRubyStringUtf8Encoding; ...@@ -64,6 +64,15 @@ rb_encoding* kRubyStringUtf8Encoding;
rb_encoding* kRubyStringASCIIEncoding; rb_encoding* kRubyStringASCIIEncoding;
rb_encoding* kRubyString8bitEncoding; rb_encoding* kRubyString8bitEncoding;
// Ruby-interned string: "descriptor". We use this identifier to store an
// instance variable on message classes we create in order to link them back to
// their descriptors.
//
// We intern this once at module load time then use the interned identifier at
// runtime in order to avoid the cost of repeatedly interning in hot paths.
const char* kDescriptorInstanceVar = "descriptor";
ID descriptor_instancevar_interned;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Initialization/entry point. // Initialization/entry point.
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -71,6 +80,7 @@ rb_encoding* kRubyString8bitEncoding; ...@@ -71,6 +80,7 @@ rb_encoding* kRubyString8bitEncoding;
// This must be named "Init_protobuf_c" because the Ruby module is named // This must be named "Init_protobuf_c" because the Ruby module is named
// "protobuf_c" -- the VM looks for this symbol in our .so. // "protobuf_c" -- the VM looks for this symbol in our .so.
void Init_protobuf_c() { void Init_protobuf_c() {
descriptor_instancevar_interned = rb_intern(kDescriptorInstanceVar);
VALUE google = rb_define_module("Google"); VALUE google = rb_define_module("Google");
VALUE protobuf = rb_define_module_under(google, "Protobuf"); VALUE protobuf = rb_define_module_under(google, "Protobuf");
VALUE internal = rb_define_module_under(protobuf, "Internal"); VALUE internal = rb_define_module_under(protobuf, "Internal");
......
...@@ -161,8 +161,6 @@ extern VALUE cOneofBuilderContext; ...@@ -161,8 +161,6 @@ extern VALUE cOneofBuilderContext;
extern VALUE cEnumBuilderContext; extern VALUE cEnumBuilderContext;
extern VALUE cBuilder; extern VALUE cBuilder;
extern const char* kDescriptorInstanceVar;
// We forward-declare all of the Ruby method implementations here because we // We forward-declare all of the Ruby method implementations here because we
// sometimes call the methods directly across .c files, rather than going // sometimes call the methods directly across .c files, rather than going
// through Ruby's method dispatching (e.g. during message parse). It's cleaner // through Ruby's method dispatching (e.g. during message parse). It's cleaner
...@@ -530,4 +528,6 @@ void check_upb_status(const upb_status* status, const char* msg); ...@@ -530,4 +528,6 @@ void check_upb_status(const upb_status* status, const char* msg);
check_upb_status(&status, msg); \ check_upb_status(&status, msg); \
} while (0) } while (0)
extern ID descriptor_instancevar_interned;
#endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__ #endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
...@@ -117,7 +117,8 @@ VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) { ...@@ -117,7 +117,8 @@ VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self) {
if (index < 0 || index >= self->size) { if (index < 0 || index >= self->size) {
return Qnil; return Qnil;
} }
void* memory = (void *) (((uint8_t *)self->elements) + index * element_size); void* memory = (void *) (((uint8_t *)self->elements) +
index * element_size);
return native_slot_get(field_type, field_type_class, memory); return native_slot_get(field_type, field_type_class, memory);
}else{ }else{
/* check if idx is Range */ /* check if idx is Range */
...@@ -497,13 +498,13 @@ VALUE RepeatedField_concat(VALUE _self, VALUE list) { ...@@ -497,13 +498,13 @@ VALUE RepeatedField_concat(VALUE _self, VALUE list) {
void validate_type_class(upb_fieldtype_t type, VALUE klass) { void validate_type_class(upb_fieldtype_t type, VALUE klass) {
if (rb_iv_get(klass, kDescriptorInstanceVar) == Qnil) { if (rb_ivar_get(klass, descriptor_instancevar_interned) == Qnil) {
rb_raise(rb_eArgError, rb_raise(rb_eArgError,
"Type class has no descriptor. Please pass a " "Type class has no descriptor. Please pass a "
"class or enum as returned by the DescriptorPool."); "class or enum as returned by the DescriptorPool.");
} }
if (type == UPB_TYPE_MESSAGE) { if (type == UPB_TYPE_MESSAGE) {
VALUE desc = rb_iv_get(klass, kDescriptorInstanceVar); VALUE desc = rb_ivar_get(klass, descriptor_instancevar_interned);
if (!RB_TYPE_P(desc, T_DATA) || !RTYPEDDATA_P(desc) || if (!RB_TYPE_P(desc, T_DATA) || !RTYPEDDATA_P(desc) ||
RTYPEDDATA_TYPE(desc) != &_Descriptor_type) { RTYPEDDATA_TYPE(desc) != &_Descriptor_type) {
rb_raise(rb_eArgError, "Descriptor has an incorrect type."); rb_raise(rb_eArgError, "Descriptor has an incorrect type.");
...@@ -513,7 +514,7 @@ void validate_type_class(upb_fieldtype_t type, VALUE klass) { ...@@ -513,7 +514,7 @@ void validate_type_class(upb_fieldtype_t type, VALUE klass) {
"Message class was not returned by the DescriptorPool."); "Message class was not returned by the DescriptorPool.");
} }
} else if (type == UPB_TYPE_ENUM) { } else if (type == UPB_TYPE_ENUM) {
VALUE enumdesc = rb_iv_get(klass, kDescriptorInstanceVar); VALUE enumdesc = rb_ivar_get(klass, descriptor_instancevar_interned);
if (!RB_TYPE_P(enumdesc, T_DATA) || !RTYPEDDATA_P(enumdesc) || if (!RB_TYPE_P(enumdesc, T_DATA) || !RTYPEDDATA_P(enumdesc) ||
RTYPEDDATA_TYPE(enumdesc) != &_EnumDescriptor_type) { RTYPEDDATA_TYPE(enumdesc) != &_EnumDescriptor_type) {
rb_raise(rb_eArgError, "Descriptor has an incorrect type."); rb_raise(rb_eArgError, "Descriptor has an incorrect type.");
......
...@@ -415,7 +415,8 @@ MessageLayout* create_layout(const upb_msgdef* msgdef) { ...@@ -415,7 +415,8 @@ MessageLayout* create_layout(const upb_msgdef* msgdef) {
// Align current offset up to |size| granularity. // Align current offset up to |size| granularity.
off = align_up_to(off, field_size); off = align_up_to(off, field_size);
layout->fields[upb_fielddef_index(field)].offset = off; layout->fields[upb_fielddef_index(field)].offset = off;
layout->fields[upb_fielddef_index(field)].case_offset = MESSAGE_FIELD_NO_CASE; layout->fields[upb_fielddef_index(field)].case_offset =
MESSAGE_FIELD_NO_CASE;
off += field_size; off += field_size;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment