Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "perf/jsperf.h"
8 #include "jscntxt.h" /* for error messages */
9 #include "jsobj.h" /* for unwrapping without a context */
11 using namespace JS;
13 // You cannot forward-declare a static object in C++, so instead
14 // we have to forward-declare the helper function that refers to it.
15 static PerfMeasurement* GetPM(JSContext* cx, JS::HandleValue value, const char* fname);
17 // Property access
19 #define GETTER(name) \
20 static bool \
21 pm_get_##name(JSContext* cx, unsigned argc, Value *vp) \
22 { \
23 CallArgs args = CallArgsFromVp(argc, vp); \
24 PerfMeasurement* p = GetPM(cx, args.thisv(), #name); \
25 if (!p) \
26 return false; \
27 args.rval().setNumber(double(p->name)); \
28 return true; \
29 }
31 GETTER(cpu_cycles)
32 GETTER(instructions)
33 GETTER(cache_references)
34 GETTER(cache_misses)
35 GETTER(branch_instructions)
36 GETTER(branch_misses)
37 GETTER(bus_cycles)
38 GETTER(page_faults)
39 GETTER(major_page_faults)
40 GETTER(context_switches)
41 GETTER(cpu_migrations)
42 GETTER(eventsMeasured)
44 #undef GETTER
46 // Calls
48 static bool
49 pm_start(JSContext* cx, unsigned argc, jsval* vp)
50 {
51 CallArgs args = CallArgsFromVp(argc, vp);
52 PerfMeasurement* p = GetPM(cx, args.thisv(), "start");
53 if (!p)
54 return false;
56 p->start();
57 args.rval().setUndefined();
58 return true;
59 }
61 static bool
62 pm_stop(JSContext* cx, unsigned argc, jsval* vp)
63 {
64 CallArgs args = CallArgsFromVp(argc, vp);
65 PerfMeasurement* p = GetPM(cx, args.thisv(), "stop");
66 if (!p)
67 return false;
69 p->stop();
70 args.rval().setUndefined();
71 return true;
72 }
74 static bool
75 pm_reset(JSContext* cx, unsigned argc, jsval* vp)
76 {
77 CallArgs args = CallArgsFromVp(argc, vp);
78 PerfMeasurement* p = GetPM(cx, args.thisv(), "reset");
79 if (!p)
80 return false;
82 p->reset();
83 args.rval().setUndefined();
84 return true;
85 }
87 static bool
88 pm_canMeasureSomething(JSContext* cx, unsigned argc, jsval* vp)
89 {
90 CallArgs args = CallArgsFromVp(argc, vp);
91 PerfMeasurement* p = GetPM(cx, args.thisv(), "canMeasureSomething");
92 if (!p)
93 return false;
95 args.rval().setBoolean(p->canMeasureSomething());
96 return true;
97 }
99 static const uint8_t PM_FATTRS = JSPROP_READONLY | JSPROP_PERMANENT;
100 static const JSFunctionSpec pm_fns[] = {
101 JS_FN("start", pm_start, 0, PM_FATTRS),
102 JS_FN("stop", pm_stop, 0, PM_FATTRS),
103 JS_FN("reset", pm_reset, 0, PM_FATTRS),
104 JS_FN("canMeasureSomething", pm_canMeasureSomething, 0, PM_FATTRS),
105 JS_FS_END
106 };
108 static const uint8_t PM_PATTRS =
109 JSPROP_ENUMERATE | JSPROP_PERMANENT;
111 #define GETTER(name) \
112 JS_PSG(#name, pm_get_##name, PM_PATTRS)
114 static const JSPropertySpec pm_props[] = {
115 GETTER(cpu_cycles),
116 GETTER(instructions),
117 GETTER(cache_references),
118 GETTER(cache_misses),
119 GETTER(branch_instructions),
120 GETTER(branch_misses),
121 GETTER(bus_cycles),
122 GETTER(page_faults),
123 GETTER(major_page_faults),
124 GETTER(context_switches),
125 GETTER(cpu_migrations),
126 GETTER(eventsMeasured),
127 JS_PS_END
128 };
130 #undef GETTER
132 // If this were C++ these would be "static const" members.
134 static const uint8_t PM_CATTRS = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT;
136 #define CONSTANT(name) { #name, PerfMeasurement::name }
138 static const struct pm_const {
139 const char *name;
140 PerfMeasurement::EventMask value;
141 } pm_consts[] = {
142 CONSTANT(CPU_CYCLES),
143 CONSTANT(INSTRUCTIONS),
144 CONSTANT(CACHE_REFERENCES),
145 CONSTANT(CACHE_MISSES),
146 CONSTANT(BRANCH_INSTRUCTIONS),
147 CONSTANT(BRANCH_MISSES),
148 CONSTANT(BUS_CYCLES),
149 CONSTANT(PAGE_FAULTS),
150 CONSTANT(MAJOR_PAGE_FAULTS),
151 CONSTANT(CONTEXT_SWITCHES),
152 CONSTANT(CPU_MIGRATIONS),
153 CONSTANT(ALL),
154 CONSTANT(NUM_MEASURABLE_EVENTS),
155 { 0, PerfMeasurement::EventMask(0) }
156 };
158 #undef CONSTANT
160 static bool pm_construct(JSContext* cx, unsigned argc, jsval* vp);
161 static void pm_finalize(JSFreeOp* fop, JSObject* obj);
163 static const JSClass pm_class = {
164 "PerfMeasurement", JSCLASS_HAS_PRIVATE,
165 JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
166 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, pm_finalize
167 };
169 // Constructor and destructor
171 static bool
172 pm_construct(JSContext* cx, unsigned argc, jsval* vp)
173 {
174 CallArgs args = CallArgsFromVp(argc, vp);
176 uint32_t mask;
177 if (!args.hasDefined(0)) {
178 js_ReportMissingArg(cx, args.calleev(), 0);
179 return false;
180 }
181 if (!JS::ToUint32(cx, args[0], &mask))
182 return false;
184 JS::RootedObject obj(cx, JS_NewObjectForConstructor(cx, &pm_class, args));
185 if (!obj)
186 return false;
188 if (!JS_FreezeObject(cx, obj))
189 return false;
191 PerfMeasurement* p = cx->new_<PerfMeasurement>(PerfMeasurement::EventMask(mask));
192 if (!p) {
193 JS_ReportOutOfMemory(cx);
194 return false;
195 }
197 JS_SetPrivate(obj, p);
198 args.rval().setObject(*obj);
199 return true;
200 }
202 static void
203 pm_finalize(JSFreeOp* fop, JSObject* obj)
204 {
205 js::FreeOp::get(fop)->delete_(static_cast<PerfMeasurement*>(JS_GetPrivate(obj)));
206 }
208 // Helpers (declared above)
210 static PerfMeasurement*
211 GetPM(JSContext* cx, JS::HandleValue value, const char* fname)
212 {
213 if (!value.isObject()) {
214 JS_ReportErrorNumber(cx, js_GetErrorMessage, 0, JSMSG_NOT_NONNULL_OBJECT);
215 return nullptr;
216 }
217 RootedObject obj(cx, &value.toObject());
218 PerfMeasurement* p = (PerfMeasurement*)
219 JS_GetInstancePrivate(cx, obj, &pm_class, nullptr);
220 if (p)
221 return p;
223 // JS_GetInstancePrivate only sets an exception if its last argument
224 // is nonzero, so we have to do it by hand.
225 JS_ReportErrorNumber(cx, js_GetErrorMessage, 0, JSMSG_INCOMPATIBLE_PROTO,
226 pm_class.name, fname, JS_GetClass(obj)->name);
227 return nullptr;
228 }
230 namespace JS {
232 JSObject*
233 RegisterPerfMeasurement(JSContext *cx, HandleObject globalArg)
234 {
235 RootedObject global(cx, globalArg);
236 RootedObject prototype(cx);
237 prototype = JS_InitClass(cx, global, js::NullPtr() /* parent */,
238 &pm_class, pm_construct, 1,
239 pm_props, pm_fns, 0, 0);
240 if (!prototype)
241 return 0;
243 RootedObject ctor(cx);
244 ctor = JS_GetConstructor(cx, prototype);
245 if (!ctor)
246 return 0;
248 for (const pm_const *c = pm_consts; c->name; c++) {
249 if (!JS_DefineProperty(cx, ctor, c->name, c->value, PM_CATTRS,
250 JS_PropertyStub, JS_StrictPropertyStub))
251 return 0;
252 }
254 if (!JS_FreezeObject(cx, prototype) ||
255 !JS_FreezeObject(cx, ctor)) {
256 return 0;
257 }
259 return prototype;
260 }
262 PerfMeasurement*
263 ExtractPerfMeasurement(jsval wrapper)
264 {
265 if (JSVAL_IS_PRIMITIVE(wrapper))
266 return 0;
268 // This is what JS_GetInstancePrivate does internally. We can't
269 // call JS_anything from here, because we don't have a JSContext.
270 JSObject *obj = JSVAL_TO_OBJECT(wrapper);
271 if (obj->getClass() != js::Valueify(&pm_class))
272 return 0;
274 return (PerfMeasurement*) obj->getPrivate();
275 }
277 } // namespace JS