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