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 : // Constructor and destructor
53 :
54 : static JSBool
55 9 : pm_construct(JSContext* cx, unsigned argc, jsval* vp)
56 : {
57 : uint32_t mask;
58 9 : if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "u", &mask))
59 0 : return JS_FALSE;
60 :
61 9 : JSObject *obj = JS_NewObjectForConstructor(cx, vp);
62 9 : if (!obj)
63 0 : return JS_FALSE;
64 :
65 9 : if (!JS_FreezeObject(cx, obj))
66 0 : return JS_FALSE;
67 :
68 9 : PerfMeasurement* p = cx->new_<PerfMeasurement>(PerfMeasurement::EventMask(mask));
69 9 : if (!p) {
70 0 : JS_ReportOutOfMemory(cx);
71 0 : return JS_FALSE;
72 : }
73 :
74 9 : JS_SetPrivate(obj, p);
75 9 : *vp = OBJECT_TO_JSVAL(obj);
76 9 : return JS_TRUE;
77 : }
78 :
79 : static void
80 22833 : pm_finalize(JSContext* cx, JSObject* obj)
81 : {
82 22833 : cx->delete_((PerfMeasurement*) JS_GetPrivate(obj));
83 22833 : }
84 :
85 : // Property access
86 :
87 : #define GETTER(name) \
88 : static JSBool \
89 : pm_get_##name(JSContext* cx, JSObject* obj, jsid /*unused*/, jsval* vp) \
90 : { \
91 : PerfMeasurement* p = GetPM(cx, obj, #name); \
92 : if (!p) \
93 : return JS_FALSE; \
94 : return JS_NewNumberValue(cx, double(p->name), vp); \
95 : }
96 :
97 0 : GETTER(cpu_cycles)
98 0 : GETTER(instructions)
99 0 : GETTER(cache_references)
100 0 : GETTER(cache_misses)
101 0 : GETTER(branch_instructions)
102 0 : GETTER(branch_misses)
103 0 : GETTER(bus_cycles)
104 0 : GETTER(page_faults)
105 0 : GETTER(major_page_faults)
106 0 : GETTER(context_switches)
107 0 : GETTER(cpu_migrations)
108 9 : GETTER(eventsMeasured)
109 :
110 : #undef GETTER
111 :
112 : // Calls
113 :
114 : static JSBool
115 0 : pm_start(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 : p->start();
122 0 : return JS_TRUE;
123 : }
124 :
125 : static JSBool
126 0 : pm_stop(JSContext* cx, unsigned /*unused*/, jsval* vp)
127 : {
128 0 : PerfMeasurement* p = GetPMFromThis(cx, vp);
129 0 : if (!p)
130 0 : return JS_FALSE;
131 :
132 0 : p->stop();
133 0 : return JS_TRUE;
134 : }
135 :
136 : static JSBool
137 0 : pm_reset(JSContext* cx, unsigned /*unused*/, jsval* vp)
138 : {
139 0 : PerfMeasurement* p = GetPMFromThis(cx, vp);
140 0 : if (!p)
141 0 : return JS_FALSE;
142 :
143 0 : p->reset();
144 0 : return JS_TRUE;
145 : }
146 :
147 : static JSBool
148 0 : pm_canMeasureSomething(JSContext* cx, unsigned /*unused*/, jsval* vp)
149 : {
150 0 : PerfMeasurement* p = GetPMFromThis(cx, vp);
151 0 : if (!p)
152 0 : return JS_FALSE;
153 :
154 0 : JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(p->canMeasureSomething()));
155 0 : return JS_TRUE;
156 : }
157 :
158 : const uint8_t PM_FATTRS = JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED;
159 : static JSFunctionSpec pm_fns[] = {
160 : JS_FN("start", pm_start, 0, PM_FATTRS),
161 : JS_FN("stop", pm_stop, 0, PM_FATTRS),
162 : JS_FN("reset", pm_reset, 0, PM_FATTRS),
163 : JS_FN("canMeasureSomething", pm_canMeasureSomething, 0, PM_FATTRS),
164 : JS_FS_END
165 : };
166 :
167 : const uint8_t PM_PATTRS =
168 : JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED;
169 :
170 : #define GETTER(name) \
171 : { #name, 0, PM_PATTRS, pm_get_##name, 0 }
172 :
173 : static JSPropertySpec pm_props[] = {
174 : GETTER(cpu_cycles),
175 : GETTER(instructions),
176 : GETTER(cache_references),
177 : GETTER(cache_misses),
178 : GETTER(branch_instructions),
179 : GETTER(branch_misses),
180 : GETTER(bus_cycles),
181 : GETTER(page_faults),
182 : GETTER(major_page_faults),
183 : GETTER(context_switches),
184 : GETTER(cpu_migrations),
185 : GETTER(eventsMeasured),
186 : {0,0,0,0,0}
187 : };
188 :
189 : #undef GETTER
190 :
191 : // If this were C++ these would be "static const" members.
192 :
193 : const uint8_t PM_CATTRS = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT;
194 :
195 : #define CONSTANT(name) { #name, PerfMeasurement::name }
196 :
197 : static const struct pm_const {
198 : const char *name;
199 : PerfMeasurement::EventMask value;
200 : } pm_consts[] = {
201 : CONSTANT(CPU_CYCLES),
202 : CONSTANT(INSTRUCTIONS),
203 : CONSTANT(CACHE_REFERENCES),
204 : CONSTANT(CACHE_MISSES),
205 : CONSTANT(BRANCH_INSTRUCTIONS),
206 : CONSTANT(BRANCH_MISSES),
207 : CONSTANT(BUS_CYCLES),
208 : CONSTANT(PAGE_FAULTS),
209 : CONSTANT(MAJOR_PAGE_FAULTS),
210 : CONSTANT(CONTEXT_SWITCHES),
211 : CONSTANT(CPU_MIGRATIONS),
212 : CONSTANT(ALL),
213 : CONSTANT(NUM_MEASURABLE_EVENTS),
214 : { 0, PerfMeasurement::EventMask(0) }
215 : };
216 :
217 : #undef CONSTANT
218 :
219 : static JSClass pm_class = {
220 : "PerfMeasurement", JSCLASS_HAS_PRIVATE,
221 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
222 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, pm_finalize,
223 : JSCLASS_NO_OPTIONAL_MEMBERS
224 : };
225 :
226 : // Helpers (declared above)
227 :
228 : static PerfMeasurement*
229 9 : GetPM(JSContext* cx, JSObject* obj, const char* fname)
230 : {
231 : PerfMeasurement* p = (PerfMeasurement*)
232 9 : JS_GetInstancePrivate(cx, obj, &pm_class, 0);
233 9 : if (p)
234 9 : return p;
235 :
236 : // JS_GetInstancePrivate only sets an exception if its last argument
237 : // is nonzero, so we have to do it by hand.
238 : JS_ReportErrorNumber(cx, js_GetErrorMessage, 0, JSMSG_INCOMPATIBLE_PROTO,
239 0 : pm_class.name, fname, JS_GetClass(obj)->name);
240 0 : return 0;
241 : }
242 :
243 : static PerfMeasurement*
244 0 : GetPMFromThis(JSContext* cx, jsval* vp)
245 : {
246 0 : JSObject* this_ = JS_THIS_OBJECT(cx, vp);
247 0 : if (!this_)
248 0 : return 0;
249 : return (PerfMeasurement*)
250 0 : JS_GetInstancePrivate(cx, this_, &pm_class, JS_ARGV(cx, vp));
251 : }
252 :
253 : namespace JS {
254 :
255 : JSObject*
256 22824 : RegisterPerfMeasurement(JSContext *cx, JSObject *global)
257 : {
258 45648 : js::RootedVarObject prototype(cx);
259 : prototype = JS_InitClass(cx, global, 0 /* parent */,
260 : &pm_class, pm_construct, 1,
261 22824 : pm_props, pm_fns, 0, 0);
262 22824 : if (!prototype)
263 0 : return 0;
264 :
265 45648 : js::RootedVarObject ctor(cx);
266 22824 : ctor = JS_GetConstructor(cx, prototype);
267 22824 : if (!ctor)
268 0 : return 0;
269 :
270 319536 : for (const pm_const *c = pm_consts; c->name; c++) {
271 593424 : if (!JS_DefineProperty(cx, ctor, c->name, INT_TO_JSVAL(c->value),
272 296712 : JS_PropertyStub, JS_StrictPropertyStub, PM_CATTRS))
273 0 : return 0;
274 : }
275 :
276 45648 : if (!JS_FreezeObject(cx, prototype) ||
277 22824 : !JS_FreezeObject(cx, ctor)) {
278 0 : return 0;
279 : }
280 :
281 22824 : return prototype;
282 : }
283 :
284 : PerfMeasurement*
285 0 : ExtractPerfMeasurement(jsval wrapper)
286 : {
287 0 : if (JSVAL_IS_PRIMITIVE(wrapper))
288 0 : return 0;
289 :
290 : // This is what JS_GetInstancePrivate does internally. We can't
291 : // call JS_anything from here, because we don't have a JSContext.
292 0 : JSObject *obj = JSVAL_TO_OBJECT(wrapper);
293 0 : if (obj->getClass() != js::Valueify(&pm_class))
294 0 : return 0;
295 :
296 0 : return (PerfMeasurement*) obj->getPrivate();
297 : }
298 :
299 : } // namespace JS
|