johnson 1.2.0 → 2.0.0.pre0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (782) hide show
  1. data/CHANGELOG.rdoc +8 -0
  2. data/Manifest.txt +762 -48
  3. data/README.rdoc +2 -1
  4. data/Rakefile +90 -18
  5. data/ext/spidermonkey/conversions.c +9 -2
  6. data/ext/spidermonkey/ruby_land_proxy.c +1 -1
  7. data/ext/spidermonkey/runtime.h +1 -1
  8. data/ext/tracemonkey/context.cc +125 -0
  9. data/ext/tracemonkey/context.h +19 -0
  10. data/ext/tracemonkey/conversions.cc +365 -0
  11. data/ext/tracemonkey/conversions.h +32 -0
  12. data/ext/tracemonkey/debugger.cc +234 -0
  13. data/ext/tracemonkey/debugger.h +10 -0
  14. data/ext/tracemonkey/extconf.rb +37 -0
  15. data/ext/tracemonkey/extensions.cc +37 -0
  16. data/ext/tracemonkey/extensions.h +12 -0
  17. data/ext/tracemonkey/global.cc +40 -0
  18. data/ext/tracemonkey/global.h +11 -0
  19. data/ext/tracemonkey/idhash.cc +16 -0
  20. data/ext/tracemonkey/idhash.h +8 -0
  21. data/ext/tracemonkey/immutable_node.cc +1199 -0
  22. data/ext/tracemonkey/immutable_node.cc.erb +559 -0
  23. data/ext/tracemonkey/immutable_node.h +22 -0
  24. data/ext/tracemonkey/jroot.h +215 -0
  25. data/ext/tracemonkey/js_land_proxy.cc +620 -0
  26. data/ext/tracemonkey/js_land_proxy.h +20 -0
  27. data/ext/tracemonkey/ruby_land_proxy.cc +618 -0
  28. data/ext/tracemonkey/ruby_land_proxy.h +38 -0
  29. data/ext/tracemonkey/runtime.cc +454 -0
  30. data/ext/tracemonkey/runtime.h +27 -0
  31. data/ext/tracemonkey/split_global.cc +392 -0
  32. data/ext/tracemonkey/split_global.h +11 -0
  33. data/ext/tracemonkey/tracemonkey.cc +23 -0
  34. data/ext/tracemonkey/tracemonkey.h +32 -0
  35. data/lib/johnson.rb +12 -4
  36. data/lib/johnson/error.rb +5 -0
  37. data/lib/johnson/js/prelude.js +16 -1
  38. data/lib/johnson/parser.rb +2 -1
  39. data/lib/johnson/runtime.rb +87 -26
  40. data/lib/johnson/spidermonkey/runtime.rb +7 -16
  41. data/lib/johnson/tracemonkey.rb +13 -0
  42. data/lib/johnson/tracemonkey/context.rb +10 -0
  43. data/lib/johnson/tracemonkey/debugger.rb +67 -0
  44. data/lib/johnson/tracemonkey/immutable_node.rb +282 -0
  45. data/lib/johnson/tracemonkey/js_land_proxy.rb +64 -0
  46. data/lib/johnson/tracemonkey/mutable_tree_visitor.rb +242 -0
  47. data/lib/johnson/tracemonkey/ruby_land_proxy.rb +17 -0
  48. data/lib/johnson/tracemonkey/runtime.rb +80 -0
  49. data/test/{johnson_test.rb → generic/johnson_test.rb} +1 -1
  50. data/test/{parser_test.rb → generic/parser_test.rb} +1 -1
  51. data/test/helper.rb +23 -4
  52. data/test/johnson/{browser_test.rb → generic/browser_test.rb} +1 -1
  53. data/test/johnson/{conversions → generic/conversions}/array_test.rb +1 -1
  54. data/test/johnson/{conversions → generic/conversions}/boolean_test.rb +1 -1
  55. data/test/johnson/{conversions → generic/conversions}/callable_test.rb +1 -1
  56. data/test/johnson/{conversions → generic/conversions}/file_test.rb +1 -1
  57. data/test/johnson/generic/conversions/helper.rb +1 -0
  58. data/test/johnson/{conversions → generic/conversions}/nil_test.rb +1 -1
  59. data/test/johnson/{conversions → generic/conversions}/number_test.rb +1 -1
  60. data/test/johnson/{conversions → generic/conversions}/regexp_test.rb +1 -1
  61. data/test/johnson/{conversions → generic/conversions}/string_test.rb +1 -1
  62. data/test/johnson/{conversions → generic/conversions}/struct_test.rb +1 -1
  63. data/test/johnson/{conversions → generic/conversions}/symbol_test.rb +1 -1
  64. data/test/johnson/{conversions → generic/conversions}/thread_test.rb +1 -1
  65. data/test/johnson/{custom_conversions_test.rb → generic/custom_conversions_test.rb} +1 -1
  66. data/test/johnson/generic/default_test.rb +12 -0
  67. data/test/johnson/{error_test.rb → generic/error_test.rb} +1 -1
  68. data/test/johnson/{extensions_test.rb → generic/extensions_test.rb} +1 -1
  69. data/test/johnson/generic/helper.rb +1 -0
  70. data/test/johnson/{nodes → generic/nodes}/array_literal_test.rb +1 -1
  71. data/test/johnson/{nodes → generic/nodes}/array_node_test.rb +1 -1
  72. data/test/johnson/{nodes → generic/nodes}/binary_node_test.rb +1 -1
  73. data/test/johnson/{nodes → generic/nodes}/bracket_access_test.rb +1 -1
  74. data/test/johnson/{nodes → generic/nodes}/delete_test.rb +1 -1
  75. data/test/johnson/{nodes → generic/nodes}/do_while_test.rb +1 -1
  76. data/test/johnson/{nodes → generic/nodes}/dot_accessor_test.rb +1 -1
  77. data/test/johnson/generic/nodes/export_test.rb +11 -0
  78. data/test/johnson/{nodes → generic/nodes}/for_test.rb +1 -1
  79. data/test/johnson/{nodes → generic/nodes}/function_test.rb +1 -1
  80. data/test/johnson/generic/nodes/helper.rb +1 -0
  81. data/test/johnson/{nodes → generic/nodes}/if_test.rb +16 -6
  82. data/test/johnson/generic/nodes/import_test.rb +15 -0
  83. data/test/johnson/{nodes → generic/nodes}/label_test.rb +1 -1
  84. data/test/johnson/{nodes → generic/nodes}/let_test.rb +1 -1
  85. data/test/johnson/{nodes → generic/nodes}/object_literal_test.rb +1 -1
  86. data/test/johnson/{nodes → generic/nodes}/return_test.rb +1 -1
  87. data/test/johnson/{nodes → generic/nodes}/semi_test.rb +1 -1
  88. data/test/johnson/{nodes → generic/nodes}/switch_test.rb +1 -1
  89. data/test/johnson/{nodes → generic/nodes}/ternary_test.rb +1 -1
  90. data/test/johnson/{nodes → generic/nodes}/throw_test.rb +1 -1
  91. data/test/johnson/{nodes → generic/nodes}/try_node_test.rb +36 -6
  92. data/test/johnson/{nodes → generic/nodes}/typeof_test.rb +1 -1
  93. data/test/johnson/{nodes → generic/nodes}/unary_node_test.rb +1 -1
  94. data/test/johnson/{nodes → generic/nodes}/void_test.rb +1 -1
  95. data/test/johnson/{nodes → generic/nodes}/while_test.rb +1 -1
  96. data/test/johnson/{nodes → generic/nodes}/with_test.rb +1 -1
  97. data/test/johnson/{prelude_test.rb → generic/prelude_test.rb} +1 -1
  98. data/test/johnson/{runtime_test.rb → generic/runtime_test.rb} +3 -6
  99. data/test/johnson/generic/version_test.rb +13 -0
  100. data/test/johnson/{visitors → generic/visitors}/dot_visitor_test.rb +1 -1
  101. data/test/johnson/{visitors → generic/visitors}/enumerating_visitor_test.rb +1 -1
  102. data/test/johnson/generic/visitors/helper.rb +1 -0
  103. data/test/johnson/spidermonkey/js_land_proxy_test.rb +1 -5
  104. data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +11 -7
  105. data/test/johnson/tracemonkey/context_test.rb +21 -0
  106. data/test/johnson/tracemonkey/immutable_node_test.rb +34 -0
  107. data/test/johnson/tracemonkey/js_land_proxy_test.rb +273 -0
  108. data/test/johnson/tracemonkey/ruby_land_proxy_test.rb +274 -0
  109. data/test/johnson/tracemonkey/runtime_test.rb +41 -0
  110. data/test/johnson/tracemonkey/split_global_test.rb +32 -0
  111. data/vendor/spidermonkey/js.pkg +2 -0
  112. data/vendor/tracemonkey/Makefile.in +668 -0
  113. data/vendor/tracemonkey/Makefile.ref +483 -0
  114. data/vendor/tracemonkey/README.html +54 -0
  115. data/vendor/tracemonkey/SpiderMonkey.rsp +11 -0
  116. data/vendor/tracemonkey/Y.js +19 -0
  117. data/vendor/tracemonkey/aclocal.m4 +9 -0
  118. data/vendor/tracemonkey/bench.sh +5 -0
  119. data/vendor/tracemonkey/build/autoconf/acoutput-fast.pl +202 -0
  120. data/vendor/tracemonkey/build/autoconf/altoptions.m4 +154 -0
  121. data/vendor/tracemonkey/build/autoconf/config.guess +1537 -0
  122. data/vendor/tracemonkey/build/autoconf/config.sub +1595 -0
  123. data/vendor/tracemonkey/build/autoconf/install-sh +119 -0
  124. data/vendor/tracemonkey/build/autoconf/make-makefile +315 -0
  125. data/vendor/tracemonkey/build/autoconf/match-dir.sh +101 -0
  126. data/vendor/tracemonkey/build/autoconf/moznbytetype.m4 +136 -0
  127. data/vendor/tracemonkey/build/autoconf/nspr.m4 +82 -0
  128. data/vendor/tracemonkey/build/autoconf/pkg.m4 +59 -0
  129. data/vendor/tracemonkey/build/autoconf/update-makefile.sh +118 -0
  130. data/vendor/tracemonkey/build/cygwin-wrapper +75 -0
  131. data/vendor/tracemonkey/build/hcc +111 -0
  132. data/vendor/tracemonkey/build/hcpp +155 -0
  133. data/vendor/tracemonkey/build/unix/mddepend.pl +165 -0
  134. data/vendor/tracemonkey/build/unix/uniq.pl +63 -0
  135. data/vendor/tracemonkey/build/win32/pgomerge.py +40 -0
  136. data/vendor/tracemonkey/builtins.tbl +91 -0
  137. data/vendor/tracemonkey/call.js +13 -0
  138. data/vendor/tracemonkey/config.mk +206 -0
  139. data/vendor/tracemonkey/config/Makefile.in +106 -0
  140. data/vendor/tracemonkey/config/Moz/Milestone.pm +232 -0
  141. data/vendor/tracemonkey/config/autoconf.mk.in +362 -0
  142. data/vendor/tracemonkey/config/check-sync-dirs.py +103 -0
  143. data/vendor/tracemonkey/config/check-sync-exceptions +7 -0
  144. data/vendor/tracemonkey/config/config.mk +881 -0
  145. data/vendor/tracemonkey/config/fastcwd.pl +66 -0
  146. data/vendor/tracemonkey/config/gcc_hidden.h +2 -0
  147. data/vendor/tracemonkey/config/insure.mk +53 -0
  148. data/vendor/tracemonkey/config/make-system-wrappers.pl +59 -0
  149. data/vendor/tracemonkey/config/milestone.pl +112 -0
  150. data/vendor/tracemonkey/config/milestone.txt +13 -0
  151. data/vendor/tracemonkey/config/mkdepend/Makefile.in +84 -0
  152. data/vendor/tracemonkey/config/mkdepend/cppsetup.c +233 -0
  153. data/vendor/tracemonkey/config/mkdepend/def.h +184 -0
  154. data/vendor/tracemonkey/config/mkdepend/ifparser.c +551 -0
  155. data/vendor/tracemonkey/config/mkdepend/ifparser.h +83 -0
  156. data/vendor/tracemonkey/config/mkdepend/imakemdep.h +733 -0
  157. data/vendor/tracemonkey/config/mkdepend/include.c +337 -0
  158. data/vendor/tracemonkey/config/mkdepend/main.c +860 -0
  159. data/vendor/tracemonkey/config/mkdepend/mkdepend.man +382 -0
  160. data/vendor/tracemonkey/config/mkdepend/parse.c +686 -0
  161. data/vendor/tracemonkey/config/mkdepend/pr.c +124 -0
  162. data/vendor/tracemonkey/config/nfspwd.pl +50 -0
  163. data/vendor/tracemonkey/config/nsinstall.c +481 -0
  164. data/vendor/tracemonkey/config/nsinstall.py +155 -0
  165. data/vendor/tracemonkey/config/pathsub.c +247 -0
  166. data/vendor/tracemonkey/config/pathsub.h +74 -0
  167. data/vendor/tracemonkey/config/preprocessor.pl +671 -0
  168. data/vendor/tracemonkey/config/revdepth-nt.pl +48 -0
  169. data/vendor/tracemonkey/config/revdepth.pl +51 -0
  170. data/vendor/tracemonkey/config/rules.mk +2310 -0
  171. data/vendor/tracemonkey/config/static-checking-config.mk +21 -0
  172. data/vendor/tracemonkey/config/static-checking.js +92 -0
  173. data/vendor/tracemonkey/config/string-format.js +61 -0
  174. data/vendor/tracemonkey/config/system-headers +1035 -0
  175. data/vendor/tracemonkey/config/version.mk +85 -0
  176. data/vendor/tracemonkey/config/version_win.pl +442 -0
  177. data/vendor/tracemonkey/configure +14183 -0
  178. data/vendor/tracemonkey/configure.in +5363 -0
  179. data/vendor/tracemonkey/correct.sh +23 -0
  180. data/vendor/tracemonkey/correct/check-3d-morph.js +55 -0
  181. data/vendor/tracemonkey/correct/check-3d-raytrace.js +445 -0
  182. data/vendor/tracemonkey/correct/check-access-binary-trees.js +52 -0
  183. data/vendor/tracemonkey/correct/check-access-fannkuch.js +66 -0
  184. data/vendor/tracemonkey/correct/check-access-nbody.js +171 -0
  185. data/vendor/tracemonkey/correct/check-access-nsieve.js +40 -0
  186. data/vendor/tracemonkey/correct/check-bitops-3bit-bits-in-byte.js +35 -0
  187. data/vendor/tracemonkey/correct/check-bitops-bits-in-byte.js +24 -0
  188. data/vendor/tracemonkey/correct/check-bitops-bitwise-and.js +29 -0
  189. data/vendor/tracemonkey/correct/check-bitops-nsieve-bits.js +40 -0
  190. data/vendor/tracemonkey/correct/check-controlflow-recursive.js +27 -0
  191. data/vendor/tracemonkey/correct/check-date-format-tofte.js +302 -0
  192. data/vendor/tracemonkey/correct/check-date-format-xparb.js +421 -0
  193. data/vendor/tracemonkey/correct/check-mont.js +119 -0
  194. data/vendor/tracemonkey/dtoa.c +3335 -0
  195. data/vendor/tracemonkey/editline/Makefile.in +55 -0
  196. data/vendor/tracemonkey/editline/Makefile.ref +143 -0
  197. data/vendor/tracemonkey/editline/README +83 -0
  198. data/vendor/tracemonkey/editline/editline.3 +175 -0
  199. data/vendor/tracemonkey/editline/editline.c +1371 -0
  200. data/vendor/tracemonkey/editline/editline.h +135 -0
  201. data/vendor/tracemonkey/editline/sysunix.c +182 -0
  202. data/vendor/tracemonkey/editline/unix.h +82 -0
  203. data/vendor/tracemonkey/if.js +13 -0
  204. data/vendor/tracemonkey/imacro_asm.js.in +396 -0
  205. data/vendor/tracemonkey/imacros.c.out +1034 -0
  206. data/vendor/tracemonkey/imacros.jsasm +770 -0
  207. data/vendor/tracemonkey/javascript-trace.d +73 -0
  208. data/vendor/tracemonkey/jitstats.tbl +55 -0
  209. data/vendor/tracemonkey/js-config.h.in +82 -0
  210. data/vendor/tracemonkey/js-config.in +111 -0
  211. data/vendor/tracemonkey/js.mdp +0 -0
  212. data/vendor/tracemonkey/js.msg +312 -0
  213. data/vendor/tracemonkey/js3240.rc +79 -0
  214. data/vendor/tracemonkey/jsOS240.def +654 -0
  215. data/vendor/tracemonkey/jsapi.cpp +6005 -0
  216. data/vendor/tracemonkey/jsapi.h +2727 -0
  217. data/vendor/tracemonkey/jsarena.cpp +450 -0
  218. data/vendor/tracemonkey/jsarena.h +318 -0
  219. data/vendor/tracemonkey/jsarray.cpp +3664 -0
  220. data/vendor/tracemonkey/jsarray.h +238 -0
  221. data/vendor/tracemonkey/jsatom.cpp +1244 -0
  222. data/vendor/tracemonkey/jsatom.h +493 -0
  223. data/vendor/tracemonkey/jsbit.h +249 -0
  224. data/vendor/tracemonkey/jsbool.cpp +184 -0
  225. data/vendor/tracemonkey/jsbool.h +88 -0
  226. data/vendor/tracemonkey/jsbuiltins.cpp +415 -0
  227. data/vendor/tracemonkey/jsbuiltins.h +456 -0
  228. data/vendor/tracemonkey/jsclist.h +139 -0
  229. data/vendor/tracemonkey/jscntxt.cpp +1816 -0
  230. data/vendor/tracemonkey/jscntxt.h +1541 -0
  231. data/vendor/tracemonkey/jscompat.h +57 -0
  232. data/vendor/tracemonkey/jsconfig.mk +181 -0
  233. data/vendor/tracemonkey/jscpucfg.cpp +194 -0
  234. data/vendor/tracemonkey/jscpucfg.h +91 -0
  235. data/vendor/tracemonkey/jsdate.cpp +2465 -0
  236. data/vendor/tracemonkey/jsdate.h +129 -0
  237. data/vendor/tracemonkey/jsdbgapi.cpp +2017 -0
  238. data/vendor/tracemonkey/jsdbgapi.h +500 -0
  239. data/vendor/tracemonkey/jsdhash.cpp +876 -0
  240. data/vendor/tracemonkey/jsdhash.h +588 -0
  241. data/vendor/tracemonkey/jsdtoa.cpp +572 -0
  242. data/vendor/tracemonkey/jsdtoa.h +131 -0
  243. data/vendor/tracemonkey/jsdtracef.c +318 -0
  244. data/vendor/tracemonkey/jsdtracef.h +81 -0
  245. data/vendor/tracemonkey/jsemit.cpp +7292 -0
  246. data/vendor/tracemonkey/jsemit.h +802 -0
  247. data/vendor/tracemonkey/jsexn.cpp +1337 -0
  248. data/vendor/tracemonkey/jsexn.h +96 -0
  249. data/vendor/tracemonkey/jsfile.cpp +2747 -0
  250. data/vendor/tracemonkey/jsfile.h +56 -0
  251. data/vendor/tracemonkey/jsfile.msg +90 -0
  252. data/vendor/tracemonkey/jsfun.cpp +3089 -0
  253. data/vendor/tracemonkey/jsfun.h +366 -0
  254. data/vendor/tracemonkey/jsgc.cpp +3816 -0
  255. data/vendor/tracemonkey/jsgc.h +429 -0
  256. data/vendor/tracemonkey/jshash.cpp +477 -0
  257. data/vendor/tracemonkey/jshash.h +151 -0
  258. data/vendor/tracemonkey/jsify.pl +483 -0
  259. data/vendor/tracemonkey/jsinterp.cpp +7441 -0
  260. data/vendor/tracemonkey/jsinterp.h +666 -0
  261. data/vendor/tracemonkey/jsinvoke.cpp +42 -0
  262. data/vendor/tracemonkey/jsiter.cpp +1040 -0
  263. data/vendor/tracemonkey/jsiter.h +140 -0
  264. data/vendor/tracemonkey/jskeyword.tbl +124 -0
  265. data/vendor/tracemonkey/jskwgen.cpp +460 -0
  266. data/vendor/tracemonkey/jslibmath.h +69 -0
  267. data/vendor/tracemonkey/jslock.cpp +1512 -0
  268. data/vendor/tracemonkey/jslock.h +325 -0
  269. data/vendor/tracemonkey/jslocko.asm +60 -0
  270. data/vendor/tracemonkey/jslog2.cpp +111 -0
  271. data/vendor/tracemonkey/jslong.h +167 -0
  272. data/vendor/tracemonkey/jsmath.cpp +806 -0
  273. data/vendor/tracemonkey/jsmath.h +63 -0
  274. data/vendor/tracemonkey/jsnum.cpp +1374 -0
  275. data/vendor/tracemonkey/jsnum.h +280 -0
  276. data/vendor/tracemonkey/jsobj.cpp +6165 -0
  277. data/vendor/tracemonkey/jsobj.h +870 -0
  278. data/vendor/tracemonkey/json.cpp +1338 -0
  279. data/vendor/tracemonkey/json.h +108 -0
  280. data/vendor/tracemonkey/jsopcode.cpp +5484 -0
  281. data/vendor/tracemonkey/jsopcode.h +434 -0
  282. data/vendor/tracemonkey/jsopcode.tbl +591 -0
  283. data/vendor/tracemonkey/jsoplengen.cpp +121 -0
  284. data/vendor/tracemonkey/jsotypes.h +202 -0
  285. data/vendor/tracemonkey/jsparse.cpp +9257 -0
  286. data/vendor/tracemonkey/jsparse.h +900 -0
  287. data/vendor/tracemonkey/jsprf.cpp +1262 -0
  288. data/vendor/tracemonkey/jsprf.h +150 -0
  289. data/vendor/tracemonkey/jsproto.tbl +117 -0
  290. data/vendor/tracemonkey/jsprvtd.h +366 -0
  291. data/vendor/tracemonkey/jspubtd.h +585 -0
  292. data/vendor/tracemonkey/jsregexp.cpp +5051 -0
  293. data/vendor/tracemonkey/jsregexp.h +199 -0
  294. data/vendor/tracemonkey/jsreops.tbl +145 -0
  295. data/vendor/tracemonkey/jsscan.cpp +2040 -0
  296. data/vendor/tracemonkey/jsscan.h +467 -0
  297. data/vendor/tracemonkey/jsscope.cpp +1966 -0
  298. data/vendor/tracemonkey/jsscope.h +487 -0
  299. data/vendor/tracemonkey/jsscript.cpp +1932 -0
  300. data/vendor/tracemonkey/jsscript.h +345 -0
  301. data/vendor/tracemonkey/jsshell.msg +54 -0
  302. data/vendor/tracemonkey/jsstack.js +167 -0
  303. data/vendor/tracemonkey/jsstaticcheck.h +69 -0
  304. data/vendor/tracemonkey/jsstddef.h +87 -0
  305. data/vendor/tracemonkey/jsstdint.h +96 -0
  306. data/vendor/tracemonkey/jsstr.cpp +5277 -0
  307. data/vendor/tracemonkey/jsstr.h +702 -0
  308. data/vendor/tracemonkey/jstracer.cpp +10991 -0
  309. data/vendor/tracemonkey/jstracer.h +794 -0
  310. data/vendor/tracemonkey/jstypes.h +481 -0
  311. data/vendor/tracemonkey/jsutil.cpp +361 -0
  312. data/vendor/tracemonkey/jsutil.h +178 -0
  313. data/vendor/tracemonkey/jsversion.h +243 -0
  314. data/vendor/tracemonkey/jswince.asm +44 -0
  315. data/vendor/tracemonkey/jsxdrapi.cpp +800 -0
  316. data/vendor/tracemonkey/jsxdrapi.h +220 -0
  317. data/vendor/tracemonkey/jsxml.cpp +8327 -0
  318. data/vendor/tracemonkey/jsxml.h +305 -0
  319. data/vendor/tracemonkey/liveconnect/LiveConnect.dsp +157 -0
  320. data/vendor/tracemonkey/liveconnect/LiveConnectShell.dsp +120 -0
  321. data/vendor/tracemonkey/liveconnect/LiveConnectShell.dsw +44 -0
  322. data/vendor/tracemonkey/liveconnect/Makefile.in +105 -0
  323. data/vendor/tracemonkey/liveconnect/Makefile.ref +169 -0
  324. data/vendor/tracemonkey/liveconnect/README.html +712 -0
  325. data/vendor/tracemonkey/liveconnect/_jni/netscape_javascript_JSException.h +14 -0
  326. data/vendor/tracemonkey/liveconnect/_jni/netscape_javascript_JSObject.h +155 -0
  327. data/vendor/tracemonkey/liveconnect/classes/Makefile.in +89 -0
  328. data/vendor/tracemonkey/liveconnect/classes/Makefile.ref +57 -0
  329. data/vendor/tracemonkey/liveconnect/classes/netscape/Makefile.ref +47 -0
  330. data/vendor/tracemonkey/liveconnect/classes/netscape/javascript/JSException.java +140 -0
  331. data/vendor/tracemonkey/liveconnect/classes/netscape/javascript/JSObject.java +183 -0
  332. data/vendor/tracemonkey/liveconnect/classes/netscape/javascript/JSProxy.java +58 -0
  333. data/vendor/tracemonkey/liveconnect/classes/netscape/javascript/JSRunnable.java +70 -0
  334. data/vendor/tracemonkey/liveconnect/classes/netscape/javascript/JSUtil.java +59 -0
  335. data/vendor/tracemonkey/liveconnect/classes/netscape/javascript/Makefile.ref +53 -0
  336. data/vendor/tracemonkey/liveconnect/config/AIX4.1.mk +45 -0
  337. data/vendor/tracemonkey/liveconnect/config/AIX4.2.mk +45 -0
  338. data/vendor/tracemonkey/liveconnect/config/AIX4.3.mk +50 -0
  339. data/vendor/tracemonkey/liveconnect/config/HP-UXB.10.10.mk +43 -0
  340. data/vendor/tracemonkey/liveconnect/config/HP-UXB.10.20.mk +43 -0
  341. data/vendor/tracemonkey/liveconnect/config/HP-UXB.11.00.mk +43 -0
  342. data/vendor/tracemonkey/liveconnect/config/IRIX6.2.mk +43 -0
  343. data/vendor/tracemonkey/liveconnect/config/IRIX6.3.mk +43 -0
  344. data/vendor/tracemonkey/liveconnect/config/IRIX6.5.mk +43 -0
  345. data/vendor/tracemonkey/liveconnect/config/Linux_All.mk +73 -0
  346. data/vendor/tracemonkey/liveconnect/config/OSF1V4.0.mk +65 -0
  347. data/vendor/tracemonkey/liveconnect/config/OSF1V5.0.mk +62 -0
  348. data/vendor/tracemonkey/liveconnect/config/SunOS5.5.1.mk +55 -0
  349. data/vendor/tracemonkey/liveconnect/config/SunOS5.6.mk +39 -0
  350. data/vendor/tracemonkey/liveconnect/config/SunOS5.7.mk +39 -0
  351. data/vendor/tracemonkey/liveconnect/config/SunOS5.8.mk +39 -0
  352. data/vendor/tracemonkey/liveconnect/config/WINNT4.0.mk +53 -0
  353. data/vendor/tracemonkey/liveconnect/jsj.c +886 -0
  354. data/vendor/tracemonkey/liveconnect/jsj.msg +98 -0
  355. data/vendor/tracemonkey/liveconnect/jsj_JSObject.c +1377 -0
  356. data/vendor/tracemonkey/liveconnect/jsj_JavaArray.c +474 -0
  357. data/vendor/tracemonkey/liveconnect/jsj_JavaClass.c +737 -0
  358. data/vendor/tracemonkey/liveconnect/jsj_JavaMember.c +191 -0
  359. data/vendor/tracemonkey/liveconnect/jsj_JavaObject.c +1079 -0
  360. data/vendor/tracemonkey/liveconnect/jsj_JavaPackage.c +569 -0
  361. data/vendor/tracemonkey/liveconnect/jsj_array.c +207 -0
  362. data/vendor/tracemonkey/liveconnect/jsj_class.c +770 -0
  363. data/vendor/tracemonkey/liveconnect/jsj_convert.c +902 -0
  364. data/vendor/tracemonkey/liveconnect/jsj_field.c +421 -0
  365. data/vendor/tracemonkey/liveconnect/jsj_hash.c +488 -0
  366. data/vendor/tracemonkey/liveconnect/jsj_hash.h +161 -0
  367. data/vendor/tracemonkey/liveconnect/jsj_method.c +1825 -0
  368. data/vendor/tracemonkey/liveconnect/jsj_nodl.c +1 -0
  369. data/vendor/tracemonkey/liveconnect/jsj_private.h +677 -0
  370. data/vendor/tracemonkey/liveconnect/jsj_simpleapi.c +219 -0
  371. data/vendor/tracemonkey/liveconnect/jsj_utils.c +513 -0
  372. data/vendor/tracemonkey/liveconnect/jsjava.h +316 -0
  373. data/vendor/tracemonkey/liveconnect/netscape_javascript_JSObject.h +155 -0
  374. data/vendor/tracemonkey/liveconnect/nsCLiveconnect.cpp +785 -0
  375. data/vendor/tracemonkey/liveconnect/nsCLiveconnect.h +197 -0
  376. data/vendor/tracemonkey/liveconnect/nsCLiveconnectFactory.cpp +118 -0
  377. data/vendor/tracemonkey/liveconnect/nsCLiveconnectFactory.h +76 -0
  378. data/vendor/tracemonkey/liveconnect/nsILiveconnect.h +197 -0
  379. data/vendor/tracemonkey/liveconnect/nsISecureLiveconnect.h +94 -0
  380. data/vendor/tracemonkey/liveconnect/nsISecurityContext.h +136 -0
  381. data/vendor/tracemonkey/lock_SunOS.s +119 -0
  382. data/vendor/tracemonkey/mandelbrot-results.js +3 -0
  383. data/vendor/tracemonkey/math-partial-sums.js +32 -0
  384. data/vendor/tracemonkey/math-trace-tests.js +507 -0
  385. data/vendor/tracemonkey/md5.js +289 -0
  386. data/vendor/tracemonkey/nanojit/Assembler.cpp +1984 -0
  387. data/vendor/tracemonkey/nanojit/Assembler.h +375 -0
  388. data/vendor/tracemonkey/nanojit/Fragmento.cpp +651 -0
  389. data/vendor/tracemonkey/nanojit/Fragmento.h +237 -0
  390. data/vendor/tracemonkey/nanojit/LIR.cpp +2314 -0
  391. data/vendor/tracemonkey/nanojit/LIR.h +879 -0
  392. data/vendor/tracemonkey/nanojit/LIRopcode.tbl +252 -0
  393. data/vendor/tracemonkey/nanojit/Native.h +127 -0
  394. data/vendor/tracemonkey/nanojit/NativeARM.cpp +1742 -0
  395. data/vendor/tracemonkey/nanojit/NativeARM.h +844 -0
  396. data/vendor/tracemonkey/nanojit/NativeSparc.cpp +1130 -0
  397. data/vendor/tracemonkey/nanojit/NativeSparc.h +948 -0
  398. data/vendor/tracemonkey/nanojit/NativeThumb.cpp +1322 -0
  399. data/vendor/tracemonkey/nanojit/NativeThumb.h +525 -0
  400. data/vendor/tracemonkey/nanojit/Nativei386.cpp +1748 -0
  401. data/vendor/tracemonkey/nanojit/Nativei386.h +857 -0
  402. data/vendor/tracemonkey/nanojit/RegAlloc.cpp +183 -0
  403. data/vendor/tracemonkey/nanojit/RegAlloc.h +95 -0
  404. data/vendor/tracemonkey/nanojit/TraceTreeDrawer.cpp +306 -0
  405. data/vendor/tracemonkey/nanojit/TraceTreeDrawer.h +88 -0
  406. data/vendor/tracemonkey/nanojit/avmplus.cpp +56 -0
  407. data/vendor/tracemonkey/nanojit/avmplus.h +1016 -0
  408. data/vendor/tracemonkey/nanojit/nanojit.h +253 -0
  409. data/vendor/tracemonkey/perfect.js +39 -0
  410. data/vendor/tracemonkey/plify_jsdhash.sed +35 -0
  411. data/vendor/tracemonkey/prmjtime.cpp +869 -0
  412. data/vendor/tracemonkey/prmjtime.h +103 -0
  413. data/vendor/tracemonkey/ref-config/AIX4.1.mk +65 -0
  414. data/vendor/tracemonkey/ref-config/AIX4.2.mk +64 -0
  415. data/vendor/tracemonkey/ref-config/AIX4.3.mk +65 -0
  416. data/vendor/tracemonkey/ref-config/Darwin.mk +85 -0
  417. data/vendor/tracemonkey/ref-config/Darwin1.3.mk +81 -0
  418. data/vendor/tracemonkey/ref-config/Darwin1.4.mk +41 -0
  419. data/vendor/tracemonkey/ref-config/Darwin5.2.mk +81 -0
  420. data/vendor/tracemonkey/ref-config/Darwin5.3.mk +81 -0
  421. data/vendor/tracemonkey/ref-config/Darwin64.mk +72 -0
  422. data/vendor/tracemonkey/ref-config/HP-UXB.10.10.mk +77 -0
  423. data/vendor/tracemonkey/ref-config/HP-UXB.10.20.mk +77 -0
  424. data/vendor/tracemonkey/ref-config/HP-UXB.11.00.mk +80 -0
  425. data/vendor/tracemonkey/ref-config/IRIX.mk +87 -0
  426. data/vendor/tracemonkey/ref-config/IRIX5.3.mk +44 -0
  427. data/vendor/tracemonkey/ref-config/IRIX6.1.mk +44 -0
  428. data/vendor/tracemonkey/ref-config/IRIX6.2.mk +44 -0
  429. data/vendor/tracemonkey/ref-config/IRIX6.3.mk +44 -0
  430. data/vendor/tracemonkey/ref-config/IRIX6.5.mk +44 -0
  431. data/vendor/tracemonkey/ref-config/Linux_All.mk +105 -0
  432. data/vendor/tracemonkey/ref-config/Mac_OS10.0.mk +82 -0
  433. data/vendor/tracemonkey/ref-config/OSF1V4.0.mk +72 -0
  434. data/vendor/tracemonkey/ref-config/OSF1V5.0.mk +69 -0
  435. data/vendor/tracemonkey/ref-config/SunOS4.1.4.mk +101 -0
  436. data/vendor/tracemonkey/ref-config/SunOS5.10.mk +50 -0
  437. data/vendor/tracemonkey/ref-config/SunOS5.3.mk +91 -0
  438. data/vendor/tracemonkey/ref-config/SunOS5.4.mk +92 -0
  439. data/vendor/tracemonkey/ref-config/SunOS5.5.1.mk +44 -0
  440. data/vendor/tracemonkey/ref-config/SunOS5.5.mk +87 -0
  441. data/vendor/tracemonkey/ref-config/SunOS5.6.mk +89 -0
  442. data/vendor/tracemonkey/ref-config/SunOS5.7.mk +44 -0
  443. data/vendor/tracemonkey/ref-config/SunOS5.8.mk +44 -0
  444. data/vendor/tracemonkey/ref-config/SunOS5.9.mk +44 -0
  445. data/vendor/tracemonkey/ref-config/WINNT4.0.mk +118 -0
  446. data/vendor/tracemonkey/ref-config/WINNT5.0.mk +118 -0
  447. data/vendor/tracemonkey/ref-config/WINNT5.1.mk +118 -0
  448. data/vendor/tracemonkey/ref-config/WINNT5.2.mk +118 -0
  449. data/vendor/tracemonkey/ref-config/WINNT6.0.mk +118 -0
  450. data/vendor/tracemonkey/ref-config/dgux.mk +64 -0
  451. data/vendor/tracemonkey/resource.h +15 -0
  452. data/vendor/tracemonkey/rules.mk +206 -0
  453. data/vendor/tracemonkey/shell/Makefile.in +72 -0
  454. data/vendor/tracemonkey/shell/js.cpp +4719 -0
  455. data/vendor/tracemonkey/t/3d-cube.js +337 -0
  456. data/vendor/tracemonkey/t/3d-morph.js +54 -0
  457. data/vendor/tracemonkey/t/3d-raytrace.js +441 -0
  458. data/vendor/tracemonkey/t/access-binary-trees.js +50 -0
  459. data/vendor/tracemonkey/t/access-fannkuch.js +66 -0
  460. data/vendor/tracemonkey/t/access-nbody.js +169 -0
  461. data/vendor/tracemonkey/t/access-nsieve.js +38 -0
  462. data/vendor/tracemonkey/t/bitops-3bit-bits-in-byte.js +32 -0
  463. data/vendor/tracemonkey/t/bitops-bits-in-byte.js +21 -0
  464. data/vendor/tracemonkey/t/bitops-bitwise-and.js +28 -0
  465. data/vendor/tracemonkey/t/bitops-nsieve-bits.js +32 -0
  466. data/vendor/tracemonkey/t/controlflow-recursive.js +25 -0
  467. data/vendor/tracemonkey/t/crypto-aes.js +422 -0
  468. data/vendor/tracemonkey/t/crypto-md5.js +286 -0
  469. data/vendor/tracemonkey/t/crypto-sha1.js +224 -0
  470. data/vendor/tracemonkey/t/date-format-tofte.js +299 -0
  471. data/vendor/tracemonkey/t/date-format-xparb.js +417 -0
  472. data/vendor/tracemonkey/t/math-cordic.js +95 -0
  473. data/vendor/tracemonkey/t/math-partial-sums.js +33 -0
  474. data/vendor/tracemonkey/t/math-spectral-norm.js +51 -0
  475. data/vendor/tracemonkey/t/regexp-dna.js +1712 -0
  476. data/vendor/tracemonkey/t/string-base64.js +135 -0
  477. data/vendor/tracemonkey/t/string-fasta.js +85 -0
  478. data/vendor/tracemonkey/t/string-tagcloud.js +265 -0
  479. data/vendor/tracemonkey/t/string-unpack-code.js +68 -0
  480. data/vendor/tracemonkey/t/string-validate-input.js +89 -0
  481. data/vendor/tracemonkey/time.sh +13 -0
  482. data/vendor/tracemonkey/trace-test.js +5564 -0
  483. data/vendor/tracemonkey/v8/base.js +187 -0
  484. data/vendor/tracemonkey/v8/crypto.js +1689 -0
  485. data/vendor/tracemonkey/v8/deltablue.js +880 -0
  486. data/vendor/tracemonkey/v8/earley-boyer.js +4682 -0
  487. data/vendor/tracemonkey/v8/raytrace.js +3418 -0
  488. data/vendor/tracemonkey/v8/richards.js +539 -0
  489. data/vendor/tracemonkey/v8/run-crypto.js +44 -0
  490. data/vendor/tracemonkey/v8/run-deltablue.js +44 -0
  491. data/vendor/tracemonkey/v8/run-earley-boyer.js +44 -0
  492. data/vendor/tracemonkey/v8/run-raytrace.js +44 -0
  493. data/vendor/tracemonkey/v8/run-richards.js +44 -0
  494. data/vendor/tracemonkey/v8/run.js +49 -0
  495. data/vendor/tracemonkey/vprof/readme.txt +93 -0
  496. data/vendor/tracemonkey/vprof/vprof.cpp +360 -0
  497. data/vendor/tracemonkey/vprof/vprof.h +245 -0
  498. data/vendor/tracemonkey/xpconnect/Makefile.in +67 -0
  499. data/vendor/tracemonkey/xpconnect/crashtests/117307-1.html +20 -0
  500. data/vendor/tracemonkey/xpconnect/crashtests/193710.html +11 -0
  501. data/vendor/tracemonkey/xpconnect/crashtests/290162-1.html +5 -0
  502. data/vendor/tracemonkey/xpconnect/crashtests/326615-1.html +16 -0
  503. data/vendor/tracemonkey/xpconnect/crashtests/328553-1.html +13 -0
  504. data/vendor/tracemonkey/xpconnect/crashtests/346258-1.html +12 -0
  505. data/vendor/tracemonkey/xpconnect/crashtests/346512-1-frame1.xhtml +16 -0
  506. data/vendor/tracemonkey/xpconnect/crashtests/346512-1-frame2.xhtml +15 -0
  507. data/vendor/tracemonkey/xpconnect/crashtests/346512-1.xhtml +30 -0
  508. data/vendor/tracemonkey/xpconnect/crashtests/382133-1.html +3 -0
  509. data/vendor/tracemonkey/xpconnect/crashtests/386680-1.html +22 -0
  510. data/vendor/tracemonkey/xpconnect/crashtests/394810-1.html +4 -0
  511. data/vendor/tracemonkey/xpconnect/crashtests/400349-1.html +20 -0
  512. data/vendor/tracemonkey/xpconnect/crashtests/403356-1.html +13 -0
  513. data/vendor/tracemonkey/xpconnect/crashtests/418139-1.svg +22 -0
  514. data/vendor/tracemonkey/xpconnect/crashtests/420513-1.html +11 -0
  515. data/vendor/tracemonkey/xpconnect/crashtests/453935-1.html +37 -0
  516. data/vendor/tracemonkey/xpconnect/crashtests/462926.html +12 -0
  517. data/vendor/tracemonkey/xpconnect/crashtests/468552-1.html +18 -0
  518. data/vendor/tracemonkey/xpconnect/crashtests/471366-1.html +12 -0
  519. data/vendor/tracemonkey/xpconnect/crashtests/475185-1.html +13 -0
  520. data/vendor/tracemonkey/xpconnect/crashtests/475291-1.html +14 -0
  521. data/vendor/tracemonkey/xpconnect/crashtests/503286-1.html +23 -0
  522. data/vendor/tracemonkey/xpconnect/crashtests/crashtests.list +21 -0
  523. data/vendor/tracemonkey/xpconnect/idl/Makefile.in +78 -0
  524. data/vendor/tracemonkey/xpconnect/idl/XPCIDispatch.idl +51 -0
  525. data/vendor/tracemonkey/xpconnect/idl/mozIJSSubScriptLoader.idl +64 -0
  526. data/vendor/tracemonkey/xpconnect/idl/nsIActiveXSecurityPolicy.idl +67 -0
  527. data/vendor/tracemonkey/xpconnect/idl/nsIDispatchSupport.idl +119 -0
  528. data/vendor/tracemonkey/xpconnect/idl/nsIJSContextStack.idl +85 -0
  529. data/vendor/tracemonkey/xpconnect/idl/nsIJSRuntimeService.idl +51 -0
  530. data/vendor/tracemonkey/xpconnect/idl/nsIScriptError.idl +102 -0
  531. data/vendor/tracemonkey/xpconnect/idl/nsIScriptableInterfaces.idl +67 -0
  532. data/vendor/tracemonkey/xpconnect/idl/nsIXPCScriptNotify.idl +66 -0
  533. data/vendor/tracemonkey/xpconnect/idl/nsIXPCScriptable.idl +183 -0
  534. data/vendor/tracemonkey/xpconnect/idl/nsIXPCSecurityManager.idl +114 -0
  535. data/vendor/tracemonkey/xpconnect/idl/nsIXPConnect.idl +819 -0
  536. data/vendor/tracemonkey/xpconnect/idl/xpcIJSModuleLoader.idl +95 -0
  537. data/vendor/tracemonkey/xpconnect/idl/xpcIJSWeakReference.idl +49 -0
  538. data/vendor/tracemonkey/xpconnect/idl/xpccomponents.idl +254 -0
  539. data/vendor/tracemonkey/xpconnect/idl/xpcexception.idl +66 -0
  540. data/vendor/tracemonkey/xpconnect/idl/xpcjsid.idl +83 -0
  541. data/vendor/tracemonkey/xpconnect/loader/ISO8601DateUtils.jsm +176 -0
  542. data/vendor/tracemonkey/xpconnect/loader/Makefile.in +63 -0
  543. data/vendor/tracemonkey/xpconnect/loader/XPCOMUtils.jsm +267 -0
  544. data/vendor/tracemonkey/xpconnect/loader/mozJSComponentLoader.cpp +1717 -0
  545. data/vendor/tracemonkey/xpconnect/loader/mozJSComponentLoader.h +172 -0
  546. data/vendor/tracemonkey/xpconnect/loader/mozJSLoaderConstructors.h +101 -0
  547. data/vendor/tracemonkey/xpconnect/loader/mozJSSubScriptLoader.cpp +360 -0
  548. data/vendor/tracemonkey/xpconnect/loader/mozJSSubScriptLoader.h +66 -0
  549. data/vendor/tracemonkey/xpconnect/public/Makefile.in +54 -0
  550. data/vendor/tracemonkey/xpconnect/public/nsAXPCNativeCallContext.h +89 -0
  551. data/vendor/tracemonkey/xpconnect/public/nsAutoJSValHolder.h +168 -0
  552. data/vendor/tracemonkey/xpconnect/public/xpc_map_end.h +327 -0
  553. data/vendor/tracemonkey/xpconnect/sample/Makefile.in +71 -0
  554. data/vendor/tracemonkey/xpconnect/sample/README +39 -0
  555. data/vendor/tracemonkey/xpconnect/sample/xpcsample1.cpp +337 -0
  556. data/vendor/tracemonkey/xpconnect/sample/xpcsample1.idl +82 -0
  557. data/vendor/tracemonkey/xpconnect/sample/xpcsample1.js +21 -0
  558. data/vendor/tracemonkey/xpconnect/shell/Makefile.in +106 -0
  559. data/vendor/tracemonkey/xpconnect/shell/jsshell.msg +50 -0
  560. data/vendor/tracemonkey/xpconnect/shell/xpcshell.cpp +1817 -0
  561. data/vendor/tracemonkey/xpconnect/shell/xpcshellMacUtils.h +43 -0
  562. data/vendor/tracemonkey/xpconnect/shell/xpcshellMacUtils.mm +54 -0
  563. data/vendor/tracemonkey/xpconnect/src/Makefile.in +228 -0
  564. data/vendor/tracemonkey/xpconnect/src/README +3 -0
  565. data/vendor/tracemonkey/xpconnect/src/XPCCrossOriginWrapper.cpp +1186 -0
  566. data/vendor/tracemonkey/xpconnect/src/XPCDispConvert.cpp +593 -0
  567. data/vendor/tracemonkey/xpconnect/src/XPCDispInlines.h +667 -0
  568. data/vendor/tracemonkey/xpconnect/src/XPCDispInterface.cpp +383 -0
  569. data/vendor/tracemonkey/xpconnect/src/XPCDispObject.cpp +516 -0
  570. data/vendor/tracemonkey/xpconnect/src/XPCDispParamPropJSClass.cpp +223 -0
  571. data/vendor/tracemonkey/xpconnect/src/XPCDispParams.cpp +103 -0
  572. data/vendor/tracemonkey/xpconnect/src/XPCDispPrivate.h +1401 -0
  573. data/vendor/tracemonkey/xpconnect/src/XPCDispTearOff.cpp +547 -0
  574. data/vendor/tracemonkey/xpconnect/src/XPCDispTypeInfo.cpp +471 -0
  575. data/vendor/tracemonkey/xpconnect/src/XPCIDispatchClassInfo.cpp +139 -0
  576. data/vendor/tracemonkey/xpconnect/src/XPCIDispatchExtension.cpp +362 -0
  577. data/vendor/tracemonkey/xpconnect/src/XPCNativeWrapper.cpp +1350 -0
  578. data/vendor/tracemonkey/xpconnect/src/XPCNativeWrapper.h +88 -0
  579. data/vendor/tracemonkey/xpconnect/src/XPCSafeJSObjectWrapper.cpp +1148 -0
  580. data/vendor/tracemonkey/xpconnect/src/XPCSystemOnlyWrapper.cpp +718 -0
  581. data/vendor/tracemonkey/xpconnect/src/XPCWrapper.cpp +850 -0
  582. data/vendor/tracemonkey/xpconnect/src/XPCWrapper.h +394 -0
  583. data/vendor/tracemonkey/xpconnect/src/dom_quickstubs.qsconf +568 -0
  584. data/vendor/tracemonkey/xpconnect/src/nsDispatchSupport.cpp +348 -0
  585. data/vendor/tracemonkey/xpconnect/src/nsScriptError.cpp +201 -0
  586. data/vendor/tracemonkey/xpconnect/src/nsXPConnect.cpp +2609 -0
  587. data/vendor/tracemonkey/xpconnect/src/qsgen.py +1487 -0
  588. data/vendor/tracemonkey/xpconnect/src/xpc.msg +217 -0
  589. data/vendor/tracemonkey/xpconnect/src/xpcJSWeakReference.cpp +148 -0
  590. data/vendor/tracemonkey/xpconnect/src/xpcJSWeakReference.h +56 -0
  591. data/vendor/tracemonkey/xpconnect/src/xpccallcontext.cpp +579 -0
  592. data/vendor/tracemonkey/xpconnect/src/xpccomponents.cpp +4144 -0
  593. data/vendor/tracemonkey/xpconnect/src/xpccontext.cpp +115 -0
  594. data/vendor/tracemonkey/xpconnect/src/xpcconvert.cpp +2298 -0
  595. data/vendor/tracemonkey/xpconnect/src/xpcdebug.cpp +481 -0
  596. data/vendor/tracemonkey/xpconnect/src/xpcexception.cpp +502 -0
  597. data/vendor/tracemonkey/xpconnect/src/xpcforwards.h +114 -0
  598. data/vendor/tracemonkey/xpconnect/src/xpcinlines.h +772 -0
  599. data/vendor/tracemonkey/xpconnect/src/xpcjsid.cpp +1025 -0
  600. data/vendor/tracemonkey/xpconnect/src/xpcjsruntime.cpp +1342 -0
  601. data/vendor/tracemonkey/xpconnect/src/xpclog.cpp +128 -0
  602. data/vendor/tracemonkey/xpconnect/src/xpclog.h +101 -0
  603. data/vendor/tracemonkey/xpconnect/src/xpcmaps.cpp +761 -0
  604. data/vendor/tracemonkey/xpconnect/src/xpcmaps.h +713 -0
  605. data/vendor/tracemonkey/xpconnect/src/xpcmodule.cpp +136 -0
  606. data/vendor/tracemonkey/xpconnect/src/xpcprivate.h +4138 -0
  607. data/vendor/tracemonkey/xpconnect/src/xpcquickstubs.cpp +1128 -0
  608. data/vendor/tracemonkey/xpconnect/src/xpcquickstubs.h +480 -0
  609. data/vendor/tracemonkey/xpconnect/src/xpcruntimesvc.cpp +179 -0
  610. data/vendor/tracemonkey/xpconnect/src/xpcstack.cpp +342 -0
  611. data/vendor/tracemonkey/xpconnect/src/xpcstring.cpp +139 -0
  612. data/vendor/tracemonkey/xpconnect/src/xpcthreadcontext.cpp +599 -0
  613. data/vendor/tracemonkey/xpconnect/src/xpcthrower.cpp +399 -0
  614. data/vendor/tracemonkey/xpconnect/src/xpcvariant.cpp +850 -0
  615. data/vendor/tracemonkey/xpconnect/src/xpcwrappedjs.cpp +670 -0
  616. data/vendor/tracemonkey/xpconnect/src/xpcwrappedjsclass.cpp +2015 -0
  617. data/vendor/tracemonkey/xpconnect/src/xpcwrappednative.cpp +3482 -0
  618. data/vendor/tracemonkey/xpconnect/src/xpcwrappednativeinfo.cpp +945 -0
  619. data/vendor/tracemonkey/xpconnect/src/xpcwrappednativejsops.cpp +2003 -0
  620. data/vendor/tracemonkey/xpconnect/src/xpcwrappednativeproto.cpp +302 -0
  621. data/vendor/tracemonkey/xpconnect/src/xpcwrappednativescope.cpp +991 -0
  622. data/vendor/tracemonkey/xpconnect/tests/Makefile.in +75 -0
  623. data/vendor/tracemonkey/xpconnect/tests/TestXPC.cpp +785 -0
  624. data/vendor/tracemonkey/xpconnect/tests/chrome/Makefile.in +51 -0
  625. data/vendor/tracemonkey/xpconnect/tests/chrome/test_bug500931.xul +43 -0
  626. data/vendor/tracemonkey/xpconnect/tests/components/Makefile.in +85 -0
  627. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_array.cpp +388 -0
  628. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_attributes.cpp +305 -0
  629. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_calljs.cpp +135 -0
  630. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_child.cpp +225 -0
  631. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_const.cpp +76 -0
  632. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_domstring.cpp +118 -0
  633. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_echo.cpp +616 -0
  634. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_in.cpp +204 -0
  635. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_inout.cpp +171 -0
  636. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_module.cpp +77 -0
  637. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_multiple.cpp +554 -0
  638. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_noisy.cpp +154 -0
  639. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_out.cpp +335 -0
  640. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_overloaded.cpp +250 -0
  641. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_private.h +192 -0
  642. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_string.cpp +185 -0
  643. data/vendor/tracemonkey/xpconnect/tests/components/xpctest_variant.cpp +355 -0
  644. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/StdAfx.cpp +12 -0
  645. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/StdAfx.h +28 -0
  646. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/XPCDispUtilities.h +28 -0
  647. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/XPCIDispatchTest.cpp +86 -0
  648. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/XPCIDispatchTest.def +9 -0
  649. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/XPCIDispatchTest.dsp +318 -0
  650. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/XPCIDispatchTest.dsw +29 -0
  651. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/XPCIDispatchTest.idl +454 -0
  652. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/XPCIDispatchTest.rc +145 -0
  653. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispSimple.cpp +44 -0
  654. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispSimple.h +56 -0
  655. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispSimple.rgs +23 -0
  656. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestArrays.cpp +221 -0
  657. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestArrays.h +53 -0
  658. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestArrays.rgs +23 -0
  659. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestMethods.cpp +699 -0
  660. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestMethods.h +138 -0
  661. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestMethods.rgs +23 -0
  662. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestNoIDispatch.cpp +23 -0
  663. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestNoIDispatch.h +41 -0
  664. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestNoIDispatch.rgs +23 -0
  665. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestProperties.cpp +256 -0
  666. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestProperties.h +88 -0
  667. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestProperties.rgs +23 -0
  668. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestScriptOff.cpp +23 -0
  669. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestScriptOff.h +43 -0
  670. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestScriptOff.rgs +23 -0
  671. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestScriptOn.cpp +29 -0
  672. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestScriptOn.h +45 -0
  673. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestScriptOn.rgs +23 -0
  674. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestWrappedJS.cpp +177 -0
  675. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestWrappedJS.h +50 -0
  676. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/nsXPCDispTestWrappedJS.rgs +23 -0
  677. data/vendor/tracemonkey/xpconnect/tests/idispatch/COM/resource.h +36 -0
  678. data/vendor/tracemonkey/xpconnect/tests/idispatch/Tests/WrappedCOM/Arrays/XPCIDispatchArrayTests.js +54 -0
  679. data/vendor/tracemonkey/xpconnect/tests/idispatch/Tests/WrappedCOM/Attributes/XPCIDispatchAttributeTests.js +150 -0
  680. data/vendor/tracemonkey/xpconnect/tests/idispatch/Tests/WrappedCOM/General/XPCIDispatchInstantiations.js +122 -0
  681. data/vendor/tracemonkey/xpconnect/tests/idispatch/Tests/WrappedCOM/General/XPCStress.js +58 -0
  682. data/vendor/tracemonkey/xpconnect/tests/idispatch/Tests/WrappedCOM/Methods/XPCIDispatchMethodTests.js +376 -0
  683. data/vendor/tracemonkey/xpconnect/tests/idispatch/Tests/WrappedCOM/shell.js +377 -0
  684. data/vendor/tracemonkey/xpconnect/tests/idispatch/Tests/WrappedJS/General/XPCIDispatchTestWrappedJS.js +76 -0
  685. data/vendor/tracemonkey/xpconnect/tests/idispatch/Tests/WrappedJS/shell.js +377 -0
  686. data/vendor/tracemonkey/xpconnect/tests/idispatch/Tests/exectests.cmd +1 -0
  687. data/vendor/tracemonkey/xpconnect/tests/idispatch/Tests/jsDriver.pl +1288 -0
  688. data/vendor/tracemonkey/xpconnect/tests/idl/Makefile.in +61 -0
  689. data/vendor/tracemonkey/xpconnect/tests/idl/xpctest.idl +312 -0
  690. data/vendor/tracemonkey/xpconnect/tests/idl/xpctest2.idl +51 -0
  691. data/vendor/tracemonkey/xpconnect/tests/idl/xpctest_attributes.idl +67 -0
  692. data/vendor/tracemonkey/xpconnect/tests/idl/xpctest_calljs.idl +59 -0
  693. data/vendor/tracemonkey/xpconnect/tests/idl/xpctest_const.idl +61 -0
  694. data/vendor/tracemonkey/xpconnect/tests/idl/xpctest_domstring.idl +59 -0
  695. data/vendor/tracemonkey/xpconnect/tests/idl/xpctest_in.idl +88 -0
  696. data/vendor/tracemonkey/xpconnect/tests/idl/xpctest_inout.idl +86 -0
  697. data/vendor/tracemonkey/xpconnect/tests/idl/xpctest_multiple.idl +77 -0
  698. data/vendor/tracemonkey/xpconnect/tests/idl/xpctest_out.idl +142 -0
  699. data/vendor/tracemonkey/xpconnect/tests/js/checkid.js +82 -0
  700. data/vendor/tracemonkey/xpconnect/tests/js/evaluate.js +311 -0
  701. data/vendor/tracemonkey/xpconnect/tests/js/exceptions-2.js +153 -0
  702. data/vendor/tracemonkey/xpconnect/tests/js/exceptions-3.js +194 -0
  703. data/vendor/tracemonkey/xpconnect/tests/js/exceptions-4.js +297 -0
  704. data/vendor/tracemonkey/xpconnect/tests/js/exceptions-5.js +343 -0
  705. data/vendor/tracemonkey/xpconnect/tests/js/exceptions.js +230 -0
  706. data/vendor/tracemonkey/xpconnect/tests/js/javascript.js +96 -0
  707. data/vendor/tracemonkey/xpconnect/tests/js/multiple-2.js +151 -0
  708. data/vendor/tracemonkey/xpconnect/tests/js/multiple-3.js +148 -0
  709. data/vendor/tracemonkey/xpconnect/tests/js/multiple-4.js +152 -0
  710. data/vendor/tracemonkey/xpconnect/tests/js/multiple.js +137 -0
  711. data/vendor/tracemonkey/xpconnect/tests/js/notscriptable.js +104 -0
  712. data/vendor/tracemonkey/xpconnect/tests/js/old/simpletest.js +36 -0
  713. data/vendor/tracemonkey/xpconnect/tests/js/old/speed.js +60 -0
  714. data/vendor/tracemonkey/xpconnect/tests/js/old/testxpc.js +464 -0
  715. data/vendor/tracemonkey/xpconnect/tests/js/old/threads.js +74 -0
  716. data/vendor/tracemonkey/xpconnect/tests/js/old/try.js +27 -0
  717. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_array.js +308 -0
  718. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_callcontext.js +68 -0
  719. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_echo.js +636 -0
  720. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_enum_and_sort.js +28 -0
  721. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_enum_constants.js +15 -0
  722. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_enum_create.js +200 -0
  723. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_exceptions.js +167 -0
  724. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_ids.js +135 -0
  725. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_observer.js +36 -0
  726. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_overloaded.js +14 -0
  727. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_primitives.js +141 -0
  728. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_propertybag.js +36 -0
  729. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_variant.js +339 -0
  730. data/vendor/tracemonkey/xpconnect/tests/js/old/xpctest_variant_array.js +30 -0
  731. data/vendor/tracemonkey/xpconnect/tests/js/readonlyattributes.js +74 -0
  732. data/vendor/tracemonkey/xpconnect/tests/js/readwriteattributes.js +101 -0
  733. data/vendor/tracemonkey/xpconnect/tests/js/scriptable.js +120 -0
  734. data/vendor/tracemonkey/xpconnect/tests/js/testin.js +203 -0
  735. data/vendor/tracemonkey/xpconnect/tests/js/xpcfun.js +234 -0
  736. data/vendor/tracemonkey/xpconnect/tests/js/xpctest_primitives.js +200 -0
  737. data/vendor/tracemonkey/xpconnect/tests/mochitest/Makefile.in +66 -0
  738. data/vendor/tracemonkey/xpconnect/tests/mochitest/bug500931_helper.html +7 -0
  739. data/vendor/tracemonkey/xpconnect/tests/mochitest/inner.html +7 -0
  740. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug361111.xul +29 -0
  741. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug384632.html +32 -0
  742. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug390488.html +65 -0
  743. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug393269.html +46 -0
  744. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug396851.html +43 -0
  745. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug428021.html +41 -0
  746. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug446584.html +49 -0
  747. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug448587.html +31 -0
  748. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug462428.html +42 -0
  749. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug478438.html +66 -0
  750. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug484107.html +100 -0
  751. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug484459.html +36 -0
  752. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_bug500691.html +28 -0
  753. data/vendor/tracemonkey/xpconnect/tests/mochitest/test_wrappers.html +116 -0
  754. data/vendor/tracemonkey/xpconnect/tests/unit/bogus_element_type.jsm +1 -0
  755. data/vendor/tracemonkey/xpconnect/tests/unit/bogus_exports_type.jsm +1 -0
  756. data/vendor/tracemonkey/xpconnect/tests/unit/bug451678_subscript.js +2 -0
  757. data/vendor/tracemonkey/xpconnect/tests/unit/component_import.js +144 -0
  758. data/vendor/tracemonkey/xpconnect/tests/unit/recursive_importA.jsm +44 -0
  759. data/vendor/tracemonkey/xpconnect/tests/unit/recursive_importB.jsm +45 -0
  760. data/vendor/tracemonkey/xpconnect/tests/unit/syntax_error.jsm +1 -0
  761. data/vendor/tracemonkey/xpconnect/tests/unit/test_bogus_files.js +88 -0
  762. data/vendor/tracemonkey/xpconnect/tests/unit/test_bug408412.js +51 -0
  763. data/vendor/tracemonkey/xpconnect/tests/unit/test_bug451678.js +52 -0
  764. data/vendor/tracemonkey/xpconnect/tests/unit/test_bug_442086.js +68 -0
  765. data/vendor/tracemonkey/xpconnect/tests/unit/test_import.js +127 -0
  766. data/vendor/tracemonkey/xpconnect/tests/unit/test_js_weak_references.js +63 -0
  767. data/vendor/tracemonkey/xpconnect/tests/unit/test_recursive_import.js +62 -0
  768. data/vendor/tracemonkey/xpconnect/tools/Makefile.in +49 -0
  769. data/vendor/tracemonkey/xpconnect/tools/idl/Makefile.in +53 -0
  770. data/vendor/tracemonkey/xpconnect/tools/idl/nsIXPCToolsCompiler.idl +60 -0
  771. data/vendor/tracemonkey/xpconnect/tools/idl/nsIXPCToolsProfiler.idl +57 -0
  772. data/vendor/tracemonkey/xpconnect/tools/js/CompileJSFiles.js +28 -0
  773. data/vendor/tracemonkey/xpconnect/tools/js/ListJSFiles.js +18 -0
  774. data/vendor/tracemonkey/xpconnect/tools/src/Makefile.in +76 -0
  775. data/vendor/tracemonkey/xpconnect/tools/src/nsXPCToolsCompiler.cpp +161 -0
  776. data/vendor/tracemonkey/xpconnect/tools/src/nsXPCToolsModule.cpp +65 -0
  777. data/vendor/tracemonkey/xpconnect/tools/src/nsXPCToolsProfiler.cpp +370 -0
  778. data/vendor/tracemonkey/xpconnect/tools/src/xpctools_private.h +236 -0
  779. metadata +782 -107
  780. data/test/johnson/nodes/export_test.rb +0 -9
  781. data/test/johnson/nodes/import_test.rb +0 -13
  782. data/test/johnson/version_test.rb +0 -13
@@ -0,0 +1,366 @@
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
+ #ifndef jsfun_h___
41
+ #define jsfun_h___
42
+ /*
43
+ * JS function definitions.
44
+ */
45
+ #include "jsprvtd.h"
46
+ #include "jspubtd.h"
47
+ #include "jsobj.h"
48
+
49
+ JS_BEGIN_EXTERN_C
50
+
51
+ typedef struct JSLocalNameMap JSLocalNameMap;
52
+
53
+ /*
54
+ * Depending on the number of arguments and variables in the function their
55
+ * names and attributes are stored either as a single atom or as an array of
56
+ * tagged atoms (when there are few locals) or as a hash-based map (when there
57
+ * are many locals). In the first 2 cases the lowest bit of the atom is used
58
+ * as a tag to distinguish const from var. See jsfun.c for details.
59
+ */
60
+ typedef union JSLocalNames {
61
+ jsuword taggedAtom;
62
+ jsuword *array;
63
+ JSLocalNameMap *map;
64
+ } JSLocalNames;
65
+
66
+ /*
67
+ * The high two bits of JSFunction.flags encode whether the function is native
68
+ * or interpreted, and if interpreted, what kind of optimized closure form (if
69
+ * any) it might be.
70
+ *
71
+ * 00 not interpreted
72
+ * 01 interpreted, neither flat nor null closure
73
+ * 10 interpreted, flat closure
74
+ * 11 interpreted, null closure
75
+ *
76
+ * FUN_FLAT_CLOSURE implies FUN_INTERPRETED and u.i.script->upvarsOffset != 0.
77
+ * FUN_NULL_CLOSURE implies FUN_INTERPRETED and u.i.script->upvarsOffset == 0.
78
+ *
79
+ * FUN_INTERPRETED but not FUN_FLAT_CLOSURE and u.i.script->upvarsOffset != 0
80
+ * is an Algol-like function expression or nested function, i.e., a function
81
+ * that never escapes upward or downward (heapward), and is only ever called.
82
+ *
83
+ * Finally, FUN_INTERPRETED and u.i.script->upvarsOffset == 0 could be either
84
+ * a non-closure (a global function definition, or any function that uses no
85
+ * outer names), or a closure of an escaping function that uses outer names
86
+ * whose values can't be snapshot (because the outer names could be reassigned
87
+ * after the closure is formed, or because assignments could not be analyzed
88
+ * due to with or eval).
89
+ *
90
+ * Such a hard-case function must use JSOP_NAME, etc., and reify outer function
91
+ * activations' call objects, etc. if it's not a global function.
92
+ *
93
+ * NB: JSFUN_EXPR_CLOSURE reuses JSFUN_STUB_GSOPS, which is an API request flag
94
+ * bit only, never stored in fun->flags.
95
+ *
96
+ * If we need more bits in the future, all flags for FUN_INTERPRETED functions
97
+ * can move to u.i.script->flags. For now we use function flag bits to minimize
98
+ * pointer-chasing.
99
+ */
100
+ #define JSFUN_EXPR_CLOSURE 0x1000 /* expression closure: function(x) x*x */
101
+ #define JSFUN_TRACEABLE 0x2000 /* can trace across calls to this native
102
+ function; use FUN_TRCINFO if set,
103
+ FUN_CLASP if unset */
104
+ #define JSFUN_INTERPRETED 0x4000 /* use u.i if kind >= this value else u.n */
105
+ #define JSFUN_FLAT_CLOSURE 0x8000 /* flag (aka "display") closure */
106
+ #define JSFUN_NULL_CLOSURE 0xc000 /* null closure entrains no scope chain */
107
+ #define JSFUN_KINDMASK 0xc000 /* encode interp vs. native and closure
108
+ optimization level -- see above */
109
+
110
+ #define FUN_OBJECT(fun) (&(fun)->object)
111
+ #define FUN_KIND(fun) ((fun)->flags & JSFUN_KINDMASK)
112
+ #define FUN_SET_KIND(fun,k) ((fun)->flags = ((fun)->flags & ~JSFUN_KINDMASK) | (k))
113
+ #define FUN_INTERPRETED(fun) (FUN_KIND(fun) >= JSFUN_INTERPRETED)
114
+ #define FUN_FLAT_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_FLAT_CLOSURE)
115
+ #define FUN_NULL_CLOSURE(fun)(FUN_KIND(fun) == JSFUN_NULL_CLOSURE)
116
+ #define FUN_SLOW_NATIVE(fun) (!FUN_INTERPRETED(fun) && !((fun)->flags & JSFUN_FAST_NATIVE))
117
+ #define FUN_SCRIPT(fun) (FUN_INTERPRETED(fun) ? (fun)->u.i.script : NULL)
118
+ #define FUN_NATIVE(fun) (FUN_SLOW_NATIVE(fun) ? (fun)->u.n.native : NULL)
119
+ #define FUN_FAST_NATIVE(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \
120
+ ? (JSFastNative) (fun)->u.n.native \
121
+ : NULL)
122
+ #define FUN_MINARGS(fun) (((fun)->flags & JSFUN_FAST_NATIVE) \
123
+ ? 0 \
124
+ : (fun)->nargs)
125
+ #define FUN_CLASP(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \
126
+ fun->u.n.clasp)
127
+ #define FUN_TRCINFO(fun) (JS_ASSERT(!FUN_INTERPRETED(fun)), \
128
+ JS_ASSERT((fun)->flags & JSFUN_TRACEABLE), \
129
+ fun->u.n.trcinfo)
130
+
131
+ struct JSFunction {
132
+ JSObject object; /* GC'ed object header */
133
+ uint16 nargs; /* maximum number of specified arguments,
134
+ reflected as f.length/f.arity */
135
+ uint16 flags; /* flags, see JSFUN_* below and in jsapi.h */
136
+ union {
137
+ struct {
138
+ uint16 extra; /* number of arg slots for local GC roots */
139
+ uint16 spare; /* reserved for future use */
140
+ JSNative native; /* native method pointer or null */
141
+ JSClass *clasp; /* class of objects constructed
142
+ by this function */
143
+ JSTraceableNative *trcinfo; /* tracer metadata; can be first
144
+ element of array */
145
+ } n;
146
+ struct {
147
+ uint16 nvars; /* number of local variables */
148
+ uint16 nupvars; /* number of upvars (computable from script
149
+ but here for faster access) */
150
+ uint16 skipmin; /* net skip amount up (toward zero) from
151
+ script->staticLevel to nearest upvar,
152
+ including upvars in nested functions */
153
+ JSPackedBool wrapper; /* true if this function is a wrapper that
154
+ rewrites bytecode optimized for a function
155
+ judged non-escaping by the compiler, which
156
+ then escaped via the debugger or a rogue
157
+ indirect eval; if true, then this function
158
+ object's proto is the wrapped object */
159
+ JSScript *script; /* interpreted bytecode descriptor or null */
160
+ JSLocalNames names; /* argument and variable names */
161
+ } i;
162
+ } u;
163
+ JSAtom *atom; /* name for diagnostics and decompiling */
164
+
165
+ #ifdef __cplusplus
166
+ bool optimizedClosure() { return FUN_KIND(this) > JSFUN_INTERPRETED; }
167
+ bool needsWrapper() { return FUN_NULL_CLOSURE(this) && u.i.skipmin != 0; }
168
+
169
+ uintN countArgsAndVars() const {
170
+ JS_ASSERT(FUN_INTERPRETED(this));
171
+ return nargs + u.i.nvars;
172
+ }
173
+
174
+ uintN countLocalNames() const {
175
+ JS_ASSERT(FUN_INTERPRETED(this));
176
+ return countArgsAndVars() + u.i.nupvars;
177
+ }
178
+
179
+ bool hasLocalNames() const {
180
+ JS_ASSERT(FUN_INTERPRETED(this));
181
+ return countLocalNames() != 0;
182
+ }
183
+ #endif
184
+ };
185
+
186
+ /*
187
+ * Traceable native. This expands to a JSFunctionSpec initializer (like JS_FN
188
+ * in jsapi.h). fastcall is a JSFastNative; trcinfo is a JSTraceableNative *.
189
+ */
190
+ #ifdef JS_TRACER
191
+ /* MSVC demands the intermediate (void *) cast here. */
192
+ # define JS_TN(name,fastcall,nargs,flags,trcinfo) \
193
+ JS_FN(name, JS_DATA_TO_FUNC_PTR(JSNative, trcinfo), nargs, \
194
+ (flags) | JSFUN_FAST_NATIVE | JSFUN_STUB_GSOPS | JSFUN_TRACEABLE)
195
+ #else
196
+ # define JS_TN(name,fastcall,nargs,flags,trcinfo) \
197
+ JS_FN(name, fastcall, nargs, flags)
198
+ #endif
199
+
200
+ extern JSClass js_ArgumentsClass;
201
+ extern JS_FRIEND_DATA(JSClass) js_CallClass;
202
+ extern JSClass js_DeclEnvClass;
203
+
204
+ /* JS_FRIEND_DATA so that VALUE_IS_FUNCTION is callable from the shell. */
205
+ extern JS_FRIEND_DATA(JSClass) js_FunctionClass;
206
+
207
+ #define HAS_FUNCTION_CLASS(obj) (STOBJ_GET_CLASS(obj) == &js_FunctionClass)
208
+
209
+ /*
210
+ * NB: jsapi.h and jsobj.h must be included before any call to this macro.
211
+ */
212
+ #define VALUE_IS_FUNCTION(cx, v) \
213
+ (!JSVAL_IS_PRIMITIVE(v) && HAS_FUNCTION_CLASS(JSVAL_TO_OBJECT(v)))
214
+
215
+ /*
216
+ * Macro to access the private slot of the function object after the slot is
217
+ * initialized.
218
+ */
219
+ #define GET_FUNCTION_PRIVATE(cx, funobj) \
220
+ (JS_ASSERT(HAS_FUNCTION_CLASS(funobj)), \
221
+ (JSFunction *) OBJ_GET_PRIVATE(cx, funobj))
222
+
223
+ extern JSObject *
224
+ js_InitFunctionClass(JSContext *cx, JSObject *obj);
225
+
226
+ extern JSObject *
227
+ js_InitArgumentsClass(JSContext *cx, JSObject *obj);
228
+
229
+ extern JSFunction *
230
+ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
231
+ uintN flags, JSObject *parent, JSAtom *atom);
232
+
233
+ extern void
234
+ js_TraceFunction(JSTracer *trc, JSFunction *fun);
235
+
236
+ extern void
237
+ js_FinalizeFunction(JSContext *cx, JSFunction *fun);
238
+
239
+ extern JSObject *
240
+ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent);
241
+
242
+ extern JS_REQUIRES_STACK JSObject *
243
+ js_NewFlatClosure(JSContext *cx, JSFunction *fun);
244
+
245
+ extern JS_REQUIRES_STACK JSObject *
246
+ js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun);
247
+
248
+ extern JSFunction *
249
+ js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
250
+ uintN nargs, uintN flags);
251
+
252
+ /*
253
+ * Flags for js_ValueToFunction and js_ReportIsNotFunction. We depend on the
254
+ * fact that JSINVOKE_CONSTRUCT (aka JSFRAME_CONSTRUCTING) is 1, and test that
255
+ * with #if/#error in jsfun.c.
256
+ */
257
+ #define JSV2F_CONSTRUCT JSINVOKE_CONSTRUCT
258
+ #define JSV2F_ITERATOR JSINVOKE_ITERATOR
259
+ #define JSV2F_SEARCH_STACK 0x10000
260
+
261
+ extern JSFunction *
262
+ js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags);
263
+
264
+ extern JSObject *
265
+ js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags);
266
+
267
+ extern JSObject *
268
+ js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags);
269
+
270
+ extern void
271
+ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags);
272
+
273
+ extern JSObject *
274
+ js_GetCallObject(JSContext *cx, JSStackFrame *fp);
275
+
276
+ extern JS_FRIEND_API(JSBool)
277
+ js_PutCallObject(JSContext *cx, JSStackFrame *fp);
278
+
279
+ extern JSBool
280
+ js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
281
+
282
+ extern JS_REQUIRES_STACK JSBool
283
+ js_GetCallVar(JSContext *cx, JSObject *obj, jsval id, jsval *vp);
284
+
285
+ /*
286
+ * Slower version of js_GetCallVar used when call_resolve detects an attempt to
287
+ * leak an optimized closure via indirect or debugger eval.
288
+ */
289
+ extern JS_REQUIRES_STACK JSBool
290
+ js_GetCallVarChecked(JSContext *cx, JSObject *obj, jsid id, jsval *vp);
291
+
292
+ extern JSBool
293
+ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp);
294
+
295
+ extern JSBool
296
+ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp);
297
+
298
+ extern JSObject *
299
+ js_GetArgsObject(JSContext *cx, JSStackFrame *fp);
300
+
301
+ extern JS_FRIEND_API(JSBool)
302
+ js_PutArgsObject(JSContext *cx, JSStackFrame *fp);
303
+
304
+ extern JSBool
305
+ js_XDRFunctionObject(JSXDRState *xdr, JSObject **objp);
306
+
307
+ typedef enum JSLocalKind {
308
+ JSLOCAL_NONE,
309
+ JSLOCAL_ARG,
310
+ JSLOCAL_VAR,
311
+ JSLOCAL_CONST,
312
+ JSLOCAL_UPVAR
313
+ } JSLocalKind;
314
+
315
+ extern JSBool
316
+ js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind);
317
+
318
+ /*
319
+ * Look up an argument or variable name returning its kind when found or
320
+ * JSLOCAL_NONE when no such name exists. When indexp is not null and the name
321
+ * exists, *indexp will receive the index of the corresponding argument or
322
+ * variable.
323
+ */
324
+ extern JSLocalKind
325
+ js_LookupLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, uintN *indexp);
326
+
327
+ /*
328
+ * Functions to work with local names as an array of words.
329
+ *
330
+ * js_GetLocalNameArray returns the array, or null if we are out of memory.
331
+ * This function must be called only when fun->hasLocalNames().
332
+ *
333
+ * The supplied pool is used to allocate the returned array, so the caller is
334
+ * obligated to mark and release to free it.
335
+ *
336
+ * The elements of the array with index less than fun->nargs correspond to the
337
+ * names of function formal parameters. An index >= fun->nargs addresses a var
338
+ * binding. Use JS_LOCAL_NAME_TO_ATOM to convert array's element to an atom
339
+ * pointer. This pointer can be null when the element is for a formal parameter
340
+ * corresponding to a destructuring pattern.
341
+ *
342
+ * If nameWord does not name a formal parameter, use JS_LOCAL_NAME_IS_CONST to
343
+ * check if nameWord corresponds to the const declaration.
344
+ */
345
+ extern jsuword *
346
+ js_GetLocalNameArray(JSContext *cx, JSFunction *fun, struct JSArenaPool *pool);
347
+
348
+ #define JS_LOCAL_NAME_TO_ATOM(nameWord) \
349
+ ((JSAtom *) ((nameWord) & ~(jsuword) 1))
350
+
351
+ #define JS_LOCAL_NAME_IS_CONST(nameWord) \
352
+ ((((nameWord) & (jsuword) 1)) != 0)
353
+
354
+ extern void
355
+ js_FreezeLocalNames(JSContext *cx, JSFunction *fun);
356
+
357
+ extern JS_REQUIRES_STACK JSBool
358
+ js_fun_apply(JSContext *cx, uintN argc, jsval *vp);
359
+
360
+ extern JS_REQUIRES_STACK JSBool
361
+ js_fun_call(JSContext *cx, uintN argc, jsval *vp);
362
+
363
+
364
+ JS_END_EXTERN_C
365
+
366
+ #endif /* jsfun_h___ */
@@ -0,0 +1,3816 @@
1
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
+ * vim: set ts=8 sw=4 et tw=78:
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
+ /*
42
+ * JS Mark-and-Sweep Garbage Collector.
43
+ *
44
+ * This GC allocates fixed-sized things with sizes up to GC_NBYTES_MAX (see
45
+ * jsgc.h). It allocates from a special GC arena pool with each arena allocated
46
+ * using malloc. It uses an ideally parallel array of flag bytes to hold the
47
+ * mark bit, finalizer type index, etc.
48
+ *
49
+ * XXX swizzle page to freelist for better locality of reference
50
+ */
51
+ #include "jsstddef.h"
52
+ #include <stdlib.h> /* for free */
53
+ #include <math.h>
54
+ #include <string.h> /* for memset used when DEBUG */
55
+ #include "jstypes.h"
56
+ #include "jsutil.h" /* Added by JSIFY */
57
+ #include "jshash.h" /* Added by JSIFY */
58
+ #include "jsbit.h"
59
+ #include "jsclist.h"
60
+ #include "jsprf.h"
61
+ #include "jsapi.h"
62
+ #include "jsatom.h"
63
+ #include "jscntxt.h"
64
+ #include "jsversion.h"
65
+ #include "jsdbgapi.h"
66
+ #include "jsexn.h"
67
+ #include "jsfun.h"
68
+ #include "jsgc.h"
69
+ #include "jsinterp.h"
70
+ #include "jsiter.h"
71
+ #include "jslock.h"
72
+ #include "jsnum.h"
73
+ #include "jsobj.h"
74
+ #include "jsparse.h"
75
+ #include "jsscope.h"
76
+ #include "jsscript.h"
77
+ #include "jsstaticcheck.h"
78
+ #include "jsstr.h"
79
+ #include "jstracer.h"
80
+
81
+ #if JS_HAS_XML_SUPPORT
82
+ #include "jsxml.h"
83
+ #endif
84
+
85
+ /*
86
+ * Check if posix_memalign is available.
87
+ */
88
+ #if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 || MOZ_MEMORY
89
+ # define HAS_POSIX_MEMALIGN 1
90
+ #else
91
+ # define HAS_POSIX_MEMALIGN 0
92
+ #endif
93
+
94
+ /*
95
+ * jemalloc provides posix_memalign.
96
+ */
97
+ #ifdef MOZ_MEMORY
98
+ extern "C" {
99
+ #include "../../memory/jemalloc/jemalloc.h"
100
+ }
101
+ #endif
102
+
103
+ /*
104
+ * Include the headers for mmap unless we have posix_memalign and do not
105
+ * insist on mmap.
106
+ */
107
+ #if JS_GC_USE_MMAP || (!defined JS_GC_USE_MMAP && !HAS_POSIX_MEMALIGN)
108
+ # if defined(XP_WIN)
109
+ # ifndef JS_GC_USE_MMAP
110
+ # define JS_GC_USE_MMAP 1
111
+ # endif
112
+ # include <windows.h>
113
+ # else
114
+ # if defined(XP_UNIX) || defined(XP_BEOS)
115
+ # include <unistd.h>
116
+ # endif
117
+ # if _POSIX_MAPPED_FILES > 0
118
+ # ifndef JS_GC_USE_MMAP
119
+ # define JS_GC_USE_MMAP 1
120
+ # endif
121
+ # include <sys/mman.h>
122
+
123
+ /* On Mac OS X MAP_ANONYMOUS is not defined. */
124
+ # if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
125
+ # define MAP_ANONYMOUS MAP_ANON
126
+ # endif
127
+ # if !defined(MAP_ANONYMOUS)
128
+ # define MAP_ANONYMOUS 0
129
+ # endif
130
+ # else
131
+ # if JS_GC_USE_MMAP
132
+ # error "JS_GC_USE_MMAP is set when mmap is not available"
133
+ # endif
134
+ # endif
135
+ # endif
136
+ #endif
137
+
138
+ /*
139
+ * Check JSTempValueUnion has the size of jsval and void * so we can
140
+ * reinterpret jsval as void* GC-thing pointer and use JSTVU_SINGLE for
141
+ * different GC-things.
142
+ */
143
+ JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(jsval));
144
+ JS_STATIC_ASSERT(sizeof(JSTempValueUnion) == sizeof(void *));
145
+
146
+
147
+ /*
148
+ * Check that JSTRACE_XML follows JSTRACE_OBJECT, JSTRACE_DOUBLE and
149
+ * JSTRACE_STRING.
150
+ */
151
+ JS_STATIC_ASSERT(JSTRACE_OBJECT == 0);
152
+ JS_STATIC_ASSERT(JSTRACE_DOUBLE == 1);
153
+ JS_STATIC_ASSERT(JSTRACE_STRING == 2);
154
+ JS_STATIC_ASSERT(JSTRACE_XML == 3);
155
+
156
+ /*
157
+ * JS_IS_VALID_TRACE_KIND assumes that JSTRACE_STRING is the last non-xml
158
+ * trace kind when JS_HAS_XML_SUPPORT is false.
159
+ */
160
+ JS_STATIC_ASSERT(JSTRACE_STRING + 1 == JSTRACE_XML);
161
+
162
+ /*
163
+ * The number of used GCX-types must stay within GCX_LIMIT.
164
+ */
165
+ JS_STATIC_ASSERT(GCX_NTYPES <= GCX_LIMIT);
166
+
167
+
168
+ /*
169
+ * Check that we can reinterpret double as JSGCDoubleCell.
170
+ */
171
+ JS_STATIC_ASSERT(sizeof(JSGCDoubleCell) == sizeof(double));
172
+
173
+ /*
174
+ * Check that we can use memset(p, 0, ...) to implement JS_CLEAR_WEAK_ROOTS.
175
+ */
176
+ JS_STATIC_ASSERT(JSVAL_NULL == 0);
177
+
178
+
179
+ /*
180
+ * A GC arena contains a fixed number of flag bits for each thing in its heap,
181
+ * and supports O(1) lookup of a flag given its thing's address.
182
+ *
183
+ * To implement this, we allocate things of the same size from a GC arena
184
+ * containing GC_ARENA_SIZE bytes aligned on GC_ARENA_SIZE boundary. The
185
+ * following picture shows arena's layout:
186
+ *
187
+ * +------------------------------+--------------------+---------------+
188
+ * | allocation area for GC thing | flags of GC things | JSGCArenaInfo |
189
+ * +------------------------------+--------------------+---------------+
190
+ *
191
+ * To find the flag bits for the thing we calculate the thing index counting
192
+ * from arena's start using:
193
+ *
194
+ * thingIndex = (thingAddress & GC_ARENA_MASK) / thingSize
195
+ *
196
+ * The details of flag's lookup depend on thing's kind. For all GC things
197
+ * except doubles we use one byte of flags where the 4 bits determine thing's
198
+ * type and the rest is used to implement GC marking, finalization and
199
+ * locking. We calculate the address of flag's byte using:
200
+ *
201
+ * flagByteAddress =
202
+ * (thingAddress | GC_ARENA_MASK) - sizeof(JSGCArenaInfo) - thingIndex
203
+ *
204
+ * where
205
+ *
206
+ * (thingAddress | GC_ARENA_MASK) - sizeof(JSGCArenaInfo)
207
+ *
208
+ * is the last byte of flags' area.
209
+ *
210
+ * This implies that the things are allocated from the start of their area and
211
+ * flags are allocated from the end. This arrangement avoids a relatively
212
+ * expensive calculation of the location of the boundary separating things and
213
+ * flags. The boundary's offset from the start of the arena is given by:
214
+ *
215
+ * thingsPerArena * thingSize
216
+ *
217
+ * where thingsPerArena is the number of things that the arena can hold:
218
+ *
219
+ * (GC_ARENA_SIZE - sizeof(JSGCArenaInfo)) / (thingSize + 1).
220
+ *
221
+ * To allocate doubles we use a specialized arena. It can contain only numbers
222
+ * so we do not need the type bits. Moreover, since the doubles do not require
223
+ * a finalizer and very few of them are locked via js_LockGCThing API, we use
224
+ * just one bit of flags per double to denote if it was marked during the
225
+ * marking phase of the GC. The locking is implemented via a hash table. Thus
226
+ * for doubles the flag area becomes a bitmap.
227
+ *
228
+ * JS_GC_USE_MMAP macro governs the choice of the aligned arena allocator.
229
+ * When it is true, a platform-dependent function like mmap is used to get
230
+ * memory aligned on CPU page boundaries. If the macro is false or undefined,
231
+ * posix_memalign is used when available. Otherwise the code uses malloc to
232
+ * over-allocate a chunk with js_gcArenasPerChunk aligned arenas. The
233
+ * approximate space overhead of this is 1/js_gcArenasPerChunk. For details,
234
+ * see NewGCChunk/DestroyGCChunk below.
235
+ *
236
+ * The code also allocates arenas in chunks when JS_GC_USE_MMAP is 1 to
237
+ * minimize the overhead of mmap/munmap. In this case js_gcArenasPerChunk can
238
+ * not be a compile-time constant as the system page size is not known until
239
+ * runtime.
240
+ */
241
+ #if JS_GC_USE_MMAP
242
+ static uint32 js_gcArenasPerChunk = 0;
243
+ static JSBool js_gcUseMmap = JS_FALSE;
244
+ #elif HAS_POSIX_MEMALIGN
245
+ # define js_gcArenasPerChunk 1
246
+ #else
247
+ # define js_gcArenasPerChunk 7
248
+ #endif
249
+
250
+ #if defined(js_gcArenasPerChunk) && js_gcArenasPerChunk == 1
251
+ # define CHUNKED_ARENA_ALLOCATION 0
252
+ #else
253
+ # define CHUNKED_ARENA_ALLOCATION 1
254
+ #endif
255
+
256
+ #define GC_ARENA_SHIFT 12
257
+ #define GC_ARENA_MASK ((jsuword) JS_BITMASK(GC_ARENA_SHIFT))
258
+ #define GC_ARENA_SIZE JS_BIT(GC_ARENA_SHIFT)
259
+
260
+ /*
261
+ * JS_GC_ARENA_PAD defines the number of bytes to pad JSGCArenaInfo structure.
262
+ * It is used to improve allocation efficiency when using posix_memalign. If
263
+ * malloc's implementation uses internal headers, then calling
264
+ *
265
+ * posix_memalign(&p, GC_ARENA_SIZE, GC_ARENA_SIZE * js_gcArenasPerChunk)
266
+ *
267
+ * in a sequence leaves holes between allocations of the size GC_ARENA_SIZE
268
+ * due to the need to fit headers. JS_GC_ARENA_PAD mitigates that so the code
269
+ * calls
270
+ *
271
+ * posix_memalign(&p, GC_ARENA_SIZE,
272
+ * GC_ARENA_SIZE * js_gcArenasPerChunk - JS_GC_ARENA_PAD)
273
+ *
274
+ * When JS_GC_ARENA_PAD is equal or greater than the number of words in the
275
+ * system header, the system can pack all allocations together without holes.
276
+ *
277
+ * With JS_GC_USE_MEMALIGN we want at least 2 word pad unless posix_memalign
278
+ * comes from jemalloc that does not use any headers/trailers.
279
+ */
280
+ #ifndef JS_GC_ARENA_PAD
281
+ # if HAS_POSIX_MEMALIGN && !MOZ_MEMORY
282
+ # define JS_GC_ARENA_PAD (2 * JS_BYTES_PER_WORD)
283
+ # else
284
+ # define JS_GC_ARENA_PAD 0
285
+ # endif
286
+ #endif
287
+
288
+ struct JSGCArenaInfo {
289
+ /*
290
+ * Allocation list for the arena or NULL if the arena holds double values.
291
+ */
292
+ JSGCArenaList *list;
293
+
294
+ /*
295
+ * Pointer to the previous arena in a linked list. The arena can either
296
+ * belong to one of JSContext.gcArenaList lists or, when it does not have
297
+ * any allocated GC things, to the list of free arenas in the chunk with
298
+ * head stored in JSGCChunkInfo.lastFreeArena.
299
+ */
300
+ JSGCArenaInfo *prev;
301
+
302
+ #if !CHUNKED_ARENA_ALLOCATION
303
+ jsuword prevUntracedPage;
304
+ #else
305
+ /*
306
+ * A link field for the list of arenas with marked but not yet traced
307
+ * things. The field is encoded as arena's page to share the space with
308
+ * firstArena and arenaIndex fields.
309
+ */
310
+ jsuword prevUntracedPage : JS_BITS_PER_WORD - GC_ARENA_SHIFT;
311
+
312
+ /*
313
+ * When firstArena is false, the index of arena in the chunk. When
314
+ * firstArena is true, the index of a free arena holding JSGCChunkInfo or
315
+ * NO_FREE_ARENAS if there are no free arenas in the chunk.
316
+ *
317
+ * GET_ARENA_INDEX and GET_CHUNK_INFO_INDEX are convenience macros to
318
+ * access either of indexes.
319
+ */
320
+ jsuword arenaIndex : GC_ARENA_SHIFT - 1;
321
+
322
+ /* Flag indicating if the arena is the first in the chunk. */
323
+ jsuword firstArena : 1;
324
+ #endif
325
+
326
+ union {
327
+ jsuword untracedThings; /* bitset for fast search of marked
328
+ but not yet traced things */
329
+ JSBool hasMarkedDoubles; /* the arena has marked doubles */
330
+ } u;
331
+
332
+ #if JS_GC_ARENA_PAD != 0
333
+ uint8 pad[JS_GC_ARENA_PAD];
334
+ #endif
335
+ };
336
+
337
+ /*
338
+ * Verify that the bit fields are indeed shared and JSGCArenaInfo is as small
339
+ * as possible. The code does not rely on this check so if on a particular
340
+ * platform this does not compile, then, as a workaround, comment the assert
341
+ * out and submit a bug report.
342
+ */
343
+ JS_STATIC_ASSERT(offsetof(JSGCArenaInfo, u) == 3 * sizeof(jsuword));
344
+
345
+ /*
346
+ * Macros to convert between JSGCArenaInfo, the start address of the arena and
347
+ * arena's page defined as (start address) >> GC_ARENA_SHIFT.
348
+ */
349
+ #define ARENA_INFO_OFFSET (GC_ARENA_SIZE - (uint32) sizeof(JSGCArenaInfo))
350
+
351
+ #define IS_ARENA_INFO_ADDRESS(arena) \
352
+ (((jsuword) (arena) & GC_ARENA_MASK) == ARENA_INFO_OFFSET)
353
+
354
+ #define ARENA_START_TO_INFO(arenaStart) \
355
+ (JS_ASSERT(((arenaStart) & (jsuword) GC_ARENA_MASK) == 0), \
356
+ (JSGCArenaInfo *) ((arenaStart) + (jsuword) ARENA_INFO_OFFSET))
357
+
358
+ #define ARENA_INFO_TO_START(arena) \
359
+ (JS_ASSERT(IS_ARENA_INFO_ADDRESS(arena)), \
360
+ (jsuword) (arena) & ~(jsuword) GC_ARENA_MASK)
361
+
362
+ #define ARENA_PAGE_TO_INFO(arenaPage) \
363
+ (JS_ASSERT(arenaPage != 0), \
364
+ JS_ASSERT(!((jsuword)(arenaPage) >> (JS_BITS_PER_WORD-GC_ARENA_SHIFT))), \
365
+ ARENA_START_TO_INFO((arenaPage) << GC_ARENA_SHIFT))
366
+
367
+ #define ARENA_INFO_TO_PAGE(arena) \
368
+ (JS_ASSERT(IS_ARENA_INFO_ADDRESS(arena)), \
369
+ ((jsuword) (arena) >> GC_ARENA_SHIFT))
370
+
371
+ #define GET_ARENA_INFO(chunk, index) \
372
+ (JS_ASSERT((index) < js_gcArenasPerChunk), \
373
+ ARENA_START_TO_INFO(chunk + ((index) << GC_ARENA_SHIFT)))
374
+
375
+ #if CHUNKED_ARENA_ALLOCATION
376
+ /*
377
+ * Definitions for allocating arenas in chunks.
378
+ *
379
+ * All chunks that have at least one free arena are put on the doubly-linked
380
+ * list with the head stored in JSRuntime.gcChunkList. JSGCChunkInfo contains
381
+ * the head of the chunk's free arena list together with the link fields for
382
+ * gcChunkList.
383
+ *
384
+ * Structure stored in one of chunk's free arenas. GET_CHUNK_INFO_INDEX gives
385
+ * the index of this arena. When all arenas in the chunk are used, it is
386
+ * removed from the list and the index is set to NO_FREE_ARENAS indicating
387
+ * that the chunk is not on gcChunkList and has no JSGCChunkInfo available.
388
+ */
389
+
390
+ struct JSGCChunkInfo {
391
+ JSGCChunkInfo **prevp;
392
+ JSGCChunkInfo *next;
393
+ JSGCArenaInfo *lastFreeArena;
394
+ uint32 numFreeArenas;
395
+ };
396
+
397
+ #define NO_FREE_ARENAS JS_BITMASK(GC_ARENA_SHIFT - 1)
398
+
399
+ #ifdef js_gcArenasPerChunk
400
+ JS_STATIC_ASSERT(1 <= js_gcArenasPerChunk &&
401
+ js_gcArenasPerChunk <= NO_FREE_ARENAS);
402
+ #endif
403
+
404
+ #define GET_ARENA_CHUNK(arena, index) \
405
+ (JS_ASSERT(GET_ARENA_INDEX(arena) == index), \
406
+ ARENA_INFO_TO_START(arena) - ((index) << GC_ARENA_SHIFT))
407
+
408
+ #define GET_ARENA_INDEX(arena) \
409
+ ((arena)->firstArena ? 0 : (uint32) (arena)->arenaIndex)
410
+
411
+ #define GET_CHUNK_INFO_INDEX(chunk) \
412
+ ((uint32) ARENA_START_TO_INFO(chunk)->arenaIndex)
413
+
414
+ #define SET_CHUNK_INFO_INDEX(chunk, index) \
415
+ (JS_ASSERT((index) < js_gcArenasPerChunk || (index) == NO_FREE_ARENAS), \
416
+ (void) (ARENA_START_TO_INFO(chunk)->arenaIndex = (jsuword) (index)))
417
+
418
+ #define GET_CHUNK_INFO(chunk, infoIndex) \
419
+ (JS_ASSERT(GET_CHUNK_INFO_INDEX(chunk) == (infoIndex)), \
420
+ JS_ASSERT((uint32) (infoIndex) < js_gcArenasPerChunk), \
421
+ (JSGCChunkInfo *) ((chunk) + ((infoIndex) << GC_ARENA_SHIFT)))
422
+
423
+ #define CHUNK_INFO_TO_INDEX(ci) \
424
+ GET_ARENA_INDEX(ARENA_START_TO_INFO((jsuword)ci))
425
+
426
+ #endif
427
+
428
+ /*
429
+ * Macros for GC-thing operations.
430
+ */
431
+ #define THINGS_PER_ARENA(thingSize) \
432
+ ((GC_ARENA_SIZE - (uint32) sizeof(JSGCArenaInfo)) / ((thingSize) + 1U))
433
+
434
+ #define THING_TO_ARENA(thing) \
435
+ ((JSGCArenaInfo *)(((jsuword) (thing) | GC_ARENA_MASK) + \
436
+ 1 - sizeof(JSGCArenaInfo)))
437
+
438
+ #define THING_TO_INDEX(thing, thingSize) \
439
+ ((uint32) ((jsuword) (thing) & GC_ARENA_MASK) / (uint32) (thingSize))
440
+
441
+ #define THING_FLAGS_END(arena) ((uint8 *)(arena))
442
+
443
+ #define THING_FLAGP(arena, thingIndex) \
444
+ (JS_ASSERT((jsuword) (thingIndex) \
445
+ < (jsuword) THINGS_PER_ARENA((arena)->list->thingSize)), \
446
+ (uint8 *)(arena) - 1 - (thingIndex))
447
+
448
+ #define THING_TO_FLAGP(thing, thingSize) \
449
+ THING_FLAGP(THING_TO_ARENA(thing), THING_TO_INDEX(thing, thingSize))
450
+
451
+ #define FLAGP_TO_ARENA(flagp) THING_TO_ARENA(flagp)
452
+
453
+ #define FLAGP_TO_INDEX(flagp) \
454
+ (JS_ASSERT(((jsuword) (flagp) & GC_ARENA_MASK) < ARENA_INFO_OFFSET), \
455
+ (ARENA_INFO_OFFSET - 1 - (uint32) ((jsuword) (flagp) & GC_ARENA_MASK)))
456
+
457
+ #define FLAGP_TO_THING(flagp, thingSize) \
458
+ (JS_ASSERT(((jsuword) (flagp) & GC_ARENA_MASK) >= \
459
+ (ARENA_INFO_OFFSET - THINGS_PER_ARENA(thingSize))), \
460
+ (JSGCThing *)(((jsuword) (flagp) & ~GC_ARENA_MASK) + \
461
+ (thingSize) * FLAGP_TO_INDEX(flagp)))
462
+
463
+ /*
464
+ * Macros for the specialized arena for doubles.
465
+ *
466
+ * DOUBLES_PER_ARENA defines the maximum number of doubles that the arena can
467
+ * hold. We find it as the following. Let n be the number of doubles in the
468
+ * arena. Together with the bitmap of flags and JSGCArenaInfo they should fit
469
+ * the arena. Hence DOUBLES_PER_ARENA or n_max is the maximum value of n for
470
+ * which the following holds:
471
+ *
472
+ * n*s + ceil(n/B) <= M (1)
473
+ *
474
+ * where "/" denotes normal real division,
475
+ * ceil(r) gives the least integer not smaller than the number r,
476
+ * s is the number of words in jsdouble,
477
+ * B is number of bits per word or B == JS_BITS_PER_WORD
478
+ * M is the number of words in the arena before JSGCArenaInfo or
479
+ * M == (GC_ARENA_SIZE - sizeof(JSGCArenaInfo)) / sizeof(jsuword).
480
+ * M == ARENA_INFO_OFFSET / sizeof(jsuword)
481
+ *
482
+ * We rewrite the inequality as
483
+ *
484
+ * n*B*s/B + ceil(n/B) <= M,
485
+ * ceil(n*B*s/B + n/B) <= M,
486
+ * ceil(n*(B*s + 1)/B) <= M (2)
487
+ *
488
+ * We define a helper function e(n, s, B),
489
+ *
490
+ * e(n, s, B) := ceil(n*(B*s + 1)/B) - n*(B*s + 1)/B, 0 <= e(n, s, B) < 1.
491
+ *
492
+ * It gives:
493
+ *
494
+ * n*(B*s + 1)/B + e(n, s, B) <= M,
495
+ * n + e*B/(B*s + 1) <= M*B/(B*s + 1)
496
+ *
497
+ * We apply the floor function to both sides of the last equation, where
498
+ * floor(r) gives the biggest integer not greater than r. As a consequence we
499
+ * have:
500
+ *
501
+ * floor(n + e*B/(B*s + 1)) <= floor(M*B/(B*s + 1)),
502
+ * n + floor(e*B/(B*s + 1)) <= floor(M*B/(B*s + 1)),
503
+ * n <= floor(M*B/(B*s + 1)), (3)
504
+ *
505
+ * where floor(e*B/(B*s + 1)) is zero as e*B/(B*s + 1) < B/(B*s + 1) < 1.
506
+ * Thus any n that satisfies the original constraint (1) or its equivalent (2),
507
+ * must also satisfy (3). That is, we got an upper estimate for the maximum
508
+ * value of n. Lets show that this upper estimate,
509
+ *
510
+ * floor(M*B/(B*s + 1)), (4)
511
+ *
512
+ * also satisfies (1) and, as such, gives the required maximum value.
513
+ * Substituting it into (2) gives:
514
+ *
515
+ * ceil(floor(M*B/(B*s + 1))*(B*s + 1)/B) == ceil(floor(M/X)*X)
516
+ *
517
+ * where X == (B*s + 1)/B > 1. But then floor(M/X)*X <= M/X*X == M and
518
+ *
519
+ * ceil(floor(M/X)*X) <= ceil(M) == M.
520
+ *
521
+ * Thus the value of (4) gives the maximum n satisfying (1).
522
+ *
523
+ * For the final result we observe that in (4)
524
+ *
525
+ * M*B == ARENA_INFO_OFFSET / sizeof(jsuword) * JS_BITS_PER_WORD
526
+ * == ARENA_INFO_OFFSET * JS_BITS_PER_BYTE
527
+ *
528
+ * and
529
+ *
530
+ * B*s == JS_BITS_PER_WORD * sizeof(jsdouble) / sizeof(jsuword)
531
+ * == JS_BITS_PER_DOUBLE.
532
+ */
533
+ #define DOUBLES_PER_ARENA \
534
+ ((ARENA_INFO_OFFSET * JS_BITS_PER_BYTE) / (JS_BITS_PER_DOUBLE + 1))
535
+
536
+ /*
537
+ * Check that ARENA_INFO_OFFSET and sizeof(jsdouble) divides sizeof(jsuword).
538
+ */
539
+ JS_STATIC_ASSERT(ARENA_INFO_OFFSET % sizeof(jsuword) == 0);
540
+ JS_STATIC_ASSERT(sizeof(jsdouble) % sizeof(jsuword) == 0);
541
+ JS_STATIC_ASSERT(sizeof(jsbitmap) == sizeof(jsuword));
542
+
543
+ #define DOUBLES_ARENA_BITMAP_WORDS \
544
+ (JS_HOWMANY(DOUBLES_PER_ARENA, JS_BITS_PER_WORD))
545
+
546
+ /* Check that DOUBLES_PER_ARENA indeed maximises (1). */
547
+ JS_STATIC_ASSERT(DOUBLES_PER_ARENA * sizeof(jsdouble) +
548
+ DOUBLES_ARENA_BITMAP_WORDS * sizeof(jsuword) <=
549
+ ARENA_INFO_OFFSET);
550
+
551
+ JS_STATIC_ASSERT((DOUBLES_PER_ARENA + 1) * sizeof(jsdouble) +
552
+ sizeof(jsuword) *
553
+ JS_HOWMANY((DOUBLES_PER_ARENA + 1), JS_BITS_PER_WORD) >
554
+ ARENA_INFO_OFFSET);
555
+
556
+ /*
557
+ * When DOUBLES_PER_ARENA % BITS_PER_DOUBLE_FLAG_UNIT != 0, some bits in the
558
+ * last byte of the occupation bitmap are unused.
559
+ */
560
+ #define UNUSED_DOUBLE_BITMAP_BITS \
561
+ (DOUBLES_ARENA_BITMAP_WORDS * JS_BITS_PER_WORD - DOUBLES_PER_ARENA)
562
+
563
+ JS_STATIC_ASSERT(UNUSED_DOUBLE_BITMAP_BITS < JS_BITS_PER_WORD);
564
+
565
+ #define DOUBLES_ARENA_BITMAP_OFFSET \
566
+ (ARENA_INFO_OFFSET - DOUBLES_ARENA_BITMAP_WORDS * sizeof(jsuword))
567
+
568
+ #define CHECK_DOUBLE_ARENA_INFO(arenaInfo) \
569
+ (JS_ASSERT(IS_ARENA_INFO_ADDRESS(arenaInfo)), \
570
+ JS_ASSERT(!(arenaInfo)->list)) \
571
+
572
+ /*
573
+ * Get the start of the bitmap area containing double mark flags in the arena.
574
+ * To access the flag the code uses
575
+ *
576
+ * JS_TEST_BIT(bitmapStart, index)
577
+ *
578
+ * That is, compared with the case of arenas with non-double things, we count
579
+ * flags from the start of the bitmap area, not from the end.
580
+ */
581
+ #define DOUBLE_ARENA_BITMAP(arenaInfo) \
582
+ (CHECK_DOUBLE_ARENA_INFO(arenaInfo), \
583
+ (jsbitmap *) arenaInfo - DOUBLES_ARENA_BITMAP_WORDS)
584
+
585
+ #define DOUBLE_THING_TO_INDEX(thing) \
586
+ (CHECK_DOUBLE_ARENA_INFO(THING_TO_ARENA(thing)), \
587
+ JS_ASSERT(((jsuword) (thing) & GC_ARENA_MASK) < \
588
+ DOUBLES_ARENA_BITMAP_OFFSET), \
589
+ ((uint32) (((jsuword) (thing) & GC_ARENA_MASK) / sizeof(jsdouble))))
590
+
591
+ static void
592
+ ClearDoubleArenaFlags(JSGCArenaInfo *a)
593
+ {
594
+ jsbitmap *bitmap, mask;
595
+ uintN nused;
596
+
597
+ /*
598
+ * When some high bits in the last byte of the double occupation bitmap
599
+ * are unused, we must set them. Otherwise RefillDoubleFreeList will
600
+ * assume that they corresponds to some free cells and tries to allocate
601
+ * them.
602
+ *
603
+ * Note that the code works correctly with UNUSED_DOUBLE_BITMAP_BITS == 0.
604
+ */
605
+ bitmap = DOUBLE_ARENA_BITMAP(a);
606
+ memset(bitmap, 0, (DOUBLES_ARENA_BITMAP_WORDS - 1) * sizeof *bitmap);
607
+ mask = ((jsbitmap) 1 << UNUSED_DOUBLE_BITMAP_BITS) - 1;
608
+ nused = JS_BITS_PER_WORD - UNUSED_DOUBLE_BITMAP_BITS;
609
+ bitmap[DOUBLES_ARENA_BITMAP_WORDS - 1] = mask << nused;
610
+ }
611
+
612
+ static JS_ALWAYS_INLINE JSBool
613
+ IsMarkedDouble(JSGCArenaInfo *a, uint32 index)
614
+ {
615
+ jsbitmap *bitmap;
616
+
617
+ JS_ASSERT(a->u.hasMarkedDoubles);
618
+ bitmap = DOUBLE_ARENA_BITMAP(a);
619
+ return JS_TEST_BIT(bitmap, index);
620
+ }
621
+
622
+ /*
623
+ * JSRuntime.gcDoubleArenaList.nextDoubleFlags points either to:
624
+ *
625
+ * 1. The next byte in the bitmap area for doubles to check for unmarked
626
+ * (or free) doubles.
627
+ * 2. Or to the end of the bitmap area when all GC cells of the arena are
628
+ * allocated.
629
+ * 3. Or to a special sentinel value indicating that there are no arenas
630
+ * to check for unmarked doubles.
631
+ *
632
+ * We set the sentinel to ARENA_INFO_OFFSET so the single check
633
+ *
634
+ * ((jsuword) nextDoubleFlags & GC_ARENA_MASK) == ARENA_INFO_OFFSET
635
+ *
636
+ * will cover both the second and the third cases.
637
+ */
638
+ #define DOUBLE_BITMAP_SENTINEL ((jsbitmap *) ARENA_INFO_OFFSET)
639
+
640
+ #ifdef JS_THREADSAFE
641
+ /*
642
+ * The maximum number of things to put on the local free list by taking
643
+ * several things from the global free list or from the tail of the last
644
+ * allocated arena to amortize the cost of rt->gcLock.
645
+ *
646
+ * We use number 8 based on benchmarks from bug 312238.
647
+ */
648
+ #define MAX_THREAD_LOCAL_THINGS 8
649
+
650
+ #endif
651
+
652
+ JS_STATIC_ASSERT(sizeof(JSStackHeader) >= 2 * sizeof(jsval));
653
+
654
+ JS_STATIC_ASSERT(sizeof(JSGCThing) >= sizeof(JSString));
655
+ JS_STATIC_ASSERT(sizeof(JSGCThing) >= sizeof(jsdouble));
656
+
657
+ /* We want to use all the available GC thing space for object's slots. */
658
+ JS_STATIC_ASSERT(sizeof(JSObject) % sizeof(JSGCThing) == 0);
659
+
660
+ /*
661
+ * Ensure that JSObject is allocated from a different GC-list rather than
662
+ * jsdouble and JSString so we can easily finalize JSObject before these 2
663
+ * types of GC things. See comments in js_GC.
664
+ */
665
+ JS_STATIC_ASSERT(GC_FREELIST_INDEX(sizeof(JSString)) !=
666
+ GC_FREELIST_INDEX(sizeof(JSObject)));
667
+ JS_STATIC_ASSERT(GC_FREELIST_INDEX(sizeof(jsdouble)) !=
668
+ GC_FREELIST_INDEX(sizeof(JSObject)));
669
+
670
+ /*
671
+ * JSPtrTable capacity growth descriptor. The table grows by powers of two
672
+ * starting from capacity JSPtrTableInfo.minCapacity, but switching to linear
673
+ * growth when capacity reaches JSPtrTableInfo.linearGrowthThreshold.
674
+ */
675
+ typedef struct JSPtrTableInfo {
676
+ uint16 minCapacity;
677
+ uint16 linearGrowthThreshold;
678
+ } JSPtrTableInfo;
679
+
680
+ #define GC_ITERATOR_TABLE_MIN 4
681
+ #define GC_ITERATOR_TABLE_LINEAR 1024
682
+
683
+ static const JSPtrTableInfo iteratorTableInfo = {
684
+ GC_ITERATOR_TABLE_MIN,
685
+ GC_ITERATOR_TABLE_LINEAR
686
+ };
687
+
688
+ /* Calculate table capacity based on the current value of JSPtrTable.count. */
689
+ static size_t
690
+ PtrTableCapacity(size_t count, const JSPtrTableInfo *info)
691
+ {
692
+ size_t linear, log, capacity;
693
+
694
+ linear = info->linearGrowthThreshold;
695
+ JS_ASSERT(info->minCapacity <= linear);
696
+
697
+ if (count == 0) {
698
+ capacity = 0;
699
+ } else if (count < linear) {
700
+ log = JS_CEILING_LOG2W(count);
701
+ JS_ASSERT(log != JS_BITS_PER_WORD);
702
+ capacity = (size_t)1 << log;
703
+ if (capacity < info->minCapacity)
704
+ capacity = info->minCapacity;
705
+ } else {
706
+ capacity = JS_ROUNDUP(count, linear);
707
+ }
708
+
709
+ JS_ASSERT(capacity >= count);
710
+ return capacity;
711
+ }
712
+
713
+ static void
714
+ FreePtrTable(JSPtrTable *table, const JSPtrTableInfo *info)
715
+ {
716
+ if (table->array) {
717
+ JS_ASSERT(table->count > 0);
718
+ free(table->array);
719
+ table->array = NULL;
720
+ table->count = 0;
721
+ }
722
+ JS_ASSERT(table->count == 0);
723
+ }
724
+
725
+ static JSBool
726
+ AddToPtrTable(JSContext *cx, JSPtrTable *table, const JSPtrTableInfo *info,
727
+ void *ptr)
728
+ {
729
+ size_t count, capacity;
730
+ void **array;
731
+
732
+ count = table->count;
733
+ capacity = PtrTableCapacity(count, info);
734
+
735
+ if (count == capacity) {
736
+ if (capacity < info->minCapacity) {
737
+ JS_ASSERT(capacity == 0);
738
+ JS_ASSERT(!table->array);
739
+ capacity = info->minCapacity;
740
+ } else {
741
+ /*
742
+ * Simplify the overflow detection assuming pointer is bigger
743
+ * than byte.
744
+ */
745
+ JS_STATIC_ASSERT(2 <= sizeof table->array[0]);
746
+ capacity = (capacity < info->linearGrowthThreshold)
747
+ ? 2 * capacity
748
+ : capacity + info->linearGrowthThreshold;
749
+ if (capacity > (size_t)-1 / sizeof table->array[0])
750
+ goto bad;
751
+ }
752
+ array = (void **) realloc(table->array,
753
+ capacity * sizeof table->array[0]);
754
+ if (!array)
755
+ goto bad;
756
+ #ifdef DEBUG
757
+ memset(array + count, JS_FREE_PATTERN,
758
+ (capacity - count) * sizeof table->array[0]);
759
+ #endif
760
+ table->array = array;
761
+ }
762
+
763
+ table->array[count] = ptr;
764
+ table->count = count + 1;
765
+
766
+ return JS_TRUE;
767
+
768
+ bad:
769
+ JS_ReportOutOfMemory(cx);
770
+ return JS_FALSE;
771
+ }
772
+
773
+ static void
774
+ ShrinkPtrTable(JSPtrTable *table, const JSPtrTableInfo *info,
775
+ size_t newCount)
776
+ {
777
+ size_t oldCapacity, capacity;
778
+ void **array;
779
+
780
+ JS_ASSERT(newCount <= table->count);
781
+ if (newCount == table->count)
782
+ return;
783
+
784
+ oldCapacity = PtrTableCapacity(table->count, info);
785
+ table->count = newCount;
786
+ capacity = PtrTableCapacity(newCount, info);
787
+
788
+ if (oldCapacity != capacity) {
789
+ array = table->array;
790
+ JS_ASSERT(array);
791
+ if (capacity == 0) {
792
+ free(array);
793
+ table->array = NULL;
794
+ return;
795
+ }
796
+ array = (void **) realloc(array, capacity * sizeof array[0]);
797
+ if (array)
798
+ table->array = array;
799
+ }
800
+ #ifdef DEBUG
801
+ memset(table->array + newCount, JS_FREE_PATTERN,
802
+ (capacity - newCount) * sizeof table->array[0]);
803
+ #endif
804
+ }
805
+
806
+ #ifdef JS_GCMETER
807
+ # define METER(x) ((void) (x))
808
+ # define METER_IF(condition, x) ((void) ((condition) && (x)))
809
+ #else
810
+ # define METER(x) ((void) 0)
811
+ # define METER_IF(condition, x) ((void) 0)
812
+ #endif
813
+
814
+ #define METER_UPDATE_MAX(maxLval, rval) \
815
+ METER_IF((maxLval) < (rval), (maxLval) = (rval))
816
+
817
+ #if JS_GC_USE_MMAP || !HAS_POSIX_MEMALIGN
818
+
819
+ /*
820
+ * For chunks allocated via over-sized malloc, get a pointer to store the gap
821
+ * between the malloc's result and the first arena in the chunk.
822
+ */
823
+ static uint32 *
824
+ GetMallocedChunkGapPtr(jsuword chunk)
825
+ {
826
+ JS_ASSERT((chunk & GC_ARENA_MASK) == 0);
827
+
828
+ /* Use the memory after the chunk, see NewGCChunk for details. */
829
+ return (uint32 *) (chunk + (js_gcArenasPerChunk << GC_ARENA_SHIFT));
830
+ }
831
+
832
+ #endif
833
+
834
+ static jsuword
835
+ NewGCChunk(void)
836
+ {
837
+ void *p;
838
+
839
+ #if JS_GC_USE_MMAP
840
+ if (js_gcUseMmap) {
841
+ # if defined(XP_WIN)
842
+ p = VirtualAlloc(NULL, js_gcArenasPerChunk << GC_ARENA_SHIFT,
843
+ MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
844
+ return (jsuword) p;
845
+ # else
846
+ p = mmap(NULL, js_gcArenasPerChunk << GC_ARENA_SHIFT,
847
+ PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
848
+ return (p == MAP_FAILED) ? 0 : (jsuword) p;
849
+ # endif
850
+ }
851
+ #endif
852
+
853
+ #if HAS_POSIX_MEMALIGN
854
+ if (0 != posix_memalign(&p, GC_ARENA_SIZE,
855
+ GC_ARENA_SIZE * js_gcArenasPerChunk -
856
+ JS_GC_ARENA_PAD)) {
857
+ return 0;
858
+ }
859
+ return (jsuword) p;
860
+ #else
861
+ /*
862
+ * Implement chunk allocation using oversized malloc if mmap and
863
+ * posix_memalign are not available.
864
+ *
865
+ * Since malloc allocates pointers aligned on the word boundary, to get
866
+ * js_gcArenasPerChunk aligned arenas, we need to malloc only
867
+ *
868
+ * ((js_gcArenasPerChunk + 1) << GC_ARENA_SHIFT) - sizeof(size_t)
869
+ *
870
+ * bytes. But since we stores the gap between the malloced pointer and the
871
+ * first arena in the chunk after the chunk, we need to ask for
872
+ *
873
+ * ((js_gcArenasPerChunk + 1) << GC_ARENA_SHIFT)
874
+ *
875
+ * bytes to ensure that we always have room to store the gap.
876
+ */
877
+ p = malloc((js_gcArenasPerChunk + 1) << GC_ARENA_SHIFT);
878
+ if (!p)
879
+ return 0;
880
+
881
+ {
882
+ jsuword chunk;
883
+
884
+ chunk = ((jsuword) p + GC_ARENA_MASK) & ~GC_ARENA_MASK;
885
+ *GetMallocedChunkGapPtr(chunk) = (uint32) (chunk - (jsuword) p);
886
+ return chunk;
887
+ }
888
+ #endif
889
+ }
890
+
891
+ static void
892
+ DestroyGCChunk(jsuword chunk)
893
+ {
894
+ JS_ASSERT((chunk & GC_ARENA_MASK) == 0);
895
+ #if JS_GC_USE_MMAP
896
+ if (js_gcUseMmap) {
897
+ # if defined(XP_WIN)
898
+ VirtualFree((void *) chunk, 0, MEM_RELEASE);
899
+ # elif defined(SOLARIS)
900
+ munmap((char *) chunk, js_gcArenasPerChunk << GC_ARENA_SHIFT);
901
+ # else
902
+ munmap((void *) chunk, js_gcArenasPerChunk << GC_ARENA_SHIFT);
903
+ # endif
904
+ return;
905
+ }
906
+ #endif
907
+
908
+ #if HAS_POSIX_MEMALIGN
909
+ free((void *) chunk);
910
+ #else
911
+ /* See comments in NewGCChunk. */
912
+ JS_ASSERT(*GetMallocedChunkGapPtr(chunk) < GC_ARENA_SIZE);
913
+ free((void *) (chunk - *GetMallocedChunkGapPtr(chunk)));
914
+ #endif
915
+ }
916
+
917
+ #if CHUNKED_ARENA_ALLOCATION
918
+
919
+ static void
920
+ AddChunkToList(JSRuntime *rt, JSGCChunkInfo *ci)
921
+ {
922
+ ci->prevp = &rt->gcChunkList;
923
+ ci->next = rt->gcChunkList;
924
+ if (rt->gcChunkList) {
925
+ JS_ASSERT(rt->gcChunkList->prevp == &rt->gcChunkList);
926
+ rt->gcChunkList->prevp = &ci->next;
927
+ }
928
+ rt->gcChunkList = ci;
929
+ }
930
+
931
+ static void
932
+ RemoveChunkFromList(JSRuntime *rt, JSGCChunkInfo *ci)
933
+ {
934
+ *ci->prevp = ci->next;
935
+ if (ci->next) {
936
+ JS_ASSERT(ci->next->prevp == &ci->next);
937
+ ci->next->prevp = ci->prevp;
938
+ }
939
+ }
940
+
941
+ #endif
942
+
943
+ static JSGCArenaInfo *
944
+ NewGCArena(JSRuntime *rt)
945
+ {
946
+ jsuword chunk;
947
+ JSGCArenaInfo *a;
948
+
949
+ if (rt->gcBytes >= rt->gcMaxBytes)
950
+ return NULL;
951
+
952
+ #if CHUNKED_ARENA_ALLOCATION
953
+ if (js_gcArenasPerChunk == 1) {
954
+ #endif
955
+ chunk = NewGCChunk();
956
+ if (chunk == 0)
957
+ return NULL;
958
+ a = ARENA_START_TO_INFO(chunk);
959
+ #if CHUNKED_ARENA_ALLOCATION
960
+ } else {
961
+ JSGCChunkInfo *ci;
962
+ uint32 i;
963
+ JSGCArenaInfo *aprev;
964
+
965
+ ci = rt->gcChunkList;
966
+ if (!ci) {
967
+ chunk = NewGCChunk();
968
+ if (chunk == 0)
969
+ return NULL;
970
+ JS_ASSERT((chunk & GC_ARENA_MASK) == 0);
971
+ a = GET_ARENA_INFO(chunk, 0);
972
+ a->firstArena = JS_TRUE;
973
+ a->arenaIndex = 0;
974
+ aprev = NULL;
975
+ i = 0;
976
+ do {
977
+ a->prev = aprev;
978
+ aprev = a;
979
+ ++i;
980
+ a = GET_ARENA_INFO(chunk, i);
981
+ a->firstArena = JS_FALSE;
982
+ a->arenaIndex = i;
983
+ } while (i != js_gcArenasPerChunk - 1);
984
+ ci = GET_CHUNK_INFO(chunk, 0);
985
+ ci->lastFreeArena = aprev;
986
+ ci->numFreeArenas = js_gcArenasPerChunk - 1;
987
+ AddChunkToList(rt, ci);
988
+ } else {
989
+ JS_ASSERT(ci->prevp == &rt->gcChunkList);
990
+ a = ci->lastFreeArena;
991
+ aprev = a->prev;
992
+ if (!aprev) {
993
+ JS_ASSERT(ci->numFreeArenas == 1);
994
+ JS_ASSERT(ARENA_INFO_TO_START(a) == (jsuword) ci);
995
+ RemoveChunkFromList(rt, ci);
996
+ chunk = GET_ARENA_CHUNK(a, GET_ARENA_INDEX(a));
997
+ SET_CHUNK_INFO_INDEX(chunk, NO_FREE_ARENAS);
998
+ } else {
999
+ JS_ASSERT(ci->numFreeArenas >= 2);
1000
+ JS_ASSERT(ARENA_INFO_TO_START(a) != (jsuword) ci);
1001
+ ci->lastFreeArena = aprev;
1002
+ ci->numFreeArenas--;
1003
+ }
1004
+ }
1005
+ }
1006
+ #endif
1007
+
1008
+ rt->gcBytes += GC_ARENA_SIZE;
1009
+ a->prevUntracedPage = 0;
1010
+ memset(&a->u, 0, sizeof(a->u));
1011
+
1012
+ return a;
1013
+ }
1014
+
1015
+ static void
1016
+ DestroyGCArenas(JSRuntime *rt, JSGCArenaInfo *last)
1017
+ {
1018
+ JSGCArenaInfo *a;
1019
+
1020
+ while (last) {
1021
+ a = last;
1022
+ last = last->prev;
1023
+
1024
+ METER(rt->gcStats.afree++);
1025
+ JS_ASSERT(rt->gcBytes >= GC_ARENA_SIZE);
1026
+ rt->gcBytes -= GC_ARENA_SIZE;
1027
+
1028
+ #if CHUNKED_ARENA_ALLOCATION
1029
+ if (js_gcArenasPerChunk == 1) {
1030
+ #endif
1031
+ DestroyGCChunk(ARENA_INFO_TO_START(a));
1032
+ #if CHUNKED_ARENA_ALLOCATION
1033
+ } else {
1034
+ uint32 arenaIndex;
1035
+ jsuword chunk;
1036
+ uint32 chunkInfoIndex;
1037
+ JSGCChunkInfo *ci;
1038
+ # ifdef DEBUG
1039
+ jsuword firstArena;
1040
+
1041
+ firstArena = a->firstArena;
1042
+ arenaIndex = a->arenaIndex;
1043
+ memset((void *) ARENA_INFO_TO_START(a), JS_FREE_PATTERN,
1044
+ GC_ARENA_SIZE - JS_GC_ARENA_PAD);
1045
+ a->firstArena = firstArena;
1046
+ a->arenaIndex = arenaIndex;
1047
+ # endif
1048
+ arenaIndex = GET_ARENA_INDEX(a);
1049
+ chunk = GET_ARENA_CHUNK(a, arenaIndex);
1050
+ chunkInfoIndex = GET_CHUNK_INFO_INDEX(chunk);
1051
+ if (chunkInfoIndex == NO_FREE_ARENAS) {
1052
+ chunkInfoIndex = arenaIndex;
1053
+ SET_CHUNK_INFO_INDEX(chunk, arenaIndex);
1054
+ ci = GET_CHUNK_INFO(chunk, chunkInfoIndex);
1055
+ a->prev = NULL;
1056
+ ci->lastFreeArena = a;
1057
+ ci->numFreeArenas = 1;
1058
+ AddChunkToList(rt, ci);
1059
+ } else {
1060
+ JS_ASSERT(chunkInfoIndex != arenaIndex);
1061
+ ci = GET_CHUNK_INFO(chunk, chunkInfoIndex);
1062
+ JS_ASSERT(ci->numFreeArenas != 0);
1063
+ JS_ASSERT(ci->lastFreeArena);
1064
+ JS_ASSERT(a != ci->lastFreeArena);
1065
+ if (ci->numFreeArenas == js_gcArenasPerChunk - 1) {
1066
+ RemoveChunkFromList(rt, ci);
1067
+ DestroyGCChunk(chunk);
1068
+ } else {
1069
+ ++ci->numFreeArenas;
1070
+ a->prev = ci->lastFreeArena;
1071
+ ci->lastFreeArena = a;
1072
+ }
1073
+ }
1074
+ }
1075
+ # endif
1076
+ }
1077
+ }
1078
+
1079
+ static void
1080
+ InitGCArenaLists(JSRuntime *rt)
1081
+ {
1082
+ uintN i, thingSize;
1083
+ JSGCArenaList *arenaList;
1084
+
1085
+ for (i = 0; i < GC_NUM_FREELISTS; i++) {
1086
+ arenaList = &rt->gcArenaList[i];
1087
+ thingSize = GC_FREELIST_NBYTES(i);
1088
+ JS_ASSERT((size_t)(uint16)thingSize == thingSize);
1089
+ arenaList->last = NULL;
1090
+ arenaList->lastCount = (uint16) THINGS_PER_ARENA(thingSize);
1091
+ arenaList->thingSize = (uint16) thingSize;
1092
+ arenaList->freeList = NULL;
1093
+ }
1094
+ rt->gcDoubleArenaList.first = NULL;
1095
+ rt->gcDoubleArenaList.nextDoubleFlags = DOUBLE_BITMAP_SENTINEL;
1096
+ }
1097
+
1098
+ static void
1099
+ FinishGCArenaLists(JSRuntime *rt)
1100
+ {
1101
+ uintN i;
1102
+ JSGCArenaList *arenaList;
1103
+
1104
+ for (i = 0; i < GC_NUM_FREELISTS; i++) {
1105
+ arenaList = &rt->gcArenaList[i];
1106
+ DestroyGCArenas(rt, arenaList->last);
1107
+ arenaList->last = NULL;
1108
+ arenaList->lastCount = THINGS_PER_ARENA(arenaList->thingSize);
1109
+ arenaList->freeList = NULL;
1110
+ }
1111
+ DestroyGCArenas(rt, rt->gcDoubleArenaList.first);
1112
+ rt->gcDoubleArenaList.first = NULL;
1113
+ rt->gcDoubleArenaList.nextDoubleFlags = DOUBLE_BITMAP_SENTINEL;
1114
+
1115
+ rt->gcBytes = 0;
1116
+ JS_ASSERT(rt->gcChunkList == 0);
1117
+ }
1118
+
1119
+ /*
1120
+ * This function must not be called when thing is jsdouble.
1121
+ */
1122
+ static uint8 *
1123
+ GetGCThingFlags(void *thing)
1124
+ {
1125
+ JSGCArenaInfo *a;
1126
+ uint32 index;
1127
+
1128
+ a = THING_TO_ARENA(thing);
1129
+ index = THING_TO_INDEX(thing, a->list->thingSize);
1130
+ return THING_FLAGP(a, index);
1131
+ }
1132
+
1133
+ /*
1134
+ * This function returns null when thing is jsdouble.
1135
+ */
1136
+ static uint8 *
1137
+ GetGCThingFlagsOrNull(void *thing)
1138
+ {
1139
+ JSGCArenaInfo *a;
1140
+ uint32 index;
1141
+
1142
+ a = THING_TO_ARENA(thing);
1143
+ if (!a->list)
1144
+ return NULL;
1145
+ index = THING_TO_INDEX(thing, a->list->thingSize);
1146
+ return THING_FLAGP(a, index);
1147
+ }
1148
+
1149
+ intN
1150
+ js_GetExternalStringGCType(JSString *str)
1151
+ {
1152
+ uintN type;
1153
+
1154
+ type = (uintN) *GetGCThingFlags(str) & GCF_TYPEMASK;
1155
+ JS_ASSERT(type == GCX_STRING || type >= GCX_EXTERNAL_STRING);
1156
+ return (type == GCX_STRING) ? -1 : (intN) (type - GCX_EXTERNAL_STRING);
1157
+ }
1158
+
1159
+ static uint32
1160
+ MapGCFlagsToTraceKind(uintN flags)
1161
+ {
1162
+ uint32 type;
1163
+
1164
+ type = flags & GCF_TYPEMASK;
1165
+ JS_ASSERT(type != GCX_DOUBLE);
1166
+ JS_ASSERT(type < GCX_NTYPES);
1167
+ return (type < GCX_EXTERNAL_STRING) ? type : JSTRACE_STRING;
1168
+ }
1169
+
1170
+ JS_FRIEND_API(uint32)
1171
+ js_GetGCThingTraceKind(void *thing)
1172
+ {
1173
+ JSGCArenaInfo *a;
1174
+ uint32 index;
1175
+
1176
+ a = THING_TO_ARENA(thing);
1177
+ if (!a->list)
1178
+ return JSTRACE_DOUBLE;
1179
+
1180
+ index = THING_TO_INDEX(thing, a->list->thingSize);
1181
+ return MapGCFlagsToTraceKind(*THING_FLAGP(a, index));
1182
+ }
1183
+
1184
+ JSRuntime*
1185
+ js_GetGCStringRuntime(JSString *str)
1186
+ {
1187
+ JSGCArenaList *list;
1188
+
1189
+ list = THING_TO_ARENA(str)->list;
1190
+
1191
+ JS_ASSERT(list->thingSize == sizeof(JSGCThing));
1192
+ JS_ASSERT(GC_FREELIST_INDEX(sizeof(JSGCThing)) == 0);
1193
+
1194
+ return (JSRuntime *)((uint8 *)list - offsetof(JSRuntime, gcArenaList));
1195
+ }
1196
+
1197
+ JSBool
1198
+ js_IsAboutToBeFinalized(JSContext *cx, void *thing)
1199
+ {
1200
+ JSGCArenaInfo *a;
1201
+ uint32 index, flags;
1202
+
1203
+ a = THING_TO_ARENA(thing);
1204
+ if (!a->list) {
1205
+ /*
1206
+ * Check if arena has no marked doubles. In that case the bitmap with
1207
+ * the mark flags contains all garbage as it is initialized only when
1208
+ * marking the first double in the arena.
1209
+ */
1210
+ if (!a->u.hasMarkedDoubles)
1211
+ return JS_TRUE;
1212
+ index = DOUBLE_THING_TO_INDEX(thing);
1213
+ return !IsMarkedDouble(a, index);
1214
+ }
1215
+ index = THING_TO_INDEX(thing, a->list->thingSize);
1216
+ flags = *THING_FLAGP(a, index);
1217
+ return !(flags & (GCF_MARK | GCF_LOCK | GCF_FINAL));
1218
+ }
1219
+
1220
+ /* This is compatible with JSDHashEntryStub. */
1221
+ typedef struct JSGCRootHashEntry {
1222
+ JSDHashEntryHdr hdr;
1223
+ void *root;
1224
+ const char *name;
1225
+ } JSGCRootHashEntry;
1226
+
1227
+ /* Initial size of the gcRootsHash table (SWAG, small enough to amortize). */
1228
+ #define GC_ROOTS_SIZE 256
1229
+
1230
+ #if CHUNKED_ARENA_ALLOCATION
1231
+
1232
+ /*
1233
+ * For a CPU with extremely large pages using them for GC things wastes
1234
+ * too much memory.
1235
+ */
1236
+ # define GC_ARENAS_PER_CPU_PAGE_LIMIT JS_BIT(18 - GC_ARENA_SHIFT)
1237
+
1238
+ JS_STATIC_ASSERT(GC_ARENAS_PER_CPU_PAGE_LIMIT <= NO_FREE_ARENAS);
1239
+
1240
+ #endif
1241
+
1242
+ JSBool
1243
+ js_InitGC(JSRuntime *rt, uint32 maxbytes)
1244
+ {
1245
+ #if JS_GC_USE_MMAP
1246
+ if (js_gcArenasPerChunk == 0) {
1247
+ size_t cpuPageSize, arenasPerPage;
1248
+ # if defined(XP_WIN)
1249
+ SYSTEM_INFO si;
1250
+
1251
+ GetSystemInfo(&si);
1252
+ cpuPageSize = si.dwPageSize;
1253
+
1254
+ # elif defined(XP_UNIX) || defined(XP_BEOS)
1255
+ cpuPageSize = (size_t) sysconf(_SC_PAGESIZE);
1256
+ # else
1257
+ # error "Not implemented"
1258
+ # endif
1259
+ /* cpuPageSize is a power of 2. */
1260
+ JS_ASSERT((cpuPageSize & (cpuPageSize - 1)) == 0);
1261
+ arenasPerPage = cpuPageSize >> GC_ARENA_SHIFT;
1262
+ #ifdef DEBUG
1263
+ if (arenasPerPage == 0) {
1264
+ fprintf(stderr,
1265
+ "JS engine warning: the size of the CPU page, %u bytes, is too low to use\n"
1266
+ "paged allocation for the garbage collector. Please report this.\n",
1267
+ (unsigned) cpuPageSize);
1268
+ }
1269
+ #endif
1270
+ if (arenasPerPage - 1 <= (size_t) (GC_ARENAS_PER_CPU_PAGE_LIMIT - 1)) {
1271
+ /*
1272
+ * Use at least 4 GC arenas per paged allocation chunk to minimize
1273
+ * the overhead of mmap/VirtualAlloc.
1274
+ */
1275
+ js_gcUseMmap = JS_TRUE;
1276
+ js_gcArenasPerChunk = JS_MAX((uint32) arenasPerPage, 4);
1277
+ } else {
1278
+ js_gcUseMmap = JS_FALSE;
1279
+ js_gcArenasPerChunk = 7;
1280
+ }
1281
+ }
1282
+ JS_ASSERT(1 <= js_gcArenasPerChunk &&
1283
+ js_gcArenasPerChunk <= NO_FREE_ARENAS);
1284
+ #endif
1285
+
1286
+ InitGCArenaLists(rt);
1287
+ if (!JS_DHashTableInit(&rt->gcRootsHash, JS_DHashGetStubOps(), NULL,
1288
+ sizeof(JSGCRootHashEntry), GC_ROOTS_SIZE)) {
1289
+ rt->gcRootsHash.ops = NULL;
1290
+ return JS_FALSE;
1291
+ }
1292
+ rt->gcLocksHash = NULL; /* create lazily */
1293
+
1294
+ /*
1295
+ * Separate gcMaxMallocBytes from gcMaxBytes but initialize to maxbytes
1296
+ * for default backward API compatibility.
1297
+ */
1298
+ rt->gcMaxBytes = rt->gcMaxMallocBytes = maxbytes;
1299
+ rt->gcEmptyArenaPoolLifespan = 30000;
1300
+
1301
+ /*
1302
+ * By default the trigger factor gets maximum possible value. This
1303
+ * means that GC will not be triggered by growth of GC memory (gcBytes).
1304
+ */
1305
+ rt->gcTriggerFactor = (uint32) -1;
1306
+
1307
+ /*
1308
+ * The assigned value prevents GC from running when GC memory is too low
1309
+ * (during JS engine start).
1310
+ */
1311
+ rt->gcLastBytes = 8192;
1312
+
1313
+ METER(memset(&rt->gcStats, 0, sizeof rt->gcStats));
1314
+ return JS_TRUE;
1315
+ }
1316
+
1317
+ #ifdef JS_GCMETER
1318
+
1319
+ static void
1320
+ UpdateArenaStats(JSGCArenaStats *st, uint32 nlivearenas, uint32 nkilledArenas,
1321
+ uint32 nthings)
1322
+ {
1323
+ size_t narenas;
1324
+
1325
+ narenas = nlivearenas + nkilledArenas;
1326
+ JS_ASSERT(narenas >= st->livearenas);
1327
+
1328
+ st->newarenas = narenas - st->livearenas;
1329
+ st->narenas = narenas;
1330
+ st->livearenas = nlivearenas;
1331
+ if (st->maxarenas < narenas)
1332
+ st->maxarenas = narenas;
1333
+ st->totalarenas += narenas;
1334
+
1335
+ st->nthings = nthings;
1336
+ if (st->maxthings < nthings)
1337
+ st->maxthings = nthings;
1338
+ st->totalthings += nthings;
1339
+ }
1340
+
1341
+ JS_FRIEND_API(void)
1342
+ js_DumpGCStats(JSRuntime *rt, FILE *fp)
1343
+ {
1344
+ int i;
1345
+ size_t sumArenas, sumTotalArenas;
1346
+ size_t sumThings, sumMaxThings;
1347
+ size_t sumThingSize, sumTotalThingSize;
1348
+ size_t sumArenaCapacity, sumTotalArenaCapacity;
1349
+ JSGCArenaStats *st;
1350
+ size_t thingSize, thingsPerArena;
1351
+ size_t sumAlloc, sumLocalAlloc, sumFail, sumRetry;
1352
+
1353
+ fprintf(fp, "\nGC allocation statistics:\n");
1354
+
1355
+ #define UL(x) ((unsigned long)(x))
1356
+ #define ULSTAT(x) UL(rt->gcStats.x)
1357
+ #define PERCENT(x,y) (100.0 * (double) (x) / (double) (y))
1358
+
1359
+ sumArenas = 0;
1360
+ sumTotalArenas = 0;
1361
+ sumThings = 0;
1362
+ sumMaxThings = 0;
1363
+ sumThingSize = 0;
1364
+ sumTotalThingSize = 0;
1365
+ sumArenaCapacity = 0;
1366
+ sumTotalArenaCapacity = 0;
1367
+ sumAlloc = 0;
1368
+ sumLocalAlloc = 0;
1369
+ sumFail = 0;
1370
+ sumRetry = 0;
1371
+ for (i = -1; i < (int) GC_NUM_FREELISTS; i++) {
1372
+ if (i == -1) {
1373
+ thingSize = sizeof(jsdouble);
1374
+ thingsPerArena = DOUBLES_PER_ARENA;
1375
+ st = &rt->gcStats.doubleArenaStats;
1376
+ fprintf(fp,
1377
+ "Arena list for double values (%lu doubles per arena):",
1378
+ UL(thingsPerArena));
1379
+ } else {
1380
+ thingSize = rt->gcArenaList[i].thingSize;
1381
+ thingsPerArena = THINGS_PER_ARENA(thingSize);
1382
+ st = &rt->gcStats.arenaStats[i];
1383
+ fprintf(fp,
1384
+ "Arena list %d (thing size %lu, %lu things per arena):",
1385
+ i, UL(GC_FREELIST_NBYTES(i)), UL(thingsPerArena));
1386
+ }
1387
+ if (st->maxarenas == 0) {
1388
+ fputs(" NEVER USED\n", fp);
1389
+ continue;
1390
+ }
1391
+ putc('\n', fp);
1392
+ fprintf(fp, " arenas before GC: %lu\n", UL(st->narenas));
1393
+ fprintf(fp, " new arenas before GC: %lu (%.1f%%)\n",
1394
+ UL(st->newarenas), PERCENT(st->newarenas, st->narenas));
1395
+ fprintf(fp, " arenas after GC: %lu (%.1f%%)\n",
1396
+ UL(st->livearenas), PERCENT(st->livearenas, st->narenas));
1397
+ fprintf(fp, " max arenas: %lu\n", UL(st->maxarenas));
1398
+ fprintf(fp, " things: %lu\n", UL(st->nthings));
1399
+ fprintf(fp, " GC cell utilization: %.1f%%\n",
1400
+ PERCENT(st->nthings, thingsPerArena * st->narenas));
1401
+ fprintf(fp, " average cell utilization: %.1f%%\n",
1402
+ PERCENT(st->totalthings, thingsPerArena * st->totalarenas));
1403
+ fprintf(fp, " max things: %lu\n", UL(st->maxthings));
1404
+ fprintf(fp, " alloc attempts: %lu\n", UL(st->alloc));
1405
+ fprintf(fp, " alloc without locks: %1u (%.1f%%)\n",
1406
+ UL(st->localalloc), PERCENT(st->localalloc, st->alloc));
1407
+ sumArenas += st->narenas;
1408
+ sumTotalArenas += st->totalarenas;
1409
+ sumThings += st->nthings;
1410
+ sumMaxThings += st->maxthings;
1411
+ sumThingSize += thingSize * st->nthings;
1412
+ sumTotalThingSize += thingSize * st->totalthings;
1413
+ sumArenaCapacity += thingSize * thingsPerArena * st->narenas;
1414
+ sumTotalArenaCapacity += thingSize * thingsPerArena * st->totalarenas;
1415
+ sumAlloc += st->alloc;
1416
+ sumLocalAlloc += st->localalloc;
1417
+ sumFail += st->fail;
1418
+ sumRetry += st->retry;
1419
+ }
1420
+ fprintf(fp, "TOTAL STATS:\n");
1421
+ fprintf(fp, " bytes allocated: %lu\n", UL(rt->gcBytes));
1422
+ fprintf(fp, " total GC arenas: %lu\n", UL(sumArenas));
1423
+ fprintf(fp, " total GC things: %lu\n", UL(sumThings));
1424
+ fprintf(fp, " max total GC things: %lu\n", UL(sumMaxThings));
1425
+ fprintf(fp, " GC cell utilization: %.1f%%\n",
1426
+ PERCENT(sumThingSize, sumArenaCapacity));
1427
+ fprintf(fp, " average cell utilization: %.1f%%\n",
1428
+ PERCENT(sumTotalThingSize, sumTotalArenaCapacity));
1429
+ fprintf(fp, "allocation retries after GC: %lu\n", UL(sumRetry));
1430
+ fprintf(fp, " alloc attempts: %lu\n", UL(sumAlloc));
1431
+ fprintf(fp, " alloc without locks: %1u (%.1f%%)\n",
1432
+ UL(sumLocalAlloc), PERCENT(sumLocalAlloc, sumAlloc));
1433
+ fprintf(fp, " allocation failures: %lu\n", UL(sumFail));
1434
+ fprintf(fp, " things born locked: %lu\n", ULSTAT(lockborn));
1435
+ fprintf(fp, " valid lock calls: %lu\n", ULSTAT(lock));
1436
+ fprintf(fp, " valid unlock calls: %lu\n", ULSTAT(unlock));
1437
+ fprintf(fp, " mark recursion depth: %lu\n", ULSTAT(depth));
1438
+ fprintf(fp, " maximum mark recursion: %lu\n", ULSTAT(maxdepth));
1439
+ fprintf(fp, " mark C recursion depth: %lu\n", ULSTAT(cdepth));
1440
+ fprintf(fp, " maximum mark C recursion: %lu\n", ULSTAT(maxcdepth));
1441
+ fprintf(fp, " delayed tracing calls: %lu\n", ULSTAT(untraced));
1442
+ #ifdef DEBUG
1443
+ fprintf(fp, " max trace later count: %lu\n", ULSTAT(maxuntraced));
1444
+ #endif
1445
+ fprintf(fp, " maximum GC nesting level: %lu\n", ULSTAT(maxlevel));
1446
+ fprintf(fp, "potentially useful GC calls: %lu\n", ULSTAT(poke));
1447
+ fprintf(fp, " thing arenas freed so far: %lu\n", ULSTAT(afree));
1448
+ fprintf(fp, " stack segments scanned: %lu\n", ULSTAT(stackseg));
1449
+ fprintf(fp, "stack segment slots scanned: %lu\n", ULSTAT(segslots));
1450
+ fprintf(fp, "reachable closeable objects: %lu\n", ULSTAT(nclose));
1451
+ fprintf(fp, " max reachable closeable: %lu\n", ULSTAT(maxnclose));
1452
+ fprintf(fp, " scheduled close hooks: %lu\n", ULSTAT(closelater));
1453
+ fprintf(fp, " max scheduled close hooks: %lu\n", ULSTAT(maxcloselater));
1454
+
1455
+ #undef UL
1456
+ #undef ULSTAT
1457
+ #undef PERCENT
1458
+
1459
+ #ifdef JS_ARENAMETER
1460
+ JS_DumpArenaStats(fp);
1461
+ #endif
1462
+ }
1463
+ #endif
1464
+
1465
+ #ifdef DEBUG
1466
+ static void
1467
+ CheckLeakedRoots(JSRuntime *rt);
1468
+ #endif
1469
+
1470
+ #ifdef JS_THREADSAFE
1471
+ static void
1472
+ TrimGCFreeListsPool(JSRuntime *rt, uintN keepCount);
1473
+ #endif
1474
+
1475
+ void
1476
+ js_FinishGC(JSRuntime *rt)
1477
+ {
1478
+ #ifdef JS_ARENAMETER
1479
+ JS_DumpArenaStats(stdout);
1480
+ #endif
1481
+ #ifdef JS_GCMETER
1482
+ js_DumpGCStats(rt, stdout);
1483
+ #endif
1484
+
1485
+ FreePtrTable(&rt->gcIteratorTable, &iteratorTableInfo);
1486
+ #ifdef JS_THREADSAFE
1487
+ TrimGCFreeListsPool(rt, 0);
1488
+ JS_ASSERT(!rt->gcFreeListsPool);
1489
+ #endif
1490
+ FinishGCArenaLists(rt);
1491
+
1492
+ if (rt->gcRootsHash.ops) {
1493
+ #ifdef DEBUG
1494
+ CheckLeakedRoots(rt);
1495
+ #endif
1496
+ JS_DHashTableFinish(&rt->gcRootsHash);
1497
+ rt->gcRootsHash.ops = NULL;
1498
+ }
1499
+ if (rt->gcLocksHash) {
1500
+ JS_DHashTableDestroy(rt->gcLocksHash);
1501
+ rt->gcLocksHash = NULL;
1502
+ }
1503
+ }
1504
+
1505
+ JSBool
1506
+ js_AddRoot(JSContext *cx, void *rp, const char *name)
1507
+ {
1508
+ JSBool ok = js_AddRootRT(cx->runtime, rp, name);
1509
+ if (!ok)
1510
+ JS_ReportOutOfMemory(cx);
1511
+ return ok;
1512
+ }
1513
+
1514
+ JSBool
1515
+ js_AddRootRT(JSRuntime *rt, void *rp, const char *name)
1516
+ {
1517
+ JSBool ok;
1518
+ JSGCRootHashEntry *rhe;
1519
+
1520
+ /*
1521
+ * Due to the long-standing, but now removed, use of rt->gcLock across the
1522
+ * bulk of js_GC, API users have come to depend on JS_AddRoot etc. locking
1523
+ * properly with a racing GC, without calling JS_AddRoot from a request.
1524
+ * We have to preserve API compatibility here, now that we avoid holding
1525
+ * rt->gcLock across the mark phase (including the root hashtable mark).
1526
+ */
1527
+ JS_LOCK_GC(rt);
1528
+ js_WaitForGC(rt);
1529
+ rhe = (JSGCRootHashEntry *)
1530
+ JS_DHashTableOperate(&rt->gcRootsHash, rp, JS_DHASH_ADD);
1531
+ if (rhe) {
1532
+ rhe->root = rp;
1533
+ rhe->name = name;
1534
+ ok = JS_TRUE;
1535
+ } else {
1536
+ ok = JS_FALSE;
1537
+ }
1538
+ JS_UNLOCK_GC(rt);
1539
+ return ok;
1540
+ }
1541
+
1542
+ JSBool
1543
+ js_RemoveRoot(JSRuntime *rt, void *rp)
1544
+ {
1545
+ /*
1546
+ * Due to the JS_RemoveRootRT API, we may be called outside of a request.
1547
+ * Same synchronization drill as above in js_AddRoot.
1548
+ */
1549
+ JS_LOCK_GC(rt);
1550
+ js_WaitForGC(rt);
1551
+ (void) JS_DHashTableOperate(&rt->gcRootsHash, rp, JS_DHASH_REMOVE);
1552
+ rt->gcPoke = JS_TRUE;
1553
+ JS_UNLOCK_GC(rt);
1554
+ return JS_TRUE;
1555
+ }
1556
+
1557
+ #ifdef DEBUG
1558
+
1559
+ static JSDHashOperator
1560
+ js_root_printer(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 i, void *arg)
1561
+ {
1562
+ uint32 *leakedroots = (uint32 *)arg;
1563
+ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
1564
+
1565
+ (*leakedroots)++;
1566
+ fprintf(stderr,
1567
+ "JS engine warning: leaking GC root \'%s\' at %p\n",
1568
+ rhe->name ? (char *)rhe->name : "", rhe->root);
1569
+
1570
+ return JS_DHASH_NEXT;
1571
+ }
1572
+
1573
+ static void
1574
+ CheckLeakedRoots(JSRuntime *rt)
1575
+ {
1576
+ uint32 leakedroots = 0;
1577
+
1578
+ /* Warn (but don't assert) debug builds of any remaining roots. */
1579
+ JS_DHashTableEnumerate(&rt->gcRootsHash, js_root_printer,
1580
+ &leakedroots);
1581
+ if (leakedroots > 0) {
1582
+ if (leakedroots == 1) {
1583
+ fprintf(stderr,
1584
+ "JS engine warning: 1 GC root remains after destroying the JSRuntime at %p.\n"
1585
+ " This root may point to freed memory. Objects reachable\n"
1586
+ " through it have not been finalized.\n",
1587
+ (void *) rt);
1588
+ } else {
1589
+ fprintf(stderr,
1590
+ "JS engine warning: %lu GC roots remain after destroying the JSRuntime at %p.\n"
1591
+ " These roots may point to freed memory. Objects reachable\n"
1592
+ " through them have not been finalized.\n",
1593
+ (unsigned long) leakedroots, (void *) rt);
1594
+ }
1595
+ }
1596
+ }
1597
+
1598
+ typedef struct NamedRootDumpArgs {
1599
+ void (*dump)(const char *name, void *rp, void *data);
1600
+ void *data;
1601
+ } NamedRootDumpArgs;
1602
+
1603
+ static JSDHashOperator
1604
+ js_named_root_dumper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
1605
+ void *arg)
1606
+ {
1607
+ NamedRootDumpArgs *args = (NamedRootDumpArgs *) arg;
1608
+ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
1609
+
1610
+ if (rhe->name)
1611
+ args->dump(rhe->name, rhe->root, args->data);
1612
+ return JS_DHASH_NEXT;
1613
+ }
1614
+
1615
+ JS_BEGIN_EXTERN_C
1616
+ void
1617
+ js_DumpNamedRoots(JSRuntime *rt,
1618
+ void (*dump)(const char *name, void *rp, void *data),
1619
+ void *data)
1620
+ {
1621
+ NamedRootDumpArgs args;
1622
+
1623
+ args.dump = dump;
1624
+ args.data = data;
1625
+ JS_DHashTableEnumerate(&rt->gcRootsHash, js_named_root_dumper, &args);
1626
+ }
1627
+ JS_END_EXTERN_C
1628
+
1629
+ #endif /* DEBUG */
1630
+
1631
+ typedef struct GCRootMapArgs {
1632
+ JSGCRootMapFun map;
1633
+ void *data;
1634
+ } GCRootMapArgs;
1635
+
1636
+ static JSDHashOperator
1637
+ js_gcroot_mapper(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
1638
+ void *arg)
1639
+ {
1640
+ GCRootMapArgs *args = (GCRootMapArgs *) arg;
1641
+ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
1642
+ intN mapflags;
1643
+ int op;
1644
+
1645
+ mapflags = args->map(rhe->root, rhe->name, args->data);
1646
+
1647
+ #if JS_MAP_GCROOT_NEXT == JS_DHASH_NEXT && \
1648
+ JS_MAP_GCROOT_STOP == JS_DHASH_STOP && \
1649
+ JS_MAP_GCROOT_REMOVE == JS_DHASH_REMOVE
1650
+ op = (JSDHashOperator)mapflags;
1651
+ #else
1652
+ op = JS_DHASH_NEXT;
1653
+ if (mapflags & JS_MAP_GCROOT_STOP)
1654
+ op |= JS_DHASH_STOP;
1655
+ if (mapflags & JS_MAP_GCROOT_REMOVE)
1656
+ op |= JS_DHASH_REMOVE;
1657
+ #endif
1658
+
1659
+ return (JSDHashOperator) op;
1660
+ }
1661
+
1662
+ uint32
1663
+ js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
1664
+ {
1665
+ GCRootMapArgs args;
1666
+ uint32 rv;
1667
+
1668
+ args.map = map;
1669
+ args.data = data;
1670
+ JS_LOCK_GC(rt);
1671
+ rv = JS_DHashTableEnumerate(&rt->gcRootsHash, js_gcroot_mapper, &args);
1672
+ JS_UNLOCK_GC(rt);
1673
+ return rv;
1674
+ }
1675
+
1676
+ JSBool
1677
+ js_RegisterCloseableIterator(JSContext *cx, JSObject *obj)
1678
+ {
1679
+ JSRuntime *rt;
1680
+ JSBool ok;
1681
+
1682
+ rt = cx->runtime;
1683
+ JS_ASSERT(!rt->gcRunning);
1684
+
1685
+ JS_LOCK_GC(rt);
1686
+ ok = AddToPtrTable(cx, &rt->gcIteratorTable, &iteratorTableInfo, obj);
1687
+ JS_UNLOCK_GC(rt);
1688
+ return ok;
1689
+ }
1690
+
1691
+ static void
1692
+ CloseNativeIterators(JSContext *cx)
1693
+ {
1694
+ JSRuntime *rt;
1695
+ size_t count, newCount, i;
1696
+ void **array;
1697
+ JSObject *obj;
1698
+
1699
+ rt = cx->runtime;
1700
+ count = rt->gcIteratorTable.count;
1701
+ array = rt->gcIteratorTable.array;
1702
+
1703
+ newCount = 0;
1704
+ for (i = 0; i != count; ++i) {
1705
+ obj = (JSObject *)array[i];
1706
+ if (js_IsAboutToBeFinalized(cx, obj))
1707
+ js_CloseNativeIterator(cx, obj);
1708
+ else
1709
+ array[newCount++] = obj;
1710
+ }
1711
+ ShrinkPtrTable(&rt->gcIteratorTable, &iteratorTableInfo, newCount);
1712
+ }
1713
+
1714
+ #if defined(DEBUG_brendan) || defined(DEBUG_timeless)
1715
+ #define DEBUG_gchist
1716
+ #endif
1717
+
1718
+ #ifdef DEBUG_gchist
1719
+ #define NGCHIST 64
1720
+
1721
+ static struct GCHist {
1722
+ bool lastDitch;
1723
+ JSGCThing *freeList;
1724
+ } gchist[NGCHIST];
1725
+
1726
+ unsigned gchpos = 0;
1727
+ #endif
1728
+
1729
+ #ifdef JS_THREADSAFE
1730
+
1731
+ const JSGCFreeListSet js_GCEmptyFreeListSet = {
1732
+ { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, NULL
1733
+ };
1734
+
1735
+ static void
1736
+ TrimGCFreeListsPool(JSRuntime *rt, uintN keepCount)
1737
+ {
1738
+ JSGCFreeListSet **cursor, *freeLists, *link;
1739
+
1740
+ cursor = &rt->gcFreeListsPool;
1741
+ while (keepCount != 0) {
1742
+ --keepCount;
1743
+ freeLists = *cursor;
1744
+ if (!freeLists)
1745
+ return;
1746
+ memset(freeLists->array, 0, sizeof freeLists->array);
1747
+ cursor = &freeLists->link;
1748
+ }
1749
+ freeLists = *cursor;
1750
+ if (freeLists) {
1751
+ *cursor = NULL;
1752
+ do {
1753
+ link = freeLists->link;
1754
+ free(freeLists);
1755
+ } while ((freeLists = link) != NULL);
1756
+ }
1757
+ }
1758
+
1759
+ void
1760
+ js_RevokeGCLocalFreeLists(JSContext *cx)
1761
+ {
1762
+ JS_ASSERT(!cx->gcLocalFreeLists->link);
1763
+ if (cx->gcLocalFreeLists != &js_GCEmptyFreeListSet) {
1764
+ cx->gcLocalFreeLists->link = cx->runtime->gcFreeListsPool;
1765
+ cx->runtime->gcFreeListsPool = cx->gcLocalFreeLists;
1766
+ cx->gcLocalFreeLists = (JSGCFreeListSet *) &js_GCEmptyFreeListSet;
1767
+ }
1768
+ }
1769
+
1770
+ static JSGCFreeListSet *
1771
+ EnsureLocalFreeList(JSContext *cx)
1772
+ {
1773
+ JSGCFreeListSet *freeLists;
1774
+
1775
+ freeLists = cx->gcLocalFreeLists;
1776
+ if (freeLists != &js_GCEmptyFreeListSet) {
1777
+ JS_ASSERT(freeLists);
1778
+ return freeLists;
1779
+ }
1780
+
1781
+ freeLists = cx->runtime->gcFreeListsPool;
1782
+ if (freeLists) {
1783
+ cx->runtime->gcFreeListsPool = freeLists->link;
1784
+ freeLists->link = NULL;
1785
+ } else {
1786
+ /* JS_malloc is not used as the caller reports out-of-memory itself. */
1787
+ freeLists = (JSGCFreeListSet *) calloc(1, sizeof *freeLists);
1788
+ if (!freeLists)
1789
+ return NULL;
1790
+ }
1791
+ cx->gcLocalFreeLists = freeLists;
1792
+ return freeLists;
1793
+ }
1794
+
1795
+ #endif
1796
+
1797
+ static JS_INLINE bool
1798
+ IsGCThresholdReached(JSRuntime *rt)
1799
+ {
1800
+ #ifdef JS_GC_ZEAL
1801
+ if (rt->gcZeal >= 1)
1802
+ return true;
1803
+ #endif
1804
+
1805
+ /*
1806
+ * Since the initial value of the gcLastBytes parameter is not equal to
1807
+ * zero (see the js_InitGC function) the return value is false when
1808
+ * the gcBytes value is close to zero at the JS engine start.
1809
+ */
1810
+ return rt->gcMallocBytes >= rt->gcMaxMallocBytes ||
1811
+ rt->gcBytes / rt->gcTriggerFactor >= rt->gcLastBytes / 100;
1812
+ }
1813
+
1814
+ void *
1815
+ js_NewGCThing(JSContext *cx, uintN flags, size_t nbytes)
1816
+ {
1817
+ JSRuntime *rt;
1818
+ uintN flindex;
1819
+ bool doGC;
1820
+ JSGCThing *thing;
1821
+ uint8 *flagp;
1822
+ JSGCArenaList *arenaList;
1823
+ JSGCArenaInfo *a;
1824
+ uintN thingsLimit;
1825
+ JSLocalRootStack *lrs;
1826
+ #ifdef JS_GCMETER
1827
+ JSGCArenaStats *astats;
1828
+ #endif
1829
+ #ifdef JS_THREADSAFE
1830
+ JSBool gcLocked;
1831
+ uintN localMallocBytes;
1832
+ JSGCFreeListSet *freeLists;
1833
+ JSGCThing **lastptr;
1834
+ JSGCThing *tmpthing;
1835
+ uint8 *tmpflagp;
1836
+ uintN maxFreeThings; /* max to take from the global free list */
1837
+ #endif
1838
+
1839
+ JS_ASSERT((flags & GCF_TYPEMASK) != GCX_DOUBLE);
1840
+ rt = cx->runtime;
1841
+ nbytes = JS_ROUNDUP(nbytes, sizeof(JSGCThing));
1842
+ flindex = GC_FREELIST_INDEX(nbytes);
1843
+
1844
+ /* Updates of metering counters here may not be thread-safe. */
1845
+ METER(astats = &cx->runtime->gcStats.arenaStats[flindex]);
1846
+ METER(astats->alloc++);
1847
+
1848
+ #ifdef JS_THREADSAFE
1849
+ gcLocked = JS_FALSE;
1850
+ JS_ASSERT(cx->thread);
1851
+ freeLists = cx->gcLocalFreeLists;
1852
+ thing = freeLists->array[flindex];
1853
+ localMallocBytes = cx->thread->gcMallocBytes;
1854
+ if (thing && rt->gcMaxMallocBytes - rt->gcMallocBytes > localMallocBytes) {
1855
+ flagp = thing->flagp;
1856
+ freeLists->array[flindex] = thing->next;
1857
+ METER(astats->localalloc++);
1858
+ goto success;
1859
+ }
1860
+
1861
+ JS_LOCK_GC(rt);
1862
+ gcLocked = JS_TRUE;
1863
+
1864
+ /* Transfer thread-local counter to global one. */
1865
+ if (localMallocBytes != 0) {
1866
+ cx->thread->gcMallocBytes = 0;
1867
+ if (rt->gcMaxMallocBytes - rt->gcMallocBytes < localMallocBytes)
1868
+ rt->gcMallocBytes = rt->gcMaxMallocBytes;
1869
+ else
1870
+ rt->gcMallocBytes += localMallocBytes;
1871
+ }
1872
+ #endif
1873
+ JS_ASSERT(!rt->gcRunning);
1874
+ if (rt->gcRunning) {
1875
+ METER(rt->gcStats.finalfail++);
1876
+ JS_UNLOCK_GC(rt);
1877
+ return NULL;
1878
+ }
1879
+
1880
+ #if defined JS_GC_ZEAL && defined JS_TRACER
1881
+ if (rt->gcZeal >= 1 && JS_TRACE_MONITOR(cx).useReservedObjects)
1882
+ goto testReservedObjects;
1883
+ #endif
1884
+
1885
+ arenaList = &rt->gcArenaList[flindex];
1886
+ doGC = IsGCThresholdReached(rt);
1887
+ for (;;) {
1888
+ if (doGC
1889
+ #ifdef JS_TRACER
1890
+ && !JS_ON_TRACE(cx) && !JS_TRACE_MONITOR(cx).useReservedObjects
1891
+ #endif
1892
+ ) {
1893
+ /*
1894
+ * Keep rt->gcLock across the call into js_GC so we don't starve
1895
+ * and lose to racing threads who deplete the heap just after
1896
+ * js_GC has replenished it (or has synchronized with a racing
1897
+ * GC that collected a bunch of garbage). This unfair scheduling
1898
+ * can happen on certain operating systems. For the gory details,
1899
+ * see bug 162779 at https://bugzilla.mozilla.org/.
1900
+ */
1901
+ js_GC(cx, GC_LAST_DITCH);
1902
+ METER(astats->retry++);
1903
+ }
1904
+
1905
+ /* Try to get thing from the free list. */
1906
+ thing = arenaList->freeList;
1907
+ if (thing) {
1908
+ arenaList->freeList = thing->next;
1909
+ flagp = thing->flagp;
1910
+ JS_ASSERT(*flagp & GCF_FINAL);
1911
+
1912
+ #ifdef JS_THREADSAFE
1913
+ /*
1914
+ * Refill the local free list by taking several things from the
1915
+ * global free list unless we are still at rt->gcMaxMallocBytes
1916
+ * barrier or the free list is already populated. The former
1917
+ * happens when GC is canceled due to gcCallback(cx, JSGC_BEGIN)
1918
+ * returning false. The latter is caused via allocating new
1919
+ * things in gcCallback(cx, JSGC_END).
1920
+ */
1921
+ if (rt->gcMallocBytes >= rt->gcMaxMallocBytes)
1922
+ break;
1923
+
1924
+ freeLists = EnsureLocalFreeList(cx);
1925
+ if (!freeLists)
1926
+ goto fail;
1927
+ if (freeLists->array[flindex])
1928
+ break;
1929
+
1930
+ tmpthing = arenaList->freeList;
1931
+ if (tmpthing) {
1932
+ maxFreeThings = MAX_THREAD_LOCAL_THINGS;
1933
+ do {
1934
+ if (!tmpthing->next)
1935
+ break;
1936
+ tmpthing = tmpthing->next;
1937
+ } while (--maxFreeThings != 0);
1938
+
1939
+ freeLists->array[flindex] = arenaList->freeList;
1940
+ arenaList->freeList = tmpthing->next;
1941
+ tmpthing->next = NULL;
1942
+ }
1943
+ #endif
1944
+ break;
1945
+ }
1946
+
1947
+ /*
1948
+ * Try to allocate things from the last arena. If it is fully used,
1949
+ * check if we can allocate a new one and, if we cannot, consider
1950
+ * doing a "last ditch" GC unless already tried.
1951
+ */
1952
+ thingsLimit = THINGS_PER_ARENA(nbytes);
1953
+ if (arenaList->lastCount != thingsLimit) {
1954
+ JS_ASSERT(arenaList->lastCount < thingsLimit);
1955
+ a = arenaList->last;
1956
+ } else {
1957
+ #ifdef JS_TRACER
1958
+ if (JS_TRACE_MONITOR(cx).useReservedObjects) {
1959
+ #ifdef JS_GC_ZEAL
1960
+ testReservedObjects:
1961
+ #endif
1962
+ JSTraceMonitor *tm = &JS_TRACE_MONITOR(cx);
1963
+
1964
+ thing = (JSGCThing *) tm->reservedObjects;
1965
+ flagp = GetGCThingFlags(thing);
1966
+ JS_ASSERT(thing);
1967
+ tm->reservedObjects = JSVAL_TO_OBJECT(tm->reservedObjects->fslots[0]);
1968
+ break;
1969
+ }
1970
+ #endif
1971
+
1972
+ a = NewGCArena(rt);
1973
+ if (!a) {
1974
+ if (doGC || JS_ON_TRACE(cx))
1975
+ goto fail;
1976
+ doGC = true;
1977
+ continue;
1978
+ }
1979
+ a->list = arenaList;
1980
+ a->prev = arenaList->last;
1981
+ a->prevUntracedPage = 0;
1982
+ a->u.untracedThings = 0;
1983
+ arenaList->last = a;
1984
+ arenaList->lastCount = 0;
1985
+ }
1986
+
1987
+ flagp = THING_FLAGP(a, arenaList->lastCount);
1988
+ thing = FLAGP_TO_THING(flagp, nbytes);
1989
+ arenaList->lastCount++;
1990
+
1991
+ #ifdef JS_THREADSAFE
1992
+ /*
1993
+ * Refill the local free list by taking free things from the last
1994
+ * arena. Prefer to order free things by ascending address in the
1995
+ * (unscientific) hope of better cache locality.
1996
+ */
1997
+ if (rt->gcMallocBytes >= rt->gcMaxMallocBytes)
1998
+ break;
1999
+
2000
+ freeLists = EnsureLocalFreeList(cx);
2001
+ if (!freeLists)
2002
+ goto fail;
2003
+ if (freeLists->array[flindex])
2004
+ break;
2005
+ lastptr = &freeLists->array[flindex];
2006
+ maxFreeThings = thingsLimit - arenaList->lastCount;
2007
+ if (maxFreeThings > MAX_THREAD_LOCAL_THINGS)
2008
+ maxFreeThings = MAX_THREAD_LOCAL_THINGS;
2009
+ while (maxFreeThings != 0) {
2010
+ --maxFreeThings;
2011
+
2012
+ tmpflagp = THING_FLAGP(a, arenaList->lastCount);
2013
+ tmpthing = FLAGP_TO_THING(tmpflagp, nbytes);
2014
+ arenaList->lastCount++;
2015
+ tmpthing->flagp = tmpflagp;
2016
+ *tmpflagp = GCF_FINAL; /* signifying that thing is free */
2017
+
2018
+ *lastptr = tmpthing;
2019
+ lastptr = &tmpthing->next;
2020
+ }
2021
+ *lastptr = NULL;
2022
+ #endif
2023
+ break;
2024
+ }
2025
+
2026
+ /* We successfully allocated the thing. */
2027
+ #ifdef JS_THREADSAFE
2028
+ success:
2029
+ #endif
2030
+ lrs = cx->localRootStack;
2031
+ if (lrs) {
2032
+ /*
2033
+ * If we're in a local root scope, don't set newborn[type] at all, to
2034
+ * avoid entraining garbage from it for an unbounded amount of time
2035
+ * on this context. A caller will leave the local root scope and pop
2036
+ * this reference, allowing thing to be GC'd if it has no other refs.
2037
+ * See JS_EnterLocalRootScope and related APIs.
2038
+ */
2039
+ if (js_PushLocalRoot(cx, lrs, (jsval) thing) < 0) {
2040
+ /*
2041
+ * When we fail for a thing allocated through the tail of the last
2042
+ * arena, thing's flag byte is not initialized. So to prevent GC
2043
+ * accessing the uninitialized flags during the finalization, we
2044
+ * always mark the thing as final. See bug 337407.
2045
+ */
2046
+ *flagp = GCF_FINAL;
2047
+ goto fail;
2048
+ }
2049
+ } else {
2050
+ /*
2051
+ * No local root scope, so we're stuck with the old, fragile model of
2052
+ * depending on a pigeon-hole newborn per type per context.
2053
+ */
2054
+ cx->weakRoots.newborn[flags & GCF_TYPEMASK] = thing;
2055
+ }
2056
+
2057
+ /* We can't fail now, so update flags. */
2058
+ *flagp = (uint8)flags;
2059
+
2060
+ #ifdef DEBUG_gchist
2061
+ gchist[gchpos].lastDitch = doGC;
2062
+ gchist[gchpos].freeList = rt->gcArenaList[flindex].freeList;
2063
+ if (++gchpos == NGCHIST)
2064
+ gchpos = 0;
2065
+ #endif
2066
+
2067
+ /* This is not thread-safe for thread-local allocations. */
2068
+ METER_IF(flags & GCF_LOCK, rt->gcStats.lockborn++);
2069
+
2070
+ #ifdef JS_THREADSAFE
2071
+ if (gcLocked)
2072
+ JS_UNLOCK_GC(rt);
2073
+ #endif
2074
+ return thing;
2075
+
2076
+ fail:
2077
+ #ifdef JS_THREADSAFE
2078
+ if (gcLocked)
2079
+ JS_UNLOCK_GC(rt);
2080
+ #endif
2081
+ METER(astats->fail++);
2082
+ js_ReportOutOfMemory(cx);
2083
+ return NULL;
2084
+ }
2085
+
2086
+ static JSGCDoubleCell *
2087
+ RefillDoubleFreeList(JSContext *cx)
2088
+ {
2089
+ JSRuntime *rt;
2090
+ jsbitmap *doubleFlags, usedBits;
2091
+ JSBool didGC = JS_FALSE;
2092
+ JSGCArenaInfo *a;
2093
+ uintN bit, index;
2094
+ JSGCDoubleCell *cell, *list, *lastcell;
2095
+
2096
+ JS_ASSERT(!cx->doubleFreeList);
2097
+
2098
+ rt = cx->runtime;
2099
+ JS_LOCK_GC(rt);
2100
+
2101
+ JS_ASSERT(!rt->gcRunning);
2102
+ if (rt->gcRunning) {
2103
+ METER(rt->gcStats.finalfail++);
2104
+ JS_UNLOCK_GC(rt);
2105
+ return NULL;
2106
+ }
2107
+
2108
+ if (IsGCThresholdReached(rt))
2109
+ goto do_gc;
2110
+
2111
+ /*
2112
+ * Loop until we find a flag bitmap byte with unset bits indicating free
2113
+ * double cells, then set all bits as used and put the cells to the free
2114
+ * list for the current context.
2115
+ */
2116
+ doubleFlags = rt->gcDoubleArenaList.nextDoubleFlags;
2117
+ for (;;) {
2118
+ if (((jsuword) doubleFlags & GC_ARENA_MASK) ==
2119
+ ARENA_INFO_OFFSET) {
2120
+ if (doubleFlags == DOUBLE_BITMAP_SENTINEL ||
2121
+ !((JSGCArenaInfo *) doubleFlags)->prev) {
2122
+ a = NewGCArena(rt);
2123
+ if (!a) {
2124
+ do_gc:
2125
+ if (didGC || JS_ON_TRACE(cx)) {
2126
+ METER(rt->gcStats.doubleArenaStats.fail++);
2127
+ JS_UNLOCK_GC(rt);
2128
+ js_ReportOutOfMemory(cx);
2129
+ return NULL;
2130
+ }
2131
+ js_GC(cx, GC_LAST_DITCH);
2132
+ METER(rt->gcStats.doubleArenaStats.retry++);
2133
+ doubleFlags = rt->gcDoubleArenaList.nextDoubleFlags;
2134
+ didGC = JS_TRUE;
2135
+ continue;
2136
+ }
2137
+ a->list = NULL;
2138
+ a->prev = NULL;
2139
+ if (doubleFlags == DOUBLE_BITMAP_SENTINEL) {
2140
+ JS_ASSERT(!rt->gcDoubleArenaList.first);
2141
+ rt->gcDoubleArenaList.first = a;
2142
+ } else {
2143
+ JS_ASSERT(rt->gcDoubleArenaList.first);
2144
+ ((JSGCArenaInfo *) doubleFlags)->prev = a;
2145
+ }
2146
+ ClearDoubleArenaFlags(a);
2147
+ doubleFlags = DOUBLE_ARENA_BITMAP(a);
2148
+ break;
2149
+ }
2150
+ doubleFlags =
2151
+ DOUBLE_ARENA_BITMAP(((JSGCArenaInfo *) doubleFlags)->prev);
2152
+ }
2153
+
2154
+ /*
2155
+ * When doubleFlags points the last bitmap's word in the arena, its
2156
+ * high bits corresponds to non-existing cells. ClearDoubleArenaFlags
2157
+ * sets such bits to 1. Thus even for this last word its bit is unset
2158
+ * iff the corresponding cell exists and free.
2159
+ */
2160
+ if (*doubleFlags != (jsbitmap) -1)
2161
+ break;
2162
+ ++doubleFlags;
2163
+ }
2164
+
2165
+ rt->gcDoubleArenaList.nextDoubleFlags = doubleFlags + 1;
2166
+ usedBits = *doubleFlags;
2167
+ JS_ASSERT(usedBits != (jsbitmap) -1);
2168
+ *doubleFlags = (jsbitmap) -1;
2169
+ JS_UNLOCK_GC(rt);
2170
+
2171
+ /*
2172
+ * Find the index corresponding to the first bit in *doubleFlags. The last
2173
+ * bit will have "index + JS_BITS_PER_WORD - 1".
2174
+ */
2175
+ index = ((uintN) ((jsuword) doubleFlags & GC_ARENA_MASK) -
2176
+ DOUBLES_ARENA_BITMAP_OFFSET) * JS_BITS_PER_BYTE;
2177
+ cell = (JSGCDoubleCell *) ((jsuword) doubleFlags & ~GC_ARENA_MASK) + index;
2178
+
2179
+ if (usedBits == 0) {
2180
+ /* The common case when all doubles from *doubleFlags are free. */
2181
+ JS_ASSERT(index + JS_BITS_PER_WORD <= DOUBLES_PER_ARENA);
2182
+ list = cell;
2183
+ for (lastcell = cell + JS_BITS_PER_WORD - 1; cell != lastcell; ++cell)
2184
+ cell->link = cell + 1;
2185
+ lastcell->link = NULL;
2186
+ } else {
2187
+ /*
2188
+ * Assemble the free list from free cells from *doubleFlags starting
2189
+ * from the tail. In the loop
2190
+ *
2191
+ * index + bit >= DOUBLES_PER_ARENA
2192
+ *
2193
+ * when bit is one of the unused bits. We do not check for such bits
2194
+ * explicitly as they must be set and the "if" check filters them out.
2195
+ */
2196
+ JS_ASSERT(index + JS_BITS_PER_WORD <=
2197
+ DOUBLES_PER_ARENA + UNUSED_DOUBLE_BITMAP_BITS);
2198
+ bit = JS_BITS_PER_WORD;
2199
+ cell += bit;
2200
+ list = NULL;
2201
+ do {
2202
+ --bit;
2203
+ --cell;
2204
+ if (!(((jsbitmap) 1 << bit) & usedBits)) {
2205
+ JS_ASSERT(index + bit < DOUBLES_PER_ARENA);
2206
+ JS_ASSERT_IF(index + bit == DOUBLES_PER_ARENA - 1, !list);
2207
+ cell->link = list;
2208
+ list = cell;
2209
+ }
2210
+ } while (bit != 0);
2211
+ }
2212
+ JS_ASSERT(list);
2213
+
2214
+ /*
2215
+ * We delegate assigning cx->doubleFreeList to js_NewDoubleInRootedValue as
2216
+ * it immediately consumes the head of the list.
2217
+ */
2218
+ return list;
2219
+ }
2220
+
2221
+ JSBool
2222
+ js_NewDoubleInRootedValue(JSContext *cx, jsdouble d, jsval *vp)
2223
+ {
2224
+ #ifdef JS_GCMETER
2225
+ JSGCArenaStats *astats;
2226
+ #endif
2227
+ JSGCDoubleCell *cell;
2228
+
2229
+ /* Updates of metering counters here are not thread-safe. */
2230
+ METER(astats = &cx->runtime->gcStats.doubleArenaStats);
2231
+ METER(astats->alloc++);
2232
+ cell = cx->doubleFreeList;
2233
+ if (!cell) {
2234
+ cell = RefillDoubleFreeList(cx);
2235
+ if (!cell) {
2236
+ METER(astats->fail++);
2237
+ return JS_FALSE;
2238
+ }
2239
+ } else {
2240
+ METER(astats->localalloc++);
2241
+ }
2242
+ cx->doubleFreeList = cell->link;
2243
+ cell->number = d;
2244
+ *vp = DOUBLE_TO_JSVAL(&cell->number);
2245
+ return JS_TRUE;
2246
+ }
2247
+
2248
+ jsdouble *
2249
+ js_NewWeaklyRootedDouble(JSContext *cx, jsdouble d)
2250
+ {
2251
+ jsval v;
2252
+ jsdouble *dp;
2253
+
2254
+ if (!js_NewDoubleInRootedValue(cx, d, &v))
2255
+ return NULL;
2256
+
2257
+ JS_ASSERT(JSVAL_IS_DOUBLE(v));
2258
+ dp = JSVAL_TO_DOUBLE(v);
2259
+ if (cx->localRootStack) {
2260
+ if (js_PushLocalRoot(cx, cx->localRootStack, v) < 0)
2261
+ return NULL;
2262
+ } else {
2263
+ cx->weakRoots.newborn[GCX_DOUBLE] = dp;
2264
+ }
2265
+ return dp;
2266
+ }
2267
+
2268
+ #ifdef JS_TRACER
2269
+ JSBool
2270
+ js_ReserveObjects(JSContext *cx, size_t nobjects)
2271
+ {
2272
+ /*
2273
+ * Ensure at least nobjects objects are in the list. fslots[1] of each
2274
+ * object on the reservedObjects list is the length of the list from there.
2275
+ */
2276
+ JSObject *&head = JS_TRACE_MONITOR(cx).reservedObjects;
2277
+ size_t i = head ? JSVAL_TO_INT(head->fslots[1]) : 0;
2278
+ while (i < nobjects) {
2279
+ JSObject *obj = (JSObject *) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
2280
+ if (!obj)
2281
+ return JS_FALSE;
2282
+ memset(obj, 0, sizeof(JSObject));
2283
+ /* The class must be set to something for finalization. */
2284
+ obj->classword = (jsuword) &js_ObjectClass;
2285
+ obj->fslots[0] = OBJECT_TO_JSVAL(head);
2286
+ i++;
2287
+ obj->fslots[1] = INT_TO_JSVAL(i);
2288
+ head = obj;
2289
+ }
2290
+
2291
+ return JS_TRUE;
2292
+ }
2293
+ #endif
2294
+
2295
+ JSBool
2296
+ js_AddAsGCBytes(JSContext *cx, size_t sz)
2297
+ {
2298
+ JSRuntime *rt;
2299
+
2300
+ rt = cx->runtime;
2301
+ if (rt->gcBytes >= rt->gcMaxBytes ||
2302
+ sz > (size_t) (rt->gcMaxBytes - rt->gcBytes) ||
2303
+ IsGCThresholdReached(rt)) {
2304
+ if (JS_ON_TRACE(cx)) {
2305
+ /*
2306
+ * If we can't leave the trace, signal OOM condition, otherwise
2307
+ * exit from trace and proceed with GC.
2308
+ */
2309
+ if (!js_CanLeaveTrace(cx)) {
2310
+ JS_UNLOCK_GC(rt);
2311
+ return JS_FALSE;
2312
+ }
2313
+ js_LeaveTrace(cx);
2314
+ }
2315
+ js_GC(cx, GC_LAST_DITCH);
2316
+ if (rt->gcBytes >= rt->gcMaxBytes ||
2317
+ sz > (size_t) (rt->gcMaxBytes - rt->gcBytes)) {
2318
+ JS_UNLOCK_GC(rt);
2319
+ JS_ReportOutOfMemory(cx);
2320
+ return JS_FALSE;
2321
+ }
2322
+ }
2323
+ rt->gcBytes += (uint32) sz;
2324
+ return JS_TRUE;
2325
+ }
2326
+
2327
+ void
2328
+ js_RemoveAsGCBytes(JSRuntime *rt, size_t sz)
2329
+ {
2330
+ JS_ASSERT((size_t) rt->gcBytes >= sz);
2331
+ rt->gcBytes -= (uint32) sz;
2332
+ }
2333
+
2334
+ /*
2335
+ * Shallow GC-things can be locked just by setting the GCF_LOCK bit, because
2336
+ * they have no descendants to mark during the GC. Currently the optimization
2337
+ * is only used for non-dependant strings.
2338
+ */
2339
+ #define GC_THING_IS_SHALLOW(flagp, thing) \
2340
+ ((flagp) && \
2341
+ ((*(flagp) & GCF_TYPEMASK) >= GCX_EXTERNAL_STRING || \
2342
+ ((*(flagp) & GCF_TYPEMASK) == GCX_STRING && \
2343
+ !JSSTRING_IS_DEPENDENT((JSString *) (thing)))))
2344
+
2345
+ /* This is compatible with JSDHashEntryStub. */
2346
+ typedef struct JSGCLockHashEntry {
2347
+ JSDHashEntryHdr hdr;
2348
+ const void *thing;
2349
+ uint32 count;
2350
+ } JSGCLockHashEntry;
2351
+
2352
+ JSBool
2353
+ js_LockGCThingRT(JSRuntime *rt, void *thing)
2354
+ {
2355
+ JSBool shallow, ok;
2356
+ uint8 *flagp;
2357
+ JSGCLockHashEntry *lhe;
2358
+
2359
+ if (!thing)
2360
+ return JS_TRUE;
2361
+
2362
+ flagp = GetGCThingFlagsOrNull(thing);
2363
+ JS_LOCK_GC(rt);
2364
+ shallow = GC_THING_IS_SHALLOW(flagp, thing);
2365
+
2366
+ /*
2367
+ * Avoid adding a rt->gcLocksHash entry for shallow things until someone
2368
+ * nests a lock.
2369
+ */
2370
+ if (shallow && !(*flagp & GCF_LOCK)) {
2371
+ *flagp |= GCF_LOCK;
2372
+ METER(rt->gcStats.lock++);
2373
+ ok = JS_TRUE;
2374
+ goto out;
2375
+ }
2376
+
2377
+ if (!rt->gcLocksHash) {
2378
+ rt->gcLocksHash = JS_NewDHashTable(JS_DHashGetStubOps(), NULL,
2379
+ sizeof(JSGCLockHashEntry),
2380
+ GC_ROOTS_SIZE);
2381
+ if (!rt->gcLocksHash) {
2382
+ ok = JS_FALSE;
2383
+ goto out;
2384
+ }
2385
+ }
2386
+
2387
+ lhe = (JSGCLockHashEntry *)
2388
+ JS_DHashTableOperate(rt->gcLocksHash, thing, JS_DHASH_ADD);
2389
+ if (!lhe) {
2390
+ ok = JS_FALSE;
2391
+ goto out;
2392
+ }
2393
+ if (!lhe->thing) {
2394
+ lhe->thing = thing;
2395
+ lhe->count = 1;
2396
+ } else {
2397
+ JS_ASSERT(lhe->count >= 1);
2398
+ lhe->count++;
2399
+ }
2400
+
2401
+ METER(rt->gcStats.lock++);
2402
+ ok = JS_TRUE;
2403
+ out:
2404
+ JS_UNLOCK_GC(rt);
2405
+ return ok;
2406
+ }
2407
+
2408
+ JSBool
2409
+ js_UnlockGCThingRT(JSRuntime *rt, void *thing)
2410
+ {
2411
+ uint8 *flagp;
2412
+ JSBool shallow;
2413
+ JSGCLockHashEntry *lhe;
2414
+
2415
+ if (!thing)
2416
+ return JS_TRUE;
2417
+
2418
+ flagp = GetGCThingFlagsOrNull(thing);
2419
+ JS_LOCK_GC(rt);
2420
+ shallow = GC_THING_IS_SHALLOW(flagp, thing);
2421
+
2422
+ if (shallow && !(*flagp & GCF_LOCK))
2423
+ goto out;
2424
+ if (!rt->gcLocksHash ||
2425
+ (lhe = (JSGCLockHashEntry *)
2426
+ JS_DHashTableOperate(rt->gcLocksHash, thing,
2427
+ JS_DHASH_LOOKUP),
2428
+ JS_DHASH_ENTRY_IS_FREE(&lhe->hdr))) {
2429
+ /* Shallow entry is not in the hash -> clear its lock bit. */
2430
+ if (shallow)
2431
+ *flagp &= ~GCF_LOCK;
2432
+ else
2433
+ goto out;
2434
+ } else {
2435
+ if (--lhe->count != 0)
2436
+ goto out;
2437
+ JS_DHashTableOperate(rt->gcLocksHash, thing, JS_DHASH_REMOVE);
2438
+ }
2439
+
2440
+ rt->gcPoke = JS_TRUE;
2441
+ METER(rt->gcStats.unlock++);
2442
+ out:
2443
+ JS_UNLOCK_GC(rt);
2444
+ return JS_TRUE;
2445
+ }
2446
+
2447
+ JS_PUBLIC_API(void)
2448
+ JS_TraceChildren(JSTracer *trc, void *thing, uint32 kind)
2449
+ {
2450
+ JSObject *obj;
2451
+ size_t nslots, i;
2452
+ jsval v;
2453
+ JSString *str;
2454
+
2455
+ switch (kind) {
2456
+ case JSTRACE_OBJECT:
2457
+ /* If obj has no map, it must be a newborn. */
2458
+ obj = (JSObject *) thing;
2459
+ if (!obj->map)
2460
+ break;
2461
+ if (obj->map->ops->trace) {
2462
+ obj->map->ops->trace(trc, obj);
2463
+ } else {
2464
+ nslots = STOBJ_NSLOTS(obj);
2465
+ for (i = 0; i != nslots; ++i) {
2466
+ v = STOBJ_GET_SLOT(obj, i);
2467
+ if (JSVAL_IS_TRACEABLE(v)) {
2468
+ JS_SET_TRACING_INDEX(trc, "slot", i);
2469
+ JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v),
2470
+ JSVAL_TRACE_KIND(v));
2471
+ }
2472
+ }
2473
+ }
2474
+ break;
2475
+
2476
+ case JSTRACE_STRING:
2477
+ str = (JSString *)thing;
2478
+ if (JSSTRING_IS_DEPENDENT(str))
2479
+ JS_CALL_STRING_TRACER(trc, JSSTRDEP_BASE(str), "base");
2480
+ break;
2481
+
2482
+ #if JS_HAS_XML_SUPPORT
2483
+ case JSTRACE_XML:
2484
+ js_TraceXML(trc, (JSXML *)thing);
2485
+ break;
2486
+ #endif
2487
+ }
2488
+ }
2489
+
2490
+ /*
2491
+ * Number of things covered by a single bit of JSGCArenaInfo.u.untracedThings.
2492
+ */
2493
+ #define THINGS_PER_UNTRACED_BIT(thingSize) \
2494
+ JS_HOWMANY(THINGS_PER_ARENA(thingSize), JS_BITS_PER_WORD)
2495
+
2496
+ static void
2497
+ DelayTracingChildren(JSRuntime *rt, uint8 *flagp)
2498
+ {
2499
+ JSGCArenaInfo *a;
2500
+ uint32 untracedBitIndex;
2501
+ jsuword bit;
2502
+
2503
+ /*
2504
+ * Things with children to be traced later are marked with
2505
+ * GCF_MARK | GCF_FINAL flags.
2506
+ */
2507
+ JS_ASSERT((*flagp & (GCF_MARK | GCF_FINAL)) == GCF_MARK);
2508
+ *flagp |= GCF_FINAL;
2509
+
2510
+ METER(rt->gcStats.untraced++);
2511
+ #ifdef DEBUG
2512
+ ++rt->gcTraceLaterCount;
2513
+ METER_UPDATE_MAX(rt->gcStats.maxuntraced, rt->gcTraceLaterCount);
2514
+ #endif
2515
+
2516
+ a = FLAGP_TO_ARENA(flagp);
2517
+ untracedBitIndex = FLAGP_TO_INDEX(flagp) /
2518
+ THINGS_PER_UNTRACED_BIT(a->list->thingSize);
2519
+ JS_ASSERT(untracedBitIndex < JS_BITS_PER_WORD);
2520
+ bit = (jsuword)1 << untracedBitIndex;
2521
+ if (a->u.untracedThings != 0) {
2522
+ JS_ASSERT(rt->gcUntracedArenaStackTop);
2523
+ if (a->u.untracedThings & bit) {
2524
+ /* bit already covers things with children to trace later. */
2525
+ return;
2526
+ }
2527
+ a->u.untracedThings |= bit;
2528
+ } else {
2529
+ /*
2530
+ * The thing is the first thing with not yet traced children in the
2531
+ * whole arena, so push the arena on the stack of arenas with things
2532
+ * to be traced later unless the arena has already been pushed. We
2533
+ * detect that through checking prevUntracedPage as the field is 0
2534
+ * only for not yet pushed arenas. To ensure that
2535
+ * prevUntracedPage != 0
2536
+ * even when the stack contains one element, we make prevUntracedPage
2537
+ * for the arena at the bottom to point to itself.
2538
+ *
2539
+ * See comments in TraceDelayedChildren.
2540
+ */
2541
+ a->u.untracedThings = bit;
2542
+ if (a->prevUntracedPage == 0) {
2543
+ if (!rt->gcUntracedArenaStackTop) {
2544
+ /* Stack was empty, mark the arena as the bottom element. */
2545
+ a->prevUntracedPage = ARENA_INFO_TO_PAGE(a);
2546
+ } else {
2547
+ JS_ASSERT(rt->gcUntracedArenaStackTop->prevUntracedPage != 0);
2548
+ a->prevUntracedPage =
2549
+ ARENA_INFO_TO_PAGE(rt->gcUntracedArenaStackTop);
2550
+ }
2551
+ rt->gcUntracedArenaStackTop = a;
2552
+ }
2553
+ }
2554
+ JS_ASSERT(rt->gcUntracedArenaStackTop);
2555
+ }
2556
+
2557
+ static void
2558
+ TraceDelayedChildren(JSTracer *trc)
2559
+ {
2560
+ JSRuntime *rt;
2561
+ JSGCArenaInfo *a, *aprev;
2562
+ uint32 thingSize;
2563
+ uint32 thingsPerUntracedBit;
2564
+ uint32 untracedBitIndex, thingIndex, indexLimit, endIndex;
2565
+ JSGCThing *thing;
2566
+ uint8 *flagp;
2567
+
2568
+ rt = trc->context->runtime;
2569
+ a = rt->gcUntracedArenaStackTop;
2570
+ if (!a) {
2571
+ JS_ASSERT(rt->gcTraceLaterCount == 0);
2572
+ return;
2573
+ }
2574
+
2575
+ for (;;) {
2576
+ /*
2577
+ * The following assert verifies that the current arena belongs to the
2578
+ * untraced stack, since DelayTracingChildren ensures that even for
2579
+ * stack's bottom prevUntracedPage != 0 but rather points to itself.
2580
+ */
2581
+ JS_ASSERT(a->prevUntracedPage != 0);
2582
+ JS_ASSERT(rt->gcUntracedArenaStackTop->prevUntracedPage != 0);
2583
+ thingSize = a->list->thingSize;
2584
+ indexLimit = (a == a->list->last)
2585
+ ? a->list->lastCount
2586
+ : THINGS_PER_ARENA(thingSize);
2587
+ thingsPerUntracedBit = THINGS_PER_UNTRACED_BIT(thingSize);
2588
+
2589
+ /*
2590
+ * We cannot use do-while loop here as a->u.untracedThings can be zero
2591
+ * before the loop as a leftover from the previous iterations. See
2592
+ * comments after the loop.
2593
+ */
2594
+ while (a->u.untracedThings != 0) {
2595
+ untracedBitIndex = JS_FLOOR_LOG2W(a->u.untracedThings);
2596
+ a->u.untracedThings &= ~((jsuword)1 << untracedBitIndex);
2597
+ thingIndex = untracedBitIndex * thingsPerUntracedBit;
2598
+ endIndex = thingIndex + thingsPerUntracedBit;
2599
+
2600
+ /*
2601
+ * endIndex can go beyond the last allocated thing as the real
2602
+ * limit can be "inside" the bit.
2603
+ */
2604
+ if (endIndex > indexLimit)
2605
+ endIndex = indexLimit;
2606
+ JS_ASSERT(thingIndex < indexLimit);
2607
+
2608
+ do {
2609
+ /*
2610
+ * Skip free or already traced things that share the bit
2611
+ * with untraced ones.
2612
+ */
2613
+ flagp = THING_FLAGP(a, thingIndex);
2614
+ if ((*flagp & (GCF_MARK|GCF_FINAL)) != (GCF_MARK|GCF_FINAL))
2615
+ continue;
2616
+ *flagp &= ~GCF_FINAL;
2617
+ #ifdef DEBUG
2618
+ JS_ASSERT(rt->gcTraceLaterCount != 0);
2619
+ --rt->gcTraceLaterCount;
2620
+ #endif
2621
+ thing = FLAGP_TO_THING(flagp, thingSize);
2622
+ JS_TraceChildren(trc, thing, MapGCFlagsToTraceKind(*flagp));
2623
+ } while (++thingIndex != endIndex);
2624
+ }
2625
+
2626
+ /*
2627
+ * We finished tracing of all things in the the arena but we can only
2628
+ * pop it from the stack if the arena is the stack's top.
2629
+ *
2630
+ * When JS_TraceChildren from the above calls JS_CallTracer that in
2631
+ * turn on low C stack calls DelayTracingChildren and the latter
2632
+ * pushes new arenas to the untraced stack, we have to skip popping
2633
+ * of this arena until it becomes the top of the stack again.
2634
+ */
2635
+ if (a == rt->gcUntracedArenaStackTop) {
2636
+ aprev = ARENA_PAGE_TO_INFO(a->prevUntracedPage);
2637
+ a->prevUntracedPage = 0;
2638
+ if (a == aprev) {
2639
+ /*
2640
+ * prevUntracedPage points to itself and we reached the
2641
+ * bottom of the stack.
2642
+ */
2643
+ break;
2644
+ }
2645
+ rt->gcUntracedArenaStackTop = a = aprev;
2646
+ } else {
2647
+ a = rt->gcUntracedArenaStackTop;
2648
+ }
2649
+ }
2650
+ JS_ASSERT(rt->gcUntracedArenaStackTop);
2651
+ JS_ASSERT(rt->gcUntracedArenaStackTop->prevUntracedPage == 0);
2652
+ rt->gcUntracedArenaStackTop = NULL;
2653
+ JS_ASSERT(rt->gcTraceLaterCount == 0);
2654
+ }
2655
+
2656
+ JS_PUBLIC_API(void)
2657
+ JS_CallTracer(JSTracer *trc, void *thing, uint32 kind)
2658
+ {
2659
+ JSContext *cx;
2660
+ JSRuntime *rt;
2661
+ JSGCArenaInfo *a;
2662
+ uintN index;
2663
+ uint8 *flagp;
2664
+
2665
+ JS_ASSERT(thing);
2666
+ JS_ASSERT(JS_IS_VALID_TRACE_KIND(kind));
2667
+ JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
2668
+
2669
+ if (!IS_GC_MARKING_TRACER(trc)) {
2670
+ trc->callback(trc, thing, kind);
2671
+ goto out;
2672
+ }
2673
+
2674
+ cx = trc->context;
2675
+ rt = cx->runtime;
2676
+ JS_ASSERT(rt->gcMarkingTracer == trc);
2677
+ JS_ASSERT(rt->gcLevel > 0);
2678
+
2679
+ /*
2680
+ * Optimize for string and double as their size is known and their tracing
2681
+ * is not recursive.
2682
+ */
2683
+ switch (kind) {
2684
+ case JSTRACE_DOUBLE:
2685
+ a = THING_TO_ARENA(thing);
2686
+ JS_ASSERT(!a->list);
2687
+ if (!a->u.hasMarkedDoubles) {
2688
+ ClearDoubleArenaFlags(a);
2689
+ a->u.hasMarkedDoubles = JS_TRUE;
2690
+ }
2691
+ index = DOUBLE_THING_TO_INDEX(thing);
2692
+ JS_SET_BIT(DOUBLE_ARENA_BITMAP(a), index);
2693
+ goto out;
2694
+
2695
+ case JSTRACE_STRING:
2696
+ for (;;) {
2697
+ flagp = THING_TO_FLAGP(thing, sizeof(JSGCThing));
2698
+ JS_ASSERT((*flagp & GCF_FINAL) == 0);
2699
+ JS_ASSERT(kind == MapGCFlagsToTraceKind(*flagp));
2700
+ if (!JSSTRING_IS_DEPENDENT((JSString *) thing)) {
2701
+ *flagp |= GCF_MARK;
2702
+ goto out;
2703
+ }
2704
+ if (*flagp & GCF_MARK)
2705
+ goto out;
2706
+ *flagp |= GCF_MARK;
2707
+ thing = JSSTRDEP_BASE((JSString *) thing);
2708
+ }
2709
+ /* NOTREACHED */
2710
+ }
2711
+
2712
+ flagp = GetGCThingFlags(thing);
2713
+ JS_ASSERT(kind == MapGCFlagsToTraceKind(*flagp));
2714
+ if (*flagp & GCF_MARK)
2715
+ goto out;
2716
+
2717
+ /*
2718
+ * We check for non-final flag only if mark is unset as
2719
+ * DelayTracingChildren uses the flag. See comments in the function.
2720
+ */
2721
+ JS_ASSERT(*flagp != GCF_FINAL);
2722
+ *flagp |= GCF_MARK;
2723
+ if (!cx->insideGCMarkCallback) {
2724
+ /*
2725
+ * With JS_GC_ASSUME_LOW_C_STACK defined the mark phase of GC always
2726
+ * uses the non-recursive code that otherwise would be called only on
2727
+ * a low C stack condition.
2728
+ */
2729
+ #ifdef JS_GC_ASSUME_LOW_C_STACK
2730
+ # define RECURSION_TOO_DEEP() JS_TRUE
2731
+ #else
2732
+ int stackDummy;
2733
+ # define RECURSION_TOO_DEEP() (!JS_CHECK_STACK_SIZE(cx, stackDummy))
2734
+ #endif
2735
+ if (RECURSION_TOO_DEEP())
2736
+ DelayTracingChildren(rt, flagp);
2737
+ else
2738
+ JS_TraceChildren(trc, thing, kind);
2739
+ } else {
2740
+ /*
2741
+ * For API compatibility we allow for the callback to assume that
2742
+ * after it calls JS_MarkGCThing for the last time, the callback can
2743
+ * start to finalize its own objects that are only referenced by
2744
+ * unmarked GC things.
2745
+ *
2746
+ * Since we do not know which call from inside the callback is the
2747
+ * last, we ensure that children of all marked things are traced and
2748
+ * call TraceDelayedChildren(trc) after tracing the thing.
2749
+ *
2750
+ * As TraceDelayedChildren unconditionally invokes JS_TraceChildren
2751
+ * for the things with untraced children, calling DelayTracingChildren
2752
+ * is useless here. Hence we always trace thing's children even with a
2753
+ * low native stack.
2754
+ */
2755
+ cx->insideGCMarkCallback = JS_FALSE;
2756
+ JS_TraceChildren(trc, thing, kind);
2757
+ TraceDelayedChildren(trc);
2758
+ cx->insideGCMarkCallback = JS_TRUE;
2759
+ }
2760
+
2761
+ out:
2762
+ #ifdef DEBUG
2763
+ trc->debugPrinter = NULL;
2764
+ trc->debugPrintArg = NULL;
2765
+ #endif
2766
+ return; /* to avoid out: right_curl when DEBUG is not defined */
2767
+ }
2768
+
2769
+ void
2770
+ js_CallValueTracerIfGCThing(JSTracer *trc, jsval v)
2771
+ {
2772
+ void *thing;
2773
+ uint32 kind;
2774
+
2775
+ if (JSVAL_IS_DOUBLE(v) || JSVAL_IS_STRING(v)) {
2776
+ thing = JSVAL_TO_TRACEABLE(v);
2777
+ kind = JSVAL_TRACE_KIND(v);
2778
+ JS_ASSERT(kind == js_GetGCThingTraceKind(JSVAL_TO_GCTHING(v)));
2779
+ } else if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) {
2780
+ /* v can be an arbitrary GC thing reinterpreted as an object. */
2781
+ thing = JSVAL_TO_OBJECT(v);
2782
+ kind = js_GetGCThingTraceKind(thing);
2783
+ } else {
2784
+ return;
2785
+ }
2786
+ JS_CallTracer(trc, thing, kind);
2787
+ }
2788
+
2789
+ static JSDHashOperator
2790
+ gc_root_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num,
2791
+ void *arg)
2792
+ {
2793
+ JSGCRootHashEntry *rhe = (JSGCRootHashEntry *)hdr;
2794
+ JSTracer *trc = (JSTracer *)arg;
2795
+ jsval *rp = (jsval *)rhe->root;
2796
+ jsval v = *rp;
2797
+
2798
+ /* Ignore null object and scalar values. */
2799
+ if (!JSVAL_IS_NULL(v) && JSVAL_IS_GCTHING(v)) {
2800
+ #ifdef DEBUG
2801
+ JSBool root_points_to_gcArenaList = JS_FALSE;
2802
+ jsuword thing = (jsuword) JSVAL_TO_GCTHING(v);
2803
+ JSRuntime *rt;
2804
+ uintN i;
2805
+ JSGCArenaList *arenaList;
2806
+ uint32 thingSize;
2807
+ JSGCArenaInfo *a;
2808
+ size_t limit;
2809
+
2810
+ rt = trc->context->runtime;
2811
+ for (i = 0; i < GC_NUM_FREELISTS; i++) {
2812
+ arenaList = &rt->gcArenaList[i];
2813
+ thingSize = arenaList->thingSize;
2814
+ limit = (size_t) arenaList->lastCount * thingSize;
2815
+ for (a = arenaList->last; a; a = a->prev) {
2816
+ if (thing - ARENA_INFO_TO_START(a) < limit) {
2817
+ root_points_to_gcArenaList = JS_TRUE;
2818
+ break;
2819
+ }
2820
+ limit = (size_t) THINGS_PER_ARENA(thingSize) * thingSize;
2821
+ }
2822
+ }
2823
+ if (!root_points_to_gcArenaList) {
2824
+ for (a = rt->gcDoubleArenaList.first; a; a = a->prev) {
2825
+ if (thing - ARENA_INFO_TO_START(a) <
2826
+ DOUBLES_PER_ARENA * sizeof(jsdouble)) {
2827
+ root_points_to_gcArenaList = JS_TRUE;
2828
+ break;
2829
+ }
2830
+ }
2831
+ }
2832
+ if (!root_points_to_gcArenaList && rhe->name) {
2833
+ fprintf(stderr,
2834
+ "JS API usage error: the address passed to JS_AddNamedRoot currently holds an\n"
2835
+ "invalid jsval. This is usually caused by a missing call to JS_RemoveRoot.\n"
2836
+ "The root's name is \"%s\".\n",
2837
+ rhe->name);
2838
+ }
2839
+ JS_ASSERT(root_points_to_gcArenaList);
2840
+ #endif
2841
+ JS_SET_TRACING_NAME(trc, rhe->name ? rhe->name : "root");
2842
+ js_CallValueTracerIfGCThing(trc, v);
2843
+ }
2844
+
2845
+ return JS_DHASH_NEXT;
2846
+ }
2847
+
2848
+ static JSDHashOperator
2849
+ gc_lock_traversal(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 num,
2850
+ void *arg)
2851
+ {
2852
+ JSGCLockHashEntry *lhe = (JSGCLockHashEntry *)hdr;
2853
+ void *thing = (void *)lhe->thing;
2854
+ JSTracer *trc = (JSTracer *)arg;
2855
+ uint32 traceKind;
2856
+
2857
+ JS_ASSERT(lhe->count >= 1);
2858
+ traceKind = js_GetGCThingTraceKind(thing);
2859
+ JS_CALL_TRACER(trc, thing, traceKind, "locked object");
2860
+ return JS_DHASH_NEXT;
2861
+ }
2862
+
2863
+ #define TRACE_JSVALS(trc, len, vec, name) \
2864
+ JS_BEGIN_MACRO \
2865
+ jsval _v, *_vp, *_end; \
2866
+ \
2867
+ for (_vp = vec, _end = _vp + len; _vp < _end; _vp++) { \
2868
+ _v = *_vp; \
2869
+ if (JSVAL_IS_TRACEABLE(_v)) { \
2870
+ JS_SET_TRACING_INDEX(trc, name, _vp - (vec)); \
2871
+ JS_CallTracer(trc, JSVAL_TO_TRACEABLE(_v), \
2872
+ JSVAL_TRACE_KIND(_v)); \
2873
+ } \
2874
+ } \
2875
+ JS_END_MACRO
2876
+
2877
+ void
2878
+ js_TraceStackFrame(JSTracer *trc, JSStackFrame *fp)
2879
+ {
2880
+ uintN nslots, minargs, skip;
2881
+
2882
+ if (fp->callobj)
2883
+ JS_CALL_OBJECT_TRACER(trc, fp->callobj, "call");
2884
+ if (fp->argsobj)
2885
+ JS_CALL_OBJECT_TRACER(trc, fp->argsobj, "arguments");
2886
+ if (fp->varobj)
2887
+ JS_CALL_OBJECT_TRACER(trc, fp->varobj, "variables");
2888
+ if (fp->script) {
2889
+ js_TraceScript(trc, fp->script);
2890
+
2891
+ /* fp->slots is null for watch pseudo-frames, see js_watch_set. */
2892
+ if (fp->slots) {
2893
+ /*
2894
+ * Don't mark what has not been pushed yet, or what has been
2895
+ * popped already.
2896
+ */
2897
+ if (fp->regs) {
2898
+ nslots = (uintN) (fp->regs->sp - fp->slots);
2899
+ JS_ASSERT(nslots >= fp->script->nfixed);
2900
+ } else {
2901
+ nslots = fp->script->nfixed;
2902
+ }
2903
+ TRACE_JSVALS(trc, nslots, fp->slots, "slot");
2904
+ }
2905
+ } else {
2906
+ JS_ASSERT(!fp->slots);
2907
+ JS_ASSERT(!fp->regs);
2908
+ }
2909
+
2910
+ /* Allow for primitive this parameter due to JSFUN_THISP_* flags. */
2911
+ JS_ASSERT(JSVAL_IS_OBJECT((jsval)fp->thisp) ||
2912
+ (fp->fun && JSFUN_THISP_FLAGS(fp->fun->flags)));
2913
+ JS_CALL_VALUE_TRACER(trc, (jsval)fp->thisp, "this");
2914
+
2915
+ if (fp->callee)
2916
+ JS_CALL_OBJECT_TRACER(trc, fp->callee, "callee");
2917
+
2918
+ if (fp->argv) {
2919
+ nslots = fp->argc;
2920
+ skip = 0;
2921
+ if (fp->fun) {
2922
+ minargs = FUN_MINARGS(fp->fun);
2923
+ if (minargs > nslots)
2924
+ nslots = minargs;
2925
+ if (!FUN_INTERPRETED(fp->fun)) {
2926
+ JS_ASSERT(!(fp->fun->flags & JSFUN_FAST_NATIVE));
2927
+ nslots += fp->fun->u.n.extra;
2928
+ }
2929
+ if (fp->fun->flags & JSFRAME_ROOTED_ARGV)
2930
+ skip = 2 + fp->argc;
2931
+ }
2932
+ TRACE_JSVALS(trc, 2 + nslots - skip, fp->argv - 2 + skip, "operand");
2933
+ }
2934
+
2935
+ JS_CALL_VALUE_TRACER(trc, fp->rval, "rval");
2936
+ if (fp->scopeChain)
2937
+ JS_CALL_OBJECT_TRACER(trc, fp->scopeChain, "scope chain");
2938
+ if (fp->sharpArray)
2939
+ JS_CALL_OBJECT_TRACER(trc, fp->sharpArray, "sharp array");
2940
+
2941
+ if (fp->xmlNamespace)
2942
+ JS_CALL_OBJECT_TRACER(trc, fp->xmlNamespace, "xmlNamespace");
2943
+ }
2944
+
2945
+ static void
2946
+ TraceWeakRoots(JSTracer *trc, JSWeakRoots *wr)
2947
+ {
2948
+ uint32 i;
2949
+ void *thing;
2950
+
2951
+ #ifdef DEBUG
2952
+ static const char *weakRootNames[JSTRACE_LIMIT] = {
2953
+ "newborn object",
2954
+ "newborn double",
2955
+ "newborn string",
2956
+ "newborn xml"
2957
+ };
2958
+ #endif
2959
+
2960
+ for (i = 0; i != JSTRACE_LIMIT; i++) {
2961
+ thing = wr->newborn[i];
2962
+ if (thing)
2963
+ JS_CALL_TRACER(trc, thing, i, weakRootNames[i]);
2964
+ }
2965
+ JS_ASSERT(i == GCX_EXTERNAL_STRING);
2966
+ for (; i != GCX_NTYPES; ++i) {
2967
+ thing = wr->newborn[i];
2968
+ if (thing) {
2969
+ JS_SET_TRACING_INDEX(trc, "newborn external string",
2970
+ i - GCX_EXTERNAL_STRING);
2971
+ JS_CallTracer(trc, thing, JSTRACE_STRING);
2972
+ }
2973
+ }
2974
+
2975
+ JS_CALL_VALUE_TRACER(trc, wr->lastAtom, "lastAtom");
2976
+ JS_SET_TRACING_NAME(trc, "lastInternalResult");
2977
+ js_CallValueTracerIfGCThing(trc, wr->lastInternalResult);
2978
+ }
2979
+
2980
+ JS_REQUIRES_STACK JS_FRIEND_API(void)
2981
+ js_TraceContext(JSTracer *trc, JSContext *acx)
2982
+ {
2983
+ JSStackFrame *fp, *nextChain;
2984
+ JSStackHeader *sh;
2985
+ JSTempValueRooter *tvr;
2986
+
2987
+ if (IS_GC_MARKING_TRACER(trc)) {
2988
+
2989
+ #define FREE_OLD_ARENAS(pool) \
2990
+ JS_BEGIN_MACRO \
2991
+ int64 _age; \
2992
+ JSArena * _a = (pool).current; \
2993
+ if (_a == (pool).first.next && \
2994
+ _a->avail == _a->base + sizeof(int64)) { \
2995
+ _age = JS_Now() - *(int64 *) _a->base; \
2996
+ if (_age > (int64) acx->runtime->gcEmptyArenaPoolLifespan * \
2997
+ 1000) \
2998
+ JS_FreeArenaPool(&(pool)); \
2999
+ } \
3000
+ JS_END_MACRO
3001
+
3002
+ #ifdef JS_THREADSAFE
3003
+ js_RevokeGCLocalFreeLists(acx);
3004
+ #endif
3005
+
3006
+ /*
3007
+ * Release the stackPool's arenas if the stackPool has existed for
3008
+ * longer than the limit specified by gcEmptyArenaPoolLifespan.
3009
+ */
3010
+ FREE_OLD_ARENAS(acx->stackPool);
3011
+
3012
+ /*
3013
+ * Release the regexpPool's arenas based on the same criterion as for
3014
+ * the stackPool.
3015
+ */
3016
+ FREE_OLD_ARENAS(acx->regexpPool);
3017
+
3018
+ /*
3019
+ * Clear the double free list to release all the pre-allocated doubles.
3020
+ */
3021
+ acx->doubleFreeList = NULL;
3022
+ }
3023
+
3024
+ /*
3025
+ * Iterate frame chain and dormant chains.
3026
+ *
3027
+ * (NB: see comment on this whole "dormant" thing in js_Execute.)
3028
+ *
3029
+ * Since js_GetTopStackFrame needs to dereference cx->thread to check for
3030
+ * JIT frames, we check for non-null thread here and avoid null checks
3031
+ * there. See bug 471197.
3032
+ */
3033
+ #ifdef JS_THREADSAFE
3034
+ if (acx->thread)
3035
+ #endif
3036
+ {
3037
+ fp = js_GetTopStackFrame(acx);
3038
+ nextChain = acx->dormantFrameChain;
3039
+ if (!fp)
3040
+ goto next_chain;
3041
+
3042
+ /* The top frame must not be dormant. */
3043
+ JS_ASSERT(!fp->dormantNext);
3044
+ for (;;) {
3045
+ do {
3046
+ js_TraceStackFrame(trc, fp);
3047
+ } while ((fp = fp->down) != NULL);
3048
+
3049
+ next_chain:
3050
+ if (!nextChain)
3051
+ break;
3052
+ fp = nextChain;
3053
+ nextChain = nextChain->dormantNext;
3054
+ }
3055
+ }
3056
+
3057
+ /* Mark other roots-by-definition in acx. */
3058
+ if (acx->globalObject && !JS_HAS_OPTION(acx, JSOPTION_UNROOTED_GLOBAL))
3059
+ JS_CALL_OBJECT_TRACER(trc, acx->globalObject, "global object");
3060
+ TraceWeakRoots(trc, &acx->weakRoots);
3061
+ if (acx->throwing) {
3062
+ JS_CALL_VALUE_TRACER(trc, acx->exception, "exception");
3063
+ } else {
3064
+ /* Avoid keeping GC-ed junk stored in JSContext.exception. */
3065
+ acx->exception = JSVAL_NULL;
3066
+ }
3067
+ #if JS_HAS_LVALUE_RETURN
3068
+ if (acx->rval2set)
3069
+ JS_CALL_VALUE_TRACER(trc, acx->rval2, "rval2");
3070
+ #endif
3071
+
3072
+ for (sh = acx->stackHeaders; sh; sh = sh->down) {
3073
+ METER(trc->context->runtime->gcStats.stackseg++);
3074
+ METER(trc->context->runtime->gcStats.segslots += sh->nslots);
3075
+ TRACE_JSVALS(trc, sh->nslots, JS_STACK_SEGMENT(sh), "stack");
3076
+ }
3077
+
3078
+ if (acx->localRootStack)
3079
+ js_TraceLocalRoots(trc, acx->localRootStack);
3080
+
3081
+ for (tvr = acx->tempValueRooters; tvr; tvr = tvr->down) {
3082
+ switch (tvr->count) {
3083
+ case JSTVU_SINGLE:
3084
+ JS_SET_TRACING_NAME(trc, "tvr->u.value");
3085
+ js_CallValueTracerIfGCThing(trc, tvr->u.value);
3086
+ break;
3087
+ case JSTVU_TRACE:
3088
+ tvr->u.trace(trc, tvr);
3089
+ break;
3090
+ case JSTVU_SPROP:
3091
+ TRACE_SCOPE_PROPERTY(trc, tvr->u.sprop);
3092
+ break;
3093
+ case JSTVU_WEAK_ROOTS:
3094
+ TraceWeakRoots(trc, tvr->u.weakRoots);
3095
+ break;
3096
+ case JSTVU_COMPILER:
3097
+ tvr->u.compiler->trace(trc);
3098
+ break;
3099
+ case JSTVU_SCRIPT:
3100
+ js_TraceScript(trc, tvr->u.script);
3101
+ break;
3102
+ default:
3103
+ JS_ASSERT(tvr->count >= 0);
3104
+ TRACE_JSVALS(trc, tvr->count, tvr->u.array, "tvr->u.array");
3105
+ }
3106
+ }
3107
+
3108
+ if (acx->sharpObjectMap.depth > 0)
3109
+ js_TraceSharpMap(trc, &acx->sharpObjectMap);
3110
+
3111
+ js_TraceRegExpStatics(trc, acx);
3112
+
3113
+ #ifdef JS_TRACER
3114
+ if (acx->nativeVp)
3115
+ TRACE_JSVALS(trc, acx->nativeVpLen, acx->nativeVp, "nativeVp");
3116
+ #endif
3117
+ }
3118
+
3119
+ #ifdef JS_TRACER
3120
+
3121
+ static void
3122
+ MarkReservedObjects(JSTraceMonitor *tm)
3123
+ {
3124
+ /* Keep the reserved objects. */
3125
+ for (JSObject *obj = tm->reservedObjects; obj; obj = JSVAL_TO_OBJECT(obj->fslots[0])) {
3126
+ uint8 *flagp = GetGCThingFlags(obj);
3127
+ JS_ASSERT((*flagp & GCF_TYPEMASK) == GCX_OBJECT);
3128
+ JS_ASSERT(*flagp != GCF_FINAL);
3129
+ *flagp |= GCF_MARK;
3130
+ }
3131
+ }
3132
+
3133
+ #ifdef JS_THREADSAFE
3134
+ static JSDHashOperator
3135
+ reserved_objects_marker(JSDHashTable *table, JSDHashEntryHdr *hdr,
3136
+ uint32, void *)
3137
+ {
3138
+ JSThread *thread = ((JSThreadsHashEntry *) hdr)->thread;
3139
+
3140
+ MarkReservedObjects(&thread->data.traceMonitor);
3141
+ return JS_DHASH_NEXT;
3142
+ }
3143
+ #endif
3144
+
3145
+ #endif
3146
+
3147
+ JS_REQUIRES_STACK void
3148
+ js_TraceRuntime(JSTracer *trc, JSBool allAtoms)
3149
+ {
3150
+ JSRuntime *rt = trc->context->runtime;
3151
+ JSContext *iter, *acx;
3152
+
3153
+ JS_DHashTableEnumerate(&rt->gcRootsHash, gc_root_traversal, trc);
3154
+ if (rt->gcLocksHash)
3155
+ JS_DHashTableEnumerate(rt->gcLocksHash, gc_lock_traversal, trc);
3156
+ js_TraceAtomState(trc, allAtoms);
3157
+ js_TraceNativeEnumerators(trc);
3158
+ js_TraceRuntimeNumberState(trc);
3159
+
3160
+ iter = NULL;
3161
+ while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
3162
+ js_TraceContext(trc, acx);
3163
+
3164
+ if (rt->gcExtraRootsTraceOp)
3165
+ rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);
3166
+
3167
+ #ifdef JS_TRACER
3168
+ for (int i = 0; i < JSBUILTIN_LIMIT; i++) {
3169
+ if (rt->builtinFunctions[i])
3170
+ JS_CALL_OBJECT_TRACER(trc, rt->builtinFunctions[i], "builtin function");
3171
+ }
3172
+
3173
+ /* Mark the reserved objects unless we are shutting down. */
3174
+ if (IS_GC_MARKING_TRACER(trc) && rt->state != JSRTS_LANDING) {
3175
+ #ifdef JS_THREADSAFE
3176
+ JS_DHashTableEnumerate(&rt->threads, reserved_objects_marker, NULL);
3177
+ #else
3178
+ MarkReservedObjects(&rt->threadData.traceMonitor);
3179
+ #endif
3180
+ }
3181
+
3182
+ #endif
3183
+ }
3184
+
3185
+ void
3186
+ js_TriggerGC(JSContext *cx, JSBool gcLocked)
3187
+ {
3188
+ JSRuntime *rt = cx->runtime;
3189
+
3190
+ #ifdef JS_THREADSAFE
3191
+ JS_ASSERT(cx->requestDepth > 0);
3192
+ #endif
3193
+ JS_ASSERT(!rt->gcRunning);
3194
+ if (rt->gcIsNeeded)
3195
+ return;
3196
+
3197
+ /*
3198
+ * Trigger the GC when it is safe to call an operation callback on any
3199
+ * thread.
3200
+ */
3201
+ rt->gcIsNeeded = JS_TRUE;
3202
+ js_TriggerAllOperationCallbacks(rt, gcLocked);
3203
+ }
3204
+
3205
+ static void
3206
+ ProcessSetSlotRequest(JSContext *cx, JSSetSlotRequest *ssr)
3207
+ {
3208
+ JSObject *obj = ssr->obj;
3209
+ JSObject *pobj = ssr->pobj;
3210
+ uint32 slot = ssr->slot;
3211
+
3212
+ while (pobj) {
3213
+ pobj = js_GetWrappedObject(cx, pobj);
3214
+ if (pobj == obj) {
3215
+ ssr->cycle = true;
3216
+ return;
3217
+ }
3218
+ pobj = JSVAL_TO_OBJECT(STOBJ_GET_SLOT(pobj, slot));
3219
+ }
3220
+
3221
+ pobj = ssr->pobj;
3222
+ if (slot == JSSLOT_PROTO) {
3223
+ STOBJ_SET_PROTO(obj, pobj);
3224
+ } else {
3225
+ JS_ASSERT(slot == JSSLOT_PARENT);
3226
+ STOBJ_SET_PARENT(obj, pobj);
3227
+ }
3228
+ }
3229
+
3230
+ void
3231
+ js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data)
3232
+ {
3233
+ JSScript **listp, *script;
3234
+
3235
+ for (size_t i = 0; i != JS_ARRAY_LENGTH(data->scriptsToGC); ++i) {
3236
+ listp = &data->scriptsToGC[i];
3237
+ while ((script = *listp) != NULL) {
3238
+ *listp = script->u.nextToGC;
3239
+ script->u.nextToGC = NULL;
3240
+ js_DestroyScript(cx, script);
3241
+ }
3242
+ }
3243
+ }
3244
+
3245
+ /*
3246
+ * The gckind flag bit GC_LOCK_HELD indicates a call from js_NewGCThing with
3247
+ * rt->gcLock already held, so the lock should be kept on return.
3248
+ */
3249
+ void
3250
+ js_GC(JSContext *cx, JSGCInvocationKind gckind)
3251
+ {
3252
+ JSRuntime *rt;
3253
+ JSBool keepAtoms;
3254
+ JSGCCallback callback;
3255
+ uintN i, type;
3256
+ JSTracer trc;
3257
+ uint32 thingSize, indexLimit;
3258
+ JSGCArenaInfo *a, **ap, *emptyArenas;
3259
+ uint8 flags, *flagp;
3260
+ JSGCThing *thing, *freeList;
3261
+ JSGCArenaList *arenaList;
3262
+ JSBool allClear;
3263
+ #ifdef JS_THREADSAFE
3264
+ uint32 requestDebit;
3265
+ #endif
3266
+ #ifdef JS_GCMETER
3267
+ uint32 nlivearenas, nkilledarenas, nthings;
3268
+ #endif
3269
+
3270
+ JS_ASSERT_IF(gckind == GC_LAST_DITCH, !JS_ON_TRACE(cx));
3271
+ rt = cx->runtime;
3272
+
3273
+ #ifdef JS_THREADSAFE
3274
+ /*
3275
+ * We allow js_GC calls outside a request but the context must be bound
3276
+ * to the current thread.
3277
+ */
3278
+ JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
3279
+
3280
+ /* Avoid deadlock. */
3281
+ JS_ASSERT(!JS_IS_RUNTIME_LOCKED(rt));
3282
+ #endif
3283
+
3284
+ if (gckind & GC_KEEP_ATOMS) {
3285
+ /*
3286
+ * The set slot request and last ditch GC kinds preserve all atoms and
3287
+ * weak roots.
3288
+ */
3289
+ keepAtoms = JS_TRUE;
3290
+ } else {
3291
+ /* Keep atoms when a suspended compile is running on another context. */
3292
+ keepAtoms = (rt->gcKeepAtoms != 0);
3293
+ JS_CLEAR_WEAK_ROOTS(&cx->weakRoots);
3294
+ }
3295
+
3296
+ /*
3297
+ * Don't collect garbage if the runtime isn't up, and cx is not the last
3298
+ * context in the runtime. The last context must force a GC, and nothing
3299
+ * should suppress that final collection or there may be shutdown leaks,
3300
+ * or runtime bloat until the next context is created.
3301
+ */
3302
+ if (rt->state != JSRTS_UP && gckind != GC_LAST_CONTEXT)
3303
+ return;
3304
+
3305
+ restart_at_beginning:
3306
+ /*
3307
+ * Let the API user decide to defer a GC if it wants to (unless this
3308
+ * is the last context). Invoke the callback regardless. Sample the
3309
+ * callback in case we are freely racing with a JS_SetGCCallback{,RT} on
3310
+ * another thread.
3311
+ */
3312
+ if (gckind != GC_SET_SLOT_REQUEST && (callback = rt->gcCallback)) {
3313
+ JSBool ok;
3314
+
3315
+ if (gckind & GC_LOCK_HELD)
3316
+ JS_UNLOCK_GC(rt);
3317
+ ok = callback(cx, JSGC_BEGIN);
3318
+ if (gckind & GC_LOCK_HELD)
3319
+ JS_LOCK_GC(rt);
3320
+ if (!ok && gckind != GC_LAST_CONTEXT) {
3321
+ /*
3322
+ * It's possible that we've looped back to this code from the 'goto
3323
+ * restart_at_beginning' below in the GC_SET_SLOT_REQUEST code and
3324
+ * that rt->gcLevel is now 0. Don't return without notifying!
3325
+ */
3326
+ if (rt->gcLevel == 0 && (gckind & GC_LOCK_HELD))
3327
+ JS_NOTIFY_GC_DONE(rt);
3328
+ return;
3329
+ }
3330
+ }
3331
+
3332
+ /* Lock out other GC allocator and collector invocations. */
3333
+ if (!(gckind & GC_LOCK_HELD))
3334
+ JS_LOCK_GC(rt);
3335
+
3336
+ METER(rt->gcStats.poke++);
3337
+ rt->gcPoke = JS_FALSE;
3338
+
3339
+ #ifdef JS_THREADSAFE
3340
+ /*
3341
+ * Check if the GC is already running on this or another thread and
3342
+ * delegate the job to it.
3343
+ */
3344
+ if (rt->gcLevel > 0) {
3345
+ JS_ASSERT(rt->gcThread);
3346
+
3347
+ /* Bump gcLevel to restart the current GC, so it finds new garbage. */
3348
+ rt->gcLevel++;
3349
+ METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel);
3350
+
3351
+ /*
3352
+ * If the GC runs on another thread, temporarily suspend the current
3353
+ * request and wait until the GC is done.
3354
+ */
3355
+ if (rt->gcThread != cx->thread) {
3356
+ requestDebit = js_DiscountRequestsForGC(cx);
3357
+ js_RecountRequestsAfterGC(rt, requestDebit);
3358
+ }
3359
+ if (!(gckind & GC_LOCK_HELD))
3360
+ JS_UNLOCK_GC(rt);
3361
+ return;
3362
+ }
3363
+
3364
+ /* No other thread is in GC, so indicate that we're now in GC. */
3365
+ rt->gcLevel = 1;
3366
+ rt->gcThread = cx->thread;
3367
+
3368
+ /*
3369
+ * Notify all operation callbacks, which will give them a chance to
3370
+ * yield their current request. Contexts that are not currently
3371
+ * executing will perform their callback at some later point,
3372
+ * which then will be unnecessary, but harmless.
3373
+ */
3374
+ js_NudgeOtherContexts(cx);
3375
+
3376
+ /*
3377
+ * Discount all the requests on the current thread from contributing
3378
+ * to rt->requestCount before we wait for all other requests to finish.
3379
+ * JS_NOTIFY_REQUEST_DONE, which will wake us up, is only called on
3380
+ * rt->requestCount transitions to 0.
3381
+ */
3382
+ requestDebit = js_CountThreadRequests(cx);
3383
+ JS_ASSERT_IF(cx->requestDepth != 0, requestDebit >= 1);
3384
+ rt->requestCount -= requestDebit;
3385
+ while (rt->requestCount > 0)
3386
+ JS_AWAIT_REQUEST_DONE(rt);
3387
+ rt->requestCount += requestDebit;
3388
+
3389
+ #else /* !JS_THREADSAFE */
3390
+
3391
+ /* Bump gcLevel and return rather than nest; the outer gc will restart. */
3392
+ rt->gcLevel++;
3393
+ METER_UPDATE_MAX(rt->gcStats.maxlevel, rt->gcLevel);
3394
+ if (rt->gcLevel > 1)
3395
+ return;
3396
+
3397
+ #endif /* !JS_THREADSAFE */
3398
+
3399
+ /*
3400
+ * Set rt->gcRunning here within the GC lock, and after waiting for any
3401
+ * active requests to end, so that new requests that try to JS_AddRoot,
3402
+ * JS_RemoveRoot, or JS_RemoveRootRT block in JS_BeginRequest waiting for
3403
+ * rt->gcLevel to drop to zero, while request-less calls to the *Root*
3404
+ * APIs block in js_AddRoot or js_RemoveRoot (see above in this file),
3405
+ * waiting for GC to finish.
3406
+ */
3407
+ rt->gcRunning = JS_TRUE;
3408
+
3409
+ if (gckind == GC_SET_SLOT_REQUEST) {
3410
+ JSSetSlotRequest *ssr;
3411
+
3412
+ while ((ssr = rt->setSlotRequests) != NULL) {
3413
+ rt->setSlotRequests = ssr->next;
3414
+ JS_UNLOCK_GC(rt);
3415
+ ssr->next = NULL;
3416
+ ProcessSetSlotRequest(cx, ssr);
3417
+ JS_LOCK_GC(rt);
3418
+ }
3419
+
3420
+ /*
3421
+ * We assume here that killing links to parent and prototype objects
3422
+ * does not create garbage (such objects typically are long-lived and
3423
+ * widely shared, e.g. global objects, Function.prototype, etc.). We
3424
+ * collect garbage only if a racing thread attempted GC and is waiting
3425
+ * for us to finish (gcLevel > 1) or if someone already poked us.
3426
+ */
3427
+ if (rt->gcLevel == 1 && !rt->gcPoke && !rt->gcIsNeeded)
3428
+ goto done_running;
3429
+
3430
+ rt->gcLevel = 0;
3431
+ rt->gcPoke = JS_FALSE;
3432
+ rt->gcRunning = JS_FALSE;
3433
+ #ifdef JS_THREADSAFE
3434
+ rt->gcThread = NULL;
3435
+ #endif
3436
+ gckind = GC_LOCK_HELD;
3437
+ goto restart_at_beginning;
3438
+ }
3439
+
3440
+ JS_UNLOCK_GC(rt);
3441
+
3442
+ #ifdef JS_TRACER
3443
+ if (JS_ON_TRACE(cx))
3444
+ goto out;
3445
+ #endif
3446
+ VOUCH_HAVE_STACK();
3447
+
3448
+ /* Clear gcIsNeeded now, when we are about to start a normal GC cycle. */
3449
+ rt->gcIsNeeded = JS_FALSE;
3450
+
3451
+ /* Reset malloc counter. */
3452
+ rt->gcMallocBytes = 0;
3453
+
3454
+ #ifdef JS_DUMP_SCOPE_METERS
3455
+ { extern void js_DumpScopeMeters(JSRuntime *rt);
3456
+ js_DumpScopeMeters(rt);
3457
+ }
3458
+ #endif
3459
+
3460
+ #ifdef JS_TRACER
3461
+ js_PurgeJITOracle();
3462
+ #endif
3463
+ js_PurgeThreads(cx);
3464
+
3465
+ restart:
3466
+ rt->gcNumber++;
3467
+ JS_ASSERT(!rt->gcUntracedArenaStackTop);
3468
+ JS_ASSERT(rt->gcTraceLaterCount == 0);
3469
+
3470
+ /*
3471
+ * Reset the property cache's type id generator so we can compress ids.
3472
+ * Same for the protoHazardShape proxy-shape standing in for all object
3473
+ * prototypes having readonly or setter properties.
3474
+ */
3475
+ rt->shapeGen = 0;
3476
+ rt->protoHazardShape = 0;
3477
+
3478
+ /*
3479
+ * Mark phase.
3480
+ */
3481
+ JS_TRACER_INIT(&trc, cx, NULL);
3482
+ rt->gcMarkingTracer = &trc;
3483
+ JS_ASSERT(IS_GC_MARKING_TRACER(&trc));
3484
+
3485
+ for (a = rt->gcDoubleArenaList.first; a; a = a->prev)
3486
+ a->u.hasMarkedDoubles = JS_FALSE;
3487
+
3488
+ js_TraceRuntime(&trc, keepAtoms);
3489
+ js_MarkScriptFilenames(rt, keepAtoms);
3490
+
3491
+ /*
3492
+ * Mark children of things that caused too deep recursion during the above
3493
+ * tracing.
3494
+ */
3495
+ TraceDelayedChildren(&trc);
3496
+
3497
+ JS_ASSERT(!cx->insideGCMarkCallback);
3498
+ if (rt->gcCallback) {
3499
+ cx->insideGCMarkCallback = JS_TRUE;
3500
+ (void) rt->gcCallback(cx, JSGC_MARK_END);
3501
+ JS_ASSERT(cx->insideGCMarkCallback);
3502
+ cx->insideGCMarkCallback = JS_FALSE;
3503
+ }
3504
+ JS_ASSERT(rt->gcTraceLaterCount == 0);
3505
+
3506
+ rt->gcMarkingTracer = NULL;
3507
+
3508
+ /*
3509
+ * Sweep phase.
3510
+ *
3511
+ * Finalize as we sweep, outside of rt->gcLock but with rt->gcRunning set
3512
+ * so that any attempt to allocate a GC-thing from a finalizer will fail,
3513
+ * rather than nest badly and leave the unmarked newborn to be swept.
3514
+ *
3515
+ * We first sweep atom state so we can use js_IsAboutToBeFinalized on
3516
+ * JSString or jsdouble held in a hashtable to check if the hashtable
3517
+ * entry can be freed. Note that even after the entry is freed, JSObject
3518
+ * finalizers can continue to access the corresponding jsdouble* and
3519
+ * JSString* assuming that they are unique. This works since the
3520
+ * atomization API must not be called during GC.
3521
+ */
3522
+ js_SweepAtomState(cx);
3523
+
3524
+ /* Finalize iterator states before the objects they iterate over. */
3525
+ CloseNativeIterators(cx);
3526
+
3527
+ /* Finalize watch points associated with unreachable objects. */
3528
+ js_SweepWatchPoints(cx);
3529
+
3530
+ #ifdef DEBUG
3531
+ /* Save the pre-sweep count of scope-mapped properties. */
3532
+ rt->liveScopePropsPreSweep = rt->liveScopeProps;
3533
+ #endif
3534
+
3535
+ /*
3536
+ * Here we need to ensure that JSObject instances are finalized before GC-
3537
+ * allocated JSString and jsdouble instances so object's finalizer can
3538
+ * access them even if they will be freed. For that we simply finalize the
3539
+ * list containing JSObject first since the static assert at the beginning
3540
+ * of the file guarantees that JSString and jsdouble instances are
3541
+ * allocated from a different list.
3542
+ */
3543
+ emptyArenas = NULL;
3544
+ for (i = 0; i < GC_NUM_FREELISTS; i++) {
3545
+ arenaList = &rt->gcArenaList[i == 0
3546
+ ? GC_FREELIST_INDEX(sizeof(JSObject))
3547
+ : i == GC_FREELIST_INDEX(sizeof(JSObject))
3548
+ ? 0
3549
+ : i];
3550
+ ap = &arenaList->last;
3551
+ if (!(a = *ap))
3552
+ continue;
3553
+
3554
+ JS_ASSERT(arenaList->lastCount > 0);
3555
+ arenaList->freeList = NULL;
3556
+ freeList = NULL;
3557
+ thingSize = arenaList->thingSize;
3558
+ indexLimit = THINGS_PER_ARENA(thingSize);
3559
+ flagp = THING_FLAGP(a, arenaList->lastCount - 1);
3560
+ METER((nlivearenas = 0, nkilledarenas = 0, nthings = 0));
3561
+ for (;;) {
3562
+ JS_ASSERT(a->prevUntracedPage == 0);
3563
+ JS_ASSERT(a->u.untracedThings == 0);
3564
+ allClear = JS_TRUE;
3565
+ do {
3566
+ flags = *flagp;
3567
+ if (flags & (GCF_MARK | GCF_LOCK)) {
3568
+ *flagp &= ~GCF_MARK;
3569
+ allClear = JS_FALSE;
3570
+ METER(nthings++);
3571
+ } else {
3572
+ thing = FLAGP_TO_THING(flagp, thingSize);
3573
+ if (!(flags & GCF_FINAL)) {
3574
+ /*
3575
+ * Call the finalizer with GCF_FINAL ORed into flags.
3576
+ */
3577
+ *flagp = (uint8)(flags | GCF_FINAL);
3578
+ type = flags & GCF_TYPEMASK;
3579
+ switch (type) {
3580
+ case GCX_OBJECT:
3581
+ js_FinalizeObject(cx, (JSObject *) thing);
3582
+ break;
3583
+ case GCX_DOUBLE:
3584
+ /* Do nothing. */
3585
+ break;
3586
+ #if JS_HAS_XML_SUPPORT
3587
+ case GCX_XML:
3588
+ js_FinalizeXML(cx, (JSXML *) thing);
3589
+ break;
3590
+ #endif
3591
+ default:
3592
+ JS_ASSERT(type == GCX_STRING ||
3593
+ type - GCX_EXTERNAL_STRING <
3594
+ GCX_NTYPES - GCX_EXTERNAL_STRING);
3595
+ js_FinalizeStringRT(rt, (JSString *) thing,
3596
+ (intN) (type -
3597
+ GCX_EXTERNAL_STRING),
3598
+ cx);
3599
+ break;
3600
+ }
3601
+ #ifdef DEBUG
3602
+ memset(thing, JS_FREE_PATTERN, thingSize);
3603
+ #endif
3604
+ }
3605
+ thing->flagp = flagp;
3606
+ thing->next = freeList;
3607
+ freeList = thing;
3608
+ }
3609
+ } while (++flagp != THING_FLAGS_END(a));
3610
+
3611
+ if (allClear) {
3612
+ /*
3613
+ * Forget just assembled free list head for the arena and
3614
+ * add the arena itself to the destroy list.
3615
+ */
3616
+ freeList = arenaList->freeList;
3617
+ if (a == arenaList->last)
3618
+ arenaList->lastCount = (uint16) indexLimit;
3619
+ *ap = a->prev;
3620
+ a->prev = emptyArenas;
3621
+ emptyArenas = a;
3622
+ METER(nkilledarenas++);
3623
+ } else {
3624
+ arenaList->freeList = freeList;
3625
+ ap = &a->prev;
3626
+ METER(nlivearenas++);
3627
+ }
3628
+ if (!(a = *ap))
3629
+ break;
3630
+ flagp = THING_FLAGP(a, indexLimit - 1);
3631
+ }
3632
+
3633
+ /*
3634
+ * We use arenaList - &rt->gcArenaList[0], not i, as the stat index
3635
+ * due to the enumeration reorder at the beginning of the loop.
3636
+ */
3637
+ METER(UpdateArenaStats(&rt->gcStats.arenaStats[arenaList -
3638
+ &rt->gcArenaList[0]],
3639
+ nlivearenas, nkilledarenas, nthings));
3640
+ }
3641
+
3642
+ #ifdef JS_THREADSAFE
3643
+ /*
3644
+ * Release all but two free list sets to avoid allocating a new set in
3645
+ * js_NewGCThing.
3646
+ */
3647
+ TrimGCFreeListsPool(rt, 2);
3648
+ #endif
3649
+
3650
+ ap = &rt->gcDoubleArenaList.first;
3651
+ METER((nlivearenas = 0, nkilledarenas = 0, nthings = 0));
3652
+ while ((a = *ap) != NULL) {
3653
+ if (!a->u.hasMarkedDoubles) {
3654
+ /* No marked double values in the arena. */
3655
+ *ap = a->prev;
3656
+ a->prev = emptyArenas;
3657
+ emptyArenas = a;
3658
+ METER(nkilledarenas++);
3659
+ } else {
3660
+ ap = &a->prev;
3661
+ #ifdef JS_GCMETER
3662
+ for (i = 0; i != DOUBLES_PER_ARENA; ++i) {
3663
+ if (IsMarkedDouble(a, index))
3664
+ METER(nthings++);
3665
+ }
3666
+ METER(nlivearenas++);
3667
+ #endif
3668
+ }
3669
+ }
3670
+ METER(UpdateArenaStats(&rt->gcStats.doubleArenaStats,
3671
+ nlivearenas, nkilledarenas, nthings));
3672
+ rt->gcDoubleArenaList.nextDoubleFlags =
3673
+ rt->gcDoubleArenaList.first
3674
+ ? DOUBLE_ARENA_BITMAP(rt->gcDoubleArenaList.first)
3675
+ : DOUBLE_BITMAP_SENTINEL;
3676
+
3677
+ /*
3678
+ * Sweep the runtime's property tree after finalizing objects, in case any
3679
+ * had watchpoints referencing tree nodes.
3680
+ */
3681
+ js_SweepScopeProperties(cx);
3682
+
3683
+ /*
3684
+ * Sweep script filenames after sweeping functions in the generic loop
3685
+ * above. In this way when a scripted function's finalizer destroys the
3686
+ * script and calls rt->destroyScriptHook, the hook can still access the
3687
+ * script's filename. See bug 323267.
3688
+ */
3689
+ js_SweepScriptFilenames(rt);
3690
+
3691
+ /*
3692
+ * Destroy arenas after we finished the sweeping sofinalizers can safely
3693
+ * use js_IsAboutToBeFinalized().
3694
+ */
3695
+ DestroyGCArenas(rt, emptyArenas);
3696
+
3697
+ if (rt->gcCallback)
3698
+ (void) rt->gcCallback(cx, JSGC_FINALIZE_END);
3699
+ #ifdef DEBUG_srcnotesize
3700
+ { extern void DumpSrcNoteSizeHist();
3701
+ DumpSrcNoteSizeHist();
3702
+ printf("GC HEAP SIZE %lu\n", (unsigned long)rt->gcBytes);
3703
+ }
3704
+ #endif
3705
+
3706
+ #ifdef JS_SCOPE_DEPTH_METER
3707
+ { static FILE *fp;
3708
+ if (!fp)
3709
+ fp = fopen("/tmp/scopedepth.stats", "w");
3710
+
3711
+ if (fp) {
3712
+ JS_DumpBasicStats(&rt->protoLookupDepthStats, "proto-lookup depth", fp);
3713
+ JS_DumpBasicStats(&rt->scopeSearchDepthStats, "scope-search depth", fp);
3714
+ JS_DumpBasicStats(&rt->hostenvScopeDepthStats, "hostenv scope depth", fp);
3715
+ JS_DumpBasicStats(&rt->lexicalScopeDepthStats, "lexical scope depth", fp);
3716
+
3717
+ putc('\n', fp);
3718
+ fflush(fp);
3719
+ }
3720
+ }
3721
+ #endif /* JS_SCOPE_DEPTH_METER */
3722
+
3723
+ #ifdef JS_DUMP_LOOP_STATS
3724
+ { static FILE *lsfp;
3725
+ if (!lsfp)
3726
+ lsfp = fopen("/tmp/loopstats", "w");
3727
+ if (lsfp) {
3728
+ JS_DumpBasicStats(&rt->loopStats, "loops", lsfp);
3729
+ fflush(lsfp);
3730
+ }
3731
+ }
3732
+ #endif /* JS_DUMP_LOOP_STATS */
3733
+
3734
+ #ifdef JS_TRACER
3735
+ out:
3736
+ #endif
3737
+ JS_LOCK_GC(rt);
3738
+
3739
+ /*
3740
+ * We want to restart GC if js_GC was called recursively or if any of the
3741
+ * finalizers called js_RemoveRoot or js_UnlockGCThingRT.
3742
+ */
3743
+ if (!JS_ON_TRACE(cx) && (rt->gcLevel > 1 || rt->gcPoke)) {
3744
+ VOUCH_HAVE_STACK();
3745
+ rt->gcLevel = 1;
3746
+ rt->gcPoke = JS_FALSE;
3747
+ JS_UNLOCK_GC(rt);
3748
+ goto restart;
3749
+ }
3750
+
3751
+ rt->gcLastBytes = rt->gcBytes;
3752
+ done_running:
3753
+ rt->gcLevel = 0;
3754
+ rt->gcRunning = JS_FALSE;
3755
+
3756
+ #ifdef JS_THREADSAFE
3757
+ rt->gcThread = NULL;
3758
+ JS_NOTIFY_GC_DONE(rt);
3759
+
3760
+ /*
3761
+ * Unlock unless we have GC_LOCK_HELD which requires locked GC on return.
3762
+ */
3763
+ if (!(gckind & GC_LOCK_HELD))
3764
+ JS_UNLOCK_GC(rt);
3765
+ #endif
3766
+
3767
+ /*
3768
+ * Execute JSGC_END callback outside the lock. Again, sample the callback
3769
+ * pointer in case it changes, since we are outside of the GC vs. requests
3770
+ * interlock mechanism here.
3771
+ */
3772
+ if (gckind != GC_SET_SLOT_REQUEST && (callback = rt->gcCallback)) {
3773
+ JSWeakRoots savedWeakRoots;
3774
+ JSTempValueRooter tvr;
3775
+
3776
+ if (gckind & GC_KEEP_ATOMS) {
3777
+ /*
3778
+ * We allow JSGC_END implementation to force a full GC or allocate
3779
+ * new GC things. Thus we must protect the weak roots from garbage
3780
+ * collection and overwrites.
3781
+ */
3782
+ savedWeakRoots = cx->weakRoots;
3783
+ JS_PUSH_TEMP_ROOT_WEAK_COPY(cx, &savedWeakRoots, &tvr);
3784
+ JS_KEEP_ATOMS(rt);
3785
+ JS_UNLOCK_GC(rt);
3786
+ }
3787
+
3788
+ (void) callback(cx, JSGC_END);
3789
+
3790
+ if (gckind & GC_KEEP_ATOMS) {
3791
+ JS_LOCK_GC(rt);
3792
+ JS_UNKEEP_ATOMS(rt);
3793
+ JS_POP_TEMP_ROOT(cx, &tvr);
3794
+ } else if (gckind == GC_LAST_CONTEXT && rt->gcPoke) {
3795
+ /*
3796
+ * On shutdown iterate until JSGC_END callback stops creating
3797
+ * garbage.
3798
+ */
3799
+ goto restart_at_beginning;
3800
+ }
3801
+ }
3802
+ }
3803
+
3804
+ void
3805
+ js_UpdateMallocCounter(JSContext *cx, size_t nbytes)
3806
+ {
3807
+ uint32 *pbytes, bytes;
3808
+
3809
+ #ifdef JS_THREADSAFE
3810
+ pbytes = &cx->thread->gcMallocBytes;
3811
+ #else
3812
+ pbytes = &cx->runtime->gcMallocBytes;
3813
+ #endif
3814
+ bytes = *pbytes;
3815
+ *pbytes = ((uint32)-1 - bytes <= nbytes) ? (uint32)-1 : bytes + nbytes;
3816
+ }