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 | * vim: set ts=8 sts=4 et sw=4 tw=99: |
michael@0 | 3 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | |
michael@0 | 8 | #include "vm/SavedStacks.h" |
michael@0 | 9 | |
michael@0 | 10 | #include "jscompartment.h" |
michael@0 | 11 | #include "jsnum.h" |
michael@0 | 12 | |
michael@0 | 13 | #include "vm/GlobalObject.h" |
michael@0 | 14 | #include "vm/StringBuffer.h" |
michael@0 | 15 | |
michael@0 | 16 | #include "jsobjinlines.h" |
michael@0 | 17 | |
michael@0 | 18 | using mozilla::AddToHash; |
michael@0 | 19 | using mozilla::HashString; |
michael@0 | 20 | |
michael@0 | 21 | namespace js { |
michael@0 | 22 | |
michael@0 | 23 | /* static */ HashNumber |
michael@0 | 24 | SavedFrame::HashPolicy::hash(const Lookup &lookup) |
michael@0 | 25 | { |
michael@0 | 26 | return AddToHash(HashString(lookup.source->chars(), lookup.source->length()), |
michael@0 | 27 | lookup.line, |
michael@0 | 28 | lookup.column, |
michael@0 | 29 | lookup.functionDisplayName, |
michael@0 | 30 | SavedFramePtrHasher::hash(lookup.parent), |
michael@0 | 31 | JSPrincipalsPtrHasher::hash(lookup.principals)); |
michael@0 | 32 | } |
michael@0 | 33 | |
michael@0 | 34 | /* static */ bool |
michael@0 | 35 | SavedFrame::HashPolicy::match(SavedFrame *existing, const Lookup &lookup) |
michael@0 | 36 | { |
michael@0 | 37 | if (existing->getLine() != lookup.line) |
michael@0 | 38 | return false; |
michael@0 | 39 | |
michael@0 | 40 | if (existing->getColumn() != lookup.column) |
michael@0 | 41 | return false; |
michael@0 | 42 | |
michael@0 | 43 | if (existing->getParent() != lookup.parent) |
michael@0 | 44 | return false; |
michael@0 | 45 | |
michael@0 | 46 | if (existing->getPrincipals() != lookup.principals) |
michael@0 | 47 | return false; |
michael@0 | 48 | |
michael@0 | 49 | JSAtom *source = existing->getSource(); |
michael@0 | 50 | if (source->length() != lookup.source->length()) |
michael@0 | 51 | return false; |
michael@0 | 52 | if (source != lookup.source) |
michael@0 | 53 | return false; |
michael@0 | 54 | |
michael@0 | 55 | JSAtom *functionDisplayName = existing->getFunctionDisplayName(); |
michael@0 | 56 | if (functionDisplayName) { |
michael@0 | 57 | if (!lookup.functionDisplayName) |
michael@0 | 58 | return false; |
michael@0 | 59 | if (functionDisplayName->length() != lookup.functionDisplayName->length()) |
michael@0 | 60 | return false; |
michael@0 | 61 | if (0 != CompareAtoms(functionDisplayName, lookup.functionDisplayName)) |
michael@0 | 62 | return false; |
michael@0 | 63 | } else if (lookup.functionDisplayName) { |
michael@0 | 64 | return false; |
michael@0 | 65 | } |
michael@0 | 66 | |
michael@0 | 67 | return true; |
michael@0 | 68 | } |
michael@0 | 69 | |
michael@0 | 70 | /* static */ void |
michael@0 | 71 | SavedFrame::HashPolicy::rekey(Key &key, const Key &newKey) |
michael@0 | 72 | { |
michael@0 | 73 | key = newKey; |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | /* static */ const Class SavedFrame::class_ = { |
michael@0 | 77 | "SavedFrame", |
michael@0 | 78 | JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS | |
michael@0 | 79 | JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT), |
michael@0 | 80 | |
michael@0 | 81 | JS_PropertyStub, // addProperty |
michael@0 | 82 | JS_DeletePropertyStub, // delProperty |
michael@0 | 83 | JS_PropertyStub, // getProperty |
michael@0 | 84 | JS_StrictPropertyStub, // setProperty |
michael@0 | 85 | JS_EnumerateStub, // enumerate |
michael@0 | 86 | JS_ResolveStub, // resolve |
michael@0 | 87 | JS_ConvertStub, // convert |
michael@0 | 88 | |
michael@0 | 89 | SavedFrame::finalize // finalize |
michael@0 | 90 | }; |
michael@0 | 91 | |
michael@0 | 92 | /* static */ void |
michael@0 | 93 | SavedFrame::finalize(FreeOp *fop, JSObject *obj) |
michael@0 | 94 | { |
michael@0 | 95 | JSPrincipals *p = obj->as<SavedFrame>().getPrincipals(); |
michael@0 | 96 | if (p) { |
michael@0 | 97 | JSRuntime *rt = obj->runtimeFromMainThread(); |
michael@0 | 98 | JS_DropPrincipals(rt, p); |
michael@0 | 99 | } |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | JSAtom * |
michael@0 | 103 | SavedFrame::getSource() |
michael@0 | 104 | { |
michael@0 | 105 | const Value &v = getReservedSlot(JSSLOT_SOURCE); |
michael@0 | 106 | JSString *s = v.toString(); |
michael@0 | 107 | return &s->asAtom(); |
michael@0 | 108 | } |
michael@0 | 109 | |
michael@0 | 110 | size_t |
michael@0 | 111 | SavedFrame::getLine() |
michael@0 | 112 | { |
michael@0 | 113 | const Value &v = getReservedSlot(JSSLOT_LINE); |
michael@0 | 114 | return v.toInt32(); |
michael@0 | 115 | } |
michael@0 | 116 | |
michael@0 | 117 | size_t |
michael@0 | 118 | SavedFrame::getColumn() |
michael@0 | 119 | { |
michael@0 | 120 | const Value &v = getReservedSlot(JSSLOT_COLUMN); |
michael@0 | 121 | return v.toInt32(); |
michael@0 | 122 | } |
michael@0 | 123 | |
michael@0 | 124 | JSAtom * |
michael@0 | 125 | SavedFrame::getFunctionDisplayName() |
michael@0 | 126 | { |
michael@0 | 127 | const Value &v = getReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME); |
michael@0 | 128 | if (v.isNull()) |
michael@0 | 129 | return nullptr; |
michael@0 | 130 | JSString *s = v.toString(); |
michael@0 | 131 | return &s->asAtom(); |
michael@0 | 132 | } |
michael@0 | 133 | |
michael@0 | 134 | SavedFrame * |
michael@0 | 135 | SavedFrame::getParent() |
michael@0 | 136 | { |
michael@0 | 137 | const Value &v = getReservedSlot(JSSLOT_PARENT); |
michael@0 | 138 | return v.isObject() ? &v.toObject().as<SavedFrame>() : nullptr; |
michael@0 | 139 | } |
michael@0 | 140 | |
michael@0 | 141 | JSPrincipals * |
michael@0 | 142 | SavedFrame::getPrincipals() |
michael@0 | 143 | { |
michael@0 | 144 | const Value &v = getReservedSlot(JSSLOT_PRINCIPALS); |
michael@0 | 145 | if (v.isUndefined()) |
michael@0 | 146 | return nullptr; |
michael@0 | 147 | return static_cast<JSPrincipals *>(v.toPrivate()); |
michael@0 | 148 | } |
michael@0 | 149 | |
michael@0 | 150 | void |
michael@0 | 151 | SavedFrame::initFromLookup(Lookup &lookup) |
michael@0 | 152 | { |
michael@0 | 153 | JS_ASSERT(lookup.source); |
michael@0 | 154 | JS_ASSERT(getReservedSlot(JSSLOT_SOURCE).isUndefined()); |
michael@0 | 155 | setReservedSlot(JSSLOT_SOURCE, StringValue(lookup.source)); |
michael@0 | 156 | |
michael@0 | 157 | setReservedSlot(JSSLOT_LINE, NumberValue(lookup.line)); |
michael@0 | 158 | setReservedSlot(JSSLOT_COLUMN, NumberValue(lookup.column)); |
michael@0 | 159 | setReservedSlot(JSSLOT_FUNCTIONDISPLAYNAME, |
michael@0 | 160 | lookup.functionDisplayName |
michael@0 | 161 | ? StringValue(lookup.functionDisplayName) |
michael@0 | 162 | : NullValue()); |
michael@0 | 163 | setReservedSlot(JSSLOT_PARENT, ObjectOrNullValue(lookup.parent)); |
michael@0 | 164 | setReservedSlot(JSSLOT_PRIVATE_PARENT, PrivateValue(lookup.parent)); |
michael@0 | 165 | |
michael@0 | 166 | JS_ASSERT(getReservedSlot(JSSLOT_PRINCIPALS).isUndefined()); |
michael@0 | 167 | if (lookup.principals) |
michael@0 | 168 | JS_HoldPrincipals(lookup.principals); |
michael@0 | 169 | setReservedSlot(JSSLOT_PRINCIPALS, PrivateValue(lookup.principals)); |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | bool |
michael@0 | 173 | SavedFrame::parentMoved() |
michael@0 | 174 | { |
michael@0 | 175 | const Value &v = getReservedSlot(JSSLOT_PRIVATE_PARENT); |
michael@0 | 176 | JSObject *p = static_cast<JSObject *>(v.toPrivate()); |
michael@0 | 177 | return p == getParent(); |
michael@0 | 178 | } |
michael@0 | 179 | |
michael@0 | 180 | void |
michael@0 | 181 | SavedFrame::updatePrivateParent() |
michael@0 | 182 | { |
michael@0 | 183 | setReservedSlot(JSSLOT_PRIVATE_PARENT, PrivateValue(getParent())); |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | bool |
michael@0 | 187 | SavedFrame::isSelfHosted() |
michael@0 | 188 | { |
michael@0 | 189 | JSAtom *source = getSource(); |
michael@0 | 190 | return StringEqualsAscii(source, "self-hosted"); |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | /* static */ bool |
michael@0 | 194 | SavedFrame::construct(JSContext *cx, unsigned argc, Value *vp) |
michael@0 | 195 | { |
michael@0 | 196 | JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR, |
michael@0 | 197 | "SavedFrame"); |
michael@0 | 198 | return false; |
michael@0 | 199 | } |
michael@0 | 200 | |
michael@0 | 201 | /* static */ SavedFrame * |
michael@0 | 202 | SavedFrame::checkThis(JSContext *cx, CallArgs &args, const char *fnName) |
michael@0 | 203 | { |
michael@0 | 204 | const Value &thisValue = args.thisv(); |
michael@0 | 205 | |
michael@0 | 206 | if (!thisValue.isObject()) { |
michael@0 | 207 | JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT); |
michael@0 | 208 | return nullptr; |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | JSObject &thisObject = thisValue.toObject(); |
michael@0 | 212 | if (!thisObject.is<SavedFrame>()) { |
michael@0 | 213 | JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, |
michael@0 | 214 | SavedFrame::class_.name, fnName, thisObject.getClass()->name); |
michael@0 | 215 | return nullptr; |
michael@0 | 216 | } |
michael@0 | 217 | |
michael@0 | 218 | // Check for SavedFrame.prototype, which has the same class as SavedFrame |
michael@0 | 219 | // instances, however doesn't actually represent a captured stack frame. It |
michael@0 | 220 | // is the only object that is<SavedFrame>() but doesn't have a source. |
michael@0 | 221 | if (thisObject.getReservedSlot(JSSLOT_SOURCE).isNull()) { |
michael@0 | 222 | JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, |
michael@0 | 223 | SavedFrame::class_.name, fnName, "prototype object"); |
michael@0 | 224 | return nullptr; |
michael@0 | 225 | } |
michael@0 | 226 | |
michael@0 | 227 | return &thisObject.as<SavedFrame>(); |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | // Get the SavedFrame * from the current this value and handle any errors that |
michael@0 | 231 | // might occur therein. |
michael@0 | 232 | // |
michael@0 | 233 | // These parameters must already exist when calling this macro: |
michael@0 | 234 | // - JSContext *cx |
michael@0 | 235 | // - unsigned argc |
michael@0 | 236 | // - Value *vp |
michael@0 | 237 | // - const char *fnName |
michael@0 | 238 | // These parameters will be defined after calling this macro: |
michael@0 | 239 | // - CallArgs args |
michael@0 | 240 | // - Rooted<SavedFrame *> frame (will be non-null) |
michael@0 | 241 | #define THIS_SAVEDFRAME(cx, argc, vp, fnName, args, frame) \ |
michael@0 | 242 | CallArgs args = CallArgsFromVp(argc, vp); \ |
michael@0 | 243 | Rooted<SavedFrame *> frame(cx, checkThis(cx, args, fnName)); \ |
michael@0 | 244 | if (!frame) \ |
michael@0 | 245 | return false |
michael@0 | 246 | |
michael@0 | 247 | /* static */ bool |
michael@0 | 248 | SavedFrame::sourceProperty(JSContext *cx, unsigned argc, Value *vp) |
michael@0 | 249 | { |
michael@0 | 250 | THIS_SAVEDFRAME(cx, argc, vp, "(get source)", args, frame); |
michael@0 | 251 | args.rval().setString(frame->getSource()); |
michael@0 | 252 | return true; |
michael@0 | 253 | } |
michael@0 | 254 | |
michael@0 | 255 | /* static */ bool |
michael@0 | 256 | SavedFrame::lineProperty(JSContext *cx, unsigned argc, Value *vp) |
michael@0 | 257 | { |
michael@0 | 258 | THIS_SAVEDFRAME(cx, argc, vp, "(get line)", args, frame); |
michael@0 | 259 | uint32_t line = frame->getLine(); |
michael@0 | 260 | args.rval().setNumber(line); |
michael@0 | 261 | return true; |
michael@0 | 262 | } |
michael@0 | 263 | |
michael@0 | 264 | /* static */ bool |
michael@0 | 265 | SavedFrame::columnProperty(JSContext *cx, unsigned argc, Value *vp) |
michael@0 | 266 | { |
michael@0 | 267 | THIS_SAVEDFRAME(cx, argc, vp, "(get column)", args, frame); |
michael@0 | 268 | uint32_t column = frame->getColumn(); |
michael@0 | 269 | args.rval().setNumber(column); |
michael@0 | 270 | return true; |
michael@0 | 271 | } |
michael@0 | 272 | |
michael@0 | 273 | /* static */ bool |
michael@0 | 274 | SavedFrame::functionDisplayNameProperty(JSContext *cx, unsigned argc, Value *vp) |
michael@0 | 275 | { |
michael@0 | 276 | THIS_SAVEDFRAME(cx, argc, vp, "(get functionDisplayName)", args, frame); |
michael@0 | 277 | RootedAtom name(cx, frame->getFunctionDisplayName()); |
michael@0 | 278 | if (name) |
michael@0 | 279 | args.rval().setString(name); |
michael@0 | 280 | else |
michael@0 | 281 | args.rval().setNull(); |
michael@0 | 282 | return true; |
michael@0 | 283 | } |
michael@0 | 284 | |
michael@0 | 285 | /* static */ bool |
michael@0 | 286 | SavedFrame::parentProperty(JSContext *cx, unsigned argc, Value *vp) |
michael@0 | 287 | { |
michael@0 | 288 | THIS_SAVEDFRAME(cx, argc, vp, "(get parent)", args, frame); |
michael@0 | 289 | JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes; |
michael@0 | 290 | JSPrincipals *principals = cx->compartment()->principals; |
michael@0 | 291 | |
michael@0 | 292 | do |
michael@0 | 293 | frame = frame->getParent(); |
michael@0 | 294 | while (frame && principals && subsumes && |
michael@0 | 295 | !subsumes(principals, frame->getPrincipals())); |
michael@0 | 296 | |
michael@0 | 297 | args.rval().setObjectOrNull(frame); |
michael@0 | 298 | return true; |
michael@0 | 299 | } |
michael@0 | 300 | |
michael@0 | 301 | /* static */ const JSPropertySpec SavedFrame::properties[] = { |
michael@0 | 302 | JS_PSG("source", SavedFrame::sourceProperty, 0), |
michael@0 | 303 | JS_PSG("line", SavedFrame::lineProperty, 0), |
michael@0 | 304 | JS_PSG("column", SavedFrame::columnProperty, 0), |
michael@0 | 305 | JS_PSG("functionDisplayName", SavedFrame::functionDisplayNameProperty, 0), |
michael@0 | 306 | JS_PSG("parent", SavedFrame::parentProperty, 0), |
michael@0 | 307 | JS_PS_END |
michael@0 | 308 | }; |
michael@0 | 309 | |
michael@0 | 310 | /* static */ bool |
michael@0 | 311 | SavedFrame::toStringMethod(JSContext *cx, unsigned argc, Value *vp) |
michael@0 | 312 | { |
michael@0 | 313 | THIS_SAVEDFRAME(cx, argc, vp, "toString", args, frame); |
michael@0 | 314 | StringBuffer sb(cx); |
michael@0 | 315 | JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes; |
michael@0 | 316 | JSPrincipals *principals = cx->compartment()->principals; |
michael@0 | 317 | |
michael@0 | 318 | do { |
michael@0 | 319 | if (principals && subsumes && !subsumes(principals, frame->getPrincipals())) |
michael@0 | 320 | continue; |
michael@0 | 321 | if (frame->isSelfHosted()) |
michael@0 | 322 | continue; |
michael@0 | 323 | |
michael@0 | 324 | RootedAtom name(cx, frame->getFunctionDisplayName()); |
michael@0 | 325 | if ((name && !sb.append(name)) |
michael@0 | 326 | || !sb.append('@') |
michael@0 | 327 | || !sb.append(frame->getSource()) |
michael@0 | 328 | || !sb.append(':') |
michael@0 | 329 | || !NumberValueToStringBuffer(cx, NumberValue(frame->getLine()), sb) |
michael@0 | 330 | || !sb.append(':') |
michael@0 | 331 | || !NumberValueToStringBuffer(cx, NumberValue(frame->getColumn()), sb) |
michael@0 | 332 | || !sb.append('\n')) { |
michael@0 | 333 | return false; |
michael@0 | 334 | } |
michael@0 | 335 | } while ((frame = frame->getParent())); |
michael@0 | 336 | |
michael@0 | 337 | args.rval().setString(sb.finishString()); |
michael@0 | 338 | return true; |
michael@0 | 339 | } |
michael@0 | 340 | |
michael@0 | 341 | /* static */ const JSFunctionSpec SavedFrame::methods[] = { |
michael@0 | 342 | JS_FN("toString", SavedFrame::toStringMethod, 0, 0), |
michael@0 | 343 | JS_FS_END |
michael@0 | 344 | }; |
michael@0 | 345 | |
michael@0 | 346 | bool |
michael@0 | 347 | SavedStacks::init() |
michael@0 | 348 | { |
michael@0 | 349 | return frames.init(); |
michael@0 | 350 | } |
michael@0 | 351 | |
michael@0 | 352 | bool |
michael@0 | 353 | SavedStacks::saveCurrentStack(JSContext *cx, MutableHandle<SavedFrame*> frame) |
michael@0 | 354 | { |
michael@0 | 355 | JS_ASSERT(initialized()); |
michael@0 | 356 | JS_ASSERT(&cx->compartment()->savedStacks() == this); |
michael@0 | 357 | |
michael@0 | 358 | ScriptFrameIter iter(cx); |
michael@0 | 359 | return insertFrames(cx, iter, frame); |
michael@0 | 360 | } |
michael@0 | 361 | |
michael@0 | 362 | void |
michael@0 | 363 | SavedStacks::sweep(JSRuntime *rt) |
michael@0 | 364 | { |
michael@0 | 365 | if (frames.initialized()) { |
michael@0 | 366 | for (SavedFrame::Set::Enum e(frames); !e.empty(); e.popFront()) { |
michael@0 | 367 | JSObject *obj = static_cast<JSObject *>(e.front()); |
michael@0 | 368 | JSObject *temp = obj; |
michael@0 | 369 | |
michael@0 | 370 | if (IsObjectAboutToBeFinalized(&obj)) { |
michael@0 | 371 | e.removeFront(); |
michael@0 | 372 | } else { |
michael@0 | 373 | SavedFrame *frame = &obj->as<SavedFrame>(); |
michael@0 | 374 | bool parentMoved = frame->parentMoved(); |
michael@0 | 375 | |
michael@0 | 376 | if (parentMoved) { |
michael@0 | 377 | frame->updatePrivateParent(); |
michael@0 | 378 | } |
michael@0 | 379 | |
michael@0 | 380 | if (obj != temp || parentMoved) { |
michael@0 | 381 | Rooted<SavedFrame*> parent(rt, frame->getParent()); |
michael@0 | 382 | e.rekeyFront(SavedFrame::Lookup(frame->getSource(), |
michael@0 | 383 | frame->getLine(), |
michael@0 | 384 | frame->getColumn(), |
michael@0 | 385 | frame->getFunctionDisplayName(), |
michael@0 | 386 | parent, |
michael@0 | 387 | frame->getPrincipals()), |
michael@0 | 388 | frame); |
michael@0 | 389 | } |
michael@0 | 390 | } |
michael@0 | 391 | } |
michael@0 | 392 | } |
michael@0 | 393 | |
michael@0 | 394 | if (savedFrameProto && IsObjectAboutToBeFinalized(&savedFrameProto)) { |
michael@0 | 395 | savedFrameProto = nullptr; |
michael@0 | 396 | } |
michael@0 | 397 | } |
michael@0 | 398 | |
michael@0 | 399 | uint32_t |
michael@0 | 400 | SavedStacks::count() |
michael@0 | 401 | { |
michael@0 | 402 | JS_ASSERT(initialized()); |
michael@0 | 403 | return frames.count(); |
michael@0 | 404 | } |
michael@0 | 405 | |
michael@0 | 406 | void |
michael@0 | 407 | SavedStacks::clear() |
michael@0 | 408 | { |
michael@0 | 409 | frames.clear(); |
michael@0 | 410 | } |
michael@0 | 411 | |
michael@0 | 412 | size_t |
michael@0 | 413 | SavedStacks::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) |
michael@0 | 414 | { |
michael@0 | 415 | return frames.sizeOfExcludingThis(mallocSizeOf); |
michael@0 | 416 | } |
michael@0 | 417 | |
michael@0 | 418 | bool |
michael@0 | 419 | SavedStacks::insertFrames(JSContext *cx, ScriptFrameIter &iter, MutableHandle<SavedFrame*> frame) |
michael@0 | 420 | { |
michael@0 | 421 | if (iter.done()) { |
michael@0 | 422 | frame.set(nullptr); |
michael@0 | 423 | return true; |
michael@0 | 424 | } |
michael@0 | 425 | |
michael@0 | 426 | ScriptFrameIter thisFrame(iter); |
michael@0 | 427 | Rooted<SavedFrame*> parentFrame(cx); |
michael@0 | 428 | if (!insertFrames(cx, ++iter, &parentFrame)) |
michael@0 | 429 | return false; |
michael@0 | 430 | |
michael@0 | 431 | RootedScript script(cx, thisFrame.script()); |
michael@0 | 432 | RootedFunction callee(cx, thisFrame.maybeCallee()); |
michael@0 | 433 | const char *filename = script->filename(); |
michael@0 | 434 | RootedAtom source(cx, Atomize(cx, filename, strlen(filename))); |
michael@0 | 435 | if (!source) |
michael@0 | 436 | return false; |
michael@0 | 437 | uint32_t column; |
michael@0 | 438 | uint32_t line = PCToLineNumber(script, thisFrame.pc(), &column); |
michael@0 | 439 | |
michael@0 | 440 | SavedFrame::Lookup lookup(source, |
michael@0 | 441 | line, |
michael@0 | 442 | column, |
michael@0 | 443 | callee ? callee->displayAtom() : nullptr, |
michael@0 | 444 | parentFrame, |
michael@0 | 445 | thisFrame.compartment()->principals); |
michael@0 | 446 | |
michael@0 | 447 | frame.set(getOrCreateSavedFrame(cx, lookup)); |
michael@0 | 448 | return frame.address() != nullptr; |
michael@0 | 449 | } |
michael@0 | 450 | |
michael@0 | 451 | SavedFrame * |
michael@0 | 452 | SavedStacks::getOrCreateSavedFrame(JSContext *cx, SavedFrame::Lookup &lookup) |
michael@0 | 453 | { |
michael@0 | 454 | SavedFrame::Set::AddPtr p = frames.lookupForAdd(lookup); |
michael@0 | 455 | if (p) |
michael@0 | 456 | return *p; |
michael@0 | 457 | |
michael@0 | 458 | Rooted<SavedFrame *> frame(cx, createFrameFromLookup(cx, lookup)); |
michael@0 | 459 | if (!frame) |
michael@0 | 460 | return nullptr; |
michael@0 | 461 | |
michael@0 | 462 | if (!frames.relookupOrAdd(p, lookup, frame)) |
michael@0 | 463 | return nullptr; |
michael@0 | 464 | |
michael@0 | 465 | return frame; |
michael@0 | 466 | } |
michael@0 | 467 | |
michael@0 | 468 | JSObject * |
michael@0 | 469 | SavedStacks::getOrCreateSavedFramePrototype(JSContext *cx) |
michael@0 | 470 | { |
michael@0 | 471 | if (savedFrameProto) |
michael@0 | 472 | return savedFrameProto; |
michael@0 | 473 | |
michael@0 | 474 | Rooted<GlobalObject *> global(cx, cx->compartment()->maybeGlobal()); |
michael@0 | 475 | if (!global) |
michael@0 | 476 | return nullptr; |
michael@0 | 477 | |
michael@0 | 478 | savedFrameProto = js_InitClass(cx, global, global->getOrCreateObjectPrototype(cx), |
michael@0 | 479 | &SavedFrame::class_, SavedFrame::construct, 0, |
michael@0 | 480 | SavedFrame::properties, SavedFrame::methods, nullptr, nullptr); |
michael@0 | 481 | // The only object with the SavedFrame::class_ that doesn't have a source |
michael@0 | 482 | // should be the prototype. |
michael@0 | 483 | savedFrameProto->setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue()); |
michael@0 | 484 | return savedFrameProto; |
michael@0 | 485 | } |
michael@0 | 486 | |
michael@0 | 487 | SavedFrame * |
michael@0 | 488 | SavedStacks::createFrameFromLookup(JSContext *cx, SavedFrame::Lookup &lookup) |
michael@0 | 489 | { |
michael@0 | 490 | RootedObject proto(cx, getOrCreateSavedFramePrototype(cx)); |
michael@0 | 491 | if (!proto) |
michael@0 | 492 | return nullptr; |
michael@0 | 493 | |
michael@0 | 494 | JS_ASSERT(proto->compartment() == cx->compartment()); |
michael@0 | 495 | |
michael@0 | 496 | RootedObject global(cx, cx->compartment()->maybeGlobal()); |
michael@0 | 497 | if (!global) |
michael@0 | 498 | return nullptr; |
michael@0 | 499 | |
michael@0 | 500 | JS_ASSERT(global->compartment() == cx->compartment()); |
michael@0 | 501 | |
michael@0 | 502 | RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto, global)); |
michael@0 | 503 | if (!frameObj) |
michael@0 | 504 | return nullptr; |
michael@0 | 505 | |
michael@0 | 506 | SavedFrame &f = frameObj->as<SavedFrame>(); |
michael@0 | 507 | f.initFromLookup(lookup); |
michael@0 | 508 | |
michael@0 | 509 | return &f; |
michael@0 | 510 | } |
michael@0 | 511 | |
michael@0 | 512 | } /* namespace js */ |