PageRenderTime 29ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/node_modules/expresso/deps/jscoverage/js/jscntxt.cpp

https://gitlab.com/stefan.pataky/tinyrpg
C++ | 1394 lines | 951 code | 150 blank | 293 comment | 236 complexity | 221c2c0028dee65e33af630c8ce805fb MD5 | raw file
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sw=4 et tw=80:
  3. *
  4. * ***** BEGIN LICENSE BLOCK *****
  5. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6. *
  7. * The contents of this file are subject to the Mozilla Public License Version
  8. * 1.1 (the "License"); you may not use this file except in compliance with
  9. * the License. You may obtain a copy of the License at
  10. * http://www.mozilla.org/MPL/
  11. *
  12. * Software distributed under the License is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. * for the specific language governing rights and limitations under the
  15. * License.
  16. *
  17. * The Original Code is Mozilla Communicator client code, released
  18. * March 31, 1998.
  19. *
  20. * The Initial Developer of the Original Code is
  21. * Netscape Communications Corporation.
  22. * Portions created by the Initial Developer are Copyright (C) 1998
  23. * the Initial Developer. All Rights Reserved.
  24. *
  25. * Contributor(s):
  26. *
  27. * Alternatively, the contents of this file may be used under the terms of
  28. * either of the GNU General Public License Version 2 or later (the "GPL"),
  29. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  30. * in which case the provisions of the GPL or the LGPL are applicable instead
  31. * of those above. If you wish to allow use of your version of this file only
  32. * under the terms of either the GPL or the LGPL, and not to allow others to
  33. * use your version of this file under the terms of the MPL, indicate your
  34. * decision by deleting the provisions above and replace them with the notice
  35. * and other provisions required by the GPL or the LGPL. If you do not delete
  36. * the provisions above, a recipient may use your version of this file under
  37. * the terms of any one of the MPL, the GPL or the LGPL.
  38. *
  39. * ***** END LICENSE BLOCK ***** */
  40. /*
  41. * JS execution context.
  42. */
  43. #include "jsstddef.h"
  44. #include <stdarg.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include "jstypes.h"
  48. #include "jsarena.h" /* Added by JSIFY */
  49. #include "jsutil.h" /* Added by JSIFY */
  50. #include "jsclist.h"
  51. #include "jsprf.h"
  52. #include "jsatom.h"
  53. #include "jscntxt.h"
  54. #include "jsversion.h"
  55. #include "jsdbgapi.h"
  56. #include "jsexn.h"
  57. #include "jsfun.h"
  58. #include "jsgc.h"
  59. #include "jslock.h"
  60. #include "jsnum.h"
  61. #include "jsobj.h"
  62. #include "jsopcode.h"
  63. #include "jsscan.h"
  64. #include "jsscope.h"
  65. #include "jsscript.h"
  66. #include "jsstr.h"
  67. #include "jstracer.h"
  68. #ifdef JS_THREADSAFE
  69. #include "prtypes.h"
  70. /*
  71. * The index for JSThread info, returned by PR_NewThreadPrivateIndex. The
  72. * index value is visible and shared by all threads, but the data associated
  73. * with it is private to each thread.
  74. */
  75. static PRUintn threadTPIndex;
  76. static JSBool tpIndexInited = JS_FALSE;
  77. JS_BEGIN_EXTERN_C
  78. JSBool
  79. js_InitThreadPrivateIndex(void (*ptr)(void *))
  80. {
  81. PRStatus status;
  82. if (tpIndexInited)
  83. return JS_TRUE;
  84. status = PR_NewThreadPrivateIndex(&threadTPIndex, ptr);
  85. if (status == PR_SUCCESS)
  86. tpIndexInited = JS_TRUE;
  87. return status == PR_SUCCESS;
  88. }
  89. JS_END_EXTERN_C
  90. /*
  91. * Callback function to delete a JSThread info when the thread that owns it
  92. * is destroyed.
  93. */
  94. void
  95. js_ThreadDestructorCB(void *ptr)
  96. {
  97. JSThread *thread = (JSThread *)ptr;
  98. if (!thread)
  99. return;
  100. /*
  101. * Check that this thread properly called either JS_DestroyContext or
  102. * JS_ClearContextThread on each JSContext it created or used.
  103. */
  104. JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
  105. GSN_CACHE_CLEAR(&thread->gsnCache);
  106. #if defined JS_TRACER
  107. js_FinishJIT(&thread->traceMonitor);
  108. #endif
  109. free(thread);
  110. }
  111. /*
  112. * Get current thread-local JSThread info, creating one if it doesn't exist.
  113. * Each thread has a unique JSThread pointer.
  114. *
  115. * Since we are dealing with thread-local data, no lock is needed.
  116. *
  117. * Return a pointer to the thread local info, NULL if the system runs out
  118. * of memory, or it failed to set thread private data (neither case is very
  119. * likely; both are probably due to out-of-memory). It is up to the caller
  120. * to report an error, if possible.
  121. */
  122. JSThread *
  123. js_GetCurrentThread(JSRuntime *rt)
  124. {
  125. JSThread *thread;
  126. thread = (JSThread *)PR_GetThreadPrivate(threadTPIndex);
  127. if (!thread) {
  128. thread = (JSThread *) malloc(sizeof(JSThread));
  129. if (!thread)
  130. return NULL;
  131. #ifdef DEBUG
  132. memset(thread, JS_FREE_PATTERN, sizeof(JSThread));
  133. #endif
  134. if (PR_FAILURE == PR_SetThreadPrivate(threadTPIndex, thread)) {
  135. free(thread);
  136. return NULL;
  137. }
  138. JS_INIT_CLIST(&thread->contextList);
  139. thread->id = js_CurrentThreadId();
  140. thread->gcMallocBytes = 0;
  141. #ifdef JS_TRACER
  142. memset(&thread->traceMonitor, 0, sizeof(thread->traceMonitor));
  143. js_InitJIT(&thread->traceMonitor);
  144. #endif
  145. thread->scriptsToGC = NULL;
  146. /*
  147. * js_SetContextThread initializes the remaining fields as necessary.
  148. */
  149. }
  150. return thread;
  151. }
  152. /*
  153. * Sets current thread as owning thread of a context by assigning the
  154. * thread-private info to the context. If the current thread doesn't have
  155. * private JSThread info, create one.
  156. */
  157. JSBool
  158. js_SetContextThread(JSContext *cx)
  159. {
  160. JSThread *thread = js_GetCurrentThread(cx->runtime);
  161. if (!thread) {
  162. JS_ReportOutOfMemory(cx);
  163. return JS_FALSE;
  164. }
  165. /*
  166. * Clear caches on each transition from 0 to 1 context active on the
  167. * current thread. See bug 425828.
  168. */
  169. if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
  170. memset(&thread->gsnCache, 0, sizeof(thread->gsnCache));
  171. memset(&thread->propertyCache, 0, sizeof(thread->propertyCache));
  172. }
  173. /* Assert that the previous cx->thread called JS_ClearContextThread(). */
  174. JS_ASSERT(!cx->thread || cx->thread == thread);
  175. if (!cx->thread)
  176. JS_APPEND_LINK(&cx->threadLinks, &thread->contextList);
  177. cx->thread = thread;
  178. return JS_TRUE;
  179. }
  180. /* Remove the owning thread info of a context. */
  181. void
  182. js_ClearContextThread(JSContext *cx)
  183. {
  184. /*
  185. * If cx is associated with a thread, this must be called only from that
  186. * thread. If not, this is a harmless no-op.
  187. */
  188. JS_ASSERT(cx->thread == js_GetCurrentThread(cx->runtime) || !cx->thread);
  189. JS_REMOVE_AND_INIT_LINK(&cx->threadLinks);
  190. cx->thread = NULL;
  191. }
  192. #endif /* JS_THREADSAFE */
  193. void
  194. js_OnVersionChange(JSContext *cx)
  195. {
  196. #ifdef DEBUG
  197. JSVersion version = JSVERSION_NUMBER(cx);
  198. JS_ASSERT(version == JSVERSION_DEFAULT || version >= JSVERSION_ECMA_3);
  199. #endif
  200. }
  201. void
  202. js_SetVersion(JSContext *cx, JSVersion version)
  203. {
  204. cx->version = version;
  205. js_OnVersionChange(cx);
  206. }
  207. JSContext *
  208. js_NewContext(JSRuntime *rt, size_t stackChunkSize)
  209. {
  210. JSContext *cx;
  211. JSBool ok, first;
  212. JSContextCallback cxCallback;
  213. cx = (JSContext *) malloc(sizeof *cx);
  214. if (!cx)
  215. return NULL;
  216. memset(cx, 0, sizeof *cx);
  217. cx->runtime = rt;
  218. JS_ClearOperationCallback(cx);
  219. cx->debugHooks = &rt->globalDebugHooks;
  220. #if JS_STACK_GROWTH_DIRECTION > 0
  221. cx->stackLimit = (jsuword)-1;
  222. #endif
  223. cx->scriptStackQuota = JS_DEFAULT_SCRIPT_STACK_QUOTA;
  224. #ifdef JS_THREADSAFE
  225. cx->gcLocalFreeLists = (JSGCFreeListSet *) &js_GCEmptyFreeListSet;
  226. JS_INIT_CLIST(&cx->threadLinks);
  227. js_SetContextThread(cx);
  228. #endif
  229. JS_LOCK_GC(rt);
  230. for (;;) {
  231. first = (rt->contextList.next == &rt->contextList);
  232. if (rt->state == JSRTS_UP) {
  233. JS_ASSERT(!first);
  234. break;
  235. }
  236. if (rt->state == JSRTS_DOWN) {
  237. JS_ASSERT(first);
  238. rt->state = JSRTS_LAUNCHING;
  239. break;
  240. }
  241. JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT);
  242. }
  243. JS_APPEND_LINK(&cx->links, &rt->contextList);
  244. JS_UNLOCK_GC(rt);
  245. /*
  246. * First we do the infallible, every-time per-context initializations.
  247. * Should a later, fallible initialization (js_InitRegExpStatics, e.g.,
  248. * or the stuff under 'if (first)' below) fail, at least the version
  249. * and arena-pools will be valid and safe to use (say, from the last GC
  250. * done by js_DestroyContext).
  251. */
  252. cx->version = JSVERSION_DEFAULT;
  253. JS_INIT_ARENA_POOL(&cx->stackPool, "stack", stackChunkSize, sizeof(jsval),
  254. &cx->scriptStackQuota);
  255. JS_INIT_ARENA_POOL(&cx->tempPool, "temp",
  256. 1024, /* FIXME: bug 421435 */
  257. sizeof(jsdouble), &cx->scriptStackQuota);
  258. /*
  259. * To avoid multiple allocations in InitMatch() (in jsregexp.c), the arena
  260. * size parameter should be at least as big as:
  261. * INITIAL_BACKTRACK
  262. * + (sizeof(REProgState) * INITIAL_STATESTACK)
  263. * + (offsetof(REMatchState, parens) + avgParanSize * sizeof(RECapture))
  264. */
  265. JS_INIT_ARENA_POOL(&cx->regexpPool, "regexp",
  266. 12 * 1024 - 40, /* FIXME: bug 421435 */
  267. sizeof(void *), &cx->scriptStackQuota);
  268. if (!js_InitRegExpStatics(cx, &cx->regExpStatics)) {
  269. js_DestroyContext(cx, JSDCM_NEW_FAILED);
  270. return NULL;
  271. }
  272. cx->resolveFlags = 0;
  273. /*
  274. * If cx is the first context on this runtime, initialize well-known atoms,
  275. * keywords, numbers, and strings. If one of these steps should fail, the
  276. * runtime will be left in a partially initialized state, with zeroes and
  277. * nulls stored in the default-initialized remainder of the struct. We'll
  278. * clean the runtime up under js_DestroyContext, because cx will be "last"
  279. * as well as "first".
  280. */
  281. if (first) {
  282. #ifdef JS_THREADSAFE
  283. JS_BeginRequest(cx);
  284. #endif
  285. ok = js_InitCommonAtoms(cx);
  286. /*
  287. * scriptFilenameTable may be left over from a previous episode of
  288. * non-zero contexts alive in rt, so don't re-init the table if it's
  289. * not necessary.
  290. */
  291. if (ok && !rt->scriptFilenameTable)
  292. ok = js_InitRuntimeScriptState(rt);
  293. if (ok)
  294. ok = js_InitRuntimeNumberState(cx);
  295. if (ok)
  296. ok = js_InitRuntimeStringState(cx);
  297. #ifdef JS_THREADSAFE
  298. JS_EndRequest(cx);
  299. #endif
  300. if (!ok) {
  301. js_DestroyContext(cx, JSDCM_NEW_FAILED);
  302. return NULL;
  303. }
  304. JS_LOCK_GC(rt);
  305. rt->state = JSRTS_UP;
  306. JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
  307. JS_UNLOCK_GC(rt);
  308. }
  309. cxCallback = rt->cxCallback;
  310. if (cxCallback && !cxCallback(cx, JSCONTEXT_NEW)) {
  311. js_DestroyContext(cx, JSDCM_NEW_FAILED);
  312. return NULL;
  313. }
  314. return cx;
  315. }
  316. void
  317. js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
  318. {
  319. JSRuntime *rt;
  320. JSContextCallback cxCallback;
  321. JSBool last;
  322. JSArgumentFormatMap *map;
  323. JSLocalRootStack *lrs;
  324. JSLocalRootChunk *lrc;
  325. rt = cx->runtime;
  326. if (mode != JSDCM_NEW_FAILED) {
  327. cxCallback = rt->cxCallback;
  328. if (cxCallback) {
  329. /*
  330. * JSCONTEXT_DESTROY callback is not allowed to fail and must
  331. * return true.
  332. */
  333. #ifdef DEBUG
  334. JSBool callbackStatus =
  335. #endif
  336. cxCallback(cx, JSCONTEXT_DESTROY);
  337. JS_ASSERT(callbackStatus);
  338. }
  339. }
  340. /* Remove cx from context list first. */
  341. JS_LOCK_GC(rt);
  342. JS_ASSERT(rt->state == JSRTS_UP || rt->state == JSRTS_LAUNCHING);
  343. JS_REMOVE_LINK(&cx->links);
  344. last = (rt->contextList.next == &rt->contextList);
  345. if (last)
  346. rt->state = JSRTS_LANDING;
  347. #ifdef JS_THREADSAFE
  348. js_RevokeGCLocalFreeLists(cx);
  349. #endif
  350. JS_UNLOCK_GC(rt);
  351. if (last) {
  352. #ifdef JS_THREADSAFE
  353. /*
  354. * If cx is not in a request already, begin one now so that we wait
  355. * for any racing GC started on a not-last context to finish, before
  356. * we plow ahead and unpin atoms. Note that even though we begin a
  357. * request here if necessary, we end all requests on cx below before
  358. * forcing a final GC. This lets any not-last context destruction
  359. * racing in another thread try to force or maybe run the GC, but by
  360. * that point, rt->state will not be JSRTS_UP, and that GC attempt
  361. * will return early.
  362. */
  363. if (cx->requestDepth == 0)
  364. JS_BeginRequest(cx);
  365. #endif
  366. /* Unlock and clear GC things held by runtime pointers. */
  367. js_FinishRuntimeNumberState(cx);
  368. js_FinishRuntimeStringState(cx);
  369. /* Unpin all common atoms before final GC. */
  370. js_FinishCommonAtoms(cx);
  371. /* Clear debugging state to remove GC roots. */
  372. JS_ClearAllTraps(cx);
  373. JS_ClearAllWatchPoints(cx);
  374. }
  375. /*
  376. * Remove more GC roots in regExpStatics, then collect garbage.
  377. * XXX anti-modularity alert: we rely on the call to js_RemoveRoot within
  378. * XXX this function call to wait for any racing GC to complete, in the
  379. * XXX case where JS_DestroyContext is called outside of a request on cx
  380. */
  381. js_FreeRegExpStatics(cx, &cx->regExpStatics);
  382. #ifdef JS_THREADSAFE
  383. /*
  384. * Destroying a context implicitly calls JS_EndRequest(). Also, we must
  385. * end our request here in case we are "last" -- in that event, another
  386. * js_DestroyContext that was not last might be waiting in the GC for our
  387. * request to end. We'll let it run below, just before we do the truly
  388. * final GC and then free atom state.
  389. *
  390. * At this point, cx must be inaccessible to other threads. It's off the
  391. * rt->contextList, and it should not be reachable via any object private
  392. * data structure.
  393. */
  394. while (cx->requestDepth != 0)
  395. JS_EndRequest(cx);
  396. #endif
  397. if (last) {
  398. js_GC(cx, GC_LAST_CONTEXT);
  399. /*
  400. * Free the script filename table if it exists and is empty. Do this
  401. * after the last GC to avoid finalizers tripping on free memory.
  402. */
  403. if (rt->scriptFilenameTable && rt->scriptFilenameTable->nentries == 0)
  404. js_FinishRuntimeScriptState(rt);
  405. /* Take the runtime down, now that it has no contexts or atoms. */
  406. JS_LOCK_GC(rt);
  407. rt->state = JSRTS_DOWN;
  408. JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
  409. JS_UNLOCK_GC(rt);
  410. } else {
  411. if (mode == JSDCM_FORCE_GC)
  412. js_GC(cx, GC_NORMAL);
  413. else if (mode == JSDCM_MAYBE_GC)
  414. JS_MaybeGC(cx);
  415. }
  416. /* Free the stuff hanging off of cx. */
  417. JS_FinishArenaPool(&cx->stackPool);
  418. JS_FinishArenaPool(&cx->tempPool);
  419. JS_FinishArenaPool(&cx->regexpPool);
  420. if (cx->lastMessage)
  421. free(cx->lastMessage);
  422. /* Remove any argument formatters. */
  423. map = cx->argumentFormatMap;
  424. while (map) {
  425. JSArgumentFormatMap *temp = map;
  426. map = map->next;
  427. JS_free(cx, temp);
  428. }
  429. /* Destroy the resolve recursion damper. */
  430. if (cx->resolvingTable) {
  431. JS_DHashTableDestroy(cx->resolvingTable);
  432. cx->resolvingTable = NULL;
  433. }
  434. lrs = cx->localRootStack;
  435. if (lrs) {
  436. while ((lrc = lrs->topChunk) != &lrs->firstChunk) {
  437. lrs->topChunk = lrc->down;
  438. JS_free(cx, lrc);
  439. }
  440. JS_free(cx, lrs);
  441. }
  442. #ifdef JS_THREADSAFE
  443. js_ClearContextThread(cx);
  444. #endif
  445. /* Finally, free cx itself. */
  446. free(cx);
  447. }
  448. JSBool
  449. js_ValidContextPointer(JSRuntime *rt, JSContext *cx)
  450. {
  451. JSCList *cl;
  452. for (cl = rt->contextList.next; cl != &rt->contextList; cl = cl->next) {
  453. if (cl == &cx->links)
  454. return JS_TRUE;
  455. }
  456. JS_RUNTIME_METER(rt, deadContexts);
  457. return JS_FALSE;
  458. }
  459. JSContext *
  460. js_ContextIterator(JSRuntime *rt, JSBool unlocked, JSContext **iterp)
  461. {
  462. JSContext *cx = *iterp;
  463. if (unlocked)
  464. JS_LOCK_GC(rt);
  465. cx = (JSContext *) (cx ? cx->links.next : rt->contextList.next);
  466. if (&cx->links == &rt->contextList)
  467. cx = NULL;
  468. *iterp = cx;
  469. if (unlocked)
  470. JS_UNLOCK_GC(rt);
  471. return cx;
  472. }
  473. static JSDHashNumber
  474. resolving_HashKey(JSDHashTable *table, const void *ptr)
  475. {
  476. const JSResolvingKey *key = (const JSResolvingKey *)ptr;
  477. return ((JSDHashNumber)JS_PTR_TO_UINT32(key->obj) >> JSVAL_TAGBITS) ^ key->id;
  478. }
  479. JS_PUBLIC_API(JSBool)
  480. resolving_MatchEntry(JSDHashTable *table,
  481. const JSDHashEntryHdr *hdr,
  482. const void *ptr)
  483. {
  484. const JSResolvingEntry *entry = (const JSResolvingEntry *)hdr;
  485. const JSResolvingKey *key = (const JSResolvingKey *)ptr;
  486. return entry->key.obj == key->obj && entry->key.id == key->id;
  487. }
  488. static const JSDHashTableOps resolving_dhash_ops = {
  489. JS_DHashAllocTable,
  490. JS_DHashFreeTable,
  491. resolving_HashKey,
  492. resolving_MatchEntry,
  493. JS_DHashMoveEntryStub,
  494. JS_DHashClearEntryStub,
  495. JS_DHashFinalizeStub,
  496. NULL
  497. };
  498. JSBool
  499. js_StartResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
  500. JSResolvingEntry **entryp)
  501. {
  502. JSDHashTable *table;
  503. JSResolvingEntry *entry;
  504. table = cx->resolvingTable;
  505. if (!table) {
  506. table = JS_NewDHashTable(&resolving_dhash_ops, NULL,
  507. sizeof(JSResolvingEntry),
  508. JS_DHASH_MIN_SIZE);
  509. if (!table)
  510. goto outofmem;
  511. cx->resolvingTable = table;
  512. }
  513. entry = (JSResolvingEntry *)
  514. JS_DHashTableOperate(table, key, JS_DHASH_ADD);
  515. if (!entry)
  516. goto outofmem;
  517. if (entry->flags & flag) {
  518. /* An entry for (key, flag) exists already -- dampen recursion. */
  519. entry = NULL;
  520. } else {
  521. /* Fill in key if we were the first to add entry, then set flag. */
  522. if (!entry->key.obj)
  523. entry->key = *key;
  524. entry->flags |= flag;
  525. }
  526. *entryp = entry;
  527. return JS_TRUE;
  528. outofmem:
  529. JS_ReportOutOfMemory(cx);
  530. return JS_FALSE;
  531. }
  532. void
  533. js_StopResolving(JSContext *cx, JSResolvingKey *key, uint32 flag,
  534. JSResolvingEntry *entry, uint32 generation)
  535. {
  536. JSDHashTable *table;
  537. /*
  538. * Clear flag from entry->flags and return early if other flags remain.
  539. * We must take care to re-lookup entry if the table has changed since
  540. * it was found by js_StartResolving.
  541. */
  542. table = cx->resolvingTable;
  543. if (!entry || table->generation != generation) {
  544. entry = (JSResolvingEntry *)
  545. JS_DHashTableOperate(table, key, JS_DHASH_LOOKUP);
  546. }
  547. JS_ASSERT(JS_DHASH_ENTRY_IS_BUSY(&entry->hdr));
  548. entry->flags &= ~flag;
  549. if (entry->flags)
  550. return;
  551. /*
  552. * Do a raw remove only if fewer entries were removed than would cause
  553. * alpha to be less than .5 (alpha is at most .75). Otherwise, we just
  554. * call JS_DHashTableOperate to re-lookup the key and remove its entry,
  555. * compressing or shrinking the table as needed.
  556. */
  557. if (table->removedCount < JS_DHASH_TABLE_SIZE(table) >> 2)
  558. JS_DHashTableRawRemove(table, &entry->hdr);
  559. else
  560. JS_DHashTableOperate(table, key, JS_DHASH_REMOVE);
  561. }
  562. JSBool
  563. js_EnterLocalRootScope(JSContext *cx)
  564. {
  565. JSLocalRootStack *lrs;
  566. int mark;
  567. lrs = cx->localRootStack;
  568. if (!lrs) {
  569. lrs = (JSLocalRootStack *) JS_malloc(cx, sizeof *lrs);
  570. if (!lrs)
  571. return JS_FALSE;
  572. lrs->scopeMark = JSLRS_NULL_MARK;
  573. lrs->rootCount = 0;
  574. lrs->topChunk = &lrs->firstChunk;
  575. lrs->firstChunk.down = NULL;
  576. cx->localRootStack = lrs;
  577. }
  578. /* Push lrs->scopeMark to save it for restore when leaving. */
  579. mark = js_PushLocalRoot(cx, lrs, INT_TO_JSVAL(lrs->scopeMark));
  580. if (mark < 0)
  581. return JS_FALSE;
  582. lrs->scopeMark = (uint32) mark;
  583. return JS_TRUE;
  584. }
  585. void
  586. js_LeaveLocalRootScopeWithResult(JSContext *cx, jsval rval)
  587. {
  588. JSLocalRootStack *lrs;
  589. uint32 mark, m, n;
  590. JSLocalRootChunk *lrc;
  591. /* Defend against buggy native callers. */
  592. lrs = cx->localRootStack;
  593. JS_ASSERT(lrs && lrs->rootCount != 0);
  594. if (!lrs || lrs->rootCount == 0)
  595. return;
  596. mark = lrs->scopeMark;
  597. JS_ASSERT(mark != JSLRS_NULL_MARK);
  598. if (mark == JSLRS_NULL_MARK)
  599. return;
  600. /* Free any chunks being popped by this leave operation. */
  601. m = mark >> JSLRS_CHUNK_SHIFT;
  602. n = (lrs->rootCount - 1) >> JSLRS_CHUNK_SHIFT;
  603. while (n > m) {
  604. lrc = lrs->topChunk;
  605. JS_ASSERT(lrc != &lrs->firstChunk);
  606. lrs->topChunk = lrc->down;
  607. JS_free(cx, lrc);
  608. --n;
  609. }
  610. /*
  611. * Pop the scope, restoring lrs->scopeMark. If rval is a GC-thing, push
  612. * it on the caller's scope, or store it in lastInternalResult if we are
  613. * leaving the outermost scope. We don't need to allocate a new lrc
  614. * because we can overwrite the old mark's slot with rval.
  615. */
  616. lrc = lrs->topChunk;
  617. m = mark & JSLRS_CHUNK_MASK;
  618. lrs->scopeMark = (uint32) JSVAL_TO_INT(lrc->roots[m]);
  619. if (JSVAL_IS_GCTHING(rval) && !JSVAL_IS_NULL(rval)) {
  620. if (mark == 0) {
  621. cx->weakRoots.lastInternalResult = rval;
  622. } else {
  623. /*
  624. * Increment m to avoid the "else if (m == 0)" case below. If
  625. * rval is not a GC-thing, that case would take care of freeing
  626. * any chunk that contained only the old mark. Since rval *is*
  627. * a GC-thing here, we want to reuse that old mark's slot.
  628. */
  629. lrc->roots[m++] = rval;
  630. ++mark;
  631. }
  632. }
  633. lrs->rootCount = (uint32) mark;
  634. /*
  635. * Free the stack eagerly, risking malloc churn. The alternative would
  636. * require an lrs->entryCount member, maintained by Enter and Leave, and
  637. * tested by the GC in addition to the cx->localRootStack non-null test.
  638. *
  639. * That approach would risk hoarding 264 bytes (net) per context. Right
  640. * now it seems better to give fresh (dirty in CPU write-back cache, and
  641. * the data is no longer needed) memory back to the malloc heap.
  642. */
  643. if (mark == 0) {
  644. cx->localRootStack = NULL;
  645. JS_free(cx, lrs);
  646. } else if (m == 0) {
  647. lrs->topChunk = lrc->down;
  648. JS_free(cx, lrc);
  649. }
  650. }
  651. void
  652. js_ForgetLocalRoot(JSContext *cx, jsval v)
  653. {
  654. JSLocalRootStack *lrs;
  655. uint32 i, j, m, n, mark;
  656. JSLocalRootChunk *lrc, *lrc2;
  657. jsval top;
  658. lrs = cx->localRootStack;
  659. JS_ASSERT(lrs && lrs->rootCount);
  660. if (!lrs || lrs->rootCount == 0)
  661. return;
  662. /* Prepare to pop the top-most value from the stack. */
  663. n = lrs->rootCount - 1;
  664. m = n & JSLRS_CHUNK_MASK;
  665. lrc = lrs->topChunk;
  666. top = lrc->roots[m];
  667. /* Be paranoid about calls on an empty scope. */
  668. mark = lrs->scopeMark;
  669. JS_ASSERT(mark < n);
  670. if (mark >= n)
  671. return;
  672. /* If v was not the last root pushed in the top scope, find it. */
  673. if (top != v) {
  674. /* Search downward in case v was recently pushed. */
  675. i = n;
  676. j = m;
  677. lrc2 = lrc;
  678. while (--i > mark) {
  679. if (j == 0)
  680. lrc2 = lrc2->down;
  681. j = i & JSLRS_CHUNK_MASK;
  682. if (lrc2->roots[j] == v)
  683. break;
  684. }
  685. /* If we didn't find v in this scope, assert and bail out. */
  686. JS_ASSERT(i != mark);
  687. if (i == mark)
  688. return;
  689. /* Swap top and v so common tail code can pop v. */
  690. lrc2->roots[j] = top;
  691. }
  692. /* Pop the last value from the stack. */
  693. lrc->roots[m] = JSVAL_NULL;
  694. lrs->rootCount = n;
  695. if (m == 0) {
  696. JS_ASSERT(n != 0);
  697. JS_ASSERT(lrc != &lrs->firstChunk);
  698. lrs->topChunk = lrc->down;
  699. JS_free(cx, lrc);
  700. }
  701. }
  702. int
  703. js_PushLocalRoot(JSContext *cx, JSLocalRootStack *lrs, jsval v)
  704. {
  705. uint32 n, m;
  706. JSLocalRootChunk *lrc;
  707. n = lrs->rootCount;
  708. m = n & JSLRS_CHUNK_MASK;
  709. if (n == 0 || m != 0) {
  710. /*
  711. * At start of first chunk, or not at start of a non-first top chunk.
  712. * Check for lrs->rootCount overflow.
  713. */
  714. if ((uint32)(n + 1) == 0) {
  715. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
  716. JSMSG_TOO_MANY_LOCAL_ROOTS);
  717. return -1;
  718. }
  719. lrc = lrs->topChunk;
  720. JS_ASSERT(n != 0 || lrc == &lrs->firstChunk);
  721. } else {
  722. /*
  723. * After lrs->firstChunk, trying to index at a power-of-two chunk
  724. * boundary: need a new chunk.
  725. */
  726. lrc = (JSLocalRootChunk *) JS_malloc(cx, sizeof *lrc);
  727. if (!lrc)
  728. return -1;
  729. lrc->down = lrs->topChunk;
  730. lrs->topChunk = lrc;
  731. }
  732. lrs->rootCount = n + 1;
  733. lrc->roots[m] = v;
  734. return (int) n;
  735. }
  736. void
  737. js_TraceLocalRoots(JSTracer *trc, JSLocalRootStack *lrs)
  738. {
  739. uint32 n, m, mark;
  740. JSLocalRootChunk *lrc;
  741. jsval v;
  742. n = lrs->rootCount;
  743. if (n == 0)
  744. return;
  745. mark = lrs->scopeMark;
  746. lrc = lrs->topChunk;
  747. do {
  748. while (--n > mark) {
  749. m = n & JSLRS_CHUNK_MASK;
  750. v = lrc->roots[m];
  751. JS_ASSERT(JSVAL_IS_GCTHING(v) && v != JSVAL_NULL);
  752. JS_SET_TRACING_INDEX(trc, "local_root", n);
  753. js_CallValueTracerIfGCThing(trc, v);
  754. if (m == 0)
  755. lrc = lrc->down;
  756. }
  757. m = n & JSLRS_CHUNK_MASK;
  758. mark = JSVAL_TO_INT(lrc->roots[m]);
  759. if (m == 0)
  760. lrc = lrc->down;
  761. } while (n != 0);
  762. JS_ASSERT(!lrc);
  763. }
  764. static void
  765. ReportError(JSContext *cx, const char *message, JSErrorReport *reportp)
  766. {
  767. /*
  768. * Check the error report, and set a JavaScript-catchable exception
  769. * if the error is defined to have an associated exception. If an
  770. * exception is thrown, then the JSREPORT_EXCEPTION flag will be set
  771. * on the error report, and exception-aware hosts should ignore it.
  772. */
  773. JS_ASSERT(reportp);
  774. if (reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
  775. reportp->flags |= JSREPORT_EXCEPTION;
  776. /*
  777. * Call the error reporter only if an exception wasn't raised.
  778. *
  779. * If an exception was raised, then we call the debugErrorHook
  780. * (if present) to give it a chance to see the error before it
  781. * propagates out of scope. This is needed for compatability
  782. * with the old scheme.
  783. */
  784. if (!cx->fp || !js_ErrorToException(cx, message, reportp)) {
  785. js_ReportErrorAgain(cx, message, reportp);
  786. } else if (cx->debugHooks->debugErrorHook && cx->errorReporter) {
  787. JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
  788. /* test local in case debugErrorHook changed on another thread */
  789. if (hook)
  790. hook(cx, message, reportp, cx->debugHooks->debugErrorHookData);
  791. }
  792. }
  793. /*
  794. * We don't post an exception in this case, since doing so runs into
  795. * complications of pre-allocating an exception object which required
  796. * running the Exception class initializer early etc.
  797. * Instead we just invoke the errorReporter with an "Out Of Memory"
  798. * type message, and then hope the process ends swiftly.
  799. */
  800. void
  801. js_ReportOutOfMemory(JSContext *cx)
  802. {
  803. JSStackFrame *fp;
  804. JSErrorReport report;
  805. JSErrorReporter onError = cx->errorReporter;
  806. /* Get the message for this error, but we won't expand any arguments. */
  807. const JSErrorFormatString *efs =
  808. js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY);
  809. const char *msg = efs ? efs->format : "Out of memory";
  810. /* Fill out the report, but don't do anything that requires allocation. */
  811. memset(&report, 0, sizeof (struct JSErrorReport));
  812. report.flags = JSREPORT_ERROR;
  813. report.errorNumber = JSMSG_OUT_OF_MEMORY;
  814. /*
  815. * Walk stack until we find a frame that is associated with some script
  816. * rather than a native frame.
  817. */
  818. for (fp = cx->fp; fp; fp = fp->down) {
  819. if (fp->regs) {
  820. report.filename = fp->script->filename;
  821. report.lineno = js_FramePCToLineNumber(cx, fp);
  822. break;
  823. }
  824. }
  825. /*
  826. * If debugErrorHook is present then we give it a chance to veto sending
  827. * the error on to the regular ErrorReporter. We also clear a pending
  828. * exception if any now so the hooks can replace the out-of-memory error
  829. * by a script-catchable exception.
  830. */
  831. cx->throwing = JS_FALSE;
  832. if (onError) {
  833. JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
  834. if (hook &&
  835. !hook(cx, msg, &report, cx->debugHooks->debugErrorHookData)) {
  836. onError = NULL;
  837. }
  838. }
  839. if (onError)
  840. onError(cx, msg, &report);
  841. }
  842. void
  843. js_ReportOutOfScriptQuota(JSContext *cx)
  844. {
  845. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
  846. JSMSG_SCRIPT_STACK_QUOTA);
  847. }
  848. void
  849. js_ReportOverRecursed(JSContext *cx)
  850. {
  851. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
  852. }
  853. void
  854. js_ReportAllocationOverflow(JSContext *cx)
  855. {
  856. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_ALLOC_OVERFLOW);
  857. }
  858. JSBool
  859. js_ReportErrorVA(JSContext *cx, uintN flags, const char *format, va_list ap)
  860. {
  861. char *message;
  862. jschar *ucmessage;
  863. size_t messagelen;
  864. JSStackFrame *fp;
  865. JSErrorReport report;
  866. JSBool warning;
  867. if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx))
  868. return JS_TRUE;
  869. message = JS_vsmprintf(format, ap);
  870. if (!message)
  871. return JS_FALSE;
  872. messagelen = strlen(message);
  873. memset(&report, 0, sizeof (struct JSErrorReport));
  874. report.flags = flags;
  875. report.errorNumber = JSMSG_USER_DEFINED_ERROR;
  876. report.ucmessage = ucmessage = js_InflateString(cx, message, &messagelen);
  877. /* Find the top-most active script frame, for best line number blame. */
  878. for (fp = cx->fp; fp; fp = fp->down) {
  879. if (fp->regs) {
  880. report.filename = fp->script->filename;
  881. report.lineno = js_FramePCToLineNumber(cx, fp);
  882. break;
  883. }
  884. }
  885. warning = JSREPORT_IS_WARNING(report.flags);
  886. if (warning && JS_HAS_WERROR_OPTION(cx)) {
  887. report.flags &= ~JSREPORT_WARNING;
  888. warning = JS_FALSE;
  889. }
  890. ReportError(cx, message, &report);
  891. free(message);
  892. JS_free(cx, ucmessage);
  893. return warning;
  894. }
  895. /*
  896. * The arguments from ap need to be packaged up into an array and stored
  897. * into the report struct.
  898. *
  899. * The format string addressed by the error number may contain operands
  900. * identified by the format {N}, where N is a decimal digit. Each of these
  901. * is to be replaced by the Nth argument from the va_list. The complete
  902. * message is placed into reportp->ucmessage converted to a JSString.
  903. *
  904. * Returns true if the expansion succeeds (can fail if out of memory).
  905. */
  906. JSBool
  907. js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
  908. void *userRef, const uintN errorNumber,
  909. char **messagep, JSErrorReport *reportp,
  910. JSBool *warningp, JSBool charArgs, va_list ap)
  911. {
  912. const JSErrorFormatString *efs;
  913. int i;
  914. int argCount;
  915. *warningp = JSREPORT_IS_WARNING(reportp->flags);
  916. if (*warningp && JS_HAS_WERROR_OPTION(cx)) {
  917. reportp->flags &= ~JSREPORT_WARNING;
  918. *warningp = JS_FALSE;
  919. }
  920. *messagep = NULL;
  921. /* Most calls supply js_GetErrorMessage; if this is so, assume NULL. */
  922. if (!callback || callback == js_GetErrorMessage)
  923. efs = js_GetLocalizedErrorMessage(cx, userRef, NULL, errorNumber);
  924. else
  925. efs = callback(userRef, NULL, errorNumber);
  926. if (efs) {
  927. size_t totalArgsLength = 0;
  928. size_t argLengths[10]; /* only {0} thru {9} supported */
  929. argCount = efs->argCount;
  930. JS_ASSERT(argCount <= 10);
  931. if (argCount > 0) {
  932. /*
  933. * Gather the arguments into an array, and accumulate
  934. * their sizes. We allocate 1 more than necessary and
  935. * null it out to act as the caboose when we free the
  936. * pointers later.
  937. */
  938. reportp->messageArgs = (const jschar **)
  939. JS_malloc(cx, sizeof(jschar *) * (argCount + 1));
  940. if (!reportp->messageArgs)
  941. return JS_FALSE;
  942. reportp->messageArgs[argCount] = NULL;
  943. for (i = 0; i < argCount; i++) {
  944. if (charArgs) {
  945. char *charArg = va_arg(ap, char *);
  946. size_t charArgLength = strlen(charArg);
  947. reportp->messageArgs[i]
  948. = js_InflateString(cx, charArg, &charArgLength);
  949. if (!reportp->messageArgs[i])
  950. goto error;
  951. } else {
  952. reportp->messageArgs[i] = va_arg(ap, jschar *);
  953. }
  954. argLengths[i] = js_strlen(reportp->messageArgs[i]);
  955. totalArgsLength += argLengths[i];
  956. }
  957. /* NULL-terminate for easy copying. */
  958. reportp->messageArgs[i] = NULL;
  959. }
  960. /*
  961. * Parse the error format, substituting the argument X
  962. * for {X} in the format.
  963. */
  964. if (argCount > 0) {
  965. if (efs->format) {
  966. jschar *buffer, *fmt, *out;
  967. int expandedArgs = 0;
  968. size_t expandedLength;
  969. size_t len = strlen(efs->format);
  970. buffer = fmt = js_InflateString (cx, efs->format, &len);
  971. if (!buffer)
  972. goto error;
  973. expandedLength = len
  974. - (3 * argCount) /* exclude the {n} */
  975. + totalArgsLength;
  976. /*
  977. * Note - the above calculation assumes that each argument
  978. * is used once and only once in the expansion !!!
  979. */
  980. reportp->ucmessage = out = (jschar *)
  981. JS_malloc(cx, (expandedLength + 1) * sizeof(jschar));
  982. if (!out) {
  983. JS_free (cx, buffer);
  984. goto error;
  985. }
  986. while (*fmt) {
  987. if (*fmt == '{') {
  988. if (isdigit(fmt[1])) {
  989. int d = JS7_UNDEC(fmt[1]);
  990. JS_ASSERT(d < argCount);
  991. js_strncpy(out, reportp->messageArgs[d],
  992. argLengths[d]);
  993. out += argLengths[d];
  994. fmt += 3;
  995. expandedArgs++;
  996. continue;
  997. }
  998. }
  999. *out++ = *fmt++;
  1000. }
  1001. JS_ASSERT(expandedArgs == argCount);
  1002. *out = 0;
  1003. JS_free (cx, buffer);
  1004. *messagep =
  1005. js_DeflateString(cx, reportp->ucmessage,
  1006. (size_t)(out - reportp->ucmessage));
  1007. if (!*messagep)
  1008. goto error;
  1009. }
  1010. } else {
  1011. /*
  1012. * Zero arguments: the format string (if it exists) is the
  1013. * entire message.
  1014. */
  1015. if (efs->format) {
  1016. size_t len;
  1017. *messagep = JS_strdup(cx, efs->format);
  1018. if (!*messagep)
  1019. goto error;
  1020. len = strlen(*messagep);
  1021. reportp->ucmessage = js_InflateString(cx, *messagep, &len);
  1022. if (!reportp->ucmessage)
  1023. goto error;
  1024. }
  1025. }
  1026. }
  1027. if (*messagep == NULL) {
  1028. /* where's the right place for this ??? */
  1029. const char *defaultErrorMessage
  1030. = "No error message available for error number %d";
  1031. size_t nbytes = strlen(defaultErrorMessage) + 16;
  1032. *messagep = (char *)JS_malloc(cx, nbytes);
  1033. if (!*messagep)
  1034. goto error;
  1035. JS_snprintf(*messagep, nbytes, defaultErrorMessage, errorNumber);
  1036. }
  1037. return JS_TRUE;
  1038. error:
  1039. if (reportp->messageArgs) {
  1040. /* free the arguments only if we allocated them */
  1041. if (charArgs) {
  1042. i = 0;
  1043. while (reportp->messageArgs[i])
  1044. JS_free(cx, (void *)reportp->messageArgs[i++]);
  1045. }
  1046. JS_free(cx, (void *)reportp->messageArgs);
  1047. reportp->messageArgs = NULL;
  1048. }
  1049. if (reportp->ucmessage) {
  1050. JS_free(cx, (void *)reportp->ucmessage);
  1051. reportp->ucmessage = NULL;
  1052. }
  1053. if (*messagep) {
  1054. JS_free(cx, (void *)*messagep);
  1055. *messagep = NULL;
  1056. }
  1057. return JS_FALSE;
  1058. }
  1059. JSBool
  1060. js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback,
  1061. void *userRef, const uintN errorNumber,
  1062. JSBool charArgs, va_list ap)
  1063. {
  1064. JSStackFrame *fp;
  1065. JSErrorReport report;
  1066. char *message;
  1067. JSBool warning;
  1068. if ((flags & JSREPORT_STRICT) && !JS_HAS_STRICT_OPTION(cx))
  1069. return JS_TRUE;
  1070. memset(&report, 0, sizeof (struct JSErrorReport));
  1071. report.flags = flags;
  1072. report.errorNumber = errorNumber;
  1073. /*
  1074. * If we can't find out where the error was based on the current frame,
  1075. * see if the next frame has a script/pc combo we can use.
  1076. */
  1077. for (fp = cx->fp; fp; fp = fp->down) {
  1078. if (fp->regs) {
  1079. report.filename = fp->script->filename;
  1080. report.lineno = js_FramePCToLineNumber(cx, fp);
  1081. break;
  1082. }
  1083. }
  1084. if (!js_ExpandErrorArguments(cx, callback, userRef, errorNumber,
  1085. &message, &report, &warning, charArgs, ap)) {
  1086. return JS_FALSE;
  1087. }
  1088. ReportError(cx, message, &report);
  1089. if (message)
  1090. JS_free(cx, message);
  1091. if (report.messageArgs) {
  1092. /*
  1093. * js_ExpandErrorArguments owns its messageArgs only if it had to
  1094. * inflate the arguments (from regular |char *|s).
  1095. */
  1096. if (charArgs) {
  1097. int i = 0;
  1098. while (report.messageArgs[i])
  1099. JS_free(cx, (void *)report.messageArgs[i++]);
  1100. }
  1101. JS_free(cx, (void *)report.messageArgs);
  1102. }
  1103. if (report.ucmessage)
  1104. JS_free(cx, (void *)report.ucmessage);
  1105. return warning;
  1106. }
  1107. JS_FRIEND_API(void)
  1108. js_ReportErrorAgain(JSContext *cx, const char *message, JSErrorReport *reportp)
  1109. {
  1110. JSErrorReporter onError;
  1111. if (!message)
  1112. return;
  1113. if (cx->lastMessage)
  1114. free(cx->lastMessage);
  1115. cx->lastMessage = JS_strdup(cx, message);
  1116. if (!cx->lastMessage)
  1117. return;
  1118. onError = cx->errorReporter;
  1119. /*
  1120. * If debugErrorHook is present then we give it a chance to veto
  1121. * sending the error on to the regular ErrorReporter.
  1122. */
  1123. if (onError) {
  1124. JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
  1125. if (hook &&
  1126. !hook(cx, cx->lastMessage, reportp,
  1127. cx->debugHooks->debugErrorHookData)) {
  1128. onError = NULL;
  1129. }
  1130. }
  1131. if (onError)
  1132. onError(cx, cx->lastMessage, reportp);
  1133. }
  1134. void
  1135. js_ReportIsNotDefined(JSContext *cx, const char *name)
  1136. {
  1137. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_DEFINED, name);
  1138. }
  1139. JSBool
  1140. js_ReportIsNullOrUndefined(JSContext *cx, intN spindex, jsval v,
  1141. JSString *fallback)
  1142. {
  1143. char *bytes;
  1144. JSBool ok;
  1145. bytes = js_DecompileValueGenerator(cx, spindex, v, fallback);
  1146. if (!bytes)
  1147. return JS_FALSE;
  1148. if (strcmp(bytes, js_undefined_str) == 0 ||
  1149. strcmp(bytes, js_null_str) == 0) {
  1150. ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
  1151. js_GetErrorMessage, NULL,
  1152. JSMSG_NO_PROPERTIES, bytes,
  1153. NULL, NULL);
  1154. } else if (JSVAL_IS_VOID(v)) {
  1155. ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
  1156. js_GetErrorMessage, NULL,
  1157. JSMSG_NULL_OR_UNDEFINED, bytes,
  1158. js_undefined_str, NULL);
  1159. } else {
  1160. JS_ASSERT(JSVAL_IS_NULL(v));
  1161. ok = JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
  1162. js_GetErrorMessage, NULL,
  1163. JSMSG_NULL_OR_UNDEFINED, bytes,
  1164. js_null_str, NULL);
  1165. }
  1166. JS_free(cx, bytes);
  1167. return ok;
  1168. }
  1169. void
  1170. js_ReportMissingArg(JSContext *cx, jsval *vp, uintN arg)
  1171. {
  1172. char argbuf[11];
  1173. char *bytes;
  1174. JSAtom *atom;
  1175. JS_snprintf(argbuf, sizeof argbuf, "%u", arg);
  1176. bytes = NULL;
  1177. if (VALUE_IS_FUNCTION(cx, *vp)) {
  1178. atom = GET_FUNCTION_PRIVATE(cx, JSVAL_TO_OBJECT(*vp))->atom;
  1179. bytes = js_DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, *vp,
  1180. ATOM_TO_STRING(atom));
  1181. if (!bytes)
  1182. return;
  1183. }
  1184. JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
  1185. JSMSG_MISSING_FUN_ARG, argbuf,
  1186. bytes ? bytes : "");
  1187. JS_free(cx, bytes);
  1188. }
  1189. JSBool
  1190. js_ReportValueErrorFlags(JSContext *cx, uintN flags, const uintN errorNumber,
  1191. intN spindex, jsval v, JSString *fallback,
  1192. const char *arg1, const char *arg2)
  1193. {
  1194. char *bytes;
  1195. JSBool ok;
  1196. JS_ASSERT(js_ErrorFormatString[errorNumber].argCount >= 1);
  1197. JS_ASSERT(js_ErrorFormatString[errorNumber].argCount <= 3);
  1198. bytes = js_DecompileValueGenerator(cx, spindex, v, fallback);
  1199. if (!bytes)
  1200. return JS_FALSE;
  1201. ok = JS_ReportErrorFlagsAndNumber(cx, flags, js_GetErrorMessage,
  1202. NULL, errorNumber, bytes, arg1, arg2);
  1203. JS_free(cx, bytes);
  1204. return ok;
  1205. }
  1206. #if defined DEBUG && defined XP_UNIX
  1207. /* For gdb usage. */
  1208. void js_traceon(JSContext *cx) { cx->tracefp = stderr; }
  1209. void js_traceoff(JSContext *cx) { cx->tracefp = NULL; }
  1210. #endif
  1211. JSErrorFormatString js_ErrorFormatString[JSErr_Limit] = {
  1212. #define MSG_DEF(name, number, count, exception, format) \
  1213. { format, count, exception } ,
  1214. #include "js.msg"
  1215. #undef MSG_DEF
  1216. };
  1217. JS_FRIEND_API(const JSErrorFormatString *)
  1218. js_GetErrorMessage(void *userRef, const char *locale, const uintN errorNumber)
  1219. {
  1220. if ((errorNumber > 0) && (errorNumber < JSErr_Limit))
  1221. return &js_ErrorFormatString[errorNumber];
  1222. return NULL;
  1223. }
  1224. JSBool
  1225. js_ResetOperationCount(JSContext *cx)
  1226. {
  1227. JSScript *script;
  1228. JS_ASSERT(cx->operationCount <= 0);
  1229. JS_ASSERT(cx->operationLimit > 0);
  1230. cx->operationCount = (int32) cx->operationLimit;
  1231. if (cx->operationCallbackIsSet)
  1232. return cx->operationCallback(cx);
  1233. if (cx->operationCallback) {
  1234. /*
  1235. * Invoke the deprecated branch callback. It may be called only when
  1236. * the top-most frame is scripted or JSOPTION_NATIVE_BRANCH_CALLBACK
  1237. * is set.
  1238. */
  1239. script = cx->fp ? cx->fp->script : NULL;
  1240. if (script || JS_HAS_OPTION(cx, JSOPTION_NATIVE_BRANCH_CALLBACK))
  1241. return ((JSBranchCallback) cx->operationCallback)(cx, script);
  1242. }
  1243. return JS_TRUE;
  1244. }