$x->post_dec_prop(N); $t = end_test($t, '$this->x--', $overhead); $x->isset_prop(N); $t = end_test($t, 'isset($this->x)', $overhead); $x->empty_prop(N); $t = end_test($t, 'empty($this->x)', $overhead); $x->call(N); $t = end_test($t, '$this->f()', $overhead); $x->read_const(N); $t = end_test($t, '$x = Foo::TEST', $overhead); create_object(N); $t = end_test($t, 'new Foo()', $overhead); read_const(N); $t = end_test($t, '$x = TEST', $overhead); read_auto_global(N); $t = end_test($t, '$x = $_GET', $overhead); read_global_var(N); $t = end_test($t, '$x = $GLOBALS[\'v\']', $overhead); read_hash(N); $t = end_test($t, '$x = $hash[\'v\']', $overhead); read_str_offset(N); $t = end_test($t, '$x = $str[0]', $overhead); issetor(N); $t = end_test($t, '$x = $a ?: null', $overhead); issetor2(N); $t = end_test($t, '$x = $f ?: tmp', $overhead); ternary(N); $t = end_test($t, '$x = $f ? $f : $a', $overhead); ternary2(N); $t = end_test($t, '$x = $f ? $f : tmp', $overhead); total($t0, "Total");
function read_hash($fh, $hash_entry_ptr, $index_list) { if (gettype($index_list) != 'array') { throw new Exception('array expected'); } $ptr = $hash_entry_ptr; if (TRACE) { printf("============\nread_hash: \$ptr: 0x%X\n", $ptr); } if (!$ptr) { return array(); } $index = array_shift($index_list); if (!is_null($index)) { $single_search = count($index_list) ? SINGLE_SEARCH_FOR_SUBHASH : SINGLE_SEARCH_FOR_SCALAR; } $is_first_round = 1; $prev_rec_ptr = $ptr; $result = array(); # обход записей хэша while ($ptr = $prev_rec_ptr) { if (TRACE) { printf("read record: \$ptr 0x%X\n", $ptr); } if (TRACE) { printf("\$is_first_round: %d, \$single_search: %d, \$index: %d \n", $is_first_round, $single_search, $index); } # чтение rec_desc $rec_desc = read_rec_desc($fh, $ptr); $field_qt = $rec_desc['FIELD_QT_BITS']; $ref_size = $rec_desc['REF_SIZE_BITS']; # если первая запись и текущая запись является узловой if ($is_first_round && $rec_desc['FIELD_QT_BITS'] == 0) { $list_entry_pos = ftell($fh); if (TRACE) { printf("\$list_entry_pos: 0x%X, \$single_search: %d, \$index: %d\n", $list_entry_pos, $single_search, $index); } if ($single_search && $index > 0) { $list_item_addr = force_get_list_item_addr($fh, $list_entry_pos, $index, false); if (is_null($list_item_addr)) { return NULL; } if (TRACE) { printf("\$list_item_addr: 0x%X\n", $list_item_addr); } $list_item_hash_entry_ptr = read_hash_entry($fh, $list_item_addr); return read_hash($fh, $list_item_hash_entry_ptr, $index_list); } elseif (!$single_search) { $pos = $list_entry_pos; $index_base = 0; $ptrs = NULL; $i = NULL; $stack = array(); array_push($stack, array()); $level = 0; if (TRACE) { printf("\$pos: 0x%X\n", $pos); } while (count($stack)) { if (is_null($ptrs)) { if (TRACE) { printf("read list section[0x%X]\n", $pos); } # считываем элементы секции списка $array = unpack('N256', read_buf(1024, $fh, SEEK_SET, $pos)); $ptrs = array_values($array); $i = count($stack) == 1 ? 1 : 0; } else { $i++; } # if (TRACE) printf("check list item[0x%X]: ptrs[%d]=0x%X, level=$level, count(\$stack)=%s\n", $pos, $i, $ptrs[$i], $level, count($stack)); if ($i > 0xff) { array_pop($stack); if (count($stack)) { $top = $stack[count($stack) - 1]; $pos = $top['pos']; $index_base = $top['index_base']; $ptrs = $top['ptrs']; $i = $top['i']; } elseif ($ptrs[0] && $level < 3) { # && $level < 3 -- предохранитель $pos = $ptrs[0]; $index_base = 0; $ptrs = NULL; $i = NULL; array_push($stack, array()); $level += 1; } } elseif ($ptrs[$i]) { if ($level - count($stack) + 1 == 0) { $result[$index_base + $i] = read_hash($fh, $ptrs[$i], $index_list); } else { # переход к "нижней" секции $top =& $stack[count($stack) - 1]; $top['pos'] = $pos; $top['index_base'] = $index_base; $top['ptrs'] = $ptrs; $top['i'] = $i; $pos = $ptrs[$i]; $index_base = $index_base + $i << 8; $ptrs = NULL; $i = NULL; array_push($stack, array()); } } } } $is_first_round = 0; $prev_rec_ptr = read_int(4, $fh, SEEK_SET, $list_entry_pos + 1024); if (TRACE) { printf("\$prev_rec_ptr: 0x%X\n", $prev_rec_ptr); } } elseif (!$is_first_round && !$field_qt) { $ref = !$ref_size ? 0 : read_int($ref_size, $fh, SEEK_CUR, 1024 + 4); $prev_rec_ptr = !$ref ? 0 : $ptr - $ref; if (TRACE) { printf("\$prev_rec_ptr: 0x%X\n", $prev_rec_ptr); } } else { if ($is_first_round) { if ($single_search && $index > 0) { return NULL; } $is_first_round = 0; } if ($field_qt == FIELD_QT_READ_MASK) { $field_qt = read_int(1, $fh, SEEK_CUR, 0) + 1; } $field_defs_len = $field_qt * 2; if (TRACE) { printf("\$field_defs_len: %d\n", $field_defs_len); } if (DUMP) { $dump_field_def_pos = ftell($fh) - 1; } # чтение FIELD_DEFS и REF $buf = read_buf($field_defs_len + $ref_size, $fh, SEEK_CUR, 0); $field_defs = unpack("C{$field_defs_len}", $buf); $fields = array(); $hash_ids = array(); $SSS_sum = 0; for ($i = 1; $i <= $field_defs_len; $i += 2) { $id = -$field_defs[$i]; $def =& $field_defs[$i + 1]; $type = $def & STRINT_TYPE_MASK; if (!$type) { $type = $def; } $SSS = ($def & SSS_READ_MASK) >> SSS_SHIFT; $SSS_sum += $SSS; $field = array('type' => $type, 'SSS' => $SSS, 'idx' => ($i - 1) / 2); if ($type == STRING_TYPE) { $field['RRR'] = ($def & RRR_READ_MASK) >> RRR_SHIFT; } $fields[$id] = $field; $hash_ids[] = $id; if ($id == $index && $single_search) { $index_field_type = $fields[$index]['type']; if ($single_search == SINGLE_SEARCH_FOR_SUBHASH && $index_field_type != HASH_TYPE || $index_field_type == NULL_TYPE) { return NULL; } } elseif ($type == NULL_TYPE && !$single_search && !array_key_exists($id, $result)) { $result[$id] = NULL; } } # парсинг REF $ref = $ref_size ? unpack_int($ref_size, substr($buf, -$ref_size, $ref_size)) : 0; $prev_rec_ptr = $ref ? $ptr - $ref : 0; $skip_len = 0; $back_len = 0; $short_values_buf = read_buf($SSS_sum, $fh, SEEK_CUR, 0); if (TRACE) { printf("\$SSS_sum: %d, strlen(\$short_values_buf): %d\n", $SSS_sum, strlen($short_values_buf)); } # обход ключей хэша $sids = array(); $hids = array(); foreach ($hash_ids as $id) { $field =& $fields[$id]; $type =& $field['type']; $SSS =& $field['SSS']; $dont_skip_this_field = $single_search && ($index == $id || $index < $id && $index_field_type == STRING_TYPE && $type == STRING_TYPE) || !$single_search && ($type == STRING_TYPE || !array_key_exists($id, $result)); if (TRACE) { printf("\$id: %d, \$type: %d, \$SSS: %d, \$dont_skip_this_field: %d\n", $id, $type, $SSS, $dont_skip_this_field); } if (!$dont_skip_this_field) { $skip_len += $SSS; if (TRACE) { printf("\$id: %d, \$skip_len: %d\n", $id, $skip_len); } } else { if (TRACE) { printf("\$skip_len: %d, \$SSS: %d, strlen(substr(\$short_values_buf, \$skip_len, \$SSS)): %d\n", $skip_len, $SSS, strlen(substr($short_values_buf, $skip_len, $SSS))); } $short_value = unpack_int($SSS, substr($short_values_buf, $back_len + $skip_len, $SSS)); $back_len += $skip_len + $SSS; $skip_len = 0; if (TRACE) { printf("\$short_value: 0x%X\n", $short_value); } if ($type == INTEGER_TYPE) { if ($single_search) { return $short_value; } $field['value'] = $short_value; } elseif ($type == STRING_TYPE) { $field['short_value'] = $short_value; $sids[] = $id; } elseif ($type == HASH_TYPE) { if (TRACE) { printf("\$field['value_hash_entry_ptr']: 0x%X\n", $short_value); } $field['value_hash_entry_ptr'] = $short_value; $hids[] = $id; } else { throw new Exception("unexpected type {$type}"); } if ($single_search && $index == $id) { break; } } } # обход коротких значений $skip_len = 0; if ($sids) { foreach ($sids as $id) { $field =& $fields[$id]; $short_value =& $field['short_value']; if (TRACE) { printf("sids: \$id: %d; \$short_value: %d\n", $id, $short_value); } if ($single_search && $index == $id || !$single_search && !array_key_exists($id, $result)) { if (TRACE) { printf("sids: \$short_value: %d, \$skip_len: %d\n", $short_value, $skip_len); } $value = read_buf($short_value, $fh, SEEK_CUR, $skip_len); $skip_len = 0; $RRR =& $field['RRR']; if ($RRR) { $RRR_buf = substr($value, -$RRR, $RRR); $tail_len = unpack_int(strlen($RRR_buf), $RRR_buf); if ($tail_len) { $value = substr($value, 0, -$tail_len); } } if ($single_search) { return $value; } $field['value'] = $value; } else { $skip_len += $short_value; if (TRACE) { printf("sids: \$skip_len: %d\n", $skip_len); } } } } if ($hids) { foreach ($hids as $id) { $field =& $fields[$id]; $field['value'] = read_hash($fh, $field['value_hash_entry_ptr'], $index_list); if ($single_search) { return $field['value']; } } } foreach ($hash_ids as $id) { if (!array_key_exists($id, $result)) { $result[$id] = $fields[$id]['value']; } } } } return $single_search ? NULL : $result; }