PageRenderTime 50ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsarena.cpp

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ | 450 lines | 300 code | 44 blank | 106 comment | 56 complexity | 1e40fc1821c48810cfb168104a28af98 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. *
  3. * ***** BEGIN LICENSE BLOCK *****
  4. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  5. *
  6. * The contents of this file are subject to the Mozilla Public License Version
  7. * 1.1 (the "License"); you may not use this file except in compliance with
  8. * the License. You may obtain a copy of the License at
  9. * http://www.mozilla.org/MPL/
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. *
  16. * The Original Code is Mozilla Communicator client code, released
  17. * March 31, 1998.
  18. *
  19. * The Initial Developer of the Original Code is
  20. * Netscape Communications Corporation.
  21. * Portions created by the Initial Developer are Copyright (C) 1998
  22. * the Initial Developer. All Rights Reserved.
  23. *
  24. * Contributor(s):
  25. *
  26. * Alternatively, the contents of this file may be used under the terms of
  27. * either of the GNU General Public License Version 2 or later (the "GPL"),
  28. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  29. * in which case the provisions of the GPL or the LGPL are applicable instead
  30. * of those above. If you wish to allow use of your version of this file only
  31. * under the terms of either the GPL or the LGPL, and not to allow others to
  32. * use your version of this file under the terms of the MPL, indicate your
  33. * decision by deleting the provisions above and replace them with the notice
  34. * and other provisions required by the GPL or the LGPL. If you do not delete
  35. * the provisions above, a recipient may use your version of this file under
  36. * the terms of any one of the MPL, the GPL or the LGPL.
  37. *
  38. * ***** END LICENSE BLOCK ***** */
  39. /*
  40. * Lifetime-based fast allocation, inspired by much prior art, including
  41. * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
  42. * David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
  43. */
  44. #include "jsstddef.h"
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include "jstypes.h"
  48. #include "jsbit.h"
  49. #include "jsarena.h" /* Added by JSIFY */
  50. #include "jsutil.h" /* Added by JSIFY */
  51. #ifdef JS_ARENAMETER
  52. static JSArenaStats *arena_stats_list;
  53. #define COUNT(pool,what) (pool)->stats.what++
  54. #else
  55. #define COUNT(pool,what) /* nothing */
  56. #endif
  57. #define JS_ARENA_DEFAULT_ALIGN sizeof(double)
  58. JS_PUBLIC_API(void)
  59. JS_INIT_NAMED_ARENA_POOL(JSArenaPool *pool, const char *name, size_t size,
  60. size_t align, size_t *quotap)
  61. {
  62. if (align == 0)
  63. align = JS_ARENA_DEFAULT_ALIGN;
  64. pool->mask = JS_BITMASK(JS_CeilingLog2(align));
  65. pool->first.next = NULL;
  66. pool->first.base = pool->first.avail = pool->first.limit =
  67. JS_ARENA_ALIGN(pool, &pool->first + 1);
  68. pool->current = &pool->first;
  69. pool->arenasize = size;
  70. pool->quotap = quotap;
  71. #ifdef JS_ARENAMETER
  72. memset(&pool->stats, 0, sizeof pool->stats);
  73. pool->stats.name = strdup(name);
  74. pool->stats.next = arena_stats_list;
  75. arena_stats_list = &pool->stats;
  76. #endif
  77. }
  78. /*
  79. * An allocation that consumes more than pool->arenasize also has a header
  80. * pointing back to its previous arena's next member. This header is not
  81. * included in [a->base, a->limit), so its space can't be wrongly claimed.
  82. *
  83. * As the header is a pointer, it must be well-aligned. If pool->mask is
  84. * greater than or equal to POINTER_MASK, the header just preceding a->base
  85. * for an oversized arena a is well-aligned, because a->base is well-aligned.
  86. * However, we may need to add more space to pad the JSArena ** back-pointer
  87. * so that it lies just behind a->base, because a might not be aligned such
  88. * that (jsuword)(a + 1) is on a pointer boundary.
  89. *
  90. * By how much must we pad? Let M be the alignment modulus for pool and P
  91. * the modulus for a pointer. Given M >= P, the base of an oversized arena
  92. * that satisfies M is well-aligned for P.
  93. *
  94. * On the other hand, if M < P, we must include enough space in the header
  95. * size to align the back-pointer on a P boundary so that it can be found by
  96. * subtracting P from a->base. This means a->base must be on a P boundary,
  97. * even though subsequent allocations from a may be aligned on a lesser (M)
  98. * boundary. Given powers of two M and P as above, the extra space needed
  99. * when M < P is P-M or POINTER_MASK - pool->mask.
  100. *
  101. * The size of a header including padding is given by the HEADER_SIZE macro,
  102. * below, for any pool (for any value of M).
  103. *
  104. * The mask to align a->base for any pool is (pool->mask | POINTER_MASK), or
  105. * HEADER_BASE_MASK(pool).
  106. *
  107. * PTR_TO_HEADER computes the address of the back-pointer, given an oversized
  108. * allocation at p. By definition, p must be a->base for the arena a that
  109. * contains p. GET_HEADER and SET_HEADER operate on an oversized arena a, in
  110. * the case of SET_HEADER with back-pointer ap.
  111. */
  112. #define POINTER_MASK ((jsuword)(JS_ALIGN_OF_POINTER - 1))
  113. #define HEADER_SIZE(pool) (sizeof(JSArena **) \
  114. + (((pool)->mask < POINTER_MASK) \
  115. ? POINTER_MASK - (pool)->mask \
  116. : 0))
  117. #define HEADER_BASE_MASK(pool) ((pool)->mask | POINTER_MASK)
  118. #define PTR_TO_HEADER(pool,p) (JS_ASSERT(((jsuword)(p) \
  119. & HEADER_BASE_MASK(pool)) \
  120. == 0), \
  121. (JSArena ***)(p) - 1)
  122. #define GET_HEADER(pool,a) (*PTR_TO_HEADER(pool, (a)->base))
  123. #define SET_HEADER(pool,a,ap) (*PTR_TO_HEADER(pool, (a)->base) = (ap))
  124. JS_PUBLIC_API(void *)
  125. JS_ArenaAllocate(JSArenaPool *pool, size_t nb)
  126. {
  127. JSArena **ap, *a, *b;
  128. jsuword extra, hdrsz, gross;
  129. void *p;
  130. /*
  131. * Search pool from current forward till we find or make enough space.
  132. *
  133. * NB: subtract nb from a->limit in the loop condition, instead of adding
  134. * nb to a->avail, to avoid overflowing a 32-bit address space (possible
  135. * when running a 32-bit program on a 64-bit system where the kernel maps
  136. * the heap up against the top of the 32-bit address space).
  137. *
  138. * Thanks to Juergen Kreileder <jk@blackdown.de>, who brought this up in
  139. * https://bugzilla.mozilla.org/show_bug.cgi?id=279273.
  140. */
  141. JS_ASSERT((nb & pool->mask) == 0);
  142. for (a = pool->current; nb > a->limit || a->avail > a->limit - nb;
  143. pool->current = a) {
  144. ap = &a->next;
  145. if (!*ap) {
  146. /* Not enough space in pool, so we must malloc. */
  147. extra = (nb > pool->arenasize) ? HEADER_SIZE(pool) : 0;
  148. hdrsz = sizeof *a + extra + pool->mask;
  149. gross = hdrsz + JS_MAX(nb, pool->arenasize);
  150. if (gross < nb)
  151. return NULL;
  152. if (pool->quotap) {
  153. if (gross > *pool->quotap)
  154. return NULL;
  155. b = (JSArena *) malloc(gross);
  156. if (!b)
  157. return NULL;
  158. *pool->quotap -= gross;
  159. } else {
  160. b = (JSArena *) malloc(gross);
  161. if (!b)
  162. return NULL;
  163. }
  164. b->next = NULL;
  165. b->limit = (jsuword)b + gross;
  166. JS_COUNT_ARENA(pool,++);
  167. COUNT(pool, nmallocs);
  168. /* If oversized, store ap in the header, just before a->base. */
  169. *ap = a = b;
  170. JS_ASSERT(gross <= JS_UPTRDIFF(a->limit, a));
  171. if (extra) {
  172. a->base = a->avail =
  173. ((jsuword)a + hdrsz) & ~HEADER_BASE_MASK(pool);
  174. SET_HEADER(pool, a, ap);
  175. } else {
  176. a->base = a->avail = JS_ARENA_ALIGN(pool, a + 1);
  177. }
  178. continue;
  179. }
  180. a = *ap; /* move to next arena */
  181. }
  182. p = (void *)a->avail;
  183. a->avail += nb;
  184. JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
  185. return p;
  186. }
  187. JS_PUBLIC_API(void *)
  188. JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr)
  189. {
  190. JSArena **ap, *a, *b;
  191. jsuword boff, aoff, extra, hdrsz, gross, growth;
  192. /*
  193. * Use the oversized-single-allocation header to avoid searching for ap.
  194. * See JS_ArenaAllocate, the SET_HEADER call.
  195. */
  196. if (size > pool->arenasize) {
  197. ap = *PTR_TO_HEADER(pool, p);
  198. a = *ap;
  199. } else {
  200. ap = &pool->first.next;
  201. while ((a = *ap) != pool->current)
  202. ap = &a->next;
  203. }
  204. JS_ASSERT(a->base == (jsuword)p);
  205. boff = JS_UPTRDIFF(a->base, a);
  206. aoff = JS_ARENA_ALIGN(pool, size + incr);
  207. JS_ASSERT(aoff > pool->arenasize);
  208. extra = HEADER_SIZE(pool); /* oversized header holds ap */
  209. hdrsz = sizeof *a + extra + pool->mask; /* header and alignment slop */
  210. gross = hdrsz + aoff;
  211. JS_ASSERT(gross > aoff);
  212. if (pool->quotap) {
  213. growth = gross - (a->limit - (jsuword) a);
  214. if (growth > *pool->quotap)
  215. return NULL;
  216. a = (JSArena *) realloc(a, gross);
  217. if (!a)
  218. return NULL;
  219. *pool->quotap -= growth;
  220. } else {
  221. a = (JSArena *) realloc(a, gross);
  222. if (!a)
  223. return NULL;
  224. }
  225. #ifdef JS_ARENAMETER
  226. pool->stats.nreallocs++;
  227. #endif
  228. if (a != *ap) {
  229. /* Oops, realloc moved the allocation: update other pointers to a. */
  230. if (pool->current == *ap)
  231. pool->current = a;
  232. b = a->next;
  233. if (b && b->avail - b->base > pool->arenasize) {
  234. JS_ASSERT(GET_HEADER(pool, b) == &(*ap)->next);
  235. SET_HEADER(pool, b, &a->next);
  236. }
  237. /* Now update *ap, the next link of the arena before a. */
  238. *ap = a;
  239. }
  240. a->base = ((jsuword)a + hdrsz) & ~HEADER_BASE_MASK(pool);
  241. a->limit = (jsuword)a + gross;
  242. a->avail = a->base + aoff;
  243. JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
  244. /* Check whether realloc aligned differently, and copy if necessary. */
  245. if (boff != JS_UPTRDIFF(a->base, a))
  246. memmove((void *)a->base, (char *)a + boff, size);
  247. /* Store ap in the oversized-load arena header. */
  248. SET_HEADER(pool, a, ap);
  249. return (void *)a->base;
  250. }
  251. JS_PUBLIC_API(void *)
  252. JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr)
  253. {
  254. void *newp;
  255. /*
  256. * If p points to an oversized allocation, it owns an entire arena, so we
  257. * can simply realloc the arena.
  258. */
  259. if (size > pool->arenasize)
  260. return JS_ArenaRealloc(pool, p, size, incr);
  261. JS_ARENA_ALLOCATE(newp, pool, size + incr);
  262. if (newp)
  263. memcpy(newp, p, size);
  264. return newp;
  265. }
  266. /*
  267. * Free tail arenas linked after head, which may not be the true list head.
  268. * Reset pool->current to point to head in case it pointed at a tail arena.
  269. */
  270. static void
  271. FreeArenaList(JSArenaPool *pool, JSArena *head)
  272. {
  273. JSArena **ap, *a;
  274. ap = &head->next;
  275. a = *ap;
  276. if (!a)
  277. return;
  278. #ifdef DEBUG
  279. do {
  280. JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
  281. a->avail = a->base;
  282. JS_CLEAR_UNUSED(a);
  283. } while ((a = a->next) != NULL);
  284. a = *ap;
  285. #endif
  286. do {
  287. *ap = a->next;
  288. if (pool->quotap)
  289. *pool->quotap += a->limit - (jsuword) a;
  290. JS_CLEAR_ARENA(a);
  291. JS_COUNT_ARENA(pool,--);
  292. free(a);
  293. } while ((a = *ap) != NULL);
  294. pool->current = head;
  295. }
  296. JS_PUBLIC_API(void)
  297. JS_ArenaRelease(JSArenaPool *pool, char *mark)
  298. {
  299. JSArena *a;
  300. for (a = &pool->first; a; a = a->next) {
  301. JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
  302. if (JS_ARENA_MARK_MATCH(a, mark)) {
  303. a->avail = JS_ARENA_ALIGN(pool, mark);
  304. JS_ASSERT(a->avail <= a->limit);
  305. FreeArenaList(pool, a);
  306. return;
  307. }
  308. }
  309. }
  310. JS_PUBLIC_API(void)
  311. JS_FreeArenaPool(JSArenaPool *pool)
  312. {
  313. FreeArenaList(pool, &pool->first);
  314. COUNT(pool, ndeallocs);
  315. }
  316. JS_PUBLIC_API(void)
  317. JS_FinishArenaPool(JSArenaPool *pool)
  318. {
  319. FreeArenaList(pool, &pool->first);
  320. #ifdef JS_ARENAMETER
  321. {
  322. JSArenaStats *stats, **statsp;
  323. if (pool->stats.name) {
  324. free(pool->stats.name);
  325. pool->stats.name = NULL;
  326. }
  327. for (statsp = &arena_stats_list; (stats = *statsp) != 0;
  328. statsp = &stats->next) {
  329. if (stats == &pool->stats) {
  330. *statsp = stats->next;
  331. return;
  332. }
  333. }
  334. }
  335. #endif
  336. }
  337. JS_PUBLIC_API(void)
  338. JS_ArenaFinish()
  339. {
  340. }
  341. JS_PUBLIC_API(void)
  342. JS_ArenaShutDown(void)
  343. {
  344. }
  345. #ifdef JS_ARENAMETER
  346. JS_PUBLIC_API(void)
  347. JS_ArenaCountAllocation(JSArenaPool *pool, size_t nb)
  348. {
  349. pool->stats.nallocs++;
  350. pool->stats.nbytes += nb;
  351. if (nb > pool->stats.maxalloc)
  352. pool->stats.maxalloc = nb;
  353. pool->stats.variance += nb * nb;
  354. }
  355. JS_PUBLIC_API(void)
  356. JS_ArenaCountInplaceGrowth(JSArenaPool *pool, size_t size, size_t incr)
  357. {
  358. pool->stats.ninplace++;
  359. }
  360. JS_PUBLIC_API(void)
  361. JS_ArenaCountGrowth(JSArenaPool *pool, size_t size, size_t incr)
  362. {
  363. pool->stats.ngrows++;
  364. pool->stats.nbytes += incr;
  365. pool->stats.variance -= size * size;
  366. size += incr;
  367. if (size > pool->stats.maxalloc)
  368. pool->stats.maxalloc = size;
  369. pool->stats.variance += size * size;
  370. }
  371. JS_PUBLIC_API(void)
  372. JS_ArenaCountRelease(JSArenaPool *pool, char *mark)
  373. {
  374. pool->stats.nreleases++;
  375. }
  376. JS_PUBLIC_API(void)
  377. JS_ArenaCountRetract(JSArenaPool *pool, char *mark)
  378. {
  379. pool->stats.nfastrels++;
  380. }
  381. #include <stdio.h>
  382. JS_PUBLIC_API(void)
  383. JS_DumpArenaStats(FILE *fp)
  384. {
  385. JSArenaStats *stats;
  386. double mean, sigma;
  387. for (stats = arena_stats_list; stats; stats = stats->next) {
  388. mean = JS_MeanAndStdDev(stats->nallocs, stats->nbytes, stats->variance,
  389. &sigma);
  390. fprintf(fp, "\n%s allocation statistics:\n", stats->name);
  391. fprintf(fp, " number of arenas: %u\n", stats->narenas);
  392. fprintf(fp, " number of allocations: %u\n", stats->nallocs);
  393. fprintf(fp, " number of malloc calls: %u\n", stats->nmallocs);
  394. fprintf(fp, " number of deallocations: %u\n", stats->ndeallocs);
  395. fprintf(fp, " number of allocation growths: %u\n", stats->ngrows);
  396. fprintf(fp, " number of in-place growths: %u\n", stats->ninplace);
  397. fprintf(fp, " number of realloc'ing growths: %u\n", stats->nreallocs);
  398. fprintf(fp, "number of released allocations: %u\n", stats->nreleases);
  399. fprintf(fp, " number of fast releases: %u\n", stats->nfastrels);
  400. fprintf(fp, " total bytes allocated: %u\n", stats->nbytes);
  401. fprintf(fp, " mean allocation size: %g\n", mean);
  402. fprintf(fp, " standard deviation: %g\n", sigma);
  403. fprintf(fp, " maximum allocation size: %u\n", stats->maxalloc);
  404. }
  405. }
  406. #endif /* JS_ARENAMETER */