diff options
Diffstat (limited to 'php/ext/google/protobuf/storage.c')
-rw-r--r-- | php/ext/google/protobuf/storage.c | 539 |
1 files changed, 0 insertions, 539 deletions
diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c deleted file mode 100644 index e5a09c17..00000000 --- a/php/ext/google/protobuf/storage.c +++ /dev/null @@ -1,539 +0,0 @@ -#include <stdint.h> -#include <protobuf.h> - -// ----------------------------------------------------------------------------- -// PHP <-> native slot management. -// ----------------------------------------------------------------------------- - -static zval* int32_to_zval(int32_t value) { - zval* tmp; - MAKE_STD_ZVAL(tmp); - ZVAL_LONG(tmp, value); - php_printf("int32 to zval\n"); - // ZVAL_LONG(tmp, 1); - return tmp; -} - -#define DEREF(memory, type) *(type*)(memory) - -size_t native_slot_size(upb_fieldtype_t type) { - switch (type) { - case UPB_TYPE_FLOAT: return 4; - case UPB_TYPE_DOUBLE: return 8; - case UPB_TYPE_BOOL: return 1; - case UPB_TYPE_STRING: return sizeof(zval*); - case UPB_TYPE_BYTES: return sizeof(zval*); - case UPB_TYPE_MESSAGE: return sizeof(zval*); - case UPB_TYPE_ENUM: return 4; - case UPB_TYPE_INT32: return 4; - case UPB_TYPE_INT64: return 8; - case UPB_TYPE_UINT32: return 4; - case UPB_TYPE_UINT64: return 8; - default: return 0; - } -} - -static bool is_php_num(zval* value) { - // Is numerial string also valid? - return (Z_TYPE_P(value) == IS_LONG || - Z_TYPE_P(value) == IS_DOUBLE); -} - -void native_slot_check_int_range_precision(upb_fieldtype_t type, zval* val) { - // TODO(teboring): Add it back. - // if (!is_php_num(val)) { - // zend_error(E_ERROR, "Expected number type for integral field."); - // } - - // if (Z_TYPE_P(val) == IS_DOUBLE) { - // double dbl_val = NUM2DBL(val); - // if (floor(dbl_val) != dbl_val) { - // zend_error(E_ERROR, - // "Non-integral floating point value assigned to integer field."); - // } - // } - // if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) { - // if (NUM2DBL(val) < 0) { - // zend_error(E_ERROR, - // "Assigning negative value to unsigned integer field."); - // } - // } -} - -zval* native_slot_get(upb_fieldtype_t type, /*VALUE type_class,*/ - const void* memory TSRMLS_DC) { - zval* retval = NULL; - switch (type) { - // TODO(teboring): Add it back. - // case UPB_TYPE_FLOAT: - // return DBL2NUM(DEREF(memory, float)); - // case UPB_TYPE_DOUBLE: - // return DBL2NUM(DEREF(memory, double)); - // case UPB_TYPE_BOOL: - // return DEREF(memory, int8_t) ? Qtrue : Qfalse; - // case UPB_TYPE_STRING: - // case UPB_TYPE_BYTES: - // case UPB_TYPE_MESSAGE: - // return DEREF(memory, VALUE); - // case UPB_TYPE_ENUM: { - // int32_t val = DEREF(memory, int32_t); - // VALUE symbol = enum_lookup(type_class, INT2NUM(val)); - // if (symbol == Qnil) { - // return INT2NUM(val); - // } else { - // return symbol; - // } - // } - case UPB_TYPE_INT32: - return int32_to_zval(DEREF(memory, int32_t)); - // TODO(teboring): Add it back. - // case UPB_TYPE_INT64: - // return LL2NUM(DEREF(memory, int64_t)); - // case UPB_TYPE_UINT32: - // return UINT2NUM(DEREF(memory, uint32_t)); - // case UPB_TYPE_UINT64: - // return ULL2NUM(DEREF(memory, uint64_t)); - default: - return EG(uninitialized_zval_ptr); - } -} - -void native_slot_init(upb_fieldtype_t type, void* memory) { - switch (type) { - case UPB_TYPE_FLOAT: - DEREF(memory, float) = 0.0; - break; - case UPB_TYPE_DOUBLE: - DEREF(memory, double) = 0.0; - break; - case UPB_TYPE_BOOL: - DEREF(memory, int8_t) = 0; - break; - // TODO(teboring): Add it back. - // case UPB_TYPE_STRING: - // case UPB_TYPE_BYTES: - // DEREF(memory, VALUE) = php_str_new2(""); - // php_enc_associate(DEREF(memory, VALUE), (type == UPB_TYPE_BYTES) - // ? kRubyString8bitEncoding - // : kRubyStringUtf8Encoding); - // break; - // case UPB_TYPE_MESSAGE: - // DEREF(memory, VALUE) = Qnil; - // break; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: - DEREF(memory, int32_t) = 0; - break; - case UPB_TYPE_INT64: - DEREF(memory, int64_t) = 0; - break; - case UPB_TYPE_UINT32: - DEREF(memory, uint32_t) = 0; - break; - case UPB_TYPE_UINT64: - DEREF(memory, uint64_t) = 0; - break; - default: - break; - } -} - -void native_slot_set(upb_fieldtype_t type, /*VALUE type_class,*/ void* memory, - zval* value) { - native_slot_set_value_and_case(type, /*type_class,*/ memory, value, NULL, 0); -} - -void native_slot_set_value_and_case(upb_fieldtype_t type, /*VALUE type_class,*/ - void* memory, zval* value, - uint32_t* case_memory, - uint32_t case_number) { - switch (type) { - case UPB_TYPE_FLOAT: - if (!Z_TYPE_P(value) == IS_LONG) { - zend_error(E_ERROR, "Expected number type for float field."); - } - DEREF(memory, float) = Z_DVAL_P(value); - break; - case UPB_TYPE_DOUBLE: - // TODO(teboring): Add it back. - // if (!is_php_num(value)) { - // zend_error(E_ERROR, "Expected number type for double field."); - // } - // DEREF(memory, double) = Z_DVAL_P(value); - break; - case UPB_TYPE_BOOL: { - int8_t val = -1; - if (zval_is_true(value)) { - val = 1; - } else { - val = 0; - } - // TODO(teboring): Add it back. - // else if (value == Qfalse) { - // val = 0; - // } - // else { - // php_raise(php_eTypeError, "Invalid argument for boolean field."); - // } - DEREF(memory, int8_t) = val; - break; - } - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - // TODO(teboring): Add it back. - // if (Z_TYPE_P(value) != IS_STRING) { - // zend_error(E_ERROR, "Invalid argument for string field."); - // } - // native_slot_validate_string_encoding(type, value); - // DEREF(memory, zval*) = value; - break; - } - case UPB_TYPE_MESSAGE: { - // TODO(teboring): Add it back. - // if (CLASS_OF(value) == CLASS_OF(Qnil)) { - // value = Qnil; - // } else if (CLASS_OF(value) != type_class) { - // php_raise(php_eTypeError, - // "Invalid type %s to assign to submessage field.", - // php_class2name(CLASS_OF(value))); - // } - // DEREF(memory, VALUE) = value; - break; - } - case UPB_TYPE_ENUM: { - // TODO(teboring): Add it back. - // int32_t int_val = 0; - // if (!is_php_num(value) && TYPE(value) != T_SYMBOL) { - // php_raise(php_eTypeError, - // "Expected number or symbol type for enum field."); - // } - // if (TYPE(value) == T_SYMBOL) { - // // Ensure that the given symbol exists in the enum module. - // VALUE lookup = php_funcall(type_class, php_intern("resolve"), 1, value); - // if (lookup == Qnil) { - // php_raise(php_eRangeError, "Unknown symbol value for enum field."); - // } else { - // int_val = NUM2INT(lookup); - // } - // } else { - // native_slot_check_int_range_precision(UPB_TYPE_INT32, value); - // int_val = NUM2INT(value); - // } - // DEREF(memory, int32_t) = int_val; - // break; - } - case UPB_TYPE_INT32: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT32: - case UPB_TYPE_UINT64: - native_slot_check_int_range_precision(type, value); - switch (type) { - case UPB_TYPE_INT32: - php_printf("Setting INT32 field\n"); - DEREF(memory, int32_t) = Z_LVAL_P(value); - break; - case UPB_TYPE_INT64: - // TODO(teboring): Add it back. - // DEREF(memory, int64_t) = NUM2LL(value); - break; - case UPB_TYPE_UINT32: - // TODO(teboring): Add it back. - // DEREF(memory, uint32_t) = NUM2UINT(value); - break; - case UPB_TYPE_UINT64: - // TODO(teboring): Add it back. - // DEREF(memory, uint64_t) = NUM2ULL(value); - break; - default: - break; - } - break; - default: - break; - } - - if (case_memory != NULL) { - *case_memory = case_number; - } -} - -// ----------------------------------------------------------------------------- -// Map field utilities. -// ---------------------------------------------------------------------------- - -const upb_msgdef* tryget_map_entry_msgdef(const upb_fielddef* field) { - const upb_msgdef* subdef; - if (upb_fielddef_label(field) != UPB_LABEL_REPEATED || - upb_fielddef_type(field) != UPB_TYPE_MESSAGE) { - return NULL; - } - subdef = upb_fielddef_msgsubdef(field); - return upb_msgdef_mapentry(subdef) ? subdef : NULL; -} - -const upb_msgdef* map_entry_msgdef(const upb_fielddef* field) { - const upb_msgdef* subdef = tryget_map_entry_msgdef(field); - assert(subdef); - return subdef; -} - -bool is_map_field(const upb_fielddef* field) { - return tryget_map_entry_msgdef(field) != NULL; -} - -// ----------------------------------------------------------------------------- -// Memory layout management. -// ----------------------------------------------------------------------------- - -static size_t align_up_to(size_t offset, size_t granularity) { - // Granularity must be a power of two. - return (offset + granularity - 1) & ~(granularity - 1); -} - -MessageLayout* create_layout(const upb_msgdef* msgdef) { - MessageLayout* layout = ALLOC(MessageLayout); - int nfields = upb_msgdef_numfields(msgdef); - upb_msg_field_iter it; - upb_msg_oneof_iter oit; - size_t off = 0; - - layout->fields = ALLOC_N(MessageField, nfields); - - for (upb_msg_field_begin(&it, msgdef); !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - size_t field_size; - - if (upb_fielddef_containingoneof(field)) { - // Oneofs are handled separately below. - continue; - } - - // Allocate |field_size| bytes for this field in the layout. - field_size = 0; - if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - field_size = sizeof(zval*); - } else { - field_size = native_slot_size(upb_fielddef_type(field)); - } - - // Align current offset up to | size | granularity. - off = align_up_to(off, field_size); - layout->fields[upb_fielddef_index(field)].offset = off; - layout->fields[upb_fielddef_index(field)].case_offset = - MESSAGE_FIELD_NO_CASE; - off += field_size; - } - - // Handle oneofs now -- we iterate over oneofs specifically and allocate only - // one slot per oneof. - // - // We assign all value slots first, then pack the 'case' fields at the end, - // since in the common case (modern 64-bit platform) these are 8 bytes and 4 - // bytes respectively and we want to avoid alignment overhead. - // - // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value - // space for oneof cases is conceptually as wide as field tag numbers. In - // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K - // members (8 or 16 bits respectively), so conceivably we could assign - // consecutive case numbers and then pick a smaller oneof case slot size, but - // the complexity to implement this indirection is probably not worthwhile. - for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit); - upb_msg_oneof_next(&oit)) { - const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); - upb_oneof_iter fit; - - // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between - // all fields. - size_t field_size = NATIVE_SLOT_MAX_SIZE; - // Align the offset . - off = align_up_to( off, field_size); - // Assign all fields in the oneof this same offset. - for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* field = upb_oneof_iter_field(&fit); - layout->fields[upb_fielddef_index(field)].offset = off; - } - off += field_size; - } - - // Now the case fields. - for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit); - upb_msg_oneof_next(&oit)) { - const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); - upb_oneof_iter fit; - - size_t field_size = sizeof(uint32_t); - // Align the offset . - off = (off + field_size - 1) & ~(field_size - 1); - // Assign all fields in the oneof this same offset. - for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit); - upb_oneof_next(&fit)) { - const upb_fielddef* field = upb_oneof_iter_field(&fit); - layout->fields[upb_fielddef_index(field)].case_offset = off; - } - off += field_size; - } - - layout->size = off; - - layout->msgdef = msgdef; - upb_msgdef_ref(layout->msgdef, &layout->msgdef); - - return layout; -} - -void free_layout(MessageLayout* layout) { - FREE(layout->fields); - upb_msgdef_unref(layout->msgdef, &layout->msgdef); - FREE(layout); -} - -// TODO(teboring): Add it back. -// VALUE field_type_class(const upb_fielddef* field) { -// VALUE type_class = Qnil; -// if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { -// VALUE submsgdesc = get_def_obj(upb_fielddef_subdef(field)); -// type_class = Descriptor_msgclass(submsgdesc); -// } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) { -// VALUE subenumdesc = get_def_obj(upb_fielddef_subdef(field)); -// type_class = EnumDescriptor_enummodule(subenumdesc); -// } -// return type_class; -// } - -static void* slot_memory(MessageLayout* layout, const void* storage, - const upb_fielddef* field) { - return ((uint8_t*)storage) + layout->fields[upb_fielddef_index(field)].offset; -} - -static uint32_t* slot_oneof_case(MessageLayout* layout, const void* storage, - const upb_fielddef* field) { - return (uint32_t*)(((uint8_t*)storage) + - layout->fields[upb_fielddef_index(field)].case_offset); -} - -void layout_set(MessageLayout* layout, void* storage, const upb_fielddef* field, - zval* val) { - void* memory = slot_memory(layout, storage, field); - uint32_t* oneof_case = slot_oneof_case(layout, storage, field); - - if (upb_fielddef_containingoneof(field)) { - if (Z_TYPE_P(val) == IS_NULL) { - // Assigning nil to a oneof field clears the oneof completely. - *oneof_case = ONEOF_CASE_NONE; - memset(memory, 0, NATIVE_SLOT_MAX_SIZE); - } else { - // The transition between field types for a single oneof (union) slot is - // somewhat complex because we need to ensure that a GC triggered at any - // point by a call into the Ruby VM sees a valid state for this field and - // does not either go off into the weeds (following what it thinks is a - // VALUE but is actually a different field type) or miss an object (seeing - // what it thinks is a primitive field but is actually a VALUE for the new - // field type). - // - // 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. Thus, we - // use native_slot_set_value_and_case(), which ensures that both the value - // and case number are altered atomically (w.r.t. the Ruby VM). - native_slot_set_value_and_case(upb_fielddef_type(field), - /*field_type_class(field),*/ memory, val, - oneof_case, upb_fielddef_number(field)); - } - } else if (is_map_field(field)) { - // TODO(teboring): Add it back. - // check_map_field_type(val, field); - // DEREF(memory, zval*) = val; - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - // TODO(teboring): Add it back. - // check_repeated_field_type(val, field); - // DEREF(memory, zval*) = val; - } else { - native_slot_set(upb_fielddef_type(field), /*field_type_class(field),*/ memory, - val); - } -} - -void layout_init(MessageLayout* layout, void* storage) { - upb_msg_field_iter it; - for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it); - upb_msg_field_next(&it)) { - const upb_fielddef* field = upb_msg_iter_field(&it); - void* memory = slot_memory(layout, storage, field); - uint32_t* oneof_case = slot_oneof_case(layout, storage, field); - - if (upb_fielddef_containingoneof(field)) { - // TODO(teboring): Add it back. - // memset(memory, 0, NATIVE_SLOT_MAX_SIZE); - // *oneof_case = ONEOF_CASE_NONE; - } else if (is_map_field(field)) { - // TODO(teboring): Add it back. - // VALUE map = Qnil; - - // const upb_fielddef* key_field = map_field_key(field); - // const upb_fielddef* value_field = map_field_value(field); - // VALUE type_class = field_type_class(value_field); - - // if (type_class != Qnil) { - // VALUE args[3] = { - // fieldtype_to_php(upb_fielddef_type(key_field)), - // fieldtype_to_php(upb_fielddef_type(value_field)), type_class, - // }; - // map = php_class_new_instance(3, args, cMap); - // } else { - // VALUE args[2] = { - // fieldtype_to_php(upb_fielddef_type(key_field)), - // fieldtype_to_php(upb_fielddef_type(value_field)), - // }; - // map = php_class_new_instance(2, args, cMap); - // } - - // DEREF(memory, VALUE) = map; - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - // TODO(teboring): Add it back. - // VALUE ary = Qnil; - - // VALUE type_class = field_type_class(field); - - // if (type_class != Qnil) { - // VALUE args[2] = { - // fieldtype_to_php(upb_fielddef_type(field)), type_class, - // }; - // ary = php_class_new_instance(2, args, cRepeatedField); - // } else { - // VALUE args[1] = {fieldtype_to_php(upb_fielddef_type(field))}; - // ary = php_class_new_instance(1, args, cRepeatedField); - // } - - // DEREF(memory, VALUE) = ary; - } else { - native_slot_init(upb_fielddef_type(field), memory); - } - } -} - -zval* layout_get(MessageLayout* layout, const void* storage, - const upb_fielddef* field TSRMLS_DC) { - void* memory = slot_memory(layout, storage, field); - uint32_t* oneof_case = slot_oneof_case(layout, storage, field); - - if (upb_fielddef_containingoneof(field)) { - if (*oneof_case != upb_fielddef_number(field)) { - return NULL; - // TODO(teboring): Add it back. - // return Qnil; - } - return NULL; - // TODO(teboring): Add it back. - // return native_slot_get(upb_fielddef_type(field), field_type_class(field), - // memory); - } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { - return NULL; - // TODO(teboring): Add it back. - // return *((VALUE*)memory); - } else { - return native_slot_get( - upb_fielddef_type(field), /*field_type_class(field), */ - memory TSRMLS_CC); - } -} |