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