X-Git-Url: https://git.m6w6.name/?a=blobdiff_plain;ds=sidebyside;f=ion_private.h;h=50d99213dbc236740c9ece3ebad95491d43f9c60;hb=5a6253e058e01c9467b15eb6d7714666c6e62a9e;hp=4f49088d8365df4d3acf84379e385e3bf547bce5;hpb=965ae10a6a58f2f87f883a473729cdfe5150f248;p=awesomized%2Fext-ion diff --git a/ion_private.h b/ion_private.h index 4f49088..50d9921 100644 --- a/ion_private.h +++ b/ion_private.h @@ -11,6 +11,7 @@ */ #include "php.h" +#include "ext/standard/php_var.h" #include "ext/date/php_date.h" #if PHP_DEBUG @@ -403,7 +404,7 @@ LOCAL void *php_ion_obj_ex(void *obj, ptrdiff_t offset) { #define ION_CHECK_RETURN(r, err, ...) do { \ iERR __err = err; \ - if (__err) { \ + if (UNEXPECTED(__err)) { \ zend_throw_exception_ex(spl_ce_RuntimeException, __err, "%s: %s", ion_error_to_str(__err), #err); \ __VA_ARGS__; \ return r; \ @@ -414,14 +415,14 @@ LOCAL void *php_ion_obj_ex(void *obj, ptrdiff_t offset) { ION_CHECK_RETURN(, err, __VA_ARGS__) #define ION_CATCH(...) do { \ - if (EG(exception)) { \ + if (UNEXPECTED(EG(exception))) { \ __VA_ARGS__; \ return; \ } \ } while (0) #define PTR_CHECK_RETURN(ret, ptr, ...) do { \ - if (!(ptr)) { \ + if (UNEXPECTED(!(ptr))) { \ zend_throw_error(NULL, "Uninitialized object"); \ __VA_ARGS__; \ return ret; \ @@ -454,15 +455,6 @@ LOCAL void update_property_obj(zend_object *obj, const char *n, size_t l, zend_o zend_update_property(obj->ce, obj, n, l, &zobj); } -LOCAL zend_object *get_property_obj(zend_object *obj, const char *n, size_t l, int type) -{ - zval tmp, *zv = zend_read_property(obj->ce, obj, n, l, 0, &tmp); - if (zv && type & Z_TYPE_P(zv)) { - return Z_PTR_P(zv); - } - return NULL; -} - #define RETURN_IONTYPE(typ) do { \ zend_object *__zo = php_ion_type_fetch(typ); \ if (UNEXPECTED(!__zo)) { \ @@ -577,7 +569,7 @@ LOCAL void php_ion_symbol_copy(php_ion_symbol *new_obj, php_ion_symbol *old_obj) ion_string_from_zend(&new_obj->sym.value, new_obj->value); } - if ((new_obj->iloc = get_property_obj(&new_obj->std, ZEND_STRL("importLocation"), IS_OBJECT))) { + if ((new_obj->iloc = old_obj->iloc)) { new_obj->sym.import_location = php_ion_obj(symbol_iloc, new_obj->iloc)->loc; } } @@ -641,13 +633,17 @@ LOCAL void php_ion_symbol_table_ctor(php_ion_symbol_table *obj) { OBJ_CHECK(obj); - ION_STRING is; - if (IERR_OK == ion_symbol_table_get_name(obj->tab, &is)) { - zend_update_property_stringl(obj->std.ce, &obj->std, ZEND_STRL("name"), (char *) is.value, is.length); - } - int32_t iv; - if (IERR_OK == ion_symbol_table_get_version(obj->tab, &iv)) { - zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("version"), iv); + ION_SYMBOL_TABLE_TYPE typ = ist_EMPTY; + ion_symbol_table_get_type(obj->tab, &typ); + if (typ != ist_LOCAL) { + ION_STRING is; + if (IERR_OK == ion_symbol_table_get_name(obj->tab, &is)) { + zend_update_property_stringl(obj->std.ce, &obj->std, ZEND_STRL("name"), (char *) is.value, is.length); + } + int32_t iv; + if (IERR_OK == ion_symbol_table_get_version(obj->tab, &iv)) { + zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("version"), iv); + } } } @@ -855,7 +851,7 @@ LOCAL void php_ion_decimal_dtor(php_ion_decimal *obj) LOCAL void php_ion_decimal_copy(php_ion_decimal *new_obj, php_ion_decimal *old_obj) { zend_objects_clone_members(&new_obj->std, &old_obj->std); - new_obj->ctx = get_property_obj(&new_obj->std, ZEND_STRL("context"), IS_OBJECT); + new_obj->ctx = old_obj->ctx; ION_CHECK(ion_decimal_copy(&new_obj->dec, &old_obj->dec)); } @@ -909,7 +905,7 @@ LOCAL zend_string *php_dt_format_from_precision(uint8_t precision) case ION_TS_YEAR: return php_ion_timestamp_format_fetch(g_intern_str.Year); default: - return zend_one_char_string['c']; + return ZSTR_CHAR('c'); } } @@ -917,6 +913,11 @@ LOCAL timelib_time* php_time_from_ion(const ION_TIMESTAMP *ts, decContext *ctx, { timelib_time *time = ecalloc(1, sizeof(*time)); + /* defaults */ + time->y = 1970; + time->m = 1; + time->d = 1; + switch (ts->precision & 0x7f) { case ION_TS_FRAC: time->us = php_usec_from_ion(&ts->fraction, ctx); @@ -1039,8 +1040,7 @@ LOCAL ION_COLLECTION *php_ion_catalog_collection(php_ion_catalog *cat) LOCAL void php_ion_catalog_copy(php_ion_catalog *new_obj, php_ion_catalog *old_obj) { - // do not clone members; they're only caches - + // do not clone cache members php_ion_catalog_ctor(new_obj); OBJ_CHECK(new_obj); @@ -1115,11 +1115,9 @@ LOCAL void php_ion_catalog_symbol_table_zval(php_ion_catalog *obj, ION_SYMBOL_TA } } - php_error_docref(NULL, E_NOTICE, "Previously unknown ion\\Symbol\\Table encountered: %s", key->val); - object_init_ex(return_value, ce_Symbol_Table_Shared); php_ion_symbol_table *o_tab = php_ion_obj(symbol_table, Z_OBJ_P(return_value)); - OBJ_CHECK(o_tab, zend_string_release(key)); + o_tab->tab = tab; php_ion_symbol_table_ctor(o_tab); if (ztabs) { @@ -1158,9 +1156,9 @@ LOCAL void php_ion_reader_options_copy(php_ion_reader_options *new_obj, php_ion_ zend_objects_clone_members(&new_obj->std, &old_obj->std); new_obj->opt = old_obj->opt; - new_obj->cat = get_property_obj(&new_obj->std, ZEND_STRL("catalog"), IS_OBJECT); - new_obj->dec_ctx = get_property_obj(&new_obj->std, ZEND_STRL("decimalContext"), IS_OBJECT); - new_obj->cb = get_property_obj(&new_obj->std, ZEND_STRL("onContextChange"), IS_OBJECT); + new_obj->cat = old_obj->cat; + new_obj->dec_ctx = old_obj->dec_ctx; + new_obj->cb = old_obj->cb; if (new_obj->cb) { zval zcb; ZVAL_OBJ(&zcb, new_obj->cb); @@ -1253,7 +1251,7 @@ LOCAL void php_ion_reader_ctor(php_ion_reader *obj) PTR_CHECK(obj->stream.ptr); GC_ADDREF(obj->stream.ptr->res); - obj->stream.buf.length = opt && opt->opt.allocation_page_size ? opt->opt.allocation_page_size : 0x10000; + obj->stream.buf.length = opt && opt->opt.chunk_threshold ? opt->opt.chunk_threshold : 0x4000; obj->stream.buf.value = emalloc(obj->stream.buf.length); err = ion_reader_open_stream(&obj->reader, obj, php_ion_reader_stream_handler, opt ? &opt->opt : NULL); @@ -1295,16 +1293,11 @@ typedef struct php_ion_writer_options { LOCAL void php_ion_writer_options_copy(php_ion_writer_options *new_obj, php_ion_writer_options *old_obj) { - new_obj->opt = old_obj->opt; + zend_objects_clone_members(&new_obj->std, &old_obj->std); - if (old_obj->cat) { - new_obj->cat = old_obj->cat; - GC_ADDREF(new_obj->cat); - } - if (old_obj->dec_ctx) { - new_obj->dec_ctx = old_obj->dec_ctx; - GC_ADDREF(new_obj->dec_ctx); - } + new_obj->opt = old_obj->opt; + new_obj->cat = old_obj->cat; + new_obj->dec_ctx = old_obj->dec_ctx; } LOCAL void php_ion_writer_options_dtor(php_ion_writer_options *obj) @@ -1328,8 +1321,8 @@ typedef struct php_ion_writer { } type; union { struct { - zval val; smart_str str; + struct _ion_user_stream *usr; } buffer; struct { ION_STRING buf; @@ -1355,82 +1348,80 @@ LOCAL iERR php_ion_writer_stream_handler(struct _ion_user_stream *user) return IERR_OK; } -#define REF_STR() do { \ - ZVAL_NEW_STR(ref, obj->buffer.str.s); \ - GC_ADDREF(obj->buffer.str.s); \ -} while (0) - -#define NEW_REF_STR() do {\ - if (Z_STR_P(ref) != obj->buffer.str.s) { \ - zval_ptr_dtor(ref); \ - REF_STR(); \ - } \ -} while(0) - LOCAL void php_ion_writer_stream_init(php_ion_writer *obj, php_ion_writer_options *opt) { PTR_CHECK(obj->stream.ptr); GC_ADDREF(obj->stream.ptr->res); - obj->stream.buf.length = opt ? opt->opt.allocation_page_size : 0x1000; + obj->stream.buf.length = opt ? opt->opt.temp_buffer_size : 0x1000; obj->stream.buf.value = emalloc(obj->stream.buf.length); } + +LOCAL void php_ion_writer_buffer_offer(php_ion_writer *obj) +{ + if (obj->buffer.usr) { + obj->buffer.usr->curr = (BYTE *) &obj->buffer.str.s->val[obj->buffer.str.s->len]; + obj->buffer.usr->limit = obj->buffer.usr->curr + obj->buffer.str.a - obj->buffer.str.s->len; + } +} + LOCAL void php_ion_writer_buffer_init(php_ion_writer *obj) { - zval *ref = &obj->buffer.val; - ZVAL_DEREF(ref); + smart_str_alloc(&obj->buffer.str, 0, false); + php_ion_writer_buffer_offer(obj); +} + +LOCAL void php_ion_writer_buffer_reset(php_ion_writer *obj) +{ + smart_str_free(&obj->buffer.str); + memset(&obj->buffer.str, 0, sizeof(obj->buffer.str)); + php_ion_writer_buffer_init(obj); +} - smart_str_alloc(&obj->buffer.str, 0, 0); +LOCAL zend_string *php_ion_writer_buffer_copy(php_ion_writer *obj) +{ + if (obj->buffer.usr) { + // ensure that brain-dead ion_stream interface calls us again + obj->buffer.usr->curr = NULL; + obj->buffer.usr->limit = NULL; + } smart_str_0(&obj->buffer.str); - REF_STR(); + return zend_string_copy(obj->buffer.str.s); } -LOCAL void php_ion_writer_buffer_grow(php_ion_writer *obj) +LOCAL void php_ion_writer_buffer_separate(php_ion_writer *obj, bool grow) { - zval *ref = &obj->buffer.val; - ZVAL_DEREF(ref); + // see zend_string_separate and smart_str_erealloc + zend_string *old_str = obj->buffer.str.s; + zend_string *new_str = zend_string_alloc(obj->buffer.str.a << grow, false); + memcpy(new_str->val, old_str->val, new_str->len = old_str->len); + zend_string_release(old_str); + obj->buffer.str.s = new_str; +} - switch (GC_REFCOUNT(obj->buffer.str.s)) { - case 2: - // nothing to do - break; - case 1: - // we've been separated - GC_ADDREF(obj->buffer.str.s); - break; - default: - // we have to separate - fprintf(stderr, "SEPARATE\n"); - obj->buffer.str.s = zend_string_dup(obj->buffer.str.s, 0); - break; +LOCAL void php_ion_writer_buffer_grow(php_ion_writer *obj) +{ + if (obj->buffer.usr && obj->buffer.usr->curr) { + obj->buffer.str.s->len = obj->buffer.usr->curr - (BYTE *) obj->buffer.str.s->val; } - - zend_string *old = obj->buffer.str.s; - GC_DELREF(old); - smart_str_erealloc(&obj->buffer.str, obj->buffer.str.a << 1); - if (old == obj->buffer.str.s) { - GC_ADDREF(old); - } else if(old == Z_STR_P(ref)) { - ZVAL_NULL(ref); + if (obj->buffer.usr && obj->buffer.usr->curr && obj->buffer.usr->curr == obj->buffer.usr->limit) { + if (UNEXPECTED(GC_REFCOUNT(obj->buffer.str.s) > 1)) { + php_ion_writer_buffer_separate(obj, true); + } else { + smart_str_erealloc(&obj->buffer.str, obj->buffer.str.a << 1); + } + } else if (UNEXPECTED(GC_REFCOUNT(obj->buffer.str.s) > 1)) { + php_ion_writer_buffer_separate(obj, false); } - - NEW_REF_STR(); + php_ion_writer_buffer_offer(obj); } + LOCAL iERR php_ion_writer_buffer_handler(struct _ion_user_stream *user) { php_ion_writer *writer = (php_ion_writer *) user->handler_state; - - if (user->curr) { - writer->buffer.str.s->len += user->curr - (BYTE *) &writer->buffer.str.s->val[writer->buffer.str.s->len]; - smart_str_0(&writer->buffer.str); - if (user->limit == user->curr) { - php_ion_writer_buffer_grow(writer); - } - } - user->curr = (BYTE *) &writer->buffer.str.s->val[writer->buffer.str.s->len]; - user->limit = user->curr + writer->buffer.str.a - writer->buffer.str.s->len; - + writer->buffer.usr = user; + php_ion_writer_buffer_grow(writer); return IERR_OK; } @@ -1451,8 +1442,6 @@ LOCAL void php_ion_writer_options_init_shared_imports(php_ion_writer_options *op ION_COLLECTION_NEXT(cur, ptr); if (*ptr) { ION_CHECK(ion_writer_options_add_shared_imports_symbol_tables(&opt->opt, ptr, 1)); - } else { - break; } } } @@ -1507,7 +1496,6 @@ LOCAL void php_ion_writer_dtor(php_ion_writer *obj) smart_str_0(&obj->buffer.str); zend_string_release(obj->buffer.str.s); } - zval_ptr_dtor(&obj->buffer.val); } } @@ -1696,8 +1684,8 @@ LOCAL void php_ion_serialize_object_std(php_ion_serializer *ser, zend_object *zo LOCAL void php_ion_serialize_object_lob(php_ion_serializer *ser, zend_object *zobject) { - zval tmp_type, *type = zend_read_property(NULL, zobject, ZEND_STRL("type"), 0, &tmp_type); - zval tmp_value, *value = zend_read_property(NULL, zobject, ZEND_STRL("value"), 0, &tmp_value); + zval tmp_type, *type = zend_read_property_ex(NULL, zobject, ZSTR_KNOWN(ZEND_STR_TYPE), 0, &tmp_type); + zval tmp_value, *value = zend_read_property_ex(NULL, zobject, ZSTR_KNOWN(ZEND_STR_VALUE), 0, &tmp_value); switch (Z_LVAL_P(zend_enum_fetch_case_value(Z_OBJ_P(type)))) { case tid_BLOB_INT: ION_CHECK(ion_writer_write_blob(ser->writer, (BYTE *) Z_STRVAL_P(value), Z_STRLEN_P(value))); @@ -2027,6 +2015,8 @@ LOCAL zval *php_ion_unserialize_class(php_ion_unserializer *ser, zval *return_va LOCAL void php_ion_unserialize_object_enum(php_ion_unserializer *ser, zval *return_value) { zend_string *zs_case = zval_get_string(return_value); + zend_hash_next_index_insert(ser->tmp, return_value); + ZVAL_NULL(return_value); ION_CATCH(); zend_class_entry *ce = zend_lookup_class(ser->annotations.object_class); @@ -2050,13 +2040,18 @@ LOCAL void php_ion_unserialize_object_iface(php_ion_unserializer *ser, zval *ret zend_class_entry *ce = zend_lookup_class(ser->annotations.object_class); if (can_call_iface_unserialize(ser, ce)) { zend_string *s = zval_get_string(return_value); + zend_hash_next_index_insert(ser->tmp, return_value); ZVAL_NULL(return_value); zval *backref = zend_hash_next_index_insert(ser->ids, return_value); if (SUCCESS == ce->unserialize(backref, ce, (BYTE *) s->val, s->len, NULL)) { RETVAL_ZVAL(backref, 0, 0); - } else if (!EG(exception)) { - zend_throw_exception_ex(spl_ce_UnexpectedValueException, IERR_INTERNAL_ERROR, - "Failed to unserialize class %s", ce->name->val); + } else { + zval_ptr_dtor(backref); + ZVAL_NULL(backref); + if (!EG(exception)) { + zend_throw_exception_ex(spl_ce_UnexpectedValueException, IERR_INTERNAL_ERROR, + "Failed to unserialize class %s", ce->name->val); + } } zend_string_release(s); } else { @@ -2096,7 +2091,7 @@ LOCAL void php_ion_unserialize_field_name(php_ion_unserializer *ser, zend_string *key = zend_string_init(ptr, end - ptr, 0); break; case 1: - *key = zend_one_char_string[*name.value]; + *key = ZSTR_CHAR(*name.value); break; default: if (is_prop) { @@ -2222,7 +2217,7 @@ LOCAL void php_ion_unserialize_object(php_ion_unserializer *ser, zval *return_va { // backup possible backref to array returned by magic/custom __serialize() zval *input = zend_hash_next_index_insert(ser->tmp, return_value); - + ZVAL_NULL(return_value); php_ion_unserialize_class(ser, return_value); ION_CATCH(); @@ -2554,7 +2549,6 @@ LOCAL void php_ion_unserialize_zval(php_ion_unserializer *ser, zval *return_valu ION_CHECK(ion_reader_read_ion_symbol(ser->reader, &sym)); php_ion_symbol_zval(&sym, return_value); if (ser->annotations.object_type) { - zend_hash_next_index_insert(ser->tmp, return_value); goto unserialize_struct; } zend_hash_next_index_insert(ser->ids, return_value); @@ -2565,7 +2559,6 @@ LOCAL void php_ion_unserialize_zval(php_ion_unserializer *ser, zval *return_valu ION_CHECK(ion_reader_read_string(ser->reader, &str)); RETVAL_STRINGL((char *) str.value, str.length); if (ser->annotations.object_type) { - zend_hash_next_index_insert(ser->tmp, return_value); goto unserialize_struct; } zend_hash_next_index_insert(ser->ids, return_value); @@ -2575,7 +2568,6 @@ LOCAL void php_ion_unserialize_zval(php_ion_unserializer *ser, zval *return_valu case tid_BLOB_INT: php_ion_reader_read_lob(ser->reader, return_value); if (ser->annotations.object_type) { - zend_hash_next_index_insert(ser->tmp, return_value); goto unserialize_struct; } zend_hash_next_index_insert(ser->ids, return_value); @@ -2661,7 +2653,8 @@ void php_ion_unserialize(php_ion_unserializer *ser, zval *zdata, zval *return_va reader->buffer = zval_get_string(zdata); } else { zend_throw_exception_ex(spl_ce_InvalidArgumentException, IERR_INVALID_ARG, - "Invalid source to unserialize; expected string or resource"); + "Invalid source to unserialize: expected string or resource, got %s", + zend_zval_type_name(zdata)); if (zo_ser) { OBJ_RELEASE(zo_ser); }