Clean up VectorEffects::init
[hiphop-php.git] / hphp / runtime / vm / event_hook.cpp
blobd69610ce9149cc1fb4cd59d4d79486d2a8e73c3c
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #include "hphp/runtime/vm/event_hook.h"
18 #include "hphp/runtime/base/types.h"
19 #include "hphp/runtime/vm/func.h"
20 #include "hphp/runtime/vm/jit/translator-inline.h"
21 #include "hphp/runtime/base/builtin_functions.h"
22 #include "hphp/runtime/base/complex_types.h"
23 #include "hphp/runtime/ext/ext_function.h"
24 #include "hphp/runtime/vm/runtime.h"
26 namespace HPHP {
28 static StaticString s_args("args");
29 static StaticString s_enter("enter");
30 static StaticString s_exit("exit");
31 static StaticString s_exception("exception");
32 static StaticString s_name("name");
33 static StaticString s_return("return");
35 void EventHook::Enable() {
36 ThreadInfo::s_threadInfo->m_reqInjectionData.setEventHookFlag();
39 void EventHook::Disable() {
40 ThreadInfo::s_threadInfo->m_reqInjectionData.clearEventHookFlag();
43 void EventHook::EnableIntercept() {
44 ThreadInfo::s_threadInfo->m_reqInjectionData.setInterceptFlag();
47 void EventHook::DisableIntercept() {
48 ThreadInfo::s_threadInfo->m_reqInjectionData.clearInterceptFlag();
51 ssize_t EventHook::CheckSurprise() {
52 ThreadInfo* info = ThreadInfo::s_threadInfo.getNoCheck();
53 return check_request_surprise(info);
56 class ExecutingSetprofileCallbackGuard {
57 public:
58 ExecutingSetprofileCallbackGuard() {
59 g_vmContext->m_executingSetprofileCallback = true;
62 ~ExecutingSetprofileCallbackGuard() {
63 g_vmContext->m_executingSetprofileCallback = false;
67 void EventHook::RunUserProfiler(const ActRec* ar, int mode) {
68 // Don't do anything if we are running the profiling function itself
69 // or if we haven't set up a profiler.
70 if (g_vmContext->m_executingSetprofileCallback ||
71 g_vmContext->m_setprofileCallback.isNull()) {
72 return;
74 // Don't profile 86ctor, since its an implementation detail,
75 // and we dont guarantee to call it
76 if (ar->m_func->cls() && ar->m_func == ar->m_func->cls()->getCtor() &&
77 Func::isSpecial(ar->m_func->name())) {
78 return;
80 Transl::VMRegAnchor _;
81 ExecutingSetprofileCallbackGuard guard;
83 Array params;
84 Array frameinfo;
86 if (mode == ProfileEnter) {
87 params.append(s_enter);
88 frameinfo.set(s_args, hhvm_get_frame_args(ar));
89 } else {
90 params.append(s_exit);
91 if (!g_vmContext->m_faults.empty()) {
92 Fault fault = g_vmContext->m_faults.back();
93 if (fault.m_faultType == Fault::Type::UserException) {
94 frameinfo.set(s_exception, fault.m_userException);
96 } else if (!ar->m_func->info() &&
97 !ar->m_func->isGenerator()) {
98 // TODO (#1131400) This is wrong for builtins
99 frameinfo.set(s_return, tvAsCVarRef(g_vmContext->m_stack.topTV()));
103 params.append(VarNR(ar->m_func->fullName()));
104 params.append(frameinfo);
106 vm_call_user_func(g_vmContext->m_setprofileCallback, params);
109 static Array get_frame_args_with_ref(const ActRec* ar) {
110 int numParams = ar->m_func->numParams();
111 int numArgs = ar->numArgs();
112 HphpArray* retval = ArrayData::Make(numArgs);
114 TypedValue* local = (TypedValue*)(uintptr_t(ar) - sizeof(TypedValue));
115 for (int i = 0; i < numArgs; ++i) {
116 if (i < numParams) {
117 // This corresponds to one of the function's formal parameters, so it's
118 // on the stack.
119 retval->appendWithRef(tvAsCVarRef(local), false);
120 --local;
121 } else {
122 // This is not a formal parameter, so it's in the ExtraArgs.
123 retval->appendWithRef(tvAsCVarRef(ar->getExtraArg(i - numParams)), false);
127 return Array(retval);
130 bool EventHook::RunInterceptHandler(ActRec* ar) {
131 const Func* func = ar->m_func;
132 if (LIKELY(func->maybeIntercepted() == 0)) return true;
134 Variant *h = get_intercept_handler(func->fullNameRef(),
135 &func->maybeIntercepted());
136 if (!h) return true;
138 Transl::VMRegAnchor _;
140 PC savePc = g_vmContext->m_pc;
142 Variant doneFlag = true;
143 Variant called_on;
145 if (ar->hasThis()) {
146 called_on = Variant(ar->getThis());
147 } else if (ar->hasClass()) {
148 // For static methods, give handler the name of called class
149 called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
151 Array intArgs =
152 CREATE_VECTOR5(ar->m_func->fullNameRef(),
153 called_on,
154 get_frame_args_with_ref(ar),
155 h->asCArrRef()[1],
156 ref(doneFlag));
158 Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
159 if (doneFlag.toBoolean()) {
160 Offset pcOff;
161 ActRec* outer = g_vmContext->getPrevVMState(ar, &pcOff);
163 frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals());
164 Stack& stack = g_vmContext->getStack();
165 stack.top() = (Cell*)(ar + 1);
166 tvDup(*ret.asTypedValue(), *stack.allocTV());
168 g_vmContext->m_fp = outer;
169 g_vmContext->m_pc = outer ? outer->m_func->unit()->at(pcOff) : nullptr;
171 return false;
173 g_vmContext->m_fp = ar;
174 g_vmContext->m_pc = savePc;
176 return true;
179 bool EventHook::onFunctionEnter(const ActRec* ar, int funcType) {
180 ssize_t flags = CheckSurprise();
181 if (flags & RequestInjectionData::InterceptFlag &&
182 !RunInterceptHandler(const_cast<ActRec*>(ar))) {
183 return false;
185 if (flags & RequestInjectionData::EventHookFlag) {
186 RunUserProfiler(ar, ProfileEnter);
187 #ifdef HOTPROFILER
188 Profiler* profiler = ThreadInfo::s_threadInfo->m_profiler;
189 if (profiler != nullptr) {
190 const char* name;
191 switch (funcType) {
192 case NormalFunc:
193 name = ar->m_func->fullName()->data();
194 if (name[0] == '\0') {
195 // We're evaling some code for internal purposes, most
196 // likely getting the default value for a function parameter
197 name = "{internal}";
199 break;
200 case PseudoMain:
201 name = StringData::GetStaticString(
202 std::string("run_init::") + ar->m_func->unit()->filepath()->data())
203 ->data();
204 break;
205 case Eval:
206 name = "_";
207 break;
208 default:
209 not_reached();
211 begin_profiler_frame(profiler, name);
213 #endif
215 return true;
218 void EventHook::onFunctionExit(const ActRec* ar) {
219 #ifdef HOTPROFILER
220 Profiler* profiler = ThreadInfo::s_threadInfo->m_profiler;
221 if (profiler != nullptr) {
222 end_profiler_frame(profiler);
224 #endif
226 // If we have a pending exception, then we're in the process of unwinding
227 // for that exception. We avoid running more PHP code (the user profiler) and
228 // also avoid raising more exceptions for surprises (including the pending
229 // exception).
230 if (ThreadInfo::s_threadInfo->m_pendingException == nullptr) {
231 RunUserProfiler(ar, ProfileExit);
232 // XXX Disabled until t2329497 is fixed:
233 // CheckSurprise();
237 } // namespace HPHP