1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sw=4 et tw=80:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
20 * The Initial Developer of the Original Code is
21 * the Mozilla Corporation.
24 * Steve Fink <sfink@mozilla.org>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
43 #ifdef INCLUDE_MOZILLA_DTRACE
44 #include "javascript-trace.h"
52 #include "methodjit/MethodJIT.h"
55 #include "vm/ObjectImpl-inl.h"
60 struct NativeAddressInfo
;
69 * The probe points defined in this file are scattered around the SpiderMonkey
70 * source tree. The presence of Probes::someEvent() means that someEvent is
71 * about to happen or has happened. To the extent possible, probes should be
72 * inserted in all paths associated with a given event, regardless of the
73 * active runmode (interpreter/traceJIT/methodJIT/ionJIT).
75 * When a probe fires, it is handled by any probe handling backends that have
76 * been compiled in. By default, most probes do nothing or at least do nothing
77 * expensive, so the presence of the probe should have negligible effect on
78 * running time. (Probes in slow paths may do something by default, as long as
79 * there is no noticeable slowdown.)
81 * For some probes, the mere existence of the probe is too expensive even if it
82 * does nothing when called. For example, just having consistent information
83 * available for a function call entry/exit probe causes the JITs to
84 * de-optimize function calls. In those cases, the JITs may query at compile
85 * time whether a probe is desired, and omit the probe invocation if not. If a
86 * probe is runtime-disabled at compilation time, it is not guaranteed to fire
87 * within a compiled function if it is later enabled.
89 * Not all backends handle all of the probes listed here.
93 * Internal use only: remember whether "profiling", whatever that means, is
94 * currently active. Used for state management.
96 extern bool ProfilingActive
;
98 extern const char nullName
[];
99 extern const char anonymousName
[];
101 /* Called when first runtime is created for this process */
102 JSBool
startEngine();
104 /* JSRuntime created, with currently valid fields */
105 bool createRuntime(JSRuntime
*rt
);
107 /* JSRuntime about to be destroyed */
108 bool destroyRuntime(JSRuntime
*rt
);
110 /* Total JS engine shutdown */
114 * Test whether we are tracking JS function call enter/exit. The JITs use this
115 * to decide whether they can optimize in a way that would prevent probes from
118 bool callTrackingActive(JSContext
*);
121 * Test whether anything is looking for JIT native code registration events.
122 * This information will not be collected otherwise.
124 bool wantNativeAddressInfo(JSContext
*);
126 /* Entering a JS function */
127 bool enterJSFun(JSContext
*, JSFunction
*, JSScript
*, int counter
= 1);
129 /* About to leave a JS function */
130 bool exitJSFun(JSContext
*, JSFunction
*, JSScript
*, int counter
= 0);
132 /* Executing a script */
133 bool startExecution(JSContext
*cx
, JSScript
*script
);
135 /* Script has completed execution */
136 bool stopExecution(JSContext
*cx
, JSScript
*script
);
138 /* Heap has been resized */
139 bool resizeHeap(JSCompartment
*compartment
, size_t oldSize
, size_t newSize
);
142 * Object has been created. |obj| must exist (its class and size are read)
144 bool createObject(JSContext
*cx
, JSObject
*obj
);
146 /* Resize events are being tracked. */
147 bool objectResizeActive();
149 /* Object has been resized */
150 bool resizeObject(JSContext
*cx
, JSObject
*obj
, size_t oldSize
, size_t newSize
);
153 * Object is about to be finalized. |obj| must still exist (its class is
156 bool finalizeObject(JSObject
*obj
);
159 * String has been created.
161 * |string|'s content is not (yet) valid. |length| is the length of the string
162 * and does not imply anything about the amount of storage consumed to store
163 * the string. (It may be a short string, an external string, or a rope, and
164 * the encoding is not taken into consideration.)
166 bool createString(JSContext
*cx
, JSString
*string
, size_t length
);
169 * String is about to be finalized
171 * |string| must still have a valid length.
173 bool finalizeString(JSString
*string
);
175 /* Script is about to be compiled */
176 bool compileScriptBegin(JSContext
*cx
, const char *filename
, int lineno
);
178 /* Script has just finished compilation */
179 bool compileScriptEnd(JSContext
*cx
, JSScript
*script
, const char *filename
, int lineno
);
181 /* About to make a call from JS into native code */
182 bool calloutBegin(JSContext
*cx
, JSFunction
*fun
);
184 /* Native code called by JS has terminated */
185 bool calloutEnd(JSContext
*cx
, JSFunction
*fun
);
188 bool acquireMemory(JSContext
*cx
, void *address
, size_t nbytes
);
189 bool releaseMemory(JSContext
*cx
, void *address
, size_t nbytes
);
192 * Garbage collection probes
194 * GC timing is tricky and at the time of this writing is changing frequently.
195 * GCStart/GCEnd are intended to bracket the entire garbage collection (either
196 * global or single-compartment), but a separate thread may continue doing work
199 * Multiple compartments' GC will be interleaved during a global collection
200 * (eg, compartment 1 starts, compartment 2 starts, compartment 1 ends, ...)
205 bool GCStartMarkPhase();
206 bool GCEndMarkPhase();
208 bool GCStartSweepPhase();
209 bool GCEndSweepPhase();
212 * Various APIs for inserting custom probe points. These might be used to mark
213 * when something starts and stops, or for various other purposes the user has
214 * in mind. These are useful to export to JS so that JS code can mark
215 * application-meaningful events and phases of execution.
217 * Not all backends support these.
219 bool CustomMark(JSString
*string
);
220 bool CustomMark(const char *string
);
221 bool CustomMark(int marker
);
223 /* JIT code observation */
225 enum JITReportGranularity
{
226 JITREPORT_GRANULARITY_NONE
= 0,
227 JITREPORT_GRANULARITY_FUNCTION
= 1,
228 JITREPORT_GRANULARITY_LINE
= 2,
229 JITREPORT_GRANULARITY_OP
= 3
233 * Observer class for JIT code allocation/deallocation. Currently, this only
234 * handles the method JIT, and does not get notifications when JIT code is
235 * changed (patched) with no new allocation.
239 struct NativeRegion
{
240 mjit::JSActiveFrame
*frame
;
242 size_t inlinedOffset
;
245 uintptr_t mainOffset
;
246 uintptr_t stubOffset
;
250 typedef Vector
<NativeRegion
, 0, RuntimeAllocPolicy
> RegionVector
;
252 virtual JITReportGranularity
granularityRequested() = 0;
255 static bool CollectNativeRegions(RegionVector
®ions
,
258 mjit::JSActiveFrame
*outerFrame
,
259 mjit::JSActiveFrame
**inlineFrames
);
261 virtual void registerMJITCode(JSContext
*cx
, js::mjit::JITChunk
*chunk
,
262 mjit::JSActiveFrame
*outerFrame
,
263 mjit::JSActiveFrame
**inlineFrames
,
264 void *mainCodeAddress
, size_t mainCodeSize
,
265 void *stubCodeAddress
, size_t stubCodeSize
) = 0;
267 virtual void discardMJITCode(FreeOp
*fop
, mjit::JITScript
*jscr
, mjit::JITChunk
*chunk
,
270 virtual void registerICCode(JSContext
*cx
,
271 js::mjit::JITChunk
*chunk
, JSScript
*script
, jsbytecode
* pc
,
272 void *start
, size_t size
) = 0;
275 virtual void discardExecutableRegion(void *start
, size_t size
) = 0;
279 * Register a JITWatcher subclass to be informed of JIT code
280 * allocation/deallocation.
283 addJITWatcher(JITWatcher
*watcher
);
286 * Remove (and destroy) a registered JITWatcher. rt may be NULL. Returns false
287 * if the watcher is not found.
290 removeJITWatcher(JSRuntime
*rt
, JITWatcher
*watcher
);
293 * Remove (and destroy) all registered JITWatchers. rt may be NULL.
296 removeAllJITWatchers(JSRuntime
*rt
);
299 * Finest granularity of JIT information desired by all watchers.
302 JITGranularityRequested();
306 * New method JIT code has been created
309 registerMJITCode(JSContext
*cx
, js::mjit::JITChunk
*chunk
,
310 mjit::JSActiveFrame
*outerFrame
,
311 mjit::JSActiveFrame
**inlineFrames
,
312 void *mainCodeAddress
, size_t mainCodeSize
,
313 void *stubCodeAddress
, size_t stubCodeSize
);
316 * Method JIT code is about to be discarded
319 discardMJITCode(FreeOp
*fop
, mjit::JITScript
*jscr
, mjit::JITChunk
*chunk
, void* address
);
322 * IC code has been allocated within the given JITChunk
325 registerICCode(JSContext
*cx
,
326 mjit::JITChunk
*chunk
, JSScript
*script
, jsbytecode
* pc
,
327 void *start
, size_t size
);
328 #endif /* JS_METHODJIT */
331 * A whole region of code has been deallocated, containing any number of ICs.
332 * (ICs are unregistered in a batch, so individual ICs are not registered.)
335 discardExecutableRegion(void *start
, size_t size
);
338 * Internal: DTrace-specific functions to be called during Probes::enterJSFun
339 * and Probes::exitJSFun. These will not be inlined, but the argument
340 * marshalling required for these probe points is expensive enough that it
341 * shouldn't really matter.
343 void DTraceEnterJSFun(JSContext
*cx
, JSFunction
*fun
, JSScript
*script
);
344 void DTraceExitJSFun(JSContext
*cx
, JSFunction
*fun
, JSScript
*script
);
347 * Internal: ETW-specific probe functions
351 bool ETWCreateRuntime(JSRuntime
*rt
);
352 bool ETWDestroyRuntime(JSRuntime
*rt
);
354 bool ETWCallTrackingActive(JSContext
*cx
);
355 bool ETWEnterJSFun(JSContext
*cx
, JSFunction
*fun
, JSScript
*script
, int counter
);
356 bool ETWExitJSFun(JSContext
*cx
, JSFunction
*fun
, JSScript
*script
, int counter
);
357 bool ETWCreateObject(JSContext
*cx
, JSObject
*obj
);
358 bool ETWFinalizeObject(JSObject
*obj
);
359 bool ETWResizeObject(JSContext
*cx
, JSObject
*obj
, size_t oldSize
, size_t newSize
);
360 bool ETWCreateString(JSContext
*cx
, JSString
*string
, size_t length
);
361 bool ETWFinalizeString(JSString
*string
);
362 bool ETWCompileScriptBegin(const char *filename
, int lineno
);
363 bool ETWCompileScriptEnd(const char *filename
, int lineno
);
364 bool ETWCalloutBegin(JSContext
*cx
, JSFunction
*fun
);
365 bool ETWCalloutEnd(JSContext
*cx
, JSFunction
*fun
);
366 bool ETWAcquireMemory(JSContext
*cx
, void *address
, size_t nbytes
);
367 bool ETWReleaseMemory(JSContext
*cx
, void *address
, size_t nbytes
);
370 bool ETWGCStartMarkPhase();
371 bool ETWGCEndMarkPhase();
372 bool ETWGCStartSweepPhase();
373 bool ETWGCEndSweepPhase();
374 bool ETWCustomMark(JSString
*string
);
375 bool ETWCustomMark(const char *string
);
376 bool ETWCustomMark(int marker
);
377 bool ETWStartExecution(JSContext
*cx
, JSScript
*script
);
378 bool ETWStopExecution(JSContext
*cx
, JSScript
*script
);
379 bool ETWResizeHeap(JSCompartment
*compartment
, size_t oldSize
, size_t newSize
);
382 } /* namespace Probes */
385 * Many probe handlers are implemented inline for minimal performance impact,
386 * especially important when no backends are enabled.
390 Probes::callTrackingActive(JSContext
*cx
)
392 #ifdef INCLUDE_MOZILLA_DTRACE
393 if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED() || JAVASCRIPT_FUNCTION_RETURN_ENABLED())
396 #ifdef MOZ_TRACE_JSCALLS
397 if (cx
->functionCallback
)
401 if (ProfilingActive
&& ETWCallTrackingActive(cx
))
408 Probes::wantNativeAddressInfo(JSContext
*cx
)
410 return (cx
->reportGranularity
>= JITREPORT_GRANULARITY_FUNCTION
&&
411 JITGranularityRequested() >= JITREPORT_GRANULARITY_FUNCTION
);
415 Probes::enterJSFun(JSContext
*cx
, JSFunction
*fun
, JSScript
*script
, int counter
)
418 #ifdef INCLUDE_MOZILLA_DTRACE
419 if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED())
420 DTraceEnterJSFun(cx
, fun
, script
);
422 #ifdef MOZ_TRACE_JSCALLS
423 cx
->doFunctionCallback(fun
, script
, counter
);
426 if (ProfilingActive
&& !ETWEnterJSFun(cx
, fun
, script
, counter
))
434 Probes::exitJSFun(JSContext
*cx
, JSFunction
*fun
, JSScript
*script
, int counter
)
438 #ifdef INCLUDE_MOZILLA_DTRACE
439 if (JAVASCRIPT_FUNCTION_RETURN_ENABLED())
440 DTraceExitJSFun(cx
, fun
, script
);
442 #ifdef MOZ_TRACE_JSCALLS
445 cx
->doFunctionCallback(fun
, script
, counter
);
448 if (ProfilingActive
&& !ETWExitJSFun(cx
, fun
, script
, counter
))
456 Probes::resizeHeap(JSCompartment
*compartment
, size_t oldSize
, size_t newSize
)
461 if (ProfilingActive
&& !ETWResizeHeap(compartment
, oldSize
, newSize
))
468 #ifdef INCLUDE_MOZILLA_DTRACE
469 static const char *ObjectClassname(JSObject
*obj
) {
471 return "(null object)";
472 Class
*clasp
= obj
->getClass();
475 const char *class_name
= clasp
->name
;
477 return "(null class name)";
483 Probes::createObject(JSContext
*cx
, JSObject
*obj
)
487 #ifdef INCLUDE_MOZILLA_DTRACE
488 if (JAVASCRIPT_OBJECT_CREATE_ENABLED())
489 JAVASCRIPT_OBJECT_CREATE(ObjectClassname(obj
), (uintptr_t)obj
);
492 if (ProfilingActive
&& !ETWCreateObject(cx
, obj
))
500 Probes::finalizeObject(JSObject
*obj
)
504 #ifdef INCLUDE_MOZILLA_DTRACE
505 if (JAVASCRIPT_OBJECT_FINALIZE_ENABLED()) {
506 Class
*clasp
= obj
->getClass();
508 /* the first arg is NULL - reserved for future use (filename?) */
509 JAVASCRIPT_OBJECT_FINALIZE(NULL
, (char *)clasp
->name
, (uintptr_t)obj
);
513 if (ProfilingActive
&& !ETWFinalizeObject(obj
))
521 Probes::objectResizeActive()
532 Probes::resizeObject(JSContext
*cx
, JSObject
*obj
, size_t oldSize
, size_t newSize
)
537 if (ProfilingActive
&& !ETWResizeObject(cx
, obj
, oldSize
, newSize
))
545 Probes::createString(JSContext
*cx
, JSString
*string
, size_t length
)
550 if (ProfilingActive
&& !ETWCreateString(cx
, string
, length
))
558 Probes::finalizeString(JSString
*string
)
563 if (ProfilingActive
&& !ETWFinalizeString(string
))
571 Probes::compileScriptBegin(JSContext
*cx
, const char *filename
, int lineno
)
576 if (ProfilingActive
&& !ETWCompileScriptBegin(filename
, lineno
))
584 Probes::compileScriptEnd(JSContext
*cx
, JSScript
*script
, const char *filename
, int lineno
)
589 if (ProfilingActive
&& !ETWCompileScriptEnd(filename
, lineno
))
597 Probes::calloutBegin(JSContext
*cx
, JSFunction
*fun
)
602 if (ProfilingActive
&& !ETWCalloutBegin(cx
, fun
))
610 Probes::calloutEnd(JSContext
*cx
, JSFunction
*fun
)
615 if (ProfilingActive
&& !ETWCalloutEnd(cx
, fun
))
623 Probes::acquireMemory(JSContext
*cx
, void *address
, size_t nbytes
)
628 if (ProfilingActive
&& !ETWAcquireMemory(cx
, address
, nbytes
))
636 Probes::releaseMemory(JSContext
*cx
, void *address
, size_t nbytes
)
641 if (ProfilingActive
&& !ETWReleaseMemory(cx
, address
, nbytes
))
654 if (ProfilingActive
&& !ETWGCStart())
667 if (ProfilingActive
&& !ETWGCEnd())
675 Probes::GCStartMarkPhase()
680 if (ProfilingActive
&& !ETWGCStartMarkPhase())
688 Probes::GCEndMarkPhase()
693 if (ProfilingActive
&& !ETWGCEndMarkPhase())
701 Probes::GCStartSweepPhase()
706 if (ProfilingActive
&& !ETWGCStartSweepPhase())
714 Probes::GCEndSweepPhase()
719 if (ProfilingActive
&& !ETWGCEndSweepPhase())
727 Probes::CustomMark(JSString
*string
)
732 if (ProfilingActive
&& !ETWCustomMark(string
))
740 Probes::CustomMark(const char *string
)
745 if (ProfilingActive
&& !ETWCustomMark(string
))
753 Probes::CustomMark(int marker
)
758 if (ProfilingActive
&& !ETWCustomMark(marker
))
766 Probes::startExecution(JSContext
*cx
, JSScript
*script
)
770 #ifdef INCLUDE_MOZILLA_DTRACE
771 if (JAVASCRIPT_EXECUTE_START_ENABLED())
772 JAVASCRIPT_EXECUTE_START((script
->filename
? (char *)script
->filename
: nullName
),
776 if (ProfilingActive
&& !ETWStartExecution(cx
, script
))
784 Probes::stopExecution(JSContext
*cx
, JSScript
*script
)
788 #ifdef INCLUDE_MOZILLA_DTRACE
789 if (JAVASCRIPT_EXECUTE_DONE_ENABLED())
790 JAVASCRIPT_EXECUTE_DONE((script
->filename
? (char *)script
->filename
: nullName
),
794 if (ProfilingActive
&& !ETWStopExecution(cx
, script
))
801 struct AutoFunctionCallProbe
{
802 JSContext
* const cx
;
805 JS_DECL_USE_GUARD_OBJECT_NOTIFIER
807 AutoFunctionCallProbe(JSContext
*cx
, JSFunction
*fun
, JSScript
*script
808 JS_GUARD_OBJECT_NOTIFIER_PARAM
)
809 : cx(cx
), fun(fun
), script(script
)
811 JS_GUARD_OBJECT_NOTIFIER_INIT
;
812 Probes::enterJSFun(cx
, fun
, script
);
815 ~AutoFunctionCallProbe() {
816 Probes::exitJSFun(cx
, fun
, script
);
823 * Internal functions for controlling various profilers. The profiler-specific
824 * implementations of these are mostly in jsdbgapi.cpp.
827 #endif /* _JSPROBES_H */