Add mode to EndCatch
[hiphop-php.git] / hphp / runtime / vm / pc-filter.cpp
blob3b9cd89939d7317650394b5c6b29ea2f69dc8630
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 | Copyright (c) 1997-2010 The PHP Group |
7 +----------------------------------------------------------------------+
8 | This source file is subject to version 3.01 of the PHP license, |
9 | that is bundled with this package in the file LICENSE, and is |
10 | available through the world-wide-web at the following url: |
11 | http://www.php.net/license/3_01.txt |
12 | If you did not receive a copy of the PHP license and are unable to |
13 | obtain it through the world-wide-web, please send a note to |
14 | license@php.net so we can mail you a copy immediately. |
15 +----------------------------------------------------------------------+
18 #include "hphp/runtime/vm/pc-filter.h"
20 #include "hphp/runtime/vm/hhbc-codec.h"
22 namespace HPHP {
24 TRACE_SET_MOD(debuggerflow);
26 //////////////////////////////////////////////////////////////////////////
28 void PCFilter::PtrMapNode::clearImpl(unsigned short bits) {
29 static_assert(sizeof(PCFilter::PtrMapNode) == sizeof(PCFilter::PtrMap) &&
30 sizeof(PCFilter::PtrMapNode) == sizeof(void*),
31 "PtrMapNode and PtrMap must hold a single pointer");
33 // clear all the sub levels and mark all slots NULL
34 if (bits <= PTRMAP_LEVEL_BITS) {
35 assertx(bits == PTRMAP_LEVEL_BITS);
36 return;
38 for (int i = 0; i < PTRMAP_LEVEL_ENTRIES; i++) {
39 if (m_entries[i].m_entries) {
40 m_entries[i].clearImpl(bits - PTRMAP_LEVEL_BITS);
41 free(m_entries[i].m_entries);
42 m_entries[i].m_entries = nullptr;
47 auto PCFilter::PtrMap::makeNode() -> PtrMapNode {
48 return {
49 static_cast<PtrMapNode*>(
50 calloc(PCFilter::PTRMAP_LEVEL_ENTRIES, sizeof(PtrMapNode))
55 void* PCFilter::PtrMap::getPointerImpl(void* ptr) const {
56 auto current = &m_root;
57 assertx(current->m_entries);
58 unsigned short cursor = PTRMAP_PTR_SIZE;
59 do {
60 cursor -= PTRMAP_LEVEL_BITS;
61 unsigned long index = ((PTRMAP_LEVEL_MASK << cursor) & (unsigned long)ptr)
62 >> cursor;
63 assertx(index < PTRMAP_LEVEL_ENTRIES);
64 current = &current->m_entries[index];
65 if (!cursor) return current->m_value;
66 } while (current->m_entries);
67 return nullptr;
70 void PCFilter::PtrMap::setPointer(void* ptr, void* val) {
71 if (!m_root.m_entries) {
72 if (!val) return;
73 m_root = makeNode();
76 auto current = &m_root;
77 unsigned short cursor = PTRMAP_PTR_SIZE;
78 while (true) {
79 cursor -= PTRMAP_LEVEL_BITS;
80 unsigned long index = ((PTRMAP_LEVEL_MASK << cursor) & (unsigned long)ptr)
81 >> cursor;
82 assertx(index < PTRMAP_LEVEL_ENTRIES);
83 if (!cursor) {
84 current->m_entries[index].m_value = val;
85 break;
87 if (!current->m_entries[index].m_entries) {
88 current->m_entries[index] = makeNode();
90 current = &current->m_entries[index];
94 void PCFilter::PtrMap::clear() {
95 if (m_root.m_entries) {
96 m_root.clearImpl(PTRMAP_PTR_SIZE);
97 free(m_root.m_entries);
98 m_root.m_entries = nullptr;
102 // Adds a range of PCs to the filter given a collection of offset ranges.
103 // Omit PCs which have opcodes that don't pass the given opcode filter.
104 void PCFilter::addRanges(const Unit* unit, const OffsetRangeVec& offsets,
105 OpcodeFilter isOpcodeAllowed) {
106 for (auto range = offsets.cbegin(); range != offsets.cend(); ++range) {
107 TRACE(3, "\toffsets [%d, %d)\n", range->base, range->past);
108 for (PC pc = unit->at(range->base); pc < unit->at(range->past);
109 pc += instrLen(pc)) {
110 if (isOpcodeAllowed(peek_op(pc))) {
111 TRACE(3, "\t\tpc %p\n", pc);
112 addPC(pc);
113 } else {
114 TRACE(3, "\t\tpc %p -- skipping (offset %d)\n", pc,
115 unit->offsetOf(pc));
121 // Removes a range of PCs to the filter given a collection of offset ranges.
122 // Omit PCs which have opcodes that don't pass the given opcode filter.
123 void PCFilter::removeRanges(const Unit* unit, const OffsetRangeVec& offsets,
124 OpcodeFilter isOpcodeAllowed) {
125 for (auto range = offsets.cbegin(); range != offsets.cend(); ++range) {
126 TRACE(3, "\toffsets [%d, %d) (remove)\n", range->base, range->past);
127 for (PC pc = unit->at(range->base); pc < unit->at(range->past);
128 pc += instrLen(pc)) {
129 if (isOpcodeAllowed(peek_op(pc))) {
130 TRACE(3, "\t\tpc %p (remove)\n", pc);
131 removePC(pc);
132 } else {
133 TRACE(3, "\t\tpc %p -- skipping (offset %d) (remove)\n", pc,
134 unit->offsetOf(pc));
140 void PCFilter::removeOffset(const Unit* unit, Offset offset) {
141 removePC(unit->at(offset));
144 ///////////////////////////////////////////////////////////////////////////////