1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * the Mozilla Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2010
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Zack Weinberg <zweinberg@mozilla.com> (original author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "jsperf.h"
40 : #include "jscntxt.h" /* for error messages */
41 : #include "jsobj.h" /* for unwrapping without a context */
42 :
43 : #include "jsobjinlines.h"
44 :
45 : using JS::PerfMeasurement;
46 :
47 : // You cannot forward-declare a static object in C++, so instead
48 : // we have to forward-declare the helper functions that refer to it.
49 : static PerfMeasurement* GetPM(JSContext* cx, JSObject* obj, const char* fname);
50 : static PerfMeasurement* GetPMFromThis(JSContext* cx, jsval* vp);
51 :
52 : // Property access
53 :
54 : #define GETTER(name) \
55 : static JSBool \
56 : pm_get_##name(JSContext* cx, JSObject* obj, jsid /*unused*/, jsval* vp) \
57 : { \
58 : PerfMeasurement* p = GetPM(cx, obj, #name); \
59 : if (!p) \
60 : return JS_FALSE; \
61 : return JS_NewNumberValue(cx, double(p->name), vp); \
62 : }
63 :
64 0 : GETTER(cpu_cycles)
65 0 : GETTER(instructions)
66 0 : GETTER(cache_references)
67 0 : GETTER(cache_misses)
68 0 : GETTER(branch_instructions)
69 0 : GETTER(branch_misses)
70 0 : GETTER(bus_cycles)
71 0 : GETTER(page_faults)
72 0 : GETTER(major_page_faults)
73 0 : GETTER(context_switches)
74 0 : GETTER(cpu_migrations)
75 9 : GETTER(eventsMeasured)
76 :
77 : #undef GETTER
78 :
79 : // Calls
80 :
81 : static JSBool
82 0 : pm_start(JSContext* cx, unsigned /*unused*/, jsval* vp)
83 : {
84 0 : PerfMeasurement* p = GetPMFromThis(cx, vp);
85 0 : if (!p)
86 0 : return JS_FALSE;
87 :
88 0 : p->start();
89 0 : return JS_TRUE;
90 : }
91 :
92 : static JSBool
93 0 : pm_stop(JSContext* cx, unsigned /*unused*/, jsval* vp)
94 : {
95 0 : PerfMeasurement* p = GetPMFromThis(cx, vp);
96 0 : if (!p)
97 0 : return JS_FALSE;
98 :
99 0 : p->stop();
100 0 : return JS_TRUE;
101 : }
102 :
103 : static JSBool
104 0 : pm_reset(JSContext* cx, unsigned /*unused*/, jsval* vp)
105 : {
106 0 : PerfMeasurement* p = GetPMFromThis(cx, vp);
107 0 : if (!p)
108 0 : return JS_FALSE;
109 :
110 0 : p->reset();
111 0 : return JS_TRUE;
112 : }
113 :
114 : static JSBool
115 0 : pm_canMeasureSomething(JSContext* cx, unsigned /*unused*/, jsval* vp)
116 : {
117 0 : PerfMeasurement* p = GetPMFromThis(cx, vp);
118 0 : if (!p)
119 0 : return JS_FALSE;
120 :
121 0 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(p->canMeasureSomething()));
122 0 : return JS_TRUE;
123 : }
124 :
125 : const uint8_t PM_FATTRS = JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED;
126 : static JSFunctionSpec pm_fns[] = {
127 : JS_FN("start", pm_start, 0, PM_FATTRS),
128 : JS_FN("stop", pm_stop, 0, PM_FATTRS),
129 : JS_FN("reset", pm_reset, 0, PM_FATTRS),
130 : JS_FN("canMeasureSomething", pm_canMeasureSomething, 0, PM_FATTRS),
131 : JS_FS_END
132 : };
133 :
134 : const uint8_t PM_PATTRS =
135 : JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED;
136 :
137 : #define GETTER(name) \
138 : { #name, 0, PM_PATTRS, pm_get_##name, 0 }
139 :
140 : static JSPropertySpec pm_props[] = {
141 : GETTER(cpu_cycles),
142 : GETTER(instructions),
143 : GETTER(cache_references),
144 : GETTER(cache_misses),
145 : GETTER(branch_instructions),
146 : GETTER(branch_misses),
147 : GETTER(bus_cycles),
148 : GETTER(page_faults),
149 : GETTER(major_page_faults),
150 : GETTER(context_switches),
151 : GETTER(cpu_migrations),
152 : GETTER(eventsMeasured),
153 : {0,0,0,0,0}
154 : };
155 :
156 : #undef GETTER
157 :
158 : // If this were C++ these would be "static const" members.
159 :
160 : const uint8_t PM_CATTRS = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT;
161 :
162 : #define CONSTANT(name) { #name, PerfMeasurement::name }
163 :
164 : static const struct pm_const {
165 : const char *name;
166 : PerfMeasurement::EventMask value;
167 : } pm_consts[] = {
168 : CONSTANT(CPU_CYCLES),
169 : CONSTANT(INSTRUCTIONS),
170 : CONSTANT(CACHE_REFERENCES),
171 : CONSTANT(CACHE_MISSES),
172 : CONSTANT(BRANCH_INSTRUCTIONS),
173 : CONSTANT(BRANCH_MISSES),
174 : CONSTANT(BUS_CYCLES),
175 : CONSTANT(PAGE_FAULTS),
176 : CONSTANT(MAJOR_PAGE_FAULTS),
177 : CONSTANT(CONTEXT_SWITCHES),
178 : CONSTANT(CPU_MIGRATIONS),
179 : CONSTANT(ALL),
180 : CONSTANT(NUM_MEASURABLE_EVENTS),
181 : { 0, PerfMeasurement::EventMask(0) }
182 : };
183 :
184 : #undef CONSTANT
185 :
186 : static JSBool pm_construct(JSContext* cx, unsigned argc, jsval* vp);
187 : static void pm_finalize(JSFreeOp* fop, JSObject* obj);
188 :
189 : static JSClass pm_class = {
190 : "PerfMeasurement", JSCLASS_HAS_PRIVATE,
191 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
192 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, pm_finalize
193 : };
194 :
195 : // Constructor and destructor
196 :
197 : static JSBool
198 9 : pm_construct(JSContext* cx, unsigned argc, jsval* vp)
199 : {
200 : uint32_t mask;
201 9 : if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "u", &mask))
202 0 : return JS_FALSE;
203 :
204 9 : JSObject *obj = JS_NewObjectForConstructor(cx, &pm_class, vp);
205 9 : if (!obj)
206 0 : return JS_FALSE;
207 :
208 9 : if (!JS_FreezeObject(cx, obj))
209 0 : return JS_FALSE;
210 :
211 9 : PerfMeasurement* p = cx->new_<PerfMeasurement>(PerfMeasurement::EventMask(mask));
212 9 : if (!p) {
213 0 : JS_ReportOutOfMemory(cx);
214 0 : return JS_FALSE;
215 : }
216 :
217 9 : JS_SetPrivate(obj, p);
218 9 : *vp = OBJECT_TO_JSVAL(obj);
219 9 : return JS_TRUE;
220 : }
221 :
222 : static void
223 23337 : pm_finalize(JSFreeOp* fop, JSObject* obj)
224 : {
225 23337 : js::FreeOp::get(fop)->delete_(static_cast<PerfMeasurement*>(JS_GetPrivate(obj)));
226 23337 : }
227 :
228 : // Helpers (declared above)
229 :
230 : static PerfMeasurement*
231 9 : GetPM(JSContext* cx, JSObject* obj, const char* fname)
232 : {
233 : PerfMeasurement* p = (PerfMeasurement*)
234 9 : JS_GetInstancePrivate(cx, obj, &pm_class, 0);
235 9 : if (p)
236 9 : return p;
237 :
238 : // JS_GetInstancePrivate only sets an exception if its last argument
239 : // is nonzero, so we have to do it by hand.
240 : JS_ReportErrorNumber(cx, js_GetErrorMessage, 0, JSMSG_INCOMPATIBLE_PROTO,
241 0 : pm_class.name, fname, JS_GetClass(obj)->name);
242 0 : return 0;
243 : }
244 :
245 : static PerfMeasurement*
246 0 : GetPMFromThis(JSContext* cx, jsval* vp)
247 : {
248 0 : JSObject* this_ = JS_THIS_OBJECT(cx, vp);
249 0 : if (!this_)
250 0 : return 0;
251 : return (PerfMeasurement*)
252 0 : JS_GetInstancePrivate(cx, this_, &pm_class, JS_ARGV(cx, vp));
253 : }
254 :
255 : namespace JS {
256 :
257 : JSObject*
258 23328 : RegisterPerfMeasurement(JSContext *cx, JSObject *global)
259 : {
260 46656 : js::RootedVarObject prototype(cx);
261 : prototype = JS_InitClass(cx, global, 0 /* parent */,
262 : &pm_class, pm_construct, 1,
263 23328 : pm_props, pm_fns, 0, 0);
264 23328 : if (!prototype)
265 0 : return 0;
266 :
267 46656 : js::RootedVarObject ctor(cx);
268 23328 : ctor = JS_GetConstructor(cx, prototype);
269 23328 : if (!ctor)
270 0 : return 0;
271 :
272 326592 : for (const pm_const *c = pm_consts; c->name; c++) {
273 606528 : if (!JS_DefineProperty(cx, ctor, c->name, INT_TO_JSVAL(c->value),
274 303264 : JS_PropertyStub, JS_StrictPropertyStub, PM_CATTRS))
275 0 : return 0;
276 : }
277 :
278 46656 : if (!JS_FreezeObject(cx, prototype) ||
279 23328 : !JS_FreezeObject(cx, ctor)) {
280 0 : return 0;
281 : }
282 :
283 23328 : return prototype;
284 : }
285 :
286 : PerfMeasurement*
287 0 : ExtractPerfMeasurement(jsval wrapper)
288 : {
289 0 : if (JSVAL_IS_PRIMITIVE(wrapper))
290 0 : return 0;
291 :
292 : // This is what JS_GetInstancePrivate does internally. We can't
293 : // call JS_anything from here, because we don't have a JSContext.
294 0 : JSObject *obj = JSVAL_TO_OBJECT(wrapper);
295 0 : if (obj->getClass() != js::Valueify(&pm_class))
296 0 : return 0;
297 :
298 0 : return (PerfMeasurement*) obj->getPrivate();
299 : }
300 :
301 : } // namespace JS
|