js/jsd/jsd_stak.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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 * JavaScript Debugging support - Call stack support
michael@0 9 */
michael@0 10
michael@0 11 #include "jsd.h"
michael@0 12 #include "jsfriendapi.h"
michael@0 13 #include "nsCxPusher.h"
michael@0 14
michael@0 15 using mozilla::AutoPushJSContext;
michael@0 16
michael@0 17 #ifdef DEBUG
michael@0 18 void JSD_ASSERT_VALID_THREAD_STATE(JSDThreadState* jsdthreadstate)
michael@0 19 {
michael@0 20 MOZ_ASSERT(jsdthreadstate);
michael@0 21 MOZ_ASSERT(jsdthreadstate->stackDepth > 0);
michael@0 22 }
michael@0 23
michael@0 24 void JSD_ASSERT_VALID_STACK_FRAME(JSDStackFrameInfo* jsdframe)
michael@0 25 {
michael@0 26 MOZ_ASSERT(jsdframe);
michael@0 27 MOZ_ASSERT(jsdframe->jsdthreadstate);
michael@0 28 }
michael@0 29 #endif
michael@0 30
michael@0 31 static JSDStackFrameInfo*
michael@0 32 _addNewFrame(JSDContext* jsdc,
michael@0 33 JSDThreadState* jsdthreadstate,
michael@0 34 JSScript* script,
michael@0 35 uintptr_t pc,
michael@0 36 bool isConstructing,
michael@0 37 JSAbstractFramePtr frame)
michael@0 38 {
michael@0 39 JSDStackFrameInfo* jsdframe;
michael@0 40 JSDScript* jsdscript = nullptr;
michael@0 41
michael@0 42 JSD_LOCK_SCRIPTS(jsdc);
michael@0 43 jsdscript = jsd_FindJSDScript(jsdc, script);
michael@0 44 JSD_UNLOCK_SCRIPTS(jsdc);
michael@0 45 if (!jsdscript || (jsdc->flags & JSD_HIDE_DISABLED_FRAMES &&
michael@0 46 !JSD_IS_DEBUG_ENABLED(jsdc, jsdscript)))
michael@0 47 {
michael@0 48 return nullptr;
michael@0 49 }
michael@0 50
michael@0 51 if (!JSD_IS_DEBUG_ENABLED(jsdc, jsdscript))
michael@0 52 jsdthreadstate->flags |= TS_HAS_DISABLED_FRAME;
michael@0 53
michael@0 54 jsdframe = (JSDStackFrameInfo*) calloc(1, sizeof(JSDStackFrameInfo));
michael@0 55 if( ! jsdframe )
michael@0 56 return nullptr;
michael@0 57
michael@0 58 jsdframe->jsdthreadstate = jsdthreadstate;
michael@0 59 jsdframe->jsdscript = jsdscript;
michael@0 60 jsdframe->isConstructing = isConstructing;
michael@0 61 jsdframe->pc = pc;
michael@0 62 jsdframe->frame = frame;
michael@0 63
michael@0 64 JS_APPEND_LINK(&jsdframe->links, &jsdthreadstate->stack);
michael@0 65 jsdthreadstate->stackDepth++;
michael@0 66
michael@0 67 return jsdframe;
michael@0 68 }
michael@0 69
michael@0 70 static void
michael@0 71 _destroyFrame(JSDStackFrameInfo* jsdframe)
michael@0 72 {
michael@0 73 /* kill any alloc'd objects in frame here... */
michael@0 74
michael@0 75 if( jsdframe )
michael@0 76 free(jsdframe);
michael@0 77 }
michael@0 78
michael@0 79 JSDThreadState*
michael@0 80 jsd_NewThreadState(JSDContext* jsdc, JSContext *cx )
michael@0 81 {
michael@0 82 JSDThreadState* jsdthreadstate;
michael@0 83
michael@0 84 jsdthreadstate = (JSDThreadState*)calloc(1, sizeof(JSDThreadState));
michael@0 85 if( ! jsdthreadstate )
michael@0 86 return nullptr;
michael@0 87
michael@0 88 jsdthreadstate->context = cx;
michael@0 89 jsdthreadstate->thread = JSD_CURRENT_THREAD();
michael@0 90 JS_INIT_CLIST(&jsdthreadstate->stack);
michael@0 91 jsdthreadstate->stackDepth = 0;
michael@0 92
michael@0 93 JS_BeginRequest(jsdthreadstate->context);
michael@0 94
michael@0 95 JSBrokenFrameIterator iter(cx);
michael@0 96 while(!iter.done())
michael@0 97 {
michael@0 98 JSAbstractFramePtr frame = iter.abstractFramePtr();
michael@0 99 JS::RootedScript script(cx, frame.script());
michael@0 100 uintptr_t pc = (uintptr_t)frame.pc();
michael@0 101 JS::RootedValue dummyThis(cx);
michael@0 102
michael@0 103 /*
michael@0 104 * don't construct a JSDStackFrame for dummy frames (those without a
michael@0 105 * |this| object, or native frames, if JSD_INCLUDE_NATIVE_FRAMES
michael@0 106 * isn't set.
michael@0 107 */
michael@0 108 if (frame.getThisValue(cx, &dummyThis))
michael@0 109 {
michael@0 110 bool isConstructing = iter.isConstructing();
michael@0 111 JSDStackFrameInfo *frameInfo = _addNewFrame( jsdc, jsdthreadstate, script, pc, isConstructing, frame );
michael@0 112
michael@0 113 if ((jsdthreadstate->stackDepth == 0 && !frameInfo) ||
michael@0 114 (jsdthreadstate->stackDepth == 1 && frameInfo &&
michael@0 115 frameInfo->jsdscript && !JSD_IS_DEBUG_ENABLED(jsdc, frameInfo->jsdscript)))
michael@0 116 {
michael@0 117 /*
michael@0 118 * if we failed to create the first frame, or the top frame
michael@0 119 * is not enabled for debugging, fail the entire thread state.
michael@0 120 */
michael@0 121 JS_INIT_CLIST(&jsdthreadstate->links);
michael@0 122 JS_EndRequest(jsdthreadstate->context);
michael@0 123 jsd_DestroyThreadState(jsdc, jsdthreadstate);
michael@0 124 return nullptr;
michael@0 125 }
michael@0 126 }
michael@0 127
michael@0 128 ++iter;
michael@0 129 }
michael@0 130 JS_EndRequest(jsdthreadstate->context);
michael@0 131
michael@0 132 if (jsdthreadstate->stackDepth == 0)
michael@0 133 {
michael@0 134 free(jsdthreadstate);
michael@0 135 return nullptr;
michael@0 136 }
michael@0 137
michael@0 138 JSD_LOCK_THREADSTATES(jsdc);
michael@0 139 JS_APPEND_LINK(&jsdthreadstate->links, &jsdc->threadsStates);
michael@0 140 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 141
michael@0 142 return jsdthreadstate;
michael@0 143 }
michael@0 144
michael@0 145 void
michael@0 146 jsd_DestroyThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
michael@0 147 {
michael@0 148 JSDStackFrameInfo* jsdframe;
michael@0 149 JSCList* list;
michael@0 150
michael@0 151 MOZ_ASSERT(jsdthreadstate);
michael@0 152 MOZ_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
michael@0 153
michael@0 154 JSD_LOCK_THREADSTATES(jsdc);
michael@0 155 JS_REMOVE_LINK(&jsdthreadstate->links);
michael@0 156 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 157
michael@0 158 list = &jsdthreadstate->stack;
michael@0 159 while( (JSDStackFrameInfo*)list != (jsdframe = (JSDStackFrameInfo*)list->next) )
michael@0 160 {
michael@0 161 JS_REMOVE_LINK(&jsdframe->links);
michael@0 162 _destroyFrame(jsdframe);
michael@0 163 }
michael@0 164 free(jsdthreadstate);
michael@0 165 }
michael@0 166
michael@0 167 unsigned
michael@0 168 jsd_GetCountOfStackFrames(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
michael@0 169 {
michael@0 170 unsigned count = 0;
michael@0 171
michael@0 172 JSD_LOCK_THREADSTATES(jsdc);
michael@0 173
michael@0 174 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
michael@0 175 count = jsdthreadstate->stackDepth;
michael@0 176
michael@0 177 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 178
michael@0 179 return count;
michael@0 180 }
michael@0 181
michael@0 182 JSDStackFrameInfo*
michael@0 183 jsd_GetStackFrame(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
michael@0 184 {
michael@0 185 JSDStackFrameInfo* jsdframe = nullptr;
michael@0 186
michael@0 187 JSD_LOCK_THREADSTATES(jsdc);
michael@0 188
michael@0 189 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
michael@0 190 jsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdthreadstate->stack);
michael@0 191 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 192
michael@0 193 return jsdframe;
michael@0 194 }
michael@0 195
michael@0 196 JSContext *
michael@0 197 jsd_GetJSContext (JSDContext* jsdc, JSDThreadState* jsdthreadstate)
michael@0 198 {
michael@0 199 JSContext* cx = nullptr;
michael@0 200
michael@0 201 JSD_LOCK_THREADSTATES(jsdc);
michael@0 202 if( jsd_IsValidThreadState(jsdc, jsdthreadstate) )
michael@0 203 cx = jsdthreadstate->context;
michael@0 204 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 205
michael@0 206 return cx;
michael@0 207 }
michael@0 208
michael@0 209 JSDStackFrameInfo*
michael@0 210 jsd_GetCallingStackFrame(JSDContext* jsdc,
michael@0 211 JSDThreadState* jsdthreadstate,
michael@0 212 JSDStackFrameInfo* jsdframe)
michael@0 213 {
michael@0 214 JSDStackFrameInfo* nextjsdframe = nullptr;
michael@0 215
michael@0 216 JSD_LOCK_THREADSTATES(jsdc);
michael@0 217
michael@0 218 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
michael@0 219 if( JS_LIST_HEAD(&jsdframe->links) != &jsdframe->jsdthreadstate->stack )
michael@0 220 nextjsdframe = (JSDStackFrameInfo*) JS_LIST_HEAD(&jsdframe->links);
michael@0 221
michael@0 222 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 223
michael@0 224 return nextjsdframe;
michael@0 225 }
michael@0 226
michael@0 227 JSDScript*
michael@0 228 jsd_GetScriptForStackFrame(JSDContext* jsdc,
michael@0 229 JSDThreadState* jsdthreadstate,
michael@0 230 JSDStackFrameInfo* jsdframe)
michael@0 231 {
michael@0 232 JSDScript* jsdscript = nullptr;
michael@0 233
michael@0 234 JSD_LOCK_THREADSTATES(jsdc);
michael@0 235
michael@0 236 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
michael@0 237 jsdscript = jsdframe->jsdscript;
michael@0 238
michael@0 239 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 240
michael@0 241 return jsdscript;
michael@0 242 }
michael@0 243
michael@0 244 uintptr_t
michael@0 245 jsd_GetPCForStackFrame(JSDContext* jsdc,
michael@0 246 JSDThreadState* jsdthreadstate,
michael@0 247 JSDStackFrameInfo* jsdframe)
michael@0 248 {
michael@0 249 uintptr_t pc = 0;
michael@0 250
michael@0 251 JSD_LOCK_THREADSTATES(jsdc);
michael@0 252
michael@0 253 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
michael@0 254 pc = jsdframe->pc;
michael@0 255
michael@0 256 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 257
michael@0 258 return pc;
michael@0 259 }
michael@0 260
michael@0 261 JSDValue*
michael@0 262 jsd_GetCallObjectForStackFrame(JSDContext* jsdc,
michael@0 263 JSDThreadState* jsdthreadstate,
michael@0 264 JSDStackFrameInfo* jsdframe)
michael@0 265 {
michael@0 266 JSObject* obj;
michael@0 267 JSDValue* jsdval = nullptr;
michael@0 268
michael@0 269 JSD_LOCK_THREADSTATES(jsdc);
michael@0 270
michael@0 271 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
michael@0 272 {
michael@0 273 obj = jsdframe->frame.callObject(jsdthreadstate->context);
michael@0 274 if(obj)
michael@0 275 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
michael@0 276 }
michael@0 277
michael@0 278 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 279
michael@0 280 return jsdval;
michael@0 281 }
michael@0 282
michael@0 283 JSDValue*
michael@0 284 jsd_GetScopeChainForStackFrame(JSDContext* jsdc,
michael@0 285 JSDThreadState* jsdthreadstate,
michael@0 286 JSDStackFrameInfo* jsdframe)
michael@0 287 {
michael@0 288 JS::RootedObject obj(jsdthreadstate->context);
michael@0 289 JSDValue* jsdval = nullptr;
michael@0 290
michael@0 291 JSD_LOCK_THREADSTATES(jsdc);
michael@0 292
michael@0 293 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
michael@0 294 {
michael@0 295 JS_BeginRequest(jsdthreadstate->context);
michael@0 296 obj = jsdframe->frame.scopeChain(jsdthreadstate->context);
michael@0 297 JS_EndRequest(jsdthreadstate->context);
michael@0 298 if(obj)
michael@0 299 jsdval = JSD_NewValue(jsdc, OBJECT_TO_JSVAL(obj));
michael@0 300 }
michael@0 301
michael@0 302 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 303
michael@0 304 return jsdval;
michael@0 305 }
michael@0 306
michael@0 307 JSDValue*
michael@0 308 jsd_GetThisForStackFrame(JSDContext* jsdc,
michael@0 309 JSDThreadState* jsdthreadstate,
michael@0 310 JSDStackFrameInfo* jsdframe)
michael@0 311 {
michael@0 312 JSDValue* jsdval = nullptr;
michael@0 313 JSD_LOCK_THREADSTATES(jsdc);
michael@0 314
michael@0 315 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
michael@0 316 {
michael@0 317 bool ok;
michael@0 318 JS::RootedValue thisval(jsdthreadstate->context);
michael@0 319 JS_BeginRequest(jsdthreadstate->context);
michael@0 320 ok = jsdframe->frame.getThisValue(jsdthreadstate->context, &thisval);
michael@0 321 JS_EndRequest(jsdthreadstate->context);
michael@0 322 if(ok)
michael@0 323 jsdval = JSD_NewValue(jsdc, thisval);
michael@0 324 }
michael@0 325
michael@0 326 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 327 return jsdval;
michael@0 328 }
michael@0 329
michael@0 330 JSString*
michael@0 331 jsd_GetIdForStackFrame(JSDContext* jsdc,
michael@0 332 JSDThreadState* jsdthreadstate,
michael@0 333 JSDStackFrameInfo* jsdframe)
michael@0 334 {
michael@0 335 JSString *rv = nullptr;
michael@0 336
michael@0 337 JSD_LOCK_THREADSTATES(jsdc);
michael@0 338
michael@0 339 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
michael@0 340 {
michael@0 341 JSFunction *fun = jsdframe->frame.maybeFun();
michael@0 342 if( fun )
michael@0 343 {
michael@0 344 rv = JS_GetFunctionId (fun);
michael@0 345
michael@0 346 /*
michael@0 347 * For compatibility we return "anonymous", not an empty string
michael@0 348 * here.
michael@0 349 */
michael@0 350 if( !rv )
michael@0 351 rv = JS_GetAnonymousString(jsdc->jsrt);
michael@0 352 }
michael@0 353 }
michael@0 354
michael@0 355 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 356 return rv;
michael@0 357 }
michael@0 358
michael@0 359 bool
michael@0 360 jsd_IsStackFrameDebugger(JSDContext* jsdc,
michael@0 361 JSDThreadState* jsdthreadstate,
michael@0 362 JSDStackFrameInfo* jsdframe)
michael@0 363 {
michael@0 364 bool rv = true;
michael@0 365 JSD_LOCK_THREADSTATES(jsdc);
michael@0 366
michael@0 367 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
michael@0 368 {
michael@0 369 rv = jsdframe->frame.isDebuggerFrame();
michael@0 370 }
michael@0 371
michael@0 372 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 373 return rv;
michael@0 374 }
michael@0 375
michael@0 376 bool
michael@0 377 jsd_IsStackFrameConstructing(JSDContext* jsdc,
michael@0 378 JSDThreadState* jsdthreadstate,
michael@0 379 JSDStackFrameInfo* jsdframe)
michael@0 380 {
michael@0 381 bool rv = true;
michael@0 382 JSD_LOCK_THREADSTATES(jsdc);
michael@0 383
michael@0 384 if( jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe) )
michael@0 385 {
michael@0 386 rv = jsdframe->isConstructing;
michael@0 387 }
michael@0 388
michael@0 389 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 390 return rv;
michael@0 391 }
michael@0 392
michael@0 393 bool
michael@0 394 jsd_EvaluateUCScriptInStackFrame(JSDContext* jsdc,
michael@0 395 JSDThreadState* jsdthreadstate,
michael@0 396 JSDStackFrameInfo* jsdframe,
michael@0 397 const jschar *bytes, unsigned length,
michael@0 398 const char *filename, unsigned lineno,
michael@0 399 bool eatExceptions, JS::MutableHandleValue rval)
michael@0 400 {
michael@0 401 bool retval;
michael@0 402 bool valid;
michael@0 403 JSExceptionState* exceptionState = nullptr;
michael@0 404
michael@0 405 MOZ_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
michael@0 406
michael@0 407 JSD_LOCK_THREADSTATES(jsdc);
michael@0 408 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
michael@0 409 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 410
michael@0 411 if( ! valid )
michael@0 412 return false;
michael@0 413
michael@0 414 AutoPushJSContext cx(jsdthreadstate->context);
michael@0 415 MOZ_ASSERT(cx);
michael@0 416
michael@0 417 if (eatExceptions)
michael@0 418 exceptionState = JS_SaveExceptionState(cx);
michael@0 419 JS_ClearPendingException(cx);
michael@0 420 jsd_StartingEvalUsingFilename(jsdc, filename);
michael@0 421 retval = jsdframe->frame.evaluateUCInStackFrame(cx, bytes, length, filename, lineno,
michael@0 422 rval);
michael@0 423 jsd_FinishedEvalUsingFilename(jsdc, filename);
michael@0 424 if (eatExceptions)
michael@0 425 JS_RestoreExceptionState(cx, exceptionState);
michael@0 426
michael@0 427 return retval;
michael@0 428 }
michael@0 429
michael@0 430 bool
michael@0 431 jsd_EvaluateScriptInStackFrame(JSDContext* jsdc,
michael@0 432 JSDThreadState* jsdthreadstate,
michael@0 433 JSDStackFrameInfo* jsdframe,
michael@0 434 const char *bytes, unsigned length,
michael@0 435 const char *filename, unsigned lineno,
michael@0 436 bool eatExceptions, JS::MutableHandleValue rval)
michael@0 437 {
michael@0 438 bool retval;
michael@0 439 bool valid;
michael@0 440 JSExceptionState* exceptionState = nullptr;
michael@0 441
michael@0 442 MOZ_ASSERT(JSD_CURRENT_THREAD() == jsdthreadstate->thread);
michael@0 443
michael@0 444 JSD_LOCK_THREADSTATES(jsdc);
michael@0 445 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
michael@0 446 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 447
michael@0 448 if (!valid)
michael@0 449 return false;
michael@0 450
michael@0 451 AutoPushJSContext cx(jsdthreadstate->context);
michael@0 452 MOZ_ASSERT(cx);
michael@0 453
michael@0 454 if (eatExceptions)
michael@0 455 exceptionState = JS_SaveExceptionState(cx);
michael@0 456 JS_ClearPendingException(cx);
michael@0 457 jsd_StartingEvalUsingFilename(jsdc, filename);
michael@0 458 retval = jsdframe->frame.evaluateInStackFrame(cx, bytes, length, filename, lineno,
michael@0 459 rval);
michael@0 460 jsd_FinishedEvalUsingFilename(jsdc, filename);
michael@0 461 if (eatExceptions)
michael@0 462 JS_RestoreExceptionState(cx, exceptionState);
michael@0 463
michael@0 464 return retval;
michael@0 465 }
michael@0 466
michael@0 467 JSString*
michael@0 468 jsd_ValToStringInStackFrame(JSDContext* jsdc,
michael@0 469 JSDThreadState* jsdthreadstate,
michael@0 470 JSDStackFrameInfo* jsdframe,
michael@0 471 jsval val)
michael@0 472 {
michael@0 473 bool valid;
michael@0 474 JSExceptionState* exceptionState;
michael@0 475 JSContext *cx = jsdthreadstate->context;
michael@0 476
michael@0 477 JSD_LOCK_THREADSTATES(jsdc);
michael@0 478 valid = jsd_IsValidFrameInThreadState(jsdc, jsdthreadstate, jsdframe);
michael@0 479 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 480
michael@0 481 if( ! valid )
michael@0 482 return nullptr;
michael@0 483
michael@0 484 JS::RootedString retval(cx);
michael@0 485 MOZ_ASSERT(cx);
michael@0 486 JS::RootedValue v(cx, val);
michael@0 487 {
michael@0 488 AutoPushJSContext cx(jsdthreadstate->context);
michael@0 489 exceptionState = JS_SaveExceptionState(cx);
michael@0 490 retval = JS::ToString(cx, v);
michael@0 491 JS_RestoreExceptionState(cx, exceptionState);
michael@0 492 }
michael@0 493
michael@0 494 return retval;
michael@0 495 }
michael@0 496
michael@0 497 bool
michael@0 498 jsd_IsValidThreadState(JSDContext* jsdc,
michael@0 499 JSDThreadState* jsdthreadstate)
michael@0 500 {
michael@0 501 JSDThreadState *cur;
michael@0 502
michael@0 503 MOZ_ASSERT( JSD_THREADSTATES_LOCKED(jsdc) );
michael@0 504
michael@0 505 for( cur = (JSDThreadState*)jsdc->threadsStates.next;
michael@0 506 cur != (JSDThreadState*)&jsdc->threadsStates;
michael@0 507 cur = (JSDThreadState*)cur->links.next )
michael@0 508 {
michael@0 509 if( cur == jsdthreadstate )
michael@0 510 return true;
michael@0 511 }
michael@0 512 return false;
michael@0 513 }
michael@0 514
michael@0 515 bool
michael@0 516 jsd_IsValidFrameInThreadState(JSDContext* jsdc,
michael@0 517 JSDThreadState* jsdthreadstate,
michael@0 518 JSDStackFrameInfo* jsdframe)
michael@0 519 {
michael@0 520 MOZ_ASSERT(JSD_THREADSTATES_LOCKED(jsdc));
michael@0 521
michael@0 522 if( ! jsd_IsValidThreadState(jsdc, jsdthreadstate) )
michael@0 523 return false;
michael@0 524 if( jsdframe->jsdthreadstate != jsdthreadstate )
michael@0 525 return false;
michael@0 526
michael@0 527 JSD_ASSERT_VALID_THREAD_STATE(jsdthreadstate);
michael@0 528 JSD_ASSERT_VALID_STACK_FRAME(jsdframe);
michael@0 529
michael@0 530 return true;
michael@0 531 }
michael@0 532
michael@0 533 static JSContext*
michael@0 534 _getContextForThreadState(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
michael@0 535 {
michael@0 536 bool valid;
michael@0 537 JSD_LOCK_THREADSTATES(jsdc);
michael@0 538 valid = jsd_IsValidThreadState(jsdc, jsdthreadstate);
michael@0 539 JSD_UNLOCK_THREADSTATES(jsdc);
michael@0 540 if( valid )
michael@0 541 return jsdthreadstate->context;
michael@0 542 return nullptr;
michael@0 543 }
michael@0 544
michael@0 545 JSDValue*
michael@0 546 jsd_GetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate)
michael@0 547 {
michael@0 548 JSContext* cx;
michael@0 549 if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
michael@0 550 return nullptr;
michael@0 551
michael@0 552 JS::RootedValue val(cx);
michael@0 553 if(JS_GetPendingException(cx, &val))
michael@0 554 return jsd_NewValue(jsdc, val);
michael@0 555 return nullptr;
michael@0 556 }
michael@0 557
michael@0 558 bool
michael@0 559 jsd_SetException(JSDContext* jsdc, JSDThreadState* jsdthreadstate,
michael@0 560 JSDValue* jsdval)
michael@0 561 {
michael@0 562 JSContext* cx;
michael@0 563
michael@0 564 if(!(cx = _getContextForThreadState(jsdc, jsdthreadstate)))
michael@0 565 return false;
michael@0 566
michael@0 567 if(jsdval) {
michael@0 568 JS::RootedValue exn(cx, JSD_GetValueWrappedJSVal(jsdc, jsdval));
michael@0 569 JS_SetPendingException(cx, exn);
michael@0 570 } else {
michael@0 571 JS_ClearPendingException(cx);
michael@0 572 }
michael@0 573 return true;
michael@0 574 }
michael@0 575

mercurial