a2e76eb7b2
The codebase had several namespace-level static data definitions and function definitions. Using namespace-level "static" in a .h file is near-always a bad idea, as follows: - for simple types, static is implied. Example: "const int x = 42;" is the same as "static const int x = 42;" - for aggregate types, static linkage implies that a copy of the aggregate will appear in every compilation unit that includes the header. - for functions, static means the function will have a separate body generated in each compilation unit including the header. - in several places functions were defined 'static inline', which is just as bad. 'inline' is just a hint which means the function may end up having a body (and actually more due to 'static'). True, gnu's linker has means to remove duplicate definition, but that's not always guaranteed or possible (think e.g. static functions that define static data inside, ouch). So static is useless at best and pernicious at worst. We should never, ever use static at namespace level in headers. I will create a bootcamp task for a lint rule. I expected the performance to be neutral after the change, but in fact there's a significant drop in instruction count and therefore a measurable reduction in CPU time: https://our.intern.facebook.com/intern/perflab/details.php?eq_id=431903
140 linhas
5.0 KiB
C++
140 linhas
5.0 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifndef incl_HPHP_DEBUGGER_HOOK_H_
|
|
#define incl_HPHP_DEBUGGER_HOOK_H_
|
|
|
|
#include "hphp/util/base.h"
|
|
#include "hphp/runtime/vm/unit.h"
|
|
#include <functional>
|
|
|
|
namespace HPHP {
|
|
namespace Eval{
|
|
class DebuggerProxy;
|
|
class PhpFile;
|
|
}}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// This is a set of functions which are primarily called from the VM to notify
|
|
// the debugger about various events. Some of the implementations also interact
|
|
// with the VM to setup further notifications, though this is not the only place
|
|
// the debugger interacts directly with the VM.
|
|
|
|
namespace HPHP {
|
|
|
|
// "Hooks" called by the VM at various points during program execution while
|
|
// debugging to give the debugger a chance to act. The debugger may block
|
|
// execution indefinitely within one of these hooks.
|
|
void phpDebuggerOpcodeHook(const uchar* pc);
|
|
void phpDebuggerExceptionHook(ObjectData* e);
|
|
void phpDebuggerEvalHook(const Func* f);
|
|
void phpDebuggerFileLoadHook(Eval::PhpFile* efile);
|
|
class Class;
|
|
class Func;
|
|
void phpDebuggerDefClassHook(const Class* cls);
|
|
void phpDebuggerDefFuncHook(const Func* func);
|
|
|
|
// Helper to apply pending breakpoints to all files.
|
|
void phpSetBreakPointsInAllFiles(Eval::DebuggerProxy* proxy);
|
|
|
|
// Add/remove breakpoints at a specific offset.
|
|
void phpAddBreakPoint(const Unit* unit, Offset offset);
|
|
void phpRemoveBreakPoint(const Unit* unit, Offset offset);
|
|
|
|
// Is this thread being debugged?
|
|
inline bool isDebuggerAttached() {
|
|
return ThreadInfo::s_threadInfo.getNoCheck()->
|
|
m_reqInjectionData.getDebugger();
|
|
}
|
|
|
|
#define DEBUGGER_ATTACHED_ONLY(code) do { \
|
|
if (isDebuggerAttached()) { \
|
|
code; \
|
|
} \
|
|
} while(0) \
|
|
|
|
// Is this process being debugged?
|
|
bool isDebuggerAttachedProcess();
|
|
|
|
// This flag ensures two things: first, that we stay in the interpreter and
|
|
// out of JIT code. Second, that phpDebuggerOpcodeHook will continue to allow
|
|
// debugger interrupts for every opcode executed (modulo filters.)
|
|
#define DEBUGGER_FORCE_INTR \
|
|
(ThreadInfo::s_threadInfo.getNoCheck()->m_reqInjectionData.getDebuggerIntr())
|
|
|
|
// Map which holds a set of PCs and supports reasonably fast addition and
|
|
// lookup. Used by the debugger to decide if a given PC falls within an
|
|
// interesting area, e.g., for breakpoints and stepping.
|
|
class PCFilter {
|
|
private:
|
|
// Radix-tree implementation of pointer map
|
|
struct PtrMapNode;
|
|
class PtrMap {
|
|
#define PTRMAP_PTR_SIZE (sizeof(void*) * 8)
|
|
#define PTRMAP_LEVEL_BITS 8LL
|
|
#define PTRMAP_LEVEL_ENTRIES (1LL << PTRMAP_LEVEL_BITS)
|
|
#define PTRMAP_LEVEL_MASK (PTRMAP_LEVEL_ENTRIES - 1LL)
|
|
|
|
public:
|
|
PtrMap() {
|
|
static_assert(PTRMAP_PTR_SIZE % PTRMAP_LEVEL_BITS == 0,
|
|
"PTRMAP_PTR_SIZE must be a multiple of PTRMAP_LEVEL_BITS");
|
|
m_root = MakeNode();
|
|
}
|
|
~PtrMap();
|
|
void setPointer(void* ptr, void* val);
|
|
void* getPointer(void* ptr);
|
|
void clear();
|
|
|
|
private:
|
|
PtrMapNode* m_root;
|
|
static PtrMapNode* MakeNode();
|
|
};
|
|
|
|
PtrMap m_map;
|
|
|
|
public:
|
|
PCFilter() {}
|
|
|
|
// Filter function to exclude opcodes when adding ranges.
|
|
typedef std::function<bool(Opcode)> OpcodeFilter;
|
|
|
|
// Add/remove offsets, either individually or by range. By default allow all
|
|
// opcodes.
|
|
void addRanges(const Unit* unit, const OffsetRangeVec& offsets,
|
|
OpcodeFilter isOpcodeAllowed = [] (Opcode) { return true; });
|
|
void removeOffset(const Unit* unit, Offset offset);
|
|
|
|
// Add/remove/check explicit PCs.
|
|
void addPC(const uchar* pc) {
|
|
m_map.setPointer((void*)pc, (void*)pc);
|
|
}
|
|
void removePC(const uchar* pc) {
|
|
m_map.setPointer((void*)pc, nullptr);
|
|
}
|
|
bool checkPC(const uchar* pc) {
|
|
return m_map.getPointer((void*)pc) == (void*)pc;
|
|
}
|
|
|
|
void clear() {
|
|
m_map.clear();
|
|
}
|
|
};
|
|
|
|
} // namespace HPHP::VM
|
|
|
|
#endif /* incl_HPHP_DEBUGGER_HOOK_H_ */
|