remove operator-> from String
[hiphop-php.git] / hphp / runtime / vm / event-hook.cpp
blob7855f32648457dd823de4f181307af189cdeb5ad
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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/mc-generator.h"
21 #include "hphp/runtime/vm/jit/translator-inline.h"
22 #include "hphp/runtime/base/builtin-functions.h"
23 #include "hphp/runtime/base/complex-types.h"
24 #include "hphp/runtime/ext/ext_function.h"
25 #include "hphp/runtime/vm/runtime.h"
27 namespace HPHP {
29 static StaticString s_args("args");
30 static StaticString s_enter("enter");
31 static StaticString s_exit("exit");
32 static StaticString s_exception("exception");
33 static StaticString s_name("name");
34 static StaticString s_return("return");
36 void EventHook::Enable() {
37 ThreadInfo::s_threadInfo->m_reqInjectionData.setEventHookFlag();
40 void EventHook::Disable() {
41 ThreadInfo::s_threadInfo->m_reqInjectionData.clearEventHookFlag();
44 void EventHook::EnableIntercept() {
45 ThreadInfo::s_threadInfo->m_reqInjectionData.setInterceptFlag();
48 void EventHook::DisableIntercept() {
49 ThreadInfo::s_threadInfo->m_reqInjectionData.clearInterceptFlag();
52 ssize_t EventHook::CheckSurprise() {
53 ThreadInfo* info = ThreadInfo::s_threadInfo.getNoCheck();
54 return check_request_surprise(info);
57 class ExecutingSetprofileCallbackGuard {
58 public:
59 ExecutingSetprofileCallbackGuard() {
60 g_context->m_executingSetprofileCallback = true;
63 ~ExecutingSetprofileCallbackGuard() {
64 g_context->m_executingSetprofileCallback = false;
68 void EventHook::RunUserProfiler(const ActRec* ar, int mode) {
69 // Don't do anything if we are running the profiling function itself
70 // or if we haven't set up a profiler.
71 if (g_context->m_executingSetprofileCallback ||
72 g_context->m_setprofileCallback.isNull()) {
73 return;
75 // Don't profile 86ctor, since its an implementation detail,
76 // and we dont guarantee to call it
77 if (ar->m_func->cls() && ar->m_func == ar->m_func->cls()->getCtor() &&
78 Func::isSpecial(ar->m_func->name())) {
79 return;
81 JIT::VMRegAnchor _;
82 ExecutingSetprofileCallbackGuard guard;
84 Array params;
85 Array frameinfo;
87 if (mode == ProfileEnter) {
88 params.append(s_enter);
89 frameinfo.set(s_args, hhvm_get_frame_args(ar, 0));
90 } else {
91 params.append(s_exit);
92 if (!g_context->m_faults.empty()) {
93 Fault fault = g_context->m_faults.back();
94 if (fault.m_faultType == Fault::Type::UserException) {
95 frameinfo.set(s_exception, fault.m_userException);
97 } else if (!ar->m_func->isCPPBuiltin() &&
98 !ar->inGenerator()) {
99 // TODO (#1131400) This is wrong for builtins
100 frameinfo.set(s_return, tvAsCVarRef(g_context->m_stack.topTV()));
104 params.append(VarNR(ar->m_func->fullName()));
105 params.append(frameinfo);
107 vm_call_user_func(g_context->m_setprofileCallback, params);
110 static Array get_frame_args_with_ref(const ActRec* ar) {
111 int numParams = ar->m_func->numParams();
112 int numArgs = ar->numArgs();
114 PackedArrayInit retArray(numArgs);
116 auto local = reinterpret_cast<TypedValue*>(
117 uintptr_t(ar) - sizeof(TypedValue)
119 for (int i = 0; i < numArgs; ++i) {
120 if (i < numParams) {
121 // This corresponds to one of the function's formal parameters, so it's
122 // on the stack.
123 retArray.appendWithRef(tvAsCVarRef(local));
124 --local;
125 } else {
126 // This is not a formal parameter, so it's in the ExtraArgs.
127 retArray.appendWithRef(tvAsCVarRef(ar->getExtraArg(i - numParams)));
131 return retArray.toArray();
134 bool EventHook::RunInterceptHandler(ActRec* ar) {
135 const Func* func = ar->m_func;
136 if (LIKELY(func->maybeIntercepted() == 0)) return true;
138 Variant *h = get_intercept_handler(func->fullNameRef(),
139 &func->maybeIntercepted());
140 if (!h) return true;
142 JIT::VMRegAnchor _;
144 PC savePc = g_context->m_pc;
146 Variant doneFlag = true;
147 Variant called_on;
149 if (ar->hasThis()) {
150 called_on = Variant(ar->getThis());
151 } else if (ar->hasClass()) {
152 // For static methods, give handler the name of called class
153 called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
155 Variant intArgs =
156 PackedArrayInit(5)
157 .append(ar->m_func->fullNameRef())
158 .append(called_on)
159 .append(get_frame_args_with_ref(ar))
160 .append(h->asCArrRef()[1])
161 .appendRef(doneFlag)
162 .toArray();
164 Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
165 if (doneFlag.toBoolean()) {
166 Offset pcOff;
167 ActRec* outer = g_context->getPrevVMState(ar, &pcOff);
169 frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals());
170 Stack& stack = g_context->getStack();
171 stack.top() = (Cell*)(ar + 1);
172 cellDup(*ret.asCell(), *stack.allocTV());
174 g_context->m_fp = outer;
175 g_context->m_pc = outer ? outer->m_func->unit()->at(pcOff) : nullptr;
177 return false;
179 g_context->m_fp = ar;
180 g_context->m_pc = savePc;
182 return true;
185 const char* EventHook::GetFunctionNameForProfiler(const ActRec* ar,
186 int funcType) {
187 const char* name;
188 switch (funcType) {
189 case EventHook::NormalFunc:
190 name = ar->m_func->fullName()->data();
191 if (name[0] == '\0') {
192 // We're evaling some code for internal purposes, most
193 // likely getting the default value for a function parameter
194 name = "{internal}";
196 break;
197 case EventHook::PseudoMain:
198 name = makeStaticString(
199 std::string("run_init::") + ar->m_func->unit()->filepath()->data())
200 ->data();
201 break;
202 case EventHook::Eval:
203 name = "_";
204 break;
205 default:
206 not_reached();
208 return name;
211 bool EventHook::onFunctionEnter(const ActRec* ar, int funcType) {
212 ssize_t flags = CheckSurprise();
213 if (flags & RequestInjectionData::InterceptFlag &&
214 !RunInterceptHandler(const_cast<ActRec*>(ar))) {
215 return false;
217 if (flags & RequestInjectionData::EventHookFlag) {
218 RunUserProfiler(ar, ProfileEnter);
219 #ifdef HOTPROFILER
220 Profiler* profiler = ThreadInfo::s_threadInfo->m_profiler;
221 if (profiler != nullptr) {
222 begin_profiler_frame(profiler, GetFunctionNameForProfiler(ar, funcType));
224 #endif
226 return true;
229 void EventHook::onFunctionExit(const ActRec* ar) {
230 auto const inlinedRip = JIT::tx->uniqueStubs.retInlHelper;
231 if ((JIT::TCA)ar->m_savedRip == inlinedRip) {
232 // Inlined calls normally skip the function enter and exit events. If we
233 // side exit in an inlined callee, we want to make sure to skip the exit
234 // event to avoid unbalancing the call stack.
235 return;
238 #ifdef HOTPROFILER
239 Profiler* profiler = ThreadInfo::s_threadInfo->m_profiler;
240 if (profiler != nullptr) {
241 // NB: we don't have a function type flag to match what we got in
242 // onFunctionEnter. That's okay, though... we tolerate this in
243 // TraceProfiler.
244 end_profiler_frame(profiler, GetFunctionNameForProfiler(ar, NormalFunc));
246 #endif
248 // If we have a pending exception, then we're in the process of unwinding
249 // for that exception. We avoid running more PHP code (the user profiler) and
250 // also avoid raising more exceptions for surprises (including the pending
251 // exception).
252 if (ThreadInfo::s_threadInfo->m_pendingException == nullptr) {
253 RunUserProfiler(ar, ProfileExit);
254 // XXX Disabled until t2329497 is fixed:
255 // CheckSurprise();
259 } // namespace HPHP