| | 274 | |
| | 275 | int xc_foreach_early_binding_class(zend_op_array *op_array, void (*callback)(zend_op *opline, int oplineno, void *data TSRMLS_DC), void *data TSRMLS_DC) /* {{{ */ |
| | 276 | { |
| | 277 | zend_op *opline, *begin, *end, *next = NULL; |
| | 278 | xc_cest_t cest; |
| | 279 | |
| | 280 | opline = begin = op_array->opcodes; |
| | 281 | end = opline + op_array->last; |
| | 282 | while (opline < end) { |
| | 283 | switch (opline->opcode) { |
| | 284 | case ZEND_JMP: |
| | 285 | next = begin + opline->op1.u.opline_num; |
| | 286 | break; |
| | 287 | |
| | 288 | case ZEND_JMPZNZ: |
| | 289 | next = begin + max(opline->op2.u.opline_num, opline->extended_value); |
| | 290 | break; |
| | 291 | |
| | 292 | case ZEND_JMPZ: |
| | 293 | case ZEND_JMPNZ: |
| | 294 | case ZEND_JMPZ_EX: |
| | 295 | case ZEND_JMPNZ_EX: |
| | 296 | next = begin + opline->op2.u.opline_num; |
| | 297 | break; |
| | 298 | |
| | 299 | case ZEND_RETURN: |
| | 300 | opline = end; |
| | 301 | break; |
| | 302 | |
| | 303 | case ZEND_DECLARE_INHERITED_CLASS: |
| | 304 | callback(opline, opline - begin, data TSRMLS_CC); |
| | 305 | break; |
| | 306 | } |
| | 307 | |
| | 308 | if (opline < next) { |
| | 309 | opline = next; |
| | 310 | } |
| | 311 | else { |
| | 312 | opline ++; |
| | 313 | } |
| | 314 | } |
| | 315 | } |
| | 316 | /* }}} */ |
| | 317 | int xc_do_early_binding(zend_op_array *op_array, HashTable *class_table, int oplineno TSRMLS_DC) /* {{{ */ |
| | 318 | { |
| | 319 | zend_op *opline, *opcodes; |
| | 320 | |
| | 321 | #ifdef DEBUG |
| | 322 | fprintf(stderr, "binding %d\n", oplineno); |
| | 323 | #endif |
| | 324 | assert(oplineno >= 0); |
| | 325 | |
| | 326 | /* do early binding */ |
| | 327 | opline = &(op_array->opcodes[oplineno]); |
| | 328 | |
| | 329 | switch (opline->opcode) { |
| | 330 | case ZEND_DECLARE_INHERITED_CLASS: |
| | 331 | #ifdef ZEND_ENGINE_2 |
| | 332 | { |
| | 333 | zval *parent_name; |
| | 334 | zend_class_entry **pce; |
| | 335 | parent_name = &(opline - 1)->op2.u.constant; |
| | 336 | #ifdef DEBUG |
| | 337 | fprintf(stderr, "binding with parent %s\n", Z_STRVAL_P(parent_name)); |
| | 338 | #endif |
| | 339 | if (zend_lookup_class(Z_STRVAL_P(parent_name), Z_STRLEN_P(parent_name), &pce TSRMLS_CC) == FAILURE) { |
| | 340 | return FAILURE; |
| | 341 | } |
| | 342 | |
| | 343 | if (do_bind_inherited_class(opline, class_table, *pce, 1 TSRMLS_CC) == NULL) { |
| | 344 | return FAILURE; |
| | 345 | } |
| | 346 | } |
| | 347 | #else |
| | 348 | if (do_bind_function_or_class(opline, NULL, class_table, 1) == FAILURE) { |
| | 349 | return FAILURE; |
| | 350 | } |
| | 351 | #endif |
| | 352 | |
| | 353 | #ifdef ZEND_FETCH_CLASS |
| | 354 | /* clear unnecessary ZEND_FETCH_CLASS opcode */ |
| | 355 | if (opline > op_array->opcodes |
| | 356 | && (opline - 1)->opcode == ZEND_FETCH_CLASS) { |
| | 357 | zend_op *fetch_class_opline = opline - 1; |
| | 358 | |
| | 359 | #ifdef DEBUG |
| | 360 | fprintf(stderr, "%s %p\n", Z_STRVAL(fetch_class_opline->op2.u.constant), Z_STRVAL(fetch_class_opline->op2.u.constant)); |
| | 361 | #endif |
| | 362 | OP_ZVAL_DTOR(fetch_class_opline->op2); |
| | 363 | fetch_class_opline->opcode = ZEND_NOP; |
| | 364 | ZEND_VM_SET_OPCODE_HANDLER(fetch_class_opline); |
| | 365 | memset(&fetch_class_opline->op1, 0, sizeof(znode)); |
| | 366 | memset(&fetch_class_opline->op2, 0, sizeof(znode)); |
| | 367 | SET_UNUSED(fetch_class_opline->op1); |
| | 368 | SET_UNUSED(fetch_class_opline->op2); |
| | 369 | SET_UNUSED(fetch_class_opline->result); |
| | 370 | } |
| | 371 | #endif |
| | 372 | break; |
| | 373 | |
| | 374 | default: |
| | 375 | return FAILURE; |
| | 376 | } |
| | 377 | |
| | 378 | zend_hash_del(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len); |
| | 379 | OP_ZVAL_DTOR(opline->op1); |
| | 380 | OP_ZVAL_DTOR(opline->op2); |
| | 381 | opline->opcode = ZEND_NOP; |
| | 382 | ZEND_VM_SET_OPCODE_HANDLER(opline); |
| | 383 | memset(&opline->op1, 0, sizeof(znode)); |
| | 384 | memset(&opline->op2, 0, sizeof(znode)); |
| | 385 | SET_UNUSED(opline->op1); |
| | 386 | SET_UNUSED(opline->op2); |
| | 387 | return SUCCESS; |
| | 388 | } |
| | 389 | /* }}} */ |