1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@zend.com> |
16 | Zeev Suraski <zeev@zend.com> |
17 +----------------------------------------------------------------------+
18 */
19
20 /* $Id$ */
21
22 #include <stdio.h>
23
24 #include "zend.h"
25 #include "zend_alloc.h"
26 #include "zend_compile.h"
27 #include "zend_extensions.h"
28 #include "zend_API.h"
29
30 #include "zend_vm.h"
31
zend_extension_op_array_ctor_handler(zend_extension * extension,zend_op_array * op_array TSRMLS_DC)32 static void zend_extension_op_array_ctor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
33 {
34 if (extension->op_array_ctor) {
35 extension->op_array_ctor(op_array);
36 }
37 }
38
zend_extension_op_array_dtor_handler(zend_extension * extension,zend_op_array * op_array TSRMLS_DC)39 static void zend_extension_op_array_dtor_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
40 {
41 if (extension->op_array_dtor) {
42 extension->op_array_dtor(op_array);
43 }
44 }
45
op_array_alloc_ops(zend_op_array * op_array,zend_uint size)46 static void op_array_alloc_ops(zend_op_array *op_array, zend_uint size)
47 {
48 op_array->opcodes = erealloc(op_array->opcodes, size * sizeof(zend_op));
49 }
50
init_op_array(zend_op_array * op_array,zend_uchar type,int initial_ops_size TSRMLS_DC)51 void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size TSRMLS_DC)
52 {
53 op_array->type = type;
54
55 if (CG(interactive)) {
56 /* We must avoid a realloc() on the op_array in interactive mode, since pointers to constants
57 * will become invalid
58 */
59 initial_ops_size = INITIAL_INTERACTIVE_OP_ARRAY_SIZE;
60 }
61
62 op_array->refcount = (zend_uint *) emalloc(sizeof(zend_uint));
63 *op_array->refcount = 1;
64 op_array->last = 0;
65 op_array->opcodes = NULL;
66 op_array_alloc_ops(op_array, initial_ops_size);
67
68 op_array->last_var = 0;
69 op_array->vars = NULL;
70
71 op_array->T = 0;
72
73 op_array->nested_calls = 0;
74 op_array->used_stack = 0;
75
76 op_array->function_name = NULL;
77 op_array->filename = zend_get_compiled_filename(TSRMLS_C);
78 op_array->doc_comment = NULL;
79 op_array->doc_comment_len = 0;
80
81 op_array->arg_info = NULL;
82 op_array->num_args = 0;
83 op_array->required_num_args = 0;
84
85 op_array->scope = NULL;
86
87 op_array->brk_cont_array = NULL;
88 op_array->try_catch_array = NULL;
89 op_array->last_brk_cont = 0;
90
91 op_array->static_variables = NULL;
92 op_array->last_try_catch = 0;
93 op_array->has_finally_block = 0;
94
95 op_array->this_var = -1;
96
97 op_array->fn_flags = CG(interactive)?ZEND_ACC_INTERACTIVE:0;
98
99 op_array->early_binding = -1;
100
101 op_array->last_literal = 0;
102 op_array->literals = NULL;
103
104 op_array->run_time_cache = NULL;
105 op_array->last_cache_slot = 0;
106
107 memset(op_array->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
108
109 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_ctor_handler, op_array TSRMLS_CC);
110 }
111
destroy_zend_function(zend_function * function TSRMLS_DC)112 ZEND_API void destroy_zend_function(zend_function *function TSRMLS_DC)
113 {
114 switch (function->type) {
115 case ZEND_USER_FUNCTION:
116 destroy_op_array((zend_op_array *) function TSRMLS_CC);
117 break;
118 case ZEND_INTERNAL_FUNCTION:
119 /* do nothing */
120 break;
121 }
122 }
123
zend_function_dtor(zend_function * function)124 ZEND_API void zend_function_dtor(zend_function *function)
125 {
126 TSRMLS_FETCH();
127
128 destroy_zend_function(function TSRMLS_CC);
129 }
130
zend_cleanup_op_array_data(zend_op_array * op_array)131 static void zend_cleanup_op_array_data(zend_op_array *op_array)
132 {
133 if (op_array->static_variables) {
134 zend_hash_clean(op_array->static_variables);
135 }
136 }
137
zend_cleanup_function_data(zend_function * function TSRMLS_DC)138 ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC)
139 {
140 if (function->type == ZEND_USER_FUNCTION) {
141 zend_cleanup_op_array_data((zend_op_array *) function);
142 return ZEND_HASH_APPLY_KEEP;
143 } else {
144 return ZEND_HASH_APPLY_STOP;
145 }
146 }
147
zend_cleanup_function_data_full(zend_function * function TSRMLS_DC)148 ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC)
149 {
150 if (function->type == ZEND_USER_FUNCTION) {
151 zend_cleanup_op_array_data((zend_op_array *) function);
152 }
153 return 0;
154 }
155
cleanup_user_class_data(zend_class_entry * ce TSRMLS_DC)156 static inline void cleanup_user_class_data(zend_class_entry *ce TSRMLS_DC)
157 {
158 /* Clean all parts that can contain run-time data */
159 /* Note that only run-time accessed data need to be cleaned up, pre-defined data can
160 not contain objects and thus are not probelmatic */
161 if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
162 zend_hash_apply(&ce->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC);
163 }
164 if (ce->static_members_table) {
165 zval **static_members = ce->static_members_table;
166 int count = ce->default_static_members_count;
167 int i;
168
169 ce->default_static_members_count = 0;
170 ce->default_static_members_table = ce->static_members_table = NULL;
171 for (i = 0; i < count; i++) {
172 zval_ptr_dtor(&static_members[i]);
173 }
174 efree(static_members);
175 }
176 }
177
cleanup_internal_class_data(zend_class_entry * ce TSRMLS_DC)178 static inline void cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC)
179 {
180 if (CE_STATIC_MEMBERS(ce)) {
181 int i;
182
183 for (i = 0; i < ce->default_static_members_count; i++) {
184 zval_ptr_dtor(&CE_STATIC_MEMBERS(ce)[i]);
185 }
186 efree(CE_STATIC_MEMBERS(ce));
187 #ifdef ZTS
188 CG(static_members_table)[(zend_intptr_t)(ce->static_members_table)] = NULL;
189 #else
190 ce->static_members_table = NULL;
191 #endif
192 }
193 }
194
zend_cleanup_internal_class_data(zend_class_entry * ce TSRMLS_DC)195 ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC)
196 {
197 cleanup_internal_class_data(ce TSRMLS_CC);
198 }
199
zend_cleanup_user_class_data(zend_class_entry ** pce TSRMLS_DC)200 ZEND_API int zend_cleanup_user_class_data(zend_class_entry **pce TSRMLS_DC)
201 {
202 if ((*pce)->type == ZEND_USER_CLASS) {
203 cleanup_user_class_data(*pce TSRMLS_CC);
204 return ZEND_HASH_APPLY_KEEP;
205 } else {
206 return ZEND_HASH_APPLY_STOP;
207 }
208 }
209
zend_cleanup_class_data(zend_class_entry ** pce TSRMLS_DC)210 ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC)
211 {
212 if ((*pce)->type == ZEND_USER_CLASS) {
213 cleanup_user_class_data(*pce TSRMLS_CC);
214 } else {
215 cleanup_internal_class_data(*pce TSRMLS_CC);
216 }
217 return 0;
218 }
219
_destroy_zend_class_traits_info(zend_class_entry * ce)220 void _destroy_zend_class_traits_info(zend_class_entry *ce)
221 {
222 if (ce->num_traits > 0 && ce->traits) {
223 efree(ce->traits);
224 }
225
226 if (ce->trait_aliases) {
227 size_t i = 0;
228 while (ce->trait_aliases[i]) {
229 if (ce->trait_aliases[i]->trait_method) {
230 if (ce->trait_aliases[i]->trait_method->method_name) {
231 efree((char*)ce->trait_aliases[i]->trait_method->method_name);
232 }
233 if (ce->trait_aliases[i]->trait_method->class_name) {
234 efree((char*)ce->trait_aliases[i]->trait_method->class_name);
235 }
236 efree(ce->trait_aliases[i]->trait_method);
237 }
238
239 if (ce->trait_aliases[i]->alias) {
240 efree((char*)ce->trait_aliases[i]->alias);
241 }
242
243 efree(ce->trait_aliases[i]);
244 i++;
245 }
246
247 efree(ce->trait_aliases);
248 }
249
250 if (ce->trait_precedences) {
251 size_t i = 0;
252
253 while (ce->trait_precedences[i]) {
254 efree((char*)ce->trait_precedences[i]->trait_method->method_name);
255 efree((char*)ce->trait_precedences[i]->trait_method->class_name);
256 efree(ce->trait_precedences[i]->trait_method);
257
258 if (ce->trait_precedences[i]->exclude_from_classes) {
259 zend_uint j = 0;
260 zend_trait_precedence *cur_precedence = ce->trait_precedences[i];
261 while (cur_precedence->exclude_from_classes[j]) {
262 efree(cur_precedence->exclude_from_classes[j]);
263 j++;
264 }
265 efree(ce->trait_precedences[i]->exclude_from_classes);
266 }
267 efree(ce->trait_precedences[i]);
268 i++;
269 }
270 efree(ce->trait_precedences);
271 }
272 }
273
destroy_zend_class(zend_class_entry ** pce)274 ZEND_API void destroy_zend_class(zend_class_entry **pce)
275 {
276 zend_class_entry *ce = *pce;
277
278 if (--ce->refcount > 0) {
279 return;
280 }
281 switch (ce->type) {
282 case ZEND_USER_CLASS:
283 if (ce->default_properties_table) {
284 int i;
285
286 for (i = 0; i < ce->default_properties_count; i++) {
287 if (ce->default_properties_table[i]) {
288 zval_ptr_dtor(&ce->default_properties_table[i]);
289 }
290 }
291 efree(ce->default_properties_table);
292 }
293 if (ce->default_static_members_table) {
294 int i;
295
296 for (i = 0; i < ce->default_static_members_count; i++) {
297 if (ce->default_static_members_table[i]) {
298 zval_ptr_dtor(&ce->default_static_members_table[i]);
299 }
300 }
301 efree(ce->default_static_members_table);
302 }
303 zend_hash_destroy(&ce->properties_info);
304 str_efree(ce->name);
305 zend_hash_destroy(&ce->function_table);
306 zend_hash_destroy(&ce->constants_table);
307 if (ce->num_interfaces > 0 && ce->interfaces) {
308 efree(ce->interfaces);
309 }
310 if (ce->info.user.doc_comment) {
311 efree((char*)ce->info.user.doc_comment);
312 }
313
314 _destroy_zend_class_traits_info(ce);
315
316 efree(ce);
317 break;
318 case ZEND_INTERNAL_CLASS:
319 if (ce->default_properties_table) {
320 int i;
321
322 for (i = 0; i < ce->default_properties_count; i++) {
323 if (ce->default_properties_table[i]) {
324 zval_internal_ptr_dtor(&ce->default_properties_table[i]);
325 }
326 }
327 free(ce->default_properties_table);
328 }
329 if (ce->default_static_members_table) {
330 int i;
331
332 for (i = 0; i < ce->default_static_members_count; i++) {
333 zval_internal_ptr_dtor(&ce->default_static_members_table[i]);
334 }
335 free(ce->default_static_members_table);
336 }
337 zend_hash_destroy(&ce->properties_info);
338 str_free(ce->name);
339 zend_hash_destroy(&ce->function_table);
340 zend_hash_destroy(&ce->constants_table);
341 if (ce->num_interfaces > 0) {
342 free(ce->interfaces);
343 }
344 free(ce);
345 break;
346 }
347 }
348
zend_class_add_ref(zend_class_entry ** ce)349 void zend_class_add_ref(zend_class_entry **ce)
350 {
351 (*ce)->refcount++;
352 }
353
destroy_op_array(zend_op_array * op_array TSRMLS_DC)354 ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC)
355 {
356 zend_literal *literal = op_array->literals;
357 zend_literal *end;
358 zend_uint i;
359
360 if (op_array->static_variables) {
361 zend_hash_destroy(op_array->static_variables);
362 FREE_HASHTABLE(op_array->static_variables);
363 }
364
365 if (op_array->run_time_cache) {
366 efree(op_array->run_time_cache);
367 }
368
369 if (--(*op_array->refcount)>0) {
370 return;
371 }
372
373 efree(op_array->refcount);
374
375 if (op_array->vars) {
376 i = op_array->last_var;
377 while (i > 0) {
378 i--;
379 str_efree(op_array->vars[i].name);
380 }
381 efree(op_array->vars);
382 }
383
384 if (literal) {
385 end = literal + op_array->last_literal;
386 while (literal < end) {
387 zval_dtor(&literal->constant);
388 literal++;
389 }
390 efree(op_array->literals);
391 }
392 efree(op_array->opcodes);
393
394 if (op_array->function_name) {
395 efree((char*)op_array->function_name);
396 }
397 if (op_array->doc_comment) {
398 efree((char*)op_array->doc_comment);
399 }
400 if (op_array->brk_cont_array) {
401 efree(op_array->brk_cont_array);
402 }
403 if (op_array->try_catch_array) {
404 efree(op_array->try_catch_array);
405 }
406 if (op_array->fn_flags & ZEND_ACC_DONE_PASS_TWO) {
407 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_dtor_handler, op_array TSRMLS_CC);
408 }
409 if (op_array->arg_info) {
410 for (i=0; i<op_array->num_args; i++) {
411 str_efree(op_array->arg_info[i].name);
412 if (op_array->arg_info[i].class_name) {
413 str_efree(op_array->arg_info[i].class_name);
414 }
415 }
416 efree(op_array->arg_info);
417 }
418 }
419
init_op(zend_op * op TSRMLS_DC)420 void init_op(zend_op *op TSRMLS_DC)
421 {
422 memset(op, 0, sizeof(zend_op));
423 op->lineno = CG(zend_lineno);
424 SET_UNUSED(op->result);
425 }
426
get_next_op(zend_op_array * op_array TSRMLS_DC)427 zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC)
428 {
429 zend_uint next_op_num = op_array->last++;
430 zend_op *next_op;
431
432 if (next_op_num >= CG(context).opcodes_size) {
433 if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) {
434 /* we messed up */
435 zend_printf("Ran out of opcode space!\n"
436 "You should probably consider writing this huge script into a file!\n");
437 zend_bailout();
438 }
439 CG(context).opcodes_size *= 4;
440 op_array_alloc_ops(op_array, CG(context).opcodes_size);
441 }
442
443 next_op = &(op_array->opcodes[next_op_num]);
444
445 init_op(next_op TSRMLS_CC);
446
447 return next_op;
448 }
449
get_next_op_number(zend_op_array * op_array)450 int get_next_op_number(zend_op_array *op_array)
451 {
452 return op_array->last;
453 }
454
get_next_brk_cont_element(zend_op_array * op_array)455 zend_brk_cont_element *get_next_brk_cont_element(zend_op_array *op_array)
456 {
457 op_array->last_brk_cont++;
458 op_array->brk_cont_array = erealloc(op_array->brk_cont_array, sizeof(zend_brk_cont_element)*op_array->last_brk_cont);
459 return &op_array->brk_cont_array[op_array->last_brk_cont-1];
460 }
461
zend_update_extended_info(zend_op_array * op_array TSRMLS_DC)462 static void zend_update_extended_info(zend_op_array *op_array TSRMLS_DC)
463 {
464 zend_op *opline = op_array->opcodes, *end=opline+op_array->last;
465
466 while (opline<end) {
467 if (opline->opcode == ZEND_EXT_STMT) {
468 if (opline+1<end) {
469 if ((opline+1)->opcode == ZEND_EXT_STMT) {
470 opline->opcode = ZEND_NOP;
471 opline++;
472 continue;
473 }
474 if (opline+1<end) {
475 opline->lineno = (opline+1)->lineno;
476 }
477 } else {
478 opline->opcode = ZEND_NOP;
479 }
480 }
481 opline++;
482 }
483 }
484
zend_extension_op_array_handler(zend_extension * extension,zend_op_array * op_array TSRMLS_DC)485 static void zend_extension_op_array_handler(zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
486 {
487 if (extension->op_array_handler) {
488 extension->op_array_handler(op_array);
489 }
490 }
491
zend_check_finally_breakout(zend_op_array * op_array,zend_uint op_num,zend_uint dst_num TSRMLS_DC)492 static void zend_check_finally_breakout(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC)
493 {
494 zend_uint i;
495
496 for (i = 0; i < op_array->last_try_catch; i++) {
497 if ((op_num < op_array->try_catch_array[i].finally_op ||
498 op_num >= op_array->try_catch_array[i].finally_end)
499 && (dst_num >= op_array->try_catch_array[i].finally_op &&
500 dst_num <= op_array->try_catch_array[i].finally_end)) {
501 CG(in_compilation) = 1;
502 CG(active_op_array) = op_array;
503 CG(zend_lineno) = op_array->opcodes[op_num].lineno;
504 zend_error_noreturn(E_COMPILE_ERROR, "jump into a finally block is disallowed");
505 } else if ((op_num >= op_array->try_catch_array[i].finally_op
506 && op_num <= op_array->try_catch_array[i].finally_end)
507 && (dst_num > op_array->try_catch_array[i].finally_end
508 || dst_num < op_array->try_catch_array[i].finally_op)) {
509 CG(in_compilation) = 1;
510 CG(active_op_array) = op_array;
511 CG(zend_lineno) = op_array->opcodes[op_num].lineno;
512 zend_error_noreturn(E_COMPILE_ERROR, "jump out of a finally block is disallowed");
513 }
514 }
515 }
516
zend_adjust_fast_call(zend_op_array * op_array,zend_uint fast_call,zend_uint start,zend_uint end TSRMLS_DC)517 static void zend_adjust_fast_call(zend_op_array *op_array, zend_uint fast_call, zend_uint start, zend_uint end TSRMLS_DC)
518 {
519 int i;
520 zend_uint op_num = 0;
521
522 for (i = 0; i < op_array->last_try_catch; i++) {
523 if (op_array->try_catch_array[i].finally_op > start
524 && op_array->try_catch_array[i].finally_end < end) {
525 op_num = op_array->try_catch_array[i].finally_op;
526 start = op_array->try_catch_array[i].finally_end;
527 }
528 }
529
530 if (op_num) {
531 /* Must be ZEND_FAST_CALL */
532 ZEND_ASSERT(op_array->opcodes[op_num - 2].opcode == ZEND_FAST_CALL);
533 op_array->opcodes[op_num - 2].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
534 op_array->opcodes[op_num - 2].op2.opline_num = fast_call;
535 }
536 }
537
zend_resolve_fast_call(zend_op_array * op_array,zend_uint fast_call,zend_uint op_num TSRMLS_DC)538 static void zend_resolve_fast_call(zend_op_array *op_array, zend_uint fast_call, zend_uint op_num TSRMLS_DC)
539 {
540 int i;
541 zend_uint finally_op_num = 0;
542
543 for (i = 0; i < op_array->last_try_catch; i++) {
544 if (op_num >= op_array->try_catch_array[i].finally_op
545 && op_num < op_array->try_catch_array[i].finally_end) {
546 finally_op_num = op_array->try_catch_array[i].finally_op;
547 }
548 }
549
550 if (finally_op_num) {
551 /* Must be ZEND_FAST_CALL */
552 ZEND_ASSERT(op_array->opcodes[finally_op_num - 2].opcode == ZEND_FAST_CALL);
553 if (op_array->opcodes[fast_call].extended_value == 0) {
554 op_array->opcodes[fast_call].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
555 op_array->opcodes[fast_call].op2.opline_num = finally_op_num - 2;
556 }
557 }
558 }
559
zend_resolve_finally_call(zend_op_array * op_array,zend_uint op_num,zend_uint dst_num TSRMLS_DC)560 static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC)
561 {
562 zend_uint start_op;
563 zend_op *opline;
564 zend_uint i = op_array->last_try_catch;
565
566 if (dst_num != (zend_uint)-1) {
567 zend_check_finally_breakout(op_array, op_num, dst_num TSRMLS_CC);
568 }
569
570 /* the backward order is mater */
571 while (i > 0) {
572 i--;
573 if (op_array->try_catch_array[i].finally_op &&
574 op_num >= op_array->try_catch_array[i].try_op &&
575 op_num < op_array->try_catch_array[i].finally_op - 1 &&
576 (dst_num < op_array->try_catch_array[i].try_op ||
577 dst_num > op_array->try_catch_array[i].finally_end)) {
578 /* we have a jump out of try block that needs executing finally */
579
580 /* generate a FAST_CALL to finally block */
581 start_op = get_next_op_number(op_array);
582
583 opline = get_next_op(op_array TSRMLS_CC);
584 opline->opcode = ZEND_FAST_CALL;
585 SET_UNUSED(opline->op1);
586 SET_UNUSED(opline->op2);
587 zend_adjust_fast_call(op_array, start_op,
588 op_array->try_catch_array[i].finally_op,
589 op_array->try_catch_array[i].finally_end TSRMLS_CC);
590 if (op_array->try_catch_array[i].catch_op) {
591 opline->extended_value = ZEND_FAST_CALL_FROM_CATCH;
592 opline->op2.opline_num = op_array->try_catch_array[i].catch_op;
593 opline->op1.opline_num = get_next_op_number(op_array);
594 /* generate a FAST_CALL to hole CALL_FROM_FINALLY */
595 opline = get_next_op(op_array TSRMLS_CC);
596 opline->opcode = ZEND_FAST_CALL;
597 SET_UNUSED(opline->op1);
598 SET_UNUSED(opline->op2);
599 zend_resolve_fast_call(op_array, start_op + 1, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC);
600 } else {
601 zend_resolve_fast_call(op_array, start_op, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC);
602 }
603 opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
604
605 /* generate a sequence of FAST_CALL to upward finally block */
606 while (i > 0) {
607 i--;
608 if (op_array->try_catch_array[i].finally_op &&
609 op_num >= op_array->try_catch_array[i].try_op &&
610 op_num < op_array->try_catch_array[i].finally_op - 1 &&
611 (dst_num < op_array->try_catch_array[i].try_op ||
612 dst_num > op_array->try_catch_array[i].finally_end)) {
613
614 opline = get_next_op(op_array TSRMLS_CC);
615 opline->opcode = ZEND_FAST_CALL;
616 SET_UNUSED(opline->op1);
617 SET_UNUSED(opline->op2);
618 opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
619 }
620 }
621
622 /* Finish the sequence with original opcode */
623 opline = get_next_op(op_array TSRMLS_CC);
624 *opline = op_array->opcodes[op_num];
625
626 /* Replace original opcode with jump to this sequence */
627 opline = op_array->opcodes + op_num;
628 opline->opcode = ZEND_JMP;
629 SET_UNUSED(opline->op1);
630 SET_UNUSED(opline->op2);
631 opline->op1.opline_num = start_op;
632
633 break;
634 }
635 }
636 }
637
zend_resolve_finally_ret(zend_op_array * op_array,zend_uint op_num TSRMLS_DC)638 static void zend_resolve_finally_ret(zend_op_array *op_array, zend_uint op_num TSRMLS_DC)
639 {
640 int i;
641 zend_uint catch_op_num = 0, finally_op_num = 0;
642
643 for (i = 0; i < op_array->last_try_catch; i++) {
644 if (op_array->try_catch_array[i].try_op > op_num) {
645 break;
646 }
647 if (op_num < op_array->try_catch_array[i].finally_op) {
648 finally_op_num = op_array->try_catch_array[i].finally_op;
649 }
650 if (op_num < op_array->try_catch_array[i].catch_op) {
651 catch_op_num = op_array->try_catch_array[i].catch_op;
652 }
653 }
654
655 if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
656 /* in case of unhandled exception return to upward finally block */
657 op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_FINALLY;
658 op_array->opcodes[op_num].op2.opline_num = finally_op_num;
659 } else if (catch_op_num) {
660 /* in case of unhandled exception return to upward catch block */
661 op_array->opcodes[op_num].extended_value = ZEND_FAST_RET_TO_CATCH;
662 op_array->opcodes[op_num].op2.opline_num = catch_op_num;
663 }
664 }
665
zend_resolve_finally_calls(zend_op_array * op_array TSRMLS_DC)666 static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC)
667 {
668 zend_uint i, j;
669 zend_op *opline;
670
671 for (i = 0, j = op_array->last; i < j; i++) {
672 opline = op_array->opcodes + i;
673 switch (opline->opcode) {
674 case ZEND_RETURN:
675 case ZEND_RETURN_BY_REF:
676 case ZEND_GENERATOR_RETURN:
677 zend_resolve_finally_call(op_array, i, (zend_uint)-1 TSRMLS_CC);
678 break;
679 case ZEND_BRK:
680 case ZEND_CONT:
681 {
682 int nest_levels, array_offset;
683 zend_brk_cont_element *jmp_to;
684
685 nest_levels = Z_LVAL(op_array->literals[opline->op2.constant].constant);
686 if ((array_offset = opline->op1.opline_num) != -1) {
687 do {
688 jmp_to = &op_array->brk_cont_array[array_offset];
689 if (nest_levels > 1) {
690 array_offset = jmp_to->parent;
691 }
692 } while (--nest_levels > 0);
693 zend_resolve_finally_call(op_array, i, opline->opcode == ZEND_BRK ? jmp_to->brk : jmp_to->cont TSRMLS_CC);
694 break;
695 }
696 }
697 case ZEND_GOTO:
698 if (Z_TYPE(op_array->literals[opline->op2.constant].constant) != IS_LONG) {
699 zend_uint num = opline->op2.constant;
700 opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
701 zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC);
702 opline->op2.constant = num;
703 }
704 /* break omitted intentionally */
705 case ZEND_JMP:
706 zend_resolve_finally_call(op_array, i, opline->op1.opline_num TSRMLS_CC);
707 break;
708 case ZEND_FAST_CALL:
709 zend_resolve_fast_call(op_array, i, i TSRMLS_CC);
710 break;
711 case ZEND_FAST_RET:
712 zend_resolve_finally_ret(op_array, i TSRMLS_CC);
713 break;
714 default:
715 break;
716 }
717 }
718 }
719
pass_two(zend_op_array * op_array TSRMLS_DC)720 ZEND_API int pass_two(zend_op_array *op_array TSRMLS_DC)
721 {
722 zend_op *opline, *end;
723
724 if (op_array->type!=ZEND_USER_FUNCTION && op_array->type!=ZEND_EVAL_CODE) {
725 return 0;
726 }
727 if (op_array->has_finally_block) {
728 zend_resolve_finally_calls(op_array TSRMLS_CC);
729 }
730 if (CG(compiler_options) & ZEND_COMPILE_EXTENDED_INFO) {
731 zend_update_extended_info(op_array TSRMLS_CC);
732 }
733 if (CG(compiler_options) & ZEND_COMPILE_HANDLE_OP_ARRAY) {
734 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) zend_extension_op_array_handler, op_array TSRMLS_CC);
735 }
736
737 if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).vars_size != op_array->last_var) {
738 op_array->vars = (zend_compiled_variable *) erealloc(op_array->vars, sizeof(zend_compiled_variable)*op_array->last_var);
739 CG(context).vars_size = op_array->last_var;
740 }
741 if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).opcodes_size != op_array->last) {
742 op_array->opcodes = (zend_op *) erealloc(op_array->opcodes, sizeof(zend_op)*op_array->last);
743 CG(context).opcodes_size = op_array->last;
744 }
745 if (!(op_array->fn_flags & ZEND_ACC_INTERACTIVE) && CG(context).literals_size != op_array->last_literal) {
746 op_array->literals = (zend_literal*)erealloc(op_array->literals, sizeof(zend_literal) * op_array->last_literal);
747 CG(context).literals_size = op_array->last_literal;
748 }
749
750 opline = op_array->opcodes;
751 end = opline + op_array->last;
752 while (opline < end) {
753 if (opline->op1_type == IS_CONST) {
754 opline->op1.zv = &op_array->literals[opline->op1.constant].constant;
755 }
756 if (opline->op2_type == IS_CONST) {
757 opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
758 }
759 switch (opline->opcode) {
760 case ZEND_GOTO:
761 if (Z_TYPE_P(opline->op2.zv) != IS_LONG) {
762 zend_resolve_goto_label(op_array, opline, 1 TSRMLS_CC);
763 }
764 /* break omitted intentionally */
765 case ZEND_JMP:
766 case ZEND_FAST_CALL:
767 opline->op1.jmp_addr = &op_array->opcodes[opline->op1.opline_num];
768 break;
769 case ZEND_JMPZ:
770 case ZEND_JMPNZ:
771 case ZEND_JMPZ_EX:
772 case ZEND_JMPNZ_EX:
773 case ZEND_JMP_SET:
774 case ZEND_JMP_SET_VAR:
775 opline->op2.jmp_addr = &op_array->opcodes[opline->op2.opline_num];
776 break;
777 case ZEND_RETURN:
778 case ZEND_RETURN_BY_REF:
779 if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
780 if (opline->op1_type != IS_CONST || Z_TYPE_P(opline->op1.zv) != IS_NULL) {
781 CG(zend_lineno) = opline->lineno;
782 zend_error_noreturn(E_COMPILE_ERROR, "Generators cannot return values using \"return\"");
783 }
784
785 opline->opcode = ZEND_GENERATOR_RETURN;
786 }
787 break;
788 }
789 ZEND_VM_SET_OPCODE_HANDLER(opline);
790 opline++;
791 }
792
793 op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO;
794 return 0;
795 }
796
print_class(zend_class_entry * class_entry TSRMLS_DC)797 int print_class(zend_class_entry *class_entry TSRMLS_DC)
798 {
799 printf("Class %s:\n", class_entry->name);
800 zend_hash_apply(&class_entry->function_table, (apply_func_t) pass_two TSRMLS_CC);
801 printf("End of class %s.\n\n", class_entry->name);
802 return 0;
803 }
804
get_unary_op(int opcode)805 ZEND_API unary_op_type get_unary_op(int opcode)
806 {
807 switch (opcode) {
808 case ZEND_BW_NOT:
809 return (unary_op_type) bitwise_not_function;
810 break;
811 case ZEND_BOOL_NOT:
812 return (unary_op_type) boolean_not_function;
813 break;
814 default:
815 return (unary_op_type) NULL;
816 break;
817 }
818 }
819
get_binary_op(int opcode)820 ZEND_API binary_op_type get_binary_op(int opcode)
821 {
822 switch (opcode) {
823 case ZEND_ADD:
824 case ZEND_ASSIGN_ADD:
825 return (binary_op_type) add_function;
826 break;
827 case ZEND_SUB:
828 case ZEND_ASSIGN_SUB:
829 return (binary_op_type) sub_function;
830 break;
831 case ZEND_MUL:
832 case ZEND_ASSIGN_MUL:
833 return (binary_op_type) mul_function;
834 break;
835 case ZEND_POW:
836 return (binary_op_type) pow_function;
837 break;
838 case ZEND_DIV:
839 case ZEND_ASSIGN_DIV:
840 return (binary_op_type) div_function;
841 break;
842 case ZEND_MOD:
843 case ZEND_ASSIGN_MOD:
844 return (binary_op_type) mod_function;
845 break;
846 case ZEND_SL:
847 case ZEND_ASSIGN_SL:
848 return (binary_op_type) shift_left_function;
849 break;
850 case ZEND_SR:
851 case ZEND_ASSIGN_SR:
852 return (binary_op_type) shift_right_function;
853 break;
854 case ZEND_CONCAT:
855 case ZEND_ASSIGN_CONCAT:
856 return (binary_op_type) concat_function;
857 break;
858 case ZEND_IS_IDENTICAL:
859 return (binary_op_type) is_identical_function;
860 break;
861 case ZEND_IS_NOT_IDENTICAL:
862 return (binary_op_type) is_not_identical_function;
863 break;
864 case ZEND_IS_EQUAL:
865 return (binary_op_type) is_equal_function;
866 break;
867 case ZEND_IS_NOT_EQUAL:
868 return (binary_op_type) is_not_equal_function;
869 break;
870 case ZEND_IS_SMALLER:
871 return (binary_op_type) is_smaller_function;
872 break;
873 case ZEND_IS_SMALLER_OR_EQUAL:
874 return (binary_op_type) is_smaller_or_equal_function;
875 break;
876 case ZEND_BW_OR:
877 case ZEND_ASSIGN_BW_OR:
878 return (binary_op_type) bitwise_or_function;
879 break;
880 case ZEND_BW_AND:
881 case ZEND_ASSIGN_BW_AND:
882 return (binary_op_type) bitwise_and_function;
883 break;
884 case ZEND_BW_XOR:
885 case ZEND_ASSIGN_BW_XOR:
886 return (binary_op_type) bitwise_xor_function;
887 break;
888 case ZEND_BOOL_XOR:
889 return (binary_op_type) boolean_xor_function;
890 break;
891 default:
892 return (binary_op_type) NULL;
893 break;
894 }
895 }
896
897 /*
898 * Local variables:
899 * tab-width: 4
900 * c-basic-offset: 4
901 * indent-tabs-mode: t
902 * End:
903 */
904