Commit 07b8b0f2 authored by Chris Fallin's avatar Chris Fallin

Addressed code-review comments.

parent 9de35e74
...@@ -349,8 +349,6 @@ static void *oneofsubmsg_handler(void *closure, ...@@ -349,8 +349,6 @@ static void *oneofsubmsg_handler(void *closure,
MessageHeader* msg = closure; MessageHeader* msg = closure;
const oneof_handlerdata_t *oneofdata = hd; const oneof_handlerdata_t *oneofdata = hd;
uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t); uint32_t oldcase = DEREF(msg, oneofdata->case_ofs, uint32_t);
DEREF(msg, oneofdata->case_ofs, uint32_t) =
oneofdata->oneof_case_num;
VALUE subdesc = VALUE subdesc =
get_def_obj((void*)oneofdata->md); get_def_obj((void*)oneofdata->md);
...@@ -361,6 +359,11 @@ static void *oneofsubmsg_handler(void *closure, ...@@ -361,6 +359,11 @@ static void *oneofsubmsg_handler(void *closure,
DEREF(msg, oneofdata->ofs, VALUE) = DEREF(msg, oneofdata->ofs, VALUE) =
rb_class_new_instance(0, NULL, subklass); rb_class_new_instance(0, NULL, subklass);
} }
// Set the oneof case *after* allocating the new class instance -- see comment
// in layout_set() as to why. There are subtle interactions with possible GC
// points and oneof field type transitions.
DEREF(msg, oneofdata->case_ofs, uint32_t) =
oneofdata->oneof_case_num;
VALUE submsg_rb = DEREF(msg, oneofdata->ofs, VALUE); VALUE submsg_rb = DEREF(msg, oneofdata->ofs, VALUE);
MessageHeader* submsg; MessageHeader* submsg;
...@@ -965,11 +968,11 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc, ...@@ -965,11 +968,11 @@ static void putmsg(VALUE msg_rb, const Descriptor* desc,
uint32_t offset = uint32_t offset =
desc->layout->fields[upb_fielddef_index(f)].offset + desc->layout->fields[upb_fielddef_index(f)].offset +
sizeof(MessageHeader); sizeof(MessageHeader);
uint32_t oneof_case_offset =
desc->layout->fields[upb_fielddef_index(f)].case_offset +
sizeof(MessageHeader);
if (upb_fielddef_containingoneof(f)) { if (upb_fielddef_containingoneof(f)) {
uint32_t oneof_case_offset =
desc->layout->fields[upb_fielddef_index(f)].case_offset +
sizeof(MessageHeader);
// For a oneof, check that this field is actually present -- skip all the // For a oneof, check that this field is actually present -- skip all the
// below if not. // below if not.
if (DEREF(msg, oneof_case_offset, uint32_t) != if (DEREF(msg, oneof_case_offset, uint32_t) !=
......
...@@ -579,15 +579,26 @@ void layout_set(MessageLayout* layout, ...@@ -579,15 +579,26 @@ void layout_set(MessageLayout* layout,
*oneof_case = 0; *oneof_case = 0;
memset(memory, 0, NATIVE_SLOT_MAX_SIZE); memset(memory, 0, NATIVE_SLOT_MAX_SIZE);
} else { } else {
// Set the oneof case *first* in case a GC is triggered during // The transition between field types for a single oneof (union) slot is
// native_slot_set(): layout_mark() depends on oneof_case to know whether // somewhat complex because we need to ensure that a GC triggered at any
// the slot may be a Ruby VALUE and so we need that lifetime to start // point by a call into the Ruby VM sees a valid state for this field and
// before we could possibly stick a VALUE in it. // does not either go off into the weeds (following what it thinks is a
*oneof_case = upb_fielddef_number(field); // VALUE but is actually a different field type) or miss an object (seeing
// We just overwrite the value directly if we changed oneof cases: // what it thinks is a primitive field but is actually a VALUE for the new
// native_slot_set() does not depend on the old value in memory. // field type).
//
// native_slot_set() has two parts: (i) conversion of some sort, and (ii)
// setting the in-memory content to the new value. It guarantees that all
// calls to the Ruby VM are completed before the memory slot is altered.
//
// In order for the transition to be safe, the oneof case slot must be in
// sync with the value slot whenever the Ruby VM has been called. Because
// we are guaranteed that no Ruby VM calls occur after native_slot_set()
// alters the memory slot and before it returns, we set the oneof case
// immediately after native_slot_set() returns.
native_slot_set(upb_fielddef_type(field), field_type_class(field), native_slot_set(upb_fielddef_type(field), field_type_class(field),
memory, val); memory, val);
*oneof_case = upb_fielddef_number(field);
} }
} else if (is_map_field(field)) { } else if (is_map_field(field)) {
check_map_field_type(val, field); check_map_field_type(val, field);
......
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