Skip to content

Commit 5001ace

Browse files
committed
TL parsing by vkext
1 parent c8cd8c8 commit 5001ace

7 files changed

Lines changed: 202 additions & 23 deletions

File tree

vkext/vk_zend.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,24 @@ static zend_always_inline void vk_zend_update_public_property_long(zval *object,
226226
#endif
227227
}
228228

229+
static zend_always_inline void vk_zend_call_known_instance_method(zval *object,
230+
const char * name, size_t name_len, zval *retval_ptr,
231+
uint32_t param_count, zval *params) {
232+
zend_object* zobj = Z_OBJ_P(object);
233+
zend_string* method_name = zend_string_init(name, name_len, 0);
234+
zend_function* fun = Z_OBJ_HANDLER_P(object, get_method)(&zobj, method_name, 0);
235+
zend_string_release(method_name);
236+
if (!fun) {
237+
return; // retval stays UNDEF
238+
}
239+
#if PHP_MAJOR_VERSION >= 8
240+
zend_call_known_instance_method(fun, zobj, retval_ptr, param_count, params);
241+
#else
242+
// TODO - this branch is not tested yet
243+
zend_call_known_instance_method(fun, object, retval_ptr, param_count, params);
244+
#endif
245+
}
246+
229247
#define ZAPI_TO_PP(az) (&(az))
230248
#define ZP_TO_API_P(az) (az)
231249
#define SMART_STRDATA(ss) ((ss).s)

vkext/vkext-rpc-req-error.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,15 @@ void tl::RpcReqError::tl_fetch() {
5959
}
6060

6161
void RpcError::try_fetch() {
62-
int op = tl_parse_int();
62+
int op = tl_lookup_int();
6363
if (op == TL_REQ_RESULT_HEADER) {
64+
(void)tl_parse_int(); // skip op
6465
flags = tl_parse_int();
6566
header.emplace().tl_fetch(flags);
66-
op = tl_parse_int();
67+
op = tl_lookup_int();
6768
}
6869
if (op == TL_RPC_REQ_ERROR) {
70+
(void)tl_parse_int(); // skip op
6971
error.emplace().tl_fetch();
7072
}
7173
}

vkext/vkext-rpc-tl-serialization.cpp

Lines changed: 167 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,7 @@ static zval *create_php_instance(const char *class_name) {
531531
return ci;
532532
}
533533

534-
static zval *make_query_result_or_error(zval **r, const vkext_rpc::tl::RpcReqError &error, const vkext_rpc::tl::RpcReqResultExtra *header = nullptr, int extra_flags = 0);
534+
static zval *make_query_result_or_error(zval *r, const vkext_rpc::tl::RpcReqError &error, const vkext_rpc::tl::RpcReqResultExtra *header = nullptr, int extra_flags = 0);
535535

536536
/**
537537
* This function extracts ORIGINAL tl name from given php class name.
@@ -923,6 +923,36 @@ inline void tl_debug(const char *s __attribute__((unused)), int n __attribute__(
923923

924924
/* {{{ Interface functions */
925925

926+
// returns 0 if no typedStore was found, otherwise returns allocated ZVAL with fetcher instance
927+
bool store_function2(VK_ZVAL_API_P arr, zval *fetcher) {
928+
ADD_CNT(store_function2)
929+
START_TIMER(store_function2)
930+
assert(arr);
931+
if (Z_TYPE_P(arr) != IS_OBJECT) {
932+
END_TIMER(store_function2)
933+
return false;
934+
}
935+
vk_zend_call_known_instance_method(arr, "typedStore", strlen("typedStore"), fetcher, 0, NULL);
936+
if (EG(exception)) {
937+
// This behavior is consistent with old code, in this case, query_one will return qid 0
938+
fprintf(stderr, "typedStore exception\n");
939+
_zend_object* old_exception = EG(exception);
940+
EG(exception) = NULL;
941+
OBJ_RELEASE(old_exception);
942+
END_TIMER(store_function2)
943+
return false;
944+
}
945+
if (Z_TYPE_P(fetcher) != IS_OBJECT) { // returned null or function not found
946+
fprintf(stderr, "typedStore fetcher type is %d\n", Z_TYPE_P(fetcher));
947+
END_TIMER(store_function2)
948+
return false;
949+
}
950+
// when using fetcher, tl_current_function_name will not be accessed. But we set it anyway in case we forgot something.
951+
tl_current_function_name = "typedStore";
952+
END_TIMER(store_function2)
953+
return true;
954+
}
955+
926956
struct tl_tree *store_function(VK_ZVAL_API_P arr) {
927957
ADD_CNT(store_function)
928958
START_TIMER(store_function)
@@ -1033,7 +1063,7 @@ struct tl_tree *store_function(VK_ZVAL_API_P arr) {
10331063
return reinterpret_cast<tl_tree *>(res);
10341064
}
10351065

1036-
zval **fetch_function(struct tl_tree *T) {
1066+
zval *fetch_function(struct tl_tree *T) {
10371067
ADD_CNT(fetch_function)
10381068
START_TIMER(fetch_function)
10391069
#ifdef VLOG
@@ -1056,10 +1086,10 @@ zval **fetch_function(struct tl_tree *T) {
10561086
vkext_rpc::RpcError rpc_error;
10571087
rpc_error.try_fetch();
10581088
if (rpc_error.error.has_value()) {
1059-
*_arr = make_query_result_or_error(NULL, rpc_error.error.value(), rpc_error.header.has_value() ? &rpc_error.header.value() : nullptr, rpc_error.flags);
1089+
zval *ret = make_query_result_or_error(NULL, rpc_error.error.value(), rpc_error.header.has_value() ? &rpc_error.header.value() : nullptr, rpc_error.flags);
10601090
DEC_REF (T);
10611091
END_TIMER(fetch_function)
1062-
return _arr;
1092+
return ret;
10631093
}
10641094
tl_parse_restore_pos(pos);
10651095

@@ -1077,28 +1107,55 @@ zval **fetch_function(struct tl_tree *T) {
10771107
VK_ALLOC_INIT_ZVAL(*_arr);
10781108
ZVAL_BOOL (*_arr, 1);
10791109
}
1080-
return _arr;
1110+
return *_arr;
10811111
} else {
10821112
if (*_arr) {
10831113
zval_dtor (*_arr);
10841114
}
10851115
*_arr = make_query_result_or_error(NULL, {TL_ERROR_RESPONSE_SYNTAX, "Can't parse response"});
1086-
return _arr;
1116+
return *_arr;
10871117
}
10881118
}
10891119

10901120
void _extra_dec_ref(struct rpc_query *q) {
1091-
if (q->extra) {
1092-
total_tl_working--;
1121+
if (!q->extra_free) {
1122+
return;
10931123
}
1094-
DEC_REF (q->extra);
1095-
q->extra = 0;
10961124
q->extra_free = 0;
1125+
total_tl_working--;
1126+
if (q->extra) {
1127+
DEC_REF (q->extra);
1128+
q->extra = 0;
1129+
}
1130+
zval_ptr_dtor(&q->fetcher);
10971131
}
10981132

10991133
struct rpc_query *vk_rpc_tl_query_one_impl(struct rpc_connection *c, double timeout, VK_ZVAL_API_P arr, int ignore_answer) {
11001134
do_rpc_clean();
11011135
START_TIMER (tmp);
1136+
zval fetcher;
1137+
ZVAL_NULL(&fetcher);
1138+
bool fetcher_found = store_function2(arr, &fetcher);
1139+
END_TIMER (tmp);
1140+
if (fetcher_found) {
1141+
struct rpc_query *q;
1142+
if (!(q = do_rpc_send_noflush(c, timeout, ignore_answer))) {
1143+
zval_ptr_dtor(&fetcher);
1144+
vkext_error(VKEXT_ERROR_NETWORK, "Can't send packet");
1145+
return 0;
1146+
}
1147+
if (q == (struct rpc_query *)1) { // answer is ignored
1148+
assert (ignore_answer);
1149+
zval_ptr_dtor(&fetcher);
1150+
return q;
1151+
}
1152+
assert (!ignore_answer);
1153+
ZVAL_COPY_VALUE(&q->fetcher, &fetcher);
1154+
q->extra_free = _extra_dec_ref;
1155+
total_tl_working++;
1156+
return q;
1157+
}
1158+
START_TIMER (tmp);
11021159
void *res = store_function(arr);
11031160
END_TIMER (tmp);
11041161
if (!res) {
@@ -1117,15 +1174,23 @@ struct rpc_query *vk_rpc_tl_query_one_impl(struct rpc_connection *c, double time
11171174
}
11181175
assert (!ignore_answer);
11191176
q->extra = res;
1177+
ZVAL_NULL(&q->fetcher);
11201178
q->extra_free = _extra_dec_ref;
11211179
total_tl_working++;
11221180
return q;
11231181
}
11241182

1125-
zval **vk_rpc_tl_query_result_one_impl(struct tl_tree *T) {
1183+
zval *fetch_function2(zval *fetcher);
1184+
1185+
zval *vk_rpc_tl_query_result_one_impl(struct tl_tree *T, zval *fetcher) {
11261186
tl_parse_init();
11271187
START_TIMER (tmp);
1128-
zval **r = fetch_function(T);
1188+
zval *r = NULL;
1189+
if (T) {
1190+
r = fetch_function(T);
1191+
}else{
1192+
r = fetch_function2(fetcher);
1193+
}
11291194
//fprintf(stderr, "~~~~ after fetch:\n");
11301195
//php_debug_zval_dump(*r, 1);
11311196
END_TIMER (tmp);
@@ -1341,9 +1406,79 @@ static zval *convert_rpc_extra_header_to_php_repr(const vkext_rpc::tl::RpcReqRes
13411406
return res;
13421407
}
13431408

1344-
static zval *make_query_result_or_error(zval **r, const vkext_rpc::tl::RpcReqError &error, const vkext_rpc::tl::RpcReqResultExtra *header, int extra_flags) {
1409+
zval *fetch_function2(zval *fetcher) {
1410+
ADD_CNT(fetch_function2)
1411+
START_TIMER(fetch_function2)
1412+
1413+
assert(fetcher);
1414+
assert(Z_TYPE_P(fetcher) == IS_OBJECT);
1415+
1416+
vkext_rpc::RpcError rpc_error;
1417+
rpc_error.try_fetch();
1418+
if (rpc_error.error.has_value()) {
1419+
zval *ret = make_query_result_or_error(NULL, rpc_error.error.value(), rpc_error.header.has_value() ? &rpc_error.header.value() : nullptr, rpc_error.flags);
1420+
END_TIMER(fetch_function2)
1421+
return ret;
1422+
}
1423+
1424+
zval* return_value;
1425+
VK_ALLOC_INIT_ZVAL(return_value);
1426+
ZVAL_UNDEF(return_value);
1427+
vk_zend_call_known_instance_method(fetcher, "typedFetch", strlen("typedFetch"), return_value, 0, NULL);
1428+
if (EG(exception)) {
1429+
efree(return_value); // it is UNDEF
1430+
1431+
_zend_object * old_exception = EG(exception);
1432+
EG(exception) = NULL;
1433+
1434+
zval exception_zval;
1435+
ZVAL_OBJ(&exception_zval, old_exception);
1436+
1437+
zval *message;
1438+
VK_ALLOC_INIT_ZVAL(message);
1439+
ZVAL_UNDEF(message);
1440+
vk_zend_call_known_instance_method(&exception_zval, "getMessage", strlen("getMessage"), message, 0, NULL);
1441+
// fprintf(stderr, "getMessage after call %d\n", Z_TYPE(message));
1442+
assert(Z_TYPE_P(message) == IS_STRING);
1443+
1444+
OBJ_RELEASE(old_exception);
1445+
1446+
zval *_err = create_php_instance(reqResult_error_class_name);
1447+
1448+
vk_zend_update_public_property_nod(_err, "error", message);
1449+
1450+
// vk_zend_update_public_property_string(_err, "error", "hren");
1451+
vk_zend_update_public_property_long(_err, "error_code", -1000);
1452+
END_TIMER(fetch_function2)
1453+
return _err;
1454+
}
1455+
fprintf(stderr, "typedFetch after call %d\n", Z_TYPE_P(return_value));
1456+
if (Z_TYPE_P(return_value) != IS_OBJECT) { // should be never, but that is user code
1457+
zval *_err = create_php_instance(reqResult_error_class_name);
1458+
vk_zend_update_public_property_string(_err, "error", "fetcher->typedFetch() did not return object, as expected");
1459+
vk_zend_update_public_property_long(_err, "error_code", -1000);
1460+
END_TIMER(fetch_function2)
1461+
return _err;
1462+
}
1463+
if (rpc_error.header.has_value()) {
1464+
zval *wrapped_err = create_php_instance(reqResult_header_class_name);
1465+
zval *header_php_repr = convert_rpc_extra_header_to_php_repr(rpc_error.header.value());
1466+
1467+
set_field_int(&wrapped_err, rpc_error.flags, "flags", -1);
1468+
set_field(&wrapped_err, header_php_repr, "extra", -1);
1469+
set_field(&wrapped_err, return_value, "result", -1);
1470+
END_TIMER(fetch_function2)
1471+
return wrapped_err;
1472+
}
1473+
zval *wrapped_err = create_php_instance(reqResult_underscore_class_name);
1474+
set_field(&wrapped_err, return_value, "result", -1);
1475+
END_TIMER(fetch_function2)
1476+
return wrapped_err;
1477+
}
1478+
1479+
static zval *make_query_result_or_error(zval *r, const vkext_rpc::tl::RpcReqError &error, const vkext_rpc::tl::RpcReqResultExtra *header, int extra_flags) {
13451480
if (r) {
1346-
return *r;
1481+
return r;
13471482
}
13481483
zval *_err;
13491484
switch (typed_mode) {
@@ -1393,13 +1528,22 @@ void vk_rpc_tl_query_result_impl(struct rpc_queue *Q, double timeout, zval **r)
13931528
}
13941529
struct rpc_query *q = rpc_query_get(qid);
13951530
tl_tree *T = reinterpret_cast<tl_tree *>(q->extra);
1531+
zval fetcher;
1532+
ZVAL_COPY(&fetcher, &q->fetcher);
13961533
tl_current_function_name = q->fun_name;
1397-
INC_REF (T);
1534+
if (T) {
1535+
INC_REF (T);
1536+
}
13981537

13991538
if (do_rpc_get_and_parse(qid, timeout - precise_now) < 0) {
1539+
// TODO - most likely. leak here (of both T and fetcher).
1540+
// But it is difficult to simulate this situation, so
1541+
// we decided to keep leak to avoid double delete in case we
1542+
// failed to completely understand this code.
14001543
continue;
14011544
}
1402-
zval *res = make_query_result_or_error(vk_rpc_tl_query_result_one_impl(T), {TL_ERROR_RESPONSE_NOT_FOUND, "Response not found, probably timed out"});
1545+
zval *res = make_query_result_or_error(vk_rpc_tl_query_result_one_impl(T, &fetcher), {TL_ERROR_RESPONSE_NOT_FOUND, "Response not found, probably timed out"});
1546+
zval_ptr_dtor(&fetcher);
14031547
vk_add_index_zval_nod (*r, qid, res);
14041548
}
14051549
}
@@ -1430,14 +1574,19 @@ void vk_rpc_tl_query_result_one(INTERNAL_FUNCTION_PARAMETERS) {
14301574
double timeout = (argc < 2) ? q->timeout : precise_now + parse_zend_double(VK_ZVAL_ARRAY_TO_API_P(z[1]));
14311575
END_TIMER (parse);
14321576
auto *T = reinterpret_cast<tl_tree *>(q->extra);
1433-
INC_REF (T);
1577+
zval fetcher;
1578+
ZVAL_COPY(&fetcher, &q->fetcher);
1579+
if (T) {
1580+
INC_REF (T);
1581+
}
14341582
if (do_rpc_get_and_parse(qid, timeout - precise_now) < 0) {
14351583
zval *r = make_query_result_or_error(NULL, {TL_ERROR_RESPONSE_NOT_FOUND, "Response not found, probably timed out"});
14361584
RETVAL_ZVAL(r, false, true);
14371585
efree(r);
14381586
return;
14391587
}
1440-
zval *r = make_query_result_or_error(vk_rpc_tl_query_result_one_impl(T), {TL_ERROR_RESPONSE_NOT_FOUND, "Response not found, probably timed out"});
1588+
zval *r = make_query_result_or_error(vk_rpc_tl_query_result_one_impl(T, &fetcher), {TL_ERROR_RESPONSE_NOT_FOUND, "Response not found, probably timed out"});
1589+
zval_ptr_dtor(&fetcher);
14411590
RETVAL_ZVAL(r, false, true);
14421591
efree(r);
14431592
}

vkext/vkext-rpc.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -854,9 +854,7 @@ static struct rpc_query *rpc_query_alloc(double timeout) {
854854
q->qid = qid;
855855
q->start_time = precise_now;
856856
q->timeout = timeout;
857-
if (tl_current_function_name) {
858-
q->fun_name = tl_current_function_name;
859-
}
857+
q->fun_name = tl_current_function_name;
860858
/* ADD_CNT(tree_insert);
861859
START_TICKS(tree_insert);
862860
query_tree = tree_insert_query (query_tree, q, lrand48 ());

vkext/vkext-rpc.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ struct rpc_query {
113113
int answer_len;
114114
enum query_status status;
115115
void *extra;
116+
zval fetcher; // set if extra == NULL
116117
void (*extra_free)(struct rpc_query *);
117118
const char *fun_name;
118119
};
@@ -294,7 +295,9 @@ struct stats {
294295
DECLARE_STAT(store);
295296
DECLARE_STAT(fetch);
296297
DECLARE_STAT(store_function);
298+
DECLARE_STAT(store_function2);
297299
DECLARE_STAT(fetch_function);
300+
DECLARE_STAT(fetch_function2);
298301
DECLARE_STAT(crc32);
299302
DECLARE_STAT(tree_insert);
300303
DECLARE_STAT(total);

vkext/vkext-tl-parse.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ int tl_parse_int() {
2727
return do_rpc_fetch_int(&tl.error);
2828
}
2929

30+
int tl_lookup_int() {
31+
if (tl.error) {
32+
return -1;
33+
}
34+
return do_rpc_lookup_int(&tl.error);
35+
}
36+
3037
long long tl_parse_long() {
3138
if (tl.error) {
3239
return -1;
@@ -90,6 +97,7 @@ std::string tl_parse_string() {
9097
return res;
9198
}
9299
res.assign(s);
100+
free(s);
93101
return res;
94102
}
95103

vkext/vkext-tl-parse.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
void tl_parse_init();
1111
int tl_parse_int();
12+
int tl_lookup_int();
1213
long long tl_parse_long();
1314
double tl_parse_double();
1415
float tl_parse_float();

0 commit comments

Comments
 (0)