johnson 2.0.0.pre1 → 2.0.0.pre2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. data/CHANGELOG.rdoc +12 -0
  2. data/Manifest.txt +4 -285
  3. data/Rakefile +13 -20
  4. data/ext/tracemonkey/global.cc +4 -1
  5. data/ext/tracemonkey/js.cc +30 -33
  6. data/ext/tracemonkey/runtime.cc +96 -6
  7. data/ext/tracemonkey/split_global.cc +0 -5
  8. data/ext/tracemonkey/tracemonkey.h +2 -2
  9. data/lib/johnson.rb +2 -2
  10. data/lib/johnson/runtime.rb +25 -15
  11. data/lib/johnson/tracemonkey/runtime.rb +6 -3
  12. data/vendor/tracemonkey/config/system-headers +1 -3
  13. data/vendor/tracemonkey/jscntxt.h +5 -2
  14. data/vendor/tracemonkey/jsdbgapi.cpp +9 -1
  15. data/vendor/tracemonkey/jsdbgapi.h +4 -0
  16. data/vendor/tracemonkey/tests/ecma/NativeObjects/browser.js +0 -0
  17. data/vendor/tracemonkey/tests/ecma/NativeObjects/jstests.list +0 -0
  18. data/vendor/tracemonkey/tests/ecma_3_1/Object/jstests.list +1 -1
  19. data/vendor/tracemonkey/tests/js1_3/misc/browser.js +0 -0
  20. data/vendor/tracemonkey/tests/js1_3/misc/jstests.list +0 -0
  21. data/vendor/tracemonkey/tests/js1_5/Regress/jstests.list +4 -4
  22. data/vendor/tracemonkey/tests/js1_5/Scope/jstests.list +1 -1
  23. data/vendor/tracemonkey/tests/js1_5/decompilation/jstests.list +2 -2
  24. data/vendor/tracemonkey/tests/js1_7/decompilation/jstests.list +1 -1
  25. data/vendor/tracemonkey/tests/shell.js +2 -1
  26. metadata +51 -309
  27. data/ext/spidermonkey/context.c +0 -116
  28. data/ext/spidermonkey/context.h +0 -19
  29. data/ext/spidermonkey/conversions.c +0 -361
  30. data/ext/spidermonkey/conversions.h +0 -31
  31. data/ext/spidermonkey/debugger.c +0 -234
  32. data/ext/spidermonkey/debugger.h +0 -10
  33. data/ext/spidermonkey/extconf.rb +0 -32
  34. data/ext/spidermonkey/extensions.c +0 -37
  35. data/ext/spidermonkey/extensions.h +0 -12
  36. data/ext/spidermonkey/global.c +0 -40
  37. data/ext/spidermonkey/global.h +0 -11
  38. data/ext/spidermonkey/idhash.c +0 -16
  39. data/ext/spidermonkey/idhash.h +0 -8
  40. data/ext/spidermonkey/immutable_node.c +0 -1153
  41. data/ext/spidermonkey/immutable_node.c.erb +0 -523
  42. data/ext/spidermonkey/immutable_node.h +0 -22
  43. data/ext/spidermonkey/jroot.h +0 -197
  44. data/ext/spidermonkey/js_land_proxy.c +0 -620
  45. data/ext/spidermonkey/js_land_proxy.h +0 -20
  46. data/ext/spidermonkey/ruby_land_proxy.c +0 -618
  47. data/ext/spidermonkey/ruby_land_proxy.h +0 -38
  48. data/ext/spidermonkey/runtime.c +0 -396
  49. data/ext/spidermonkey/runtime.h +0 -27
  50. data/ext/spidermonkey/spidermonkey.c +0 -22
  51. data/ext/spidermonkey/spidermonkey.h +0 -29
  52. data/lib/johnson/spidermonkey.rb +0 -12
  53. data/lib/johnson/spidermonkey/context.rb +0 -10
  54. data/lib/johnson/spidermonkey/debugger.rb +0 -67
  55. data/lib/johnson/spidermonkey/immutable_node.rb +0 -282
  56. data/lib/johnson/spidermonkey/js_land_proxy.rb +0 -64
  57. data/lib/johnson/spidermonkey/mutable_tree_visitor.rb +0 -242
  58. data/lib/johnson/spidermonkey/ruby_land_proxy.rb +0 -17
  59. data/lib/johnson/spidermonkey/runtime.rb +0 -74
  60. data/test/johnson/spidermonkey/context_test.rb +0 -21
  61. data/test/johnson/spidermonkey/immutable_node_test.rb +0 -34
  62. data/test/johnson/spidermonkey/js_land_proxy_test.rb +0 -273
  63. data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +0 -274
  64. data/test/johnson/spidermonkey/runtime_test.rb +0 -41
  65. data/vendor/spidermonkey/.cvsignore +0 -9
  66. data/vendor/spidermonkey/Makefile.in +0 -449
  67. data/vendor/spidermonkey/Makefile.ref +0 -365
  68. data/vendor/spidermonkey/README.html +0 -820
  69. data/vendor/spidermonkey/SpiderMonkey.rsp +0 -12
  70. data/vendor/spidermonkey/Y.js +0 -19
  71. data/vendor/spidermonkey/build.mk +0 -43
  72. data/vendor/spidermonkey/config.mk +0 -192
  73. data/vendor/spidermonkey/config/AIX4.1.mk +0 -65
  74. data/vendor/spidermonkey/config/AIX4.2.mk +0 -64
  75. data/vendor/spidermonkey/config/AIX4.3.mk +0 -65
  76. data/vendor/spidermonkey/config/Darwin.mk +0 -83
  77. data/vendor/spidermonkey/config/Darwin1.3.mk +0 -81
  78. data/vendor/spidermonkey/config/Darwin1.4.mk +0 -41
  79. data/vendor/spidermonkey/config/Darwin5.2.mk +0 -81
  80. data/vendor/spidermonkey/config/Darwin5.3.mk +0 -81
  81. data/vendor/spidermonkey/config/HP-UXB.10.10.mk +0 -77
  82. data/vendor/spidermonkey/config/HP-UXB.10.20.mk +0 -77
  83. data/vendor/spidermonkey/config/HP-UXB.11.00.mk +0 -80
  84. data/vendor/spidermonkey/config/IRIX.mk +0 -87
  85. data/vendor/spidermonkey/config/IRIX5.3.mk +0 -44
  86. data/vendor/spidermonkey/config/IRIX6.1.mk +0 -44
  87. data/vendor/spidermonkey/config/IRIX6.2.mk +0 -44
  88. data/vendor/spidermonkey/config/IRIX6.3.mk +0 -44
  89. data/vendor/spidermonkey/config/IRIX6.5.mk +0 -44
  90. data/vendor/spidermonkey/config/Linux_All.mk +0 -103
  91. data/vendor/spidermonkey/config/Mac_OS10.0.mk +0 -82
  92. data/vendor/spidermonkey/config/OSF1V4.0.mk +0 -72
  93. data/vendor/spidermonkey/config/OSF1V5.0.mk +0 -69
  94. data/vendor/spidermonkey/config/SunOS4.1.4.mk +0 -101
  95. data/vendor/spidermonkey/config/SunOS5.10.mk +0 -50
  96. data/vendor/spidermonkey/config/SunOS5.3.mk +0 -91
  97. data/vendor/spidermonkey/config/SunOS5.4.mk +0 -92
  98. data/vendor/spidermonkey/config/SunOS5.5.1.mk +0 -44
  99. data/vendor/spidermonkey/config/SunOS5.5.mk +0 -87
  100. data/vendor/spidermonkey/config/SunOS5.6.mk +0 -89
  101. data/vendor/spidermonkey/config/SunOS5.7.mk +0 -44
  102. data/vendor/spidermonkey/config/SunOS5.8.mk +0 -44
  103. data/vendor/spidermonkey/config/SunOS5.9.mk +0 -44
  104. data/vendor/spidermonkey/config/WINNT4.0.mk +0 -117
  105. data/vendor/spidermonkey/config/WINNT5.0.mk +0 -117
  106. data/vendor/spidermonkey/config/WINNT5.1.mk +0 -117
  107. data/vendor/spidermonkey/config/WINNT5.2.mk +0 -117
  108. data/vendor/spidermonkey/config/WINNT6.0.mk +0 -117
  109. data/vendor/spidermonkey/config/dgux.mk +0 -64
  110. data/vendor/spidermonkey/editline/Makefile.ref +0 -144
  111. data/vendor/spidermonkey/editline/README +0 -83
  112. data/vendor/spidermonkey/editline/editline.3 +0 -175
  113. data/vendor/spidermonkey/editline/editline.c +0 -1369
  114. data/vendor/spidermonkey/editline/editline.h +0 -135
  115. data/vendor/spidermonkey/editline/sysunix.c +0 -182
  116. data/vendor/spidermonkey/editline/unix.h +0 -82
  117. data/vendor/spidermonkey/fdlibm/.cvsignore +0 -7
  118. data/vendor/spidermonkey/fdlibm/Makefile.in +0 -127
  119. data/vendor/spidermonkey/fdlibm/Makefile.ref +0 -192
  120. data/vendor/spidermonkey/fdlibm/e_acos.c +0 -147
  121. data/vendor/spidermonkey/fdlibm/e_acosh.c +0 -105
  122. data/vendor/spidermonkey/fdlibm/e_asin.c +0 -156
  123. data/vendor/spidermonkey/fdlibm/e_atan2.c +0 -165
  124. data/vendor/spidermonkey/fdlibm/e_atanh.c +0 -110
  125. data/vendor/spidermonkey/fdlibm/e_cosh.c +0 -133
  126. data/vendor/spidermonkey/fdlibm/e_exp.c +0 -202
  127. data/vendor/spidermonkey/fdlibm/e_fmod.c +0 -184
  128. data/vendor/spidermonkey/fdlibm/e_gamma.c +0 -71
  129. data/vendor/spidermonkey/fdlibm/e_gamma_r.c +0 -70
  130. data/vendor/spidermonkey/fdlibm/e_hypot.c +0 -173
  131. data/vendor/spidermonkey/fdlibm/e_j0.c +0 -524
  132. data/vendor/spidermonkey/fdlibm/e_j1.c +0 -523
  133. data/vendor/spidermonkey/fdlibm/e_jn.c +0 -315
  134. data/vendor/spidermonkey/fdlibm/e_lgamma.c +0 -71
  135. data/vendor/spidermonkey/fdlibm/e_lgamma_r.c +0 -347
  136. data/vendor/spidermonkey/fdlibm/e_log.c +0 -184
  137. data/vendor/spidermonkey/fdlibm/e_log10.c +0 -134
  138. data/vendor/spidermonkey/fdlibm/e_pow.c +0 -386
  139. data/vendor/spidermonkey/fdlibm/e_rem_pio2.c +0 -222
  140. data/vendor/spidermonkey/fdlibm/e_remainder.c +0 -120
  141. data/vendor/spidermonkey/fdlibm/e_scalb.c +0 -89
  142. data/vendor/spidermonkey/fdlibm/e_sinh.c +0 -122
  143. data/vendor/spidermonkey/fdlibm/e_sqrt.c +0 -497
  144. data/vendor/spidermonkey/fdlibm/fdlibm.h +0 -273
  145. data/vendor/spidermonkey/fdlibm/fdlibm.mak +0 -1453
  146. data/vendor/spidermonkey/fdlibm/fdlibm.mdp +0 -0
  147. data/vendor/spidermonkey/fdlibm/k_cos.c +0 -135
  148. data/vendor/spidermonkey/fdlibm/k_rem_pio2.c +0 -354
  149. data/vendor/spidermonkey/fdlibm/k_sin.c +0 -114
  150. data/vendor/spidermonkey/fdlibm/k_standard.c +0 -785
  151. data/vendor/spidermonkey/fdlibm/k_tan.c +0 -170
  152. data/vendor/spidermonkey/fdlibm/s_asinh.c +0 -101
  153. data/vendor/spidermonkey/fdlibm/s_atan.c +0 -175
  154. data/vendor/spidermonkey/fdlibm/s_cbrt.c +0 -133
  155. data/vendor/spidermonkey/fdlibm/s_ceil.c +0 -120
  156. data/vendor/spidermonkey/fdlibm/s_copysign.c +0 -72
  157. data/vendor/spidermonkey/fdlibm/s_cos.c +0 -118
  158. data/vendor/spidermonkey/fdlibm/s_erf.c +0 -356
  159. data/vendor/spidermonkey/fdlibm/s_expm1.c +0 -267
  160. data/vendor/spidermonkey/fdlibm/s_fabs.c +0 -70
  161. data/vendor/spidermonkey/fdlibm/s_finite.c +0 -71
  162. data/vendor/spidermonkey/fdlibm/s_floor.c +0 -121
  163. data/vendor/spidermonkey/fdlibm/s_frexp.c +0 -99
  164. data/vendor/spidermonkey/fdlibm/s_ilogb.c +0 -85
  165. data/vendor/spidermonkey/fdlibm/s_isnan.c +0 -74
  166. data/vendor/spidermonkey/fdlibm/s_ldexp.c +0 -66
  167. data/vendor/spidermonkey/fdlibm/s_lib_version.c +0 -73
  168. data/vendor/spidermonkey/fdlibm/s_log1p.c +0 -211
  169. data/vendor/spidermonkey/fdlibm/s_logb.c +0 -79
  170. data/vendor/spidermonkey/fdlibm/s_matherr.c +0 -64
  171. data/vendor/spidermonkey/fdlibm/s_modf.c +0 -132
  172. data/vendor/spidermonkey/fdlibm/s_nextafter.c +0 -124
  173. data/vendor/spidermonkey/fdlibm/s_rint.c +0 -131
  174. data/vendor/spidermonkey/fdlibm/s_scalbn.c +0 -107
  175. data/vendor/spidermonkey/fdlibm/s_signgam.c +0 -40
  176. data/vendor/spidermonkey/fdlibm/s_significand.c +0 -68
  177. data/vendor/spidermonkey/fdlibm/s_sin.c +0 -118
  178. data/vendor/spidermonkey/fdlibm/s_tan.c +0 -112
  179. data/vendor/spidermonkey/fdlibm/s_tanh.c +0 -122
  180. data/vendor/spidermonkey/fdlibm/w_acos.c +0 -78
  181. data/vendor/spidermonkey/fdlibm/w_acosh.c +0 -78
  182. data/vendor/spidermonkey/fdlibm/w_asin.c +0 -80
  183. data/vendor/spidermonkey/fdlibm/w_atan2.c +0 -79
  184. data/vendor/spidermonkey/fdlibm/w_atanh.c +0 -81
  185. data/vendor/spidermonkey/fdlibm/w_cosh.c +0 -77
  186. data/vendor/spidermonkey/fdlibm/w_exp.c +0 -88
  187. data/vendor/spidermonkey/fdlibm/w_fmod.c +0 -78
  188. data/vendor/spidermonkey/fdlibm/w_gamma.c +0 -85
  189. data/vendor/spidermonkey/fdlibm/w_gamma_r.c +0 -81
  190. data/vendor/spidermonkey/fdlibm/w_hypot.c +0 -78
  191. data/vendor/spidermonkey/fdlibm/w_j0.c +0 -105
  192. data/vendor/spidermonkey/fdlibm/w_j1.c +0 -106
  193. data/vendor/spidermonkey/fdlibm/w_jn.c +0 -128
  194. data/vendor/spidermonkey/fdlibm/w_lgamma.c +0 -85
  195. data/vendor/spidermonkey/fdlibm/w_lgamma_r.c +0 -81
  196. data/vendor/spidermonkey/fdlibm/w_log.c +0 -78
  197. data/vendor/spidermonkey/fdlibm/w_log10.c +0 -81
  198. data/vendor/spidermonkey/fdlibm/w_pow.c +0 -99
  199. data/vendor/spidermonkey/fdlibm/w_remainder.c +0 -77
  200. data/vendor/spidermonkey/fdlibm/w_scalb.c +0 -95
  201. data/vendor/spidermonkey/fdlibm/w_sinh.c +0 -77
  202. data/vendor/spidermonkey/fdlibm/w_sqrt.c +0 -77
  203. data/vendor/spidermonkey/javascript-trace.d +0 -73
  204. data/vendor/spidermonkey/js.c +0 -3951
  205. data/vendor/spidermonkey/js.mdp +0 -0
  206. data/vendor/spidermonkey/js.msg +0 -308
  207. data/vendor/spidermonkey/js.pkg +0 -2
  208. data/vendor/spidermonkey/js3240.rc +0 -79
  209. data/vendor/spidermonkey/jsOS240.def +0 -654
  210. data/vendor/spidermonkey/jsapi.c +0 -5836
  211. data/vendor/spidermonkey/jsapi.h +0 -2624
  212. data/vendor/spidermonkey/jsarena.c +0 -450
  213. data/vendor/spidermonkey/jsarena.h +0 -318
  214. data/vendor/spidermonkey/jsarray.c +0 -2996
  215. data/vendor/spidermonkey/jsarray.h +0 -127
  216. data/vendor/spidermonkey/jsatom.c +0 -1045
  217. data/vendor/spidermonkey/jsatom.h +0 -442
  218. data/vendor/spidermonkey/jsbit.h +0 -253
  219. data/vendor/spidermonkey/jsbool.c +0 -176
  220. data/vendor/spidermonkey/jsbool.h +0 -73
  221. data/vendor/spidermonkey/jsclist.h +0 -139
  222. data/vendor/spidermonkey/jscntxt.c +0 -1348
  223. data/vendor/spidermonkey/jscntxt.h +0 -1120
  224. data/vendor/spidermonkey/jscompat.h +0 -57
  225. data/vendor/spidermonkey/jsconfig.h +0 -248
  226. data/vendor/spidermonkey/jsconfig.mk +0 -181
  227. data/vendor/spidermonkey/jscpucfg.c +0 -396
  228. data/vendor/spidermonkey/jscpucfg.h +0 -212
  229. data/vendor/spidermonkey/jsdate.c +0 -2390
  230. data/vendor/spidermonkey/jsdate.h +0 -124
  231. data/vendor/spidermonkey/jsdbgapi.c +0 -1802
  232. data/vendor/spidermonkey/jsdbgapi.h +0 -464
  233. data/vendor/spidermonkey/jsdhash.c +0 -868
  234. data/vendor/spidermonkey/jsdhash.h +0 -592
  235. data/vendor/spidermonkey/jsdtoa.c +0 -3167
  236. data/vendor/spidermonkey/jsdtoa.h +0 -130
  237. data/vendor/spidermonkey/jsdtracef.c +0 -317
  238. data/vendor/spidermonkey/jsdtracef.h +0 -77
  239. data/vendor/spidermonkey/jsemit.c +0 -6909
  240. data/vendor/spidermonkey/jsemit.h +0 -741
  241. data/vendor/spidermonkey/jsexn.c +0 -1371
  242. data/vendor/spidermonkey/jsexn.h +0 -96
  243. data/vendor/spidermonkey/jsfile.c +0 -2736
  244. data/vendor/spidermonkey/jsfile.h +0 -56
  245. data/vendor/spidermonkey/jsfile.msg +0 -90
  246. data/vendor/spidermonkey/jsfun.c +0 -2634
  247. data/vendor/spidermonkey/jsfun.h +0 -254
  248. data/vendor/spidermonkey/jsgc.c +0 -3562
  249. data/vendor/spidermonkey/jsgc.h +0 -403
  250. data/vendor/spidermonkey/jshash.c +0 -476
  251. data/vendor/spidermonkey/jshash.h +0 -151
  252. data/vendor/spidermonkey/jsify.pl +0 -485
  253. data/vendor/spidermonkey/jsinterp.c +0 -7007
  254. data/vendor/spidermonkey/jsinterp.h +0 -525
  255. data/vendor/spidermonkey/jsinvoke.c +0 -43
  256. data/vendor/spidermonkey/jsiter.c +0 -1067
  257. data/vendor/spidermonkey/jsiter.h +0 -122
  258. data/vendor/spidermonkey/jskeyword.tbl +0 -124
  259. data/vendor/spidermonkey/jskwgen.c +0 -460
  260. data/vendor/spidermonkey/jslibmath.h +0 -266
  261. data/vendor/spidermonkey/jslock.c +0 -1309
  262. data/vendor/spidermonkey/jslock.h +0 -313
  263. data/vendor/spidermonkey/jslocko.asm +0 -60
  264. data/vendor/spidermonkey/jslog2.c +0 -94
  265. data/vendor/spidermonkey/jslong.c +0 -264
  266. data/vendor/spidermonkey/jslong.h +0 -412
  267. data/vendor/spidermonkey/jsmath.c +0 -567
  268. data/vendor/spidermonkey/jsmath.h +0 -57
  269. data/vendor/spidermonkey/jsnum.c +0 -1239
  270. data/vendor/spidermonkey/jsnum.h +0 -283
  271. data/vendor/spidermonkey/jsobj.c +0 -5282
  272. data/vendor/spidermonkey/jsobj.h +0 -709
  273. data/vendor/spidermonkey/jsopcode.c +0 -5245
  274. data/vendor/spidermonkey/jsopcode.h +0 -394
  275. data/vendor/spidermonkey/jsopcode.tbl +0 -523
  276. data/vendor/spidermonkey/jsotypes.h +0 -202
  277. data/vendor/spidermonkey/jsparse.c +0 -6704
  278. data/vendor/spidermonkey/jsparse.h +0 -511
  279. data/vendor/spidermonkey/jsprf.c +0 -1264
  280. data/vendor/spidermonkey/jsprf.h +0 -150
  281. data/vendor/spidermonkey/jsproto.tbl +0 -128
  282. data/vendor/spidermonkey/jsprvtd.h +0 -267
  283. data/vendor/spidermonkey/jspubtd.h +0 -744
  284. data/vendor/spidermonkey/jsregexp.c +0 -4364
  285. data/vendor/spidermonkey/jsregexp.h +0 -183
  286. data/vendor/spidermonkey/jsreops.tbl +0 -145
  287. data/vendor/spidermonkey/jsscan.c +0 -2012
  288. data/vendor/spidermonkey/jsscan.h +0 -387
  289. data/vendor/spidermonkey/jsscope.c +0 -1957
  290. data/vendor/spidermonkey/jsscope.h +0 -418
  291. data/vendor/spidermonkey/jsscript.c +0 -1832
  292. data/vendor/spidermonkey/jsscript.h +0 -287
  293. data/vendor/spidermonkey/jsshell.msg +0 -50
  294. data/vendor/spidermonkey/jsstddef.h +0 -83
  295. data/vendor/spidermonkey/jsstr.c +0 -5005
  296. data/vendor/spidermonkey/jsstr.h +0 -641
  297. data/vendor/spidermonkey/jstypes.h +0 -475
  298. data/vendor/spidermonkey/jsutil.c +0 -345
  299. data/vendor/spidermonkey/jsutil.h +0 -157
  300. data/vendor/spidermonkey/jsxdrapi.c +0 -800
  301. data/vendor/spidermonkey/jsxdrapi.h +0 -218
  302. data/vendor/spidermonkey/jsxml.c +0 -8476
  303. data/vendor/spidermonkey/jsxml.h +0 -349
  304. data/vendor/spidermonkey/lock_SunOS.s +0 -119
  305. data/vendor/spidermonkey/perfect.js +0 -39
  306. data/vendor/spidermonkey/plify_jsdhash.sed +0 -36
  307. data/vendor/spidermonkey/prmjtime.c +0 -846
  308. data/vendor/spidermonkey/prmjtime.h +0 -103
  309. data/vendor/spidermonkey/resource.h +0 -15
  310. data/vendor/spidermonkey/rules.mk +0 -197
  311. data/vendor/spidermonkey/win32.order +0 -384
@@ -1,387 +0,0 @@
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 jsscan_h___
41
- #define jsscan_h___
42
- /*
43
- * JS lexical scanner interface.
44
- */
45
- #include <stddef.h>
46
- #include <stdio.h>
47
- #include "jsconfig.h"
48
- #include "jsopcode.h"
49
- #include "jsprvtd.h"
50
- #include "jspubtd.h"
51
-
52
- JS_BEGIN_EXTERN_C
53
-
54
- #define JS_KEYWORD(keyword, type, op, version) \
55
- extern const char js_##keyword##_str[];
56
- #include "jskeyword.tbl"
57
- #undef JS_KEYWORD
58
-
59
- typedef enum JSTokenType {
60
- TOK_ERROR = -1, /* well-known as the only code < EOF */
61
- TOK_EOF = 0, /* end of file */
62
- TOK_EOL = 1, /* end of line */
63
- TOK_SEMI = 2, /* semicolon */
64
- TOK_COMMA = 3, /* comma operator */
65
- TOK_ASSIGN = 4, /* assignment ops (= += -= etc.) */
66
- TOK_HOOK = 5, TOK_COLON = 6, /* conditional (?:) */
67
- TOK_OR = 7, /* logical or (||) */
68
- TOK_AND = 8, /* logical and (&&) */
69
- TOK_BITOR = 9, /* bitwise-or (|) */
70
- TOK_BITXOR = 10, /* bitwise-xor (^) */
71
- TOK_BITAND = 11, /* bitwise-and (&) */
72
- TOK_EQOP = 12, /* equality ops (== !=) */
73
- TOK_RELOP = 13, /* relational ops (< <= > >=) */
74
- TOK_SHOP = 14, /* shift ops (<< >> >>>) */
75
- TOK_PLUS = 15, /* plus */
76
- TOK_MINUS = 16, /* minus */
77
- TOK_STAR = 17, TOK_DIVOP = 18, /* multiply/divide ops (* / %) */
78
- TOK_UNARYOP = 19, /* unary prefix operator */
79
- TOK_INC = 20, TOK_DEC = 21, /* increment/decrement (++ --) */
80
- TOK_DOT = 22, /* member operator (.) */
81
- TOK_LB = 23, TOK_RB = 24, /* left and right brackets */
82
- TOK_LC = 25, TOK_RC = 26, /* left and right curlies (braces) */
83
- TOK_LP = 27, TOK_RP = 28, /* left and right parentheses */
84
- TOK_NAME = 29, /* identifier */
85
- TOK_NUMBER = 30, /* numeric constant */
86
- TOK_STRING = 31, /* string constant */
87
- TOK_REGEXP = 32, /* RegExp constant */
88
- TOK_PRIMARY = 33, /* true, false, null, this, super */
89
- TOK_FUNCTION = 34, /* function keyword */
90
- TOK_EXPORT = 35, /* export keyword */
91
- TOK_IMPORT = 36, /* import keyword */
92
- TOK_IF = 37, /* if keyword */
93
- TOK_ELSE = 38, /* else keyword */
94
- TOK_SWITCH = 39, /* switch keyword */
95
- TOK_CASE = 40, /* case keyword */
96
- TOK_DEFAULT = 41, /* default keyword */
97
- TOK_WHILE = 42, /* while keyword */
98
- TOK_DO = 43, /* do keyword */
99
- TOK_FOR = 44, /* for keyword */
100
- TOK_BREAK = 45, /* break keyword */
101
- TOK_CONTINUE = 46, /* continue keyword */
102
- TOK_IN = 47, /* in keyword */
103
- TOK_VAR = 48, /* var keyword */
104
- TOK_WITH = 49, /* with keyword */
105
- TOK_RETURN = 50, /* return keyword */
106
- TOK_NEW = 51, /* new keyword */
107
- TOK_DELETE = 52, /* delete keyword */
108
- TOK_DEFSHARP = 53, /* #n= for object/array initializers */
109
- TOK_USESHARP = 54, /* #n# for object/array initializers */
110
- TOK_TRY = 55, /* try keyword */
111
- TOK_CATCH = 56, /* catch keyword */
112
- TOK_FINALLY = 57, /* finally keyword */
113
- TOK_THROW = 58, /* throw keyword */
114
- TOK_INSTANCEOF = 59, /* instanceof keyword */
115
- TOK_DEBUGGER = 60, /* debugger keyword */
116
- TOK_XMLSTAGO = 61, /* XML start tag open (<) */
117
- TOK_XMLETAGO = 62, /* XML end tag open (</) */
118
- TOK_XMLPTAGC = 63, /* XML point tag close (/>) */
119
- TOK_XMLTAGC = 64, /* XML start or end tag close (>) */
120
- TOK_XMLNAME = 65, /* XML start-tag non-final fragment */
121
- TOK_XMLATTR = 66, /* XML quoted attribute value */
122
- TOK_XMLSPACE = 67, /* XML whitespace */
123
- TOK_XMLTEXT = 68, /* XML text */
124
- TOK_XMLCOMMENT = 69, /* XML comment */
125
- TOK_XMLCDATA = 70, /* XML CDATA section */
126
- TOK_XMLPI = 71, /* XML processing instruction */
127
- TOK_AT = 72, /* XML attribute op (@) */
128
- TOK_DBLCOLON = 73, /* namespace qualified name op (::) */
129
- TOK_ANYNAME = 74, /* XML AnyName singleton (*) */
130
- TOK_DBLDOT = 75, /* XML descendant op (..) */
131
- TOK_FILTER = 76, /* XML filtering predicate op (.()) */
132
- TOK_XMLELEM = 77, /* XML element node type (no token) */
133
- TOK_XMLLIST = 78, /* XML list node type (no token) */
134
- TOK_YIELD = 79, /* yield from generator function */
135
- TOK_ARRAYCOMP = 80, /* array comprehension initialiser */
136
- TOK_ARRAYPUSH = 81, /* array push within comprehension */
137
- TOK_LEXICALSCOPE = 82, /* block scope AST node label */
138
- TOK_LET = 83, /* let keyword */
139
- TOK_BODY = 84, /* synthetic body of function with
140
- destructuring formal parameters */
141
- TOK_RESERVED, /* reserved keywords */
142
- TOK_LIMIT /* domain size */
143
- } JSTokenType;
144
-
145
- #define IS_PRIMARY_TOKEN(tt) \
146
- ((uintN)((tt) - TOK_NAME) <= (uintN)(TOK_PRIMARY - TOK_NAME))
147
-
148
- #define TOKEN_TYPE_IS_XML(tt) \
149
- (tt == TOK_AT || tt == TOK_DBLCOLON || tt == TOK_ANYNAME)
150
-
151
- #if JS_HAS_BLOCK_SCOPE
152
- # define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR || (tt) == TOK_LET)
153
- #else
154
- # define TOKEN_TYPE_IS_DECL(tt) ((tt) == TOK_VAR)
155
- #endif
156
-
157
- struct JSStringBuffer {
158
- jschar *base;
159
- jschar *limit; /* length limit for quick bounds check */
160
- jschar *ptr; /* slot for next non-NUL char to store */
161
- void *data;
162
- JSBool (*grow)(JSStringBuffer *sb, size_t newlength);
163
- void (*free)(JSStringBuffer *sb);
164
- };
165
-
166
- #define STRING_BUFFER_ERROR_BASE ((jschar *) 1)
167
- #define STRING_BUFFER_OK(sb) ((sb)->base != STRING_BUFFER_ERROR_BASE)
168
- #define STRING_BUFFER_OFFSET(sb) ((sb)->ptr -(sb)->base)
169
-
170
- extern void
171
- js_InitStringBuffer(JSStringBuffer *sb);
172
-
173
- extern void
174
- js_FinishStringBuffer(JSStringBuffer *sb);
175
-
176
- extern void
177
- js_AppendChar(JSStringBuffer *sb, jschar c);
178
-
179
- extern void
180
- js_RepeatChar(JSStringBuffer *sb, jschar c, uintN count);
181
-
182
- extern void
183
- js_AppendCString(JSStringBuffer *sb, const char *asciiz);
184
-
185
- extern void
186
- js_AppendJSString(JSStringBuffer *sb, JSString *str);
187
-
188
- struct JSTokenPtr {
189
- uint16 index; /* index of char in physical line */
190
- uint16 lineno; /* physical line number */
191
- };
192
-
193
- struct JSTokenPos {
194
- JSTokenPtr begin; /* first character and line of token */
195
- JSTokenPtr end; /* index 1 past last char, last line */
196
- };
197
-
198
- struct JSToken {
199
- JSTokenType type; /* char value or above enumerator */
200
- JSTokenPos pos; /* token position in file */
201
- jschar *ptr; /* beginning of token in line buffer */
202
- union {
203
- struct { /* name or string literal */
204
- JSOp op; /* operator, for minimal parser */
205
- JSAtom *atom; /* atom table entry */
206
- } s;
207
- uintN reflags; /* regexp flags, use tokenbuf to access
208
- regexp chars */
209
- struct { /* atom pair, for XML PIs */
210
- JSAtom *atom2; /* auxiliary atom table entry */
211
- JSAtom *atom; /* main atom table entry */
212
- } p;
213
- jsdouble dval; /* floating point number */
214
- } u;
215
- };
216
-
217
- #define t_op u.s.op
218
- #define t_reflags u.reflags
219
- #define t_atom u.s.atom
220
- #define t_atom2 u.p.atom2
221
- #define t_dval u.dval
222
-
223
- typedef struct JSTokenBuf {
224
- jschar *base; /* base of line or stream buffer */
225
- jschar *limit; /* limit for quick bounds check */
226
- jschar *ptr; /* next char to get, or slot to use */
227
- } JSTokenBuf;
228
-
229
- #define JS_LINE_LIMIT 256 /* logical line buffer size limit --
230
- physical line length is unlimited */
231
- #define NTOKENS 4 /* 1 current + 2 lookahead, rounded */
232
- #define NTOKENS_MASK (NTOKENS-1) /* to power of 2 to avoid divmod by 3 */
233
-
234
- struct JSTokenStream {
235
- JSToken tokens[NTOKENS];/* circular token buffer */
236
- uintN cursor; /* index of last parsed token */
237
- uintN lookahead; /* count of lookahead tokens */
238
- uintN lineno; /* current line number */
239
- uintN ungetpos; /* next free char slot in ungetbuf */
240
- jschar ungetbuf[6]; /* at most 6, for \uXXXX lookahead */
241
- uintN flags; /* flags -- see below */
242
- ptrdiff_t linelen; /* physical linebuf segment length */
243
- ptrdiff_t linepos; /* linebuf offset in physical line */
244
- JSTokenBuf linebuf; /* line buffer for diagnostics */
245
- JSTokenBuf userbuf; /* user input buffer if !file */
246
- JSStringBuffer tokenbuf; /* current token string buffer */
247
- const char *filename; /* input filename or null */
248
- FILE *file; /* stdio stream if reading from file */
249
- JSSourceHandler listener; /* callback for source; eg debugger */
250
- void *listenerData; /* listener 'this' data */
251
- void *listenerTSData;/* listener data for this TokenStream */
252
- jschar *saveEOL; /* save next end of line in userbuf, to
253
- optimize for very long lines */
254
- };
255
-
256
- #define CURRENT_TOKEN(ts) ((ts)->tokens[(ts)->cursor])
257
- #define ON_CURRENT_LINE(ts,pos) ((uint16)(ts)->lineno == (pos).end.lineno)
258
-
259
- /* JSTokenStream flags */
260
- #define TSF_ERROR 0x01 /* fatal error while compiling */
261
- #define TSF_EOF 0x02 /* hit end of file */
262
- #define TSF_NEWLINES 0x04 /* tokenize newlines */
263
- #define TSF_OPERAND 0x08 /* looking for operand, not operator */
264
- #define TSF_NLFLAG 0x20 /* last linebuf ended with \n */
265
- #define TSF_CRFLAG 0x40 /* linebuf would have ended with \r */
266
- #define TSF_DIRTYLINE 0x80 /* non-whitespace since start of line */
267
- #define TSF_OWNFILENAME 0x100 /* ts->filename is malloc'd */
268
- #define TSF_XMLTAGMODE 0x200 /* scanning within an XML tag in E4X */
269
- #define TSF_XMLTEXTMODE 0x400 /* scanning XMLText terminal from E4X */
270
- #define TSF_XMLONLYMODE 0x800 /* don't scan {expr} within text/tag */
271
-
272
- /* Flag indicating unexpected end of input, i.e. TOK_EOF not at top-level. */
273
- #define TSF_UNEXPECTED_EOF 0x1000
274
-
275
- /*
276
- * To handle the hard case of contiguous HTML comments, we want to clear the
277
- * TSF_DIRTYINPUT flag at the end of each such comment. But we'd rather not
278
- * scan for --> within every //-style comment unless we have to. So we set
279
- * TSF_IN_HTML_COMMENT when a <!-- is scanned as an HTML begin-comment, and
280
- * clear it (and TSF_DIRTYINPUT) when we scan --> either on a clean line, or
281
- * only if (ts->flags & TSF_IN_HTML_COMMENT), in a //-style comment.
282
- *
283
- * This still works as before given a malformed comment hiding hack such as:
284
- *
285
- * <script>
286
- * <!-- comment hiding hack #1
287
- * code goes here
288
- * // --> oops, markup for script-unaware browsers goes here!
289
- * </script>
290
- *
291
- * It does not cope with malformed comment hiding hacks where --> is hidden
292
- * by C-style comments, or on a dirty line. Such cases are already broken.
293
- */
294
- #define TSF_IN_HTML_COMMENT 0x2000
295
-
296
- /* Ignore keywords and return TOK_NAME instead to the parser. */
297
- #define TSF_KEYWORD_IS_NAME 0x4000
298
-
299
- /* Unicode separators that are treated as line terminators, in addition to \n, \r */
300
- #define LINE_SEPARATOR 0x2028
301
- #define PARA_SEPARATOR 0x2029
302
-
303
- /*
304
- * Create a new token stream, either from an input buffer or from a file.
305
- * Return null on file-open or memory-allocation failure.
306
- *
307
- * The function uses JSContext.tempPool to allocate internal buffers. The
308
- * caller should release them using JS_ARENA_RELEASE after it has finished
309
- * with the token stream and has called js_CloseTokenStream.
310
- */
311
- extern JSBool
312
- js_InitTokenStream(JSContext *cx, JSTokenStream *ts,
313
- const jschar *base, size_t length,
314
- FILE *fp, const char *filename, uintN lineno);
315
-
316
- extern void
317
- js_CloseTokenStream(JSContext *cx, JSTokenStream *ts);
318
-
319
- extern JS_FRIEND_API(int)
320
- js_fgets(char *buf, int size, FILE *file);
321
-
322
- /*
323
- * If the given char array forms JavaScript keyword, return corresponding
324
- * token. Otherwise return TOK_EOF.
325
- */
326
- extern JSTokenType
327
- js_CheckKeyword(const jschar *chars, size_t length);
328
-
329
- /*
330
- * Friend-exported API entry point to call a mapping function on each reserved
331
- * identifier in the scanner's keyword table.
332
- */
333
- extern JS_FRIEND_API(void)
334
- js_MapKeywords(void (*mapfun)(const char *));
335
-
336
- /*
337
- * Check that str forms a valid JS identifier name. The function does not
338
- * check if str is a JS keyword.
339
- */
340
- extern JSBool
341
- js_IsIdentifier(JSString *str);
342
-
343
- /*
344
- * Report a compile-time error by its number. Return true for a warning, false
345
- * for an error. When pn is not null, use it to report error's location.
346
- * Otherwise use ts, which must not be null.
347
- */
348
- JSBool
349
- js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn,
350
- uintN flags, uintN errorNumber, ...);
351
-
352
- /*
353
- * Steal one JSREPORT_* bit (see jsapi.h) to tell that arguments to the error
354
- * message have const jschar* type, not const char*.
355
- */
356
- #define JSREPORT_UC 0x100
357
-
358
- /*
359
- * Look ahead one token and return its type.
360
- */
361
- extern JSTokenType
362
- js_PeekToken(JSContext *cx, JSTokenStream *ts);
363
-
364
- extern JSTokenType
365
- js_PeekTokenSameLine(JSContext *cx, JSTokenStream *ts);
366
-
367
- /*
368
- * Get the next token from ts.
369
- */
370
- extern JSTokenType
371
- js_GetToken(JSContext *cx, JSTokenStream *ts);
372
-
373
- /*
374
- * Push back the last scanned token onto ts.
375
- */
376
- extern void
377
- js_UngetToken(JSTokenStream *ts);
378
-
379
- /*
380
- * Get the next token from ts if its type is tt.
381
- */
382
- extern JSBool
383
- js_MatchToken(JSContext *cx, JSTokenStream *ts, JSTokenType tt);
384
-
385
- JS_END_EXTERN_C
386
-
387
- #endif /* jsscan_h___ */
@@ -1,1957 +0,0 @@
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 symbol tables.
43
- */
44
- #include "jsstddef.h"
45
- #include <stdlib.h>
46
- #include <string.h>
47
- #include "jstypes.h"
48
- #include "jsarena.h"
49
- #include "jsbit.h"
50
- #include "jsclist.h"
51
- #include "jsdhash.h"
52
- #include "jsutil.h" /* Added by JSIFY */
53
- #include "jsapi.h"
54
- #include "jsatom.h"
55
- #include "jscntxt.h"
56
- #include "jsdbgapi.h"
57
- #include "jslock.h"
58
- #include "jsnum.h"
59
- #include "jsscope.h"
60
- #include "jsstr.h"
61
-
62
- JSScope *
63
- js_GetMutableScope(JSContext *cx, JSObject *obj)
64
- {
65
- JSScope *scope, *newscope;
66
- JSClass *clasp;
67
- uint32 freeslot;
68
-
69
- scope = OBJ_SCOPE(obj);
70
- JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope));
71
- if (scope->object == obj)
72
- return scope;
73
- newscope = js_NewScope(cx, 0, scope->map.ops, LOCKED_OBJ_GET_CLASS(obj),
74
- obj);
75
- if (!newscope)
76
- return NULL;
77
- JS_LOCK_SCOPE(cx, newscope);
78
- obj->map = js_HoldObjectMap(cx, &newscope->map);
79
- JS_ASSERT(newscope->map.freeslot == JSSLOT_FREE(STOBJ_GET_CLASS(obj)));
80
- clasp = STOBJ_GET_CLASS(obj);
81
- if (clasp->reserveSlots) {
82
- freeslot = JSSLOT_FREE(clasp) + clasp->reserveSlots(cx, obj);
83
- if (freeslot > STOBJ_NSLOTS(obj))
84
- freeslot = STOBJ_NSLOTS(obj);
85
- if (newscope->map.freeslot < freeslot)
86
- newscope->map.freeslot = freeslot;
87
- }
88
- scope = (JSScope *) js_DropObjectMap(cx, &scope->map, obj);
89
- JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope);
90
- return newscope;
91
- }
92
-
93
- /*
94
- * JSScope uses multiplicative hashing, _a la_ jsdhash.[ch], but specialized
95
- * to minimize footprint. But if a scope has fewer than SCOPE_HASH_THRESHOLD
96
- * entries, we use linear search and avoid allocating scope->table.
97
- */
98
- #define SCOPE_HASH_THRESHOLD 6
99
- #define MIN_SCOPE_SIZE_LOG2 4
100
- #define MIN_SCOPE_SIZE JS_BIT(MIN_SCOPE_SIZE_LOG2)
101
- #define SCOPE_TABLE_NBYTES(n) ((n) * sizeof(JSScopeProperty *))
102
-
103
- static void
104
- InitMinimalScope(JSScope *scope)
105
- {
106
- scope->shape = 0;
107
- scope->hashShift = JS_DHASH_BITS - MIN_SCOPE_SIZE_LOG2;
108
- scope->entryCount = scope->removedCount = 0;
109
- scope->table = NULL;
110
- scope->lastProp = NULL;
111
- }
112
-
113
- static JSBool
114
- CreateScopeTable(JSContext *cx, JSScope *scope, JSBool report)
115
- {
116
- int sizeLog2;
117
- JSScopeProperty *sprop, **spp;
118
-
119
- JS_ASSERT(!scope->table);
120
- JS_ASSERT(scope->lastProp);
121
-
122
- if (scope->entryCount > SCOPE_HASH_THRESHOLD) {
123
- /*
124
- * Either we're creating a table for a large scope that was populated
125
- * via property cache hit logic under JSOP_INITPROP, JSOP_SETNAME, or
126
- * JSOP_SETPROP; or else calloc failed at least once already. In any
127
- * event, let's try to grow, overallocating to hold at least twice the
128
- * current population.
129
- */
130
- sizeLog2 = JS_CeilingLog2(2 * scope->entryCount);
131
- scope->hashShift = JS_DHASH_BITS - sizeLog2;
132
- } else {
133
- JS_ASSERT(scope->hashShift == JS_DHASH_BITS - MIN_SCOPE_SIZE_LOG2);
134
- sizeLog2 = MIN_SCOPE_SIZE_LOG2;
135
- }
136
-
137
- scope->table = (JSScopeProperty **)
138
- calloc(JS_BIT(sizeLog2), sizeof(JSScopeProperty *));
139
- if (!scope->table) {
140
- if (report)
141
- JS_ReportOutOfMemory(cx);
142
- return JS_FALSE;
143
- }
144
- js_UpdateMallocCounter(cx, JS_BIT(sizeLog2) * sizeof(JSScopeProperty *));
145
-
146
- scope->hashShift = JS_DHASH_BITS - sizeLog2;
147
- for (sprop = scope->lastProp; sprop; sprop = sprop->parent) {
148
- spp = js_SearchScope(scope, sprop->id, JS_TRUE);
149
- SPROP_STORE_PRESERVING_COLLISION(spp, sprop);
150
- }
151
- return JS_TRUE;
152
- }
153
-
154
- JSScope *
155
- js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
156
- JSObject *obj)
157
- {
158
- JSScope *scope;
159
-
160
- scope = (JSScope *) JS_malloc(cx, sizeof(JSScope));
161
- if (!scope)
162
- return NULL;
163
-
164
- js_InitObjectMap(&scope->map, nrefs, ops, clasp);
165
- scope->object = obj;
166
- scope->flags = 0;
167
- InitMinimalScope(scope);
168
-
169
- #ifdef JS_THREADSAFE
170
- js_InitTitle(cx, &scope->title);
171
- #endif
172
- JS_RUNTIME_METER(cx->runtime, liveScopes);
173
- JS_RUNTIME_METER(cx->runtime, totalScopes);
174
- return scope;
175
- }
176
-
177
- #ifdef DEBUG_SCOPE_COUNT
178
- extern void
179
- js_unlog_scope(JSScope *scope);
180
- #endif
181
-
182
- #if defined DEBUG || defined JS_DUMP_PROPTREE_STATS
183
- # include "jsprf.h"
184
- # define LIVE_SCOPE_METER(cx,expr) JS_LOCK_RUNTIME_VOID(cx->runtime,expr)
185
- #else
186
- # define LIVE_SCOPE_METER(cx,expr) /* nothing */
187
- #endif
188
-
189
- void
190
- js_DestroyScope(JSContext *cx, JSScope *scope)
191
- {
192
- #ifdef DEBUG_SCOPE_COUNT
193
- js_unlog_scope(scope);
194
- #endif
195
-
196
- #ifdef JS_THREADSAFE
197
- js_FinishTitle(cx, &scope->title);
198
- #endif
199
- if (scope->table)
200
- JS_free(cx, scope->table);
201
-
202
- LIVE_SCOPE_METER(cx, cx->runtime->liveScopeProps -= scope->entryCount);
203
- JS_RUNTIME_UNMETER(cx->runtime, liveScopes);
204
- JS_free(cx, scope);
205
- }
206
-
207
- #ifdef JS_DUMP_PROPTREE_STATS
208
- typedef struct JSScopeStats {
209
- jsrefcount searches;
210
- jsrefcount hits;
211
- jsrefcount misses;
212
- jsrefcount hashes;
213
- jsrefcount steps;
214
- jsrefcount stepHits;
215
- jsrefcount stepMisses;
216
- jsrefcount adds;
217
- jsrefcount redundantAdds;
218
- jsrefcount addFailures;
219
- jsrefcount changeFailures;
220
- jsrefcount compresses;
221
- jsrefcount grows;
222
- jsrefcount removes;
223
- jsrefcount removeFrees;
224
- jsrefcount uselessRemoves;
225
- jsrefcount shrinks;
226
- } JSScopeStats;
227
-
228
- JS_FRIEND_DATA(JSScopeStats) js_scope_stats = {0};
229
-
230
- # define METER(x) JS_ATOMIC_INCREMENT(&js_scope_stats.x)
231
- #else
232
- # define METER(x) /* nothing */
233
- #endif
234
-
235
- JS_STATIC_ASSERT(sizeof(JSHashNumber) == 4);
236
- JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD);
237
-
238
- #if JS_BYTES_PER_WORD == 4
239
- # define HASH_ID(id) ((JSHashNumber)(id))
240
- #elif JS_BYTES_PER_WORD == 8
241
- # define HASH_ID(id) ((JSHashNumber)(id) ^ (JSHashNumber)((id) >> 32))
242
- #else
243
- # error "Unsupported configuration"
244
- #endif
245
-
246
- /*
247
- * Double hashing needs the second hash code to be relatively prime to table
248
- * size, so we simply make hash2 odd. The inputs to multiplicative hash are
249
- * the golden ratio, expressed as a fixed-point 32 bit fraction, and the id
250
- * itself.
251
- */
252
- #define SCOPE_HASH0(id) (HASH_ID(id) * JS_GOLDEN_RATIO)
253
- #define SCOPE_HASH1(hash0,shift) ((hash0) >> (shift))
254
- #define SCOPE_HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1)
255
-
256
- JS_FRIEND_API(JSScopeProperty **)
257
- js_SearchScope(JSScope *scope, jsid id, JSBool adding)
258
- {
259
- JSHashNumber hash0, hash1, hash2;
260
- int hashShift, sizeLog2;
261
- JSScopeProperty *stored, *sprop, **spp, **firstRemoved;
262
- uint32 sizeMask;
263
-
264
- METER(searches);
265
- if (!scope->table) {
266
- /* Not enough properties to justify hashing: search from lastProp. */
267
- JS_ASSERT(!SCOPE_HAD_MIDDLE_DELETE(scope));
268
- for (spp = &scope->lastProp; (sprop = *spp); spp = &sprop->parent) {
269
- if (sprop->id == id) {
270
- METER(hits);
271
- return spp;
272
- }
273
- }
274
- METER(misses);
275
- return spp;
276
- }
277
-
278
- /* Compute the primary hash address. */
279
- METER(hashes);
280
- hash0 = SCOPE_HASH0(id);
281
- hashShift = scope->hashShift;
282
- hash1 = SCOPE_HASH1(hash0, hashShift);
283
- spp = scope->table + hash1;
284
-
285
- /* Miss: return space for a new entry. */
286
- stored = *spp;
287
- if (SPROP_IS_FREE(stored)) {
288
- METER(misses);
289
- return spp;
290
- }
291
-
292
- /* Hit: return entry. */
293
- sprop = SPROP_CLEAR_COLLISION(stored);
294
- if (sprop && sprop->id == id) {
295
- METER(hits);
296
- return spp;
297
- }
298
-
299
- /* Collision: double hash. */
300
- sizeLog2 = JS_DHASH_BITS - hashShift;
301
- hash2 = SCOPE_HASH2(hash0, sizeLog2, hashShift);
302
- sizeMask = JS_BITMASK(sizeLog2);
303
-
304
- /* Save the first removed entry pointer so we can recycle it if adding. */
305
- if (SPROP_IS_REMOVED(stored)) {
306
- firstRemoved = spp;
307
- } else {
308
- firstRemoved = NULL;
309
- if (adding && !SPROP_HAD_COLLISION(stored))
310
- SPROP_FLAG_COLLISION(spp, sprop);
311
- }
312
-
313
- for (;;) {
314
- METER(steps);
315
- hash1 -= hash2;
316
- hash1 &= sizeMask;
317
- spp = scope->table + hash1;
318
-
319
- stored = *spp;
320
- if (SPROP_IS_FREE(stored)) {
321
- METER(stepMisses);
322
- return (adding && firstRemoved) ? firstRemoved : spp;
323
- }
324
-
325
- sprop = SPROP_CLEAR_COLLISION(stored);
326
- if (sprop && sprop->id == id) {
327
- METER(stepHits);
328
- return spp;
329
- }
330
-
331
- if (SPROP_IS_REMOVED(stored)) {
332
- if (!firstRemoved)
333
- firstRemoved = spp;
334
- } else {
335
- if (adding && !SPROP_HAD_COLLISION(stored))
336
- SPROP_FLAG_COLLISION(spp, sprop);
337
- }
338
- }
339
-
340
- /* NOTREACHED */
341
- return NULL;
342
- }
343
-
344
- static JSBool
345
- ChangeScope(JSContext *cx, JSScope *scope, int change)
346
- {
347
- int oldlog2, newlog2;
348
- uint32 oldsize, newsize, nbytes;
349
- JSScopeProperty **table, **oldtable, **spp, **oldspp, *sprop;
350
-
351
- if (!scope->table)
352
- return CreateScopeTable(cx, scope, JS_TRUE);
353
-
354
- /* Grow, shrink, or compress by changing scope->table. */
355
- oldlog2 = JS_DHASH_BITS - scope->hashShift;
356
- newlog2 = oldlog2 + change;
357
- oldsize = JS_BIT(oldlog2);
358
- newsize = JS_BIT(newlog2);
359
- nbytes = SCOPE_TABLE_NBYTES(newsize);
360
- table = (JSScopeProperty **) calloc(nbytes, 1);
361
- if (!table) {
362
- JS_ReportOutOfMemory(cx);
363
- return JS_FALSE;
364
- }
365
-
366
- /* Now that we have a new table allocated, update scope members. */
367
- scope->hashShift = JS_DHASH_BITS - newlog2;
368
- scope->removedCount = 0;
369
- oldtable = scope->table;
370
- scope->table = table;
371
-
372
- /* Treat the above calloc as a JS_malloc, to match CreateScopeTable. */
373
- cx->runtime->gcMallocBytes += nbytes;
374
-
375
- /* Copy only live entries, leaving removed and free ones behind. */
376
- for (oldspp = oldtable; oldsize != 0; oldspp++) {
377
- sprop = SPROP_FETCH(oldspp);
378
- if (sprop) {
379
- spp = js_SearchScope(scope, sprop->id, JS_TRUE);
380
- JS_ASSERT(SPROP_IS_FREE(*spp));
381
- *spp = sprop;
382
- }
383
- oldsize--;
384
- }
385
-
386
- /* Finally, free the old table storage. */
387
- JS_free(cx, oldtable);
388
- return JS_TRUE;
389
- }
390
-
391
- /*
392
- * Take care to exclude the mark bits in case we're called from the GC.
393
- */
394
- #define SPROP_FLAGS_NOT_MATCHED (SPROP_MARK | SPROP_FLAG_SHAPE_REGEN)
395
-
396
- JS_STATIC_DLL_CALLBACK(JSDHashNumber)
397
- js_HashScopeProperty(JSDHashTable *table, const void *key)
398
- {
399
- const JSScopeProperty *sprop = (const JSScopeProperty *)key;
400
- JSDHashNumber hash;
401
- JSPropertyOp gsop;
402
-
403
- /* Accumulate from least to most random so the low bits are most random. */
404
- hash = 0;
405
- gsop = sprop->getter;
406
- if (gsop)
407
- hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsword)gsop;
408
- gsop = sprop->setter;
409
- if (gsop)
410
- hash = JS_ROTATE_LEFT32(hash, 4) ^ (jsword)gsop;
411
-
412
- hash = JS_ROTATE_LEFT32(hash, 4)
413
- ^ (sprop->flags & ~SPROP_FLAGS_NOT_MATCHED);
414
-
415
- hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->attrs;
416
- hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->shortid;
417
- hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->slot;
418
- hash = JS_ROTATE_LEFT32(hash, 4) ^ sprop->id;
419
- return hash;
420
- }
421
-
422
- #define SPROP_MATCH(sprop, child) \
423
- SPROP_MATCH_PARAMS(sprop, (child)->id, (child)->getter, (child)->setter, \
424
- (child)->slot, (child)->attrs, (child)->flags, \
425
- (child)->shortid)
426
-
427
- #define SPROP_MATCH_PARAMS(sprop, aid, agetter, asetter, aslot, aattrs, \
428
- aflags, ashortid) \
429
- ((sprop)->id == (aid) && \
430
- SPROP_MATCH_PARAMS_AFTER_ID(sprop, agetter, asetter, aslot, aattrs, \
431
- aflags, ashortid))
432
-
433
- #define SPROP_MATCH_PARAMS_AFTER_ID(sprop, agetter, asetter, aslot, aattrs, \
434
- aflags, ashortid) \
435
- ((sprop)->getter == (agetter) && \
436
- (sprop)->setter == (asetter) && \
437
- (sprop)->slot == (aslot) && \
438
- (sprop)->attrs == (aattrs) && \
439
- (((sprop)->flags ^ (aflags)) & ~SPROP_FLAGS_NOT_MATCHED) == 0 && \
440
- (sprop)->shortid == (ashortid))
441
-
442
- JS_STATIC_DLL_CALLBACK(JSBool)
443
- js_MatchScopeProperty(JSDHashTable *table,
444
- const JSDHashEntryHdr *hdr,
445
- const void *key)
446
- {
447
- const JSPropertyTreeEntry *entry = (const JSPropertyTreeEntry *)hdr;
448
- const JSScopeProperty *sprop = entry->child;
449
- const JSScopeProperty *kprop = (const JSScopeProperty *)key;
450
-
451
- return SPROP_MATCH(sprop, kprop);
452
- }
453
-
454
- static const JSDHashTableOps PropertyTreeHashOps = {
455
- JS_DHashAllocTable,
456
- JS_DHashFreeTable,
457
- js_HashScopeProperty,
458
- js_MatchScopeProperty,
459
- JS_DHashMoveEntryStub,
460
- JS_DHashClearEntryStub,
461
- JS_DHashFinalizeStub,
462
- NULL
463
- };
464
-
465
- /*
466
- * A property tree node on rt->propertyFreeList overlays the following prefix
467
- * struct on JSScopeProperty.
468
- */
469
- typedef struct FreeNode {
470
- jsid id;
471
- JSScopeProperty *next;
472
- JSScopeProperty **prevp;
473
- } FreeNode;
474
-
475
- #define FREENODE(sprop) ((FreeNode *) (sprop))
476
-
477
- #define FREENODE_INSERT(list, sprop) \
478
- JS_BEGIN_MACRO \
479
- FREENODE(sprop)->next = (list); \
480
- FREENODE(sprop)->prevp = &(list); \
481
- if (list) \
482
- FREENODE(list)->prevp = &FREENODE(sprop)->next; \
483
- (list) = (sprop); \
484
- JS_END_MACRO
485
-
486
- #define FREENODE_REMOVE(sprop) \
487
- JS_BEGIN_MACRO \
488
- *FREENODE(sprop)->prevp = FREENODE(sprop)->next; \
489
- if (FREENODE(sprop)->next) \
490
- FREENODE(FREENODE(sprop)->next)->prevp = FREENODE(sprop)->prevp; \
491
- JS_END_MACRO
492
-
493
- /* NB: Called with rt->gcLock held. */
494
- static JSScopeProperty *
495
- NewScopeProperty(JSRuntime *rt)
496
- {
497
- JSScopeProperty *sprop;
498
-
499
- sprop = rt->propertyFreeList;
500
- if (sprop) {
501
- FREENODE_REMOVE(sprop);
502
- } else {
503
- JS_ARENA_ALLOCATE_CAST(sprop, JSScopeProperty *,
504
- &rt->propertyArenaPool,
505
- sizeof(JSScopeProperty));
506
- if (!sprop)
507
- return NULL;
508
- }
509
-
510
- JS_RUNTIME_METER(rt, livePropTreeNodes);
511
- JS_RUNTIME_METER(rt, totalPropTreeNodes);
512
- return sprop;
513
- }
514
-
515
- #define CHUNKY_KIDS_TAG ((jsuword)1)
516
- #define KIDS_IS_CHUNKY(kids) ((jsuword)(kids) & CHUNKY_KIDS_TAG)
517
- #define KIDS_TO_CHUNK(kids) ((PropTreeKidsChunk *) \
518
- ((jsuword)(kids) & ~CHUNKY_KIDS_TAG))
519
- #define CHUNK_TO_KIDS(chunk) ((JSScopeProperty *) \
520
- ((jsuword)(chunk) | CHUNKY_KIDS_TAG))
521
- #define MAX_KIDS_PER_CHUNK 10
522
- #define CHUNK_HASH_THRESHOLD 30
523
-
524
- typedef struct PropTreeKidsChunk PropTreeKidsChunk;
525
-
526
- struct PropTreeKidsChunk {
527
- JSScopeProperty *kids[MAX_KIDS_PER_CHUNK];
528
- JSDHashTable *table;
529
- PropTreeKidsChunk *next;
530
- };
531
-
532
- static PropTreeKidsChunk *
533
- NewPropTreeKidsChunk(JSRuntime *rt)
534
- {
535
- PropTreeKidsChunk *chunk;
536
-
537
- chunk = (PropTreeKidsChunk *) calloc(1, sizeof *chunk);
538
- if (!chunk)
539
- return NULL;
540
- JS_ASSERT(((jsuword)chunk & CHUNKY_KIDS_TAG) == 0);
541
- JS_RUNTIME_METER(rt, propTreeKidsChunks);
542
- return chunk;
543
- }
544
-
545
- static void
546
- DestroyPropTreeKidsChunk(JSRuntime *rt, PropTreeKidsChunk *chunk)
547
- {
548
- JS_RUNTIME_UNMETER(rt, propTreeKidsChunks);
549
- if (chunk->table)
550
- JS_DHashTableDestroy(chunk->table);
551
- free(chunk);
552
- }
553
-
554
- /* NB: Called with rt->gcLock held. */
555
- static JSBool
556
- InsertPropertyTreeChild(JSRuntime *rt, JSScopeProperty *parent,
557
- JSScopeProperty *child, PropTreeKidsChunk *sweptChunk)
558
- {
559
- JSDHashTable *table;
560
- JSPropertyTreeEntry *entry;
561
- JSScopeProperty **childp, *kids, *sprop;
562
- PropTreeKidsChunk *chunk, **chunkp;
563
- uintN i;
564
-
565
- JS_ASSERT(!parent || child->parent != parent);
566
-
567
- if (!parent) {
568
- table = &rt->propertyTreeHash;
569
- entry = (JSPropertyTreeEntry *)
570
- JS_DHashTableOperate(table, child, JS_DHASH_ADD);
571
- if (!entry)
572
- return JS_FALSE;
573
- childp = &entry->child;
574
- sprop = *childp;
575
- if (!sprop) {
576
- *childp = child;
577
- } else {
578
- /*
579
- * A "Duplicate child" case.
580
- *
581
- * We can't do away with child, as at least one live scope entry
582
- * still points at it. What's more, that scope's lastProp chains
583
- * through an ancestor line to reach child, and js_Enumerate and
584
- * others count on this linkage. We must leave child out of the
585
- * hash table, and not require it to be there when we eventually
586
- * GC it (see RemovePropertyTreeChild, below).
587
- *
588
- * It is necessary to leave the duplicate child out of the hash
589
- * table to preserve entry uniqueness. It is safe to leave the
590
- * child out of the hash table (unlike the duplicate child cases
591
- * below), because the child's parent link will be null, which
592
- * can't dangle.
593
- */
594
- JS_ASSERT(sprop != child && SPROP_MATCH(sprop, child));
595
- JS_RUNTIME_METER(rt, duplicatePropTreeNodes);
596
- }
597
- } else {
598
- childp = &parent->kids;
599
- kids = *childp;
600
- if (kids) {
601
- if (KIDS_IS_CHUNKY(kids)) {
602
- chunk = KIDS_TO_CHUNK(kids);
603
-
604
- table = chunk->table;
605
- if (table) {
606
- entry = (JSPropertyTreeEntry *)
607
- JS_DHashTableOperate(table, child, JS_DHASH_ADD);
608
- if (!entry)
609
- return JS_FALSE;
610
- if (!entry->child) {
611
- entry->child = child;
612
- while (chunk->next)
613
- chunk = chunk->next;
614
- for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
615
- childp = &chunk->kids[i];
616
- sprop = *childp;
617
- if (!sprop)
618
- goto insert;
619
- }
620
- chunkp = &chunk->next;
621
- goto new_chunk;
622
- }
623
- }
624
-
625
- do {
626
- for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
627
- childp = &chunk->kids[i];
628
- sprop = *childp;
629
- if (!sprop)
630
- goto insert;
631
-
632
- JS_ASSERT(sprop != child);
633
- if (SPROP_MATCH(sprop, child)) {
634
- /*
635
- * Duplicate child, see comment above. In this
636
- * case, we must let the duplicate be inserted at
637
- * this level in the tree, so we keep iterating,
638
- * looking for an empty slot in which to insert.
639
- */
640
- JS_ASSERT(sprop != child);
641
- JS_RUNTIME_METER(rt, duplicatePropTreeNodes);
642
- }
643
- }
644
- chunkp = &chunk->next;
645
- } while ((chunk = *chunkp) != NULL);
646
-
647
- new_chunk:
648
- if (sweptChunk) {
649
- chunk = sweptChunk;
650
- } else {
651
- chunk = NewPropTreeKidsChunk(rt);
652
- if (!chunk)
653
- return JS_FALSE;
654
- }
655
- *chunkp = chunk;
656
- childp = &chunk->kids[0];
657
- } else {
658
- sprop = kids;
659
- JS_ASSERT(sprop != child);
660
- if (SPROP_MATCH(sprop, child)) {
661
- /*
662
- * Duplicate child, see comment above. Once again, we
663
- * must let duplicates created by deletion pile up in a
664
- * kids-chunk-list, in order to find them when sweeping
665
- * and thereby avoid dangling parent pointers.
666
- */
667
- JS_RUNTIME_METER(rt, duplicatePropTreeNodes);
668
- }
669
- if (sweptChunk) {
670
- chunk = sweptChunk;
671
- } else {
672
- chunk = NewPropTreeKidsChunk(rt);
673
- if (!chunk)
674
- return JS_FALSE;
675
- }
676
- parent->kids = CHUNK_TO_KIDS(chunk);
677
- chunk->kids[0] = sprop;
678
- childp = &chunk->kids[1];
679
- }
680
- }
681
- insert:
682
- *childp = child;
683
- }
684
-
685
- child->parent = parent;
686
- return JS_TRUE;
687
- }
688
-
689
- /* NB: Called with rt->gcLock held. */
690
- static PropTreeKidsChunk *
691
- RemovePropertyTreeChild(JSRuntime *rt, JSScopeProperty *child)
692
- {
693
- PropTreeKidsChunk *freeChunk;
694
- JSScopeProperty *parent, *kids, *kid;
695
- JSDHashTable *table;
696
- PropTreeKidsChunk *list, *chunk, **chunkp, *lastChunk;
697
- uintN i, j;
698
- JSPropertyTreeEntry *entry;
699
-
700
- freeChunk = NULL;
701
- parent = child->parent;
702
- if (!parent) {
703
- /*
704
- * Don't remove child if it is not in rt->propertyTreeHash, but only
705
- * matches a root child in the table that has compatible members. See
706
- * the "Duplicate child" comments in InsertPropertyTreeChild, above.
707
- */
708
- table = &rt->propertyTreeHash;
709
- } else {
710
- kids = parent->kids;
711
- if (KIDS_IS_CHUNKY(kids)) {
712
- list = chunk = KIDS_TO_CHUNK(kids);
713
- chunkp = &list;
714
- table = chunk->table;
715
-
716
- do {
717
- for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
718
- if (chunk->kids[i] == child) {
719
- lastChunk = chunk;
720
- if (!lastChunk->next) {
721
- j = i + 1;
722
- } else {
723
- j = 0;
724
- do {
725
- chunkp = &lastChunk->next;
726
- lastChunk = *chunkp;
727
- } while (lastChunk->next);
728
- }
729
- for (; j < MAX_KIDS_PER_CHUNK; j++) {
730
- if (!lastChunk->kids[j])
731
- break;
732
- }
733
- --j;
734
- if (chunk != lastChunk || j > i)
735
- chunk->kids[i] = lastChunk->kids[j];
736
- lastChunk->kids[j] = NULL;
737
- if (j == 0) {
738
- *chunkp = NULL;
739
- if (!list)
740
- parent->kids = NULL;
741
- freeChunk = lastChunk;
742
- }
743
- goto out;
744
- }
745
- }
746
-
747
- chunkp = &chunk->next;
748
- } while ((chunk = *chunkp) != NULL);
749
- } else {
750
- table = NULL;
751
- kid = kids;
752
- if (kid == child)
753
- parent->kids = NULL;
754
- }
755
- }
756
-
757
- out:
758
- if (table) {
759
- entry = (JSPropertyTreeEntry *)
760
- JS_DHashTableOperate(table, child, JS_DHASH_LOOKUP);
761
-
762
- if (entry->child == child)
763
- JS_DHashTableRawRemove(table, &entry->hdr);
764
- }
765
- return freeChunk;
766
- }
767
-
768
- static JSDHashTable *
769
- HashChunks(PropTreeKidsChunk *chunk, uintN n)
770
- {
771
- JSDHashTable *table;
772
- uintN i;
773
- JSScopeProperty *sprop;
774
- JSPropertyTreeEntry *entry;
775
-
776
- table = JS_NewDHashTable(&PropertyTreeHashOps, NULL,
777
- sizeof(JSPropertyTreeEntry),
778
- JS_DHASH_DEFAULT_CAPACITY(n + 1));
779
- if (!table)
780
- return NULL;
781
- do {
782
- for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
783
- sprop = chunk->kids[i];
784
- if (!sprop)
785
- break;
786
- entry = (JSPropertyTreeEntry *)
787
- JS_DHashTableOperate(table, sprop, JS_DHASH_ADD);
788
- entry->child = sprop;
789
- }
790
- } while ((chunk = chunk->next) != NULL);
791
- return table;
792
- }
793
-
794
- /*
795
- * Called without cx->runtime->gcLock held. This function acquires that lock
796
- * only when inserting a new child. Thus there may be races to find or add a
797
- * node that result in duplicates. We expect such races to be rare!
798
- *
799
- * We use rt->gcLock, not rt->rtLock, to allow the GC potentially to nest here
800
- * under js_GenerateShape.
801
- */
802
- static JSScopeProperty *
803
- GetPropertyTreeChild(JSContext *cx, JSScopeProperty *parent,
804
- JSScopeProperty *child)
805
- {
806
- JSRuntime *rt;
807
- JSDHashTable *table;
808
- JSPropertyTreeEntry *entry;
809
- JSScopeProperty *sprop;
810
- PropTreeKidsChunk *chunk;
811
- uintN i, n;
812
- uint32 shape;
813
-
814
- rt = cx->runtime;
815
- if (!parent) {
816
- JS_LOCK_GC(rt);
817
-
818
- table = &rt->propertyTreeHash;
819
- entry = (JSPropertyTreeEntry *)
820
- JS_DHashTableOperate(table, child, JS_DHASH_ADD);
821
- if (!entry)
822
- goto out_of_memory;
823
-
824
- sprop = entry->child;
825
- if (sprop)
826
- goto out;
827
- } else {
828
- /*
829
- * Because chunks are appended at the end and never deleted except by
830
- * the GC, we can search without taking the runtime's GC lock. We may
831
- * miss a matching sprop added by another thread, and make a duplicate
832
- * one, but that is an unlikely, therefore small, cost. The property
833
- * tree has extremely low fan-out below its root in popular embeddings
834
- * with real-world workloads.
835
- *
836
- * Patterns such as defining closures that capture a constructor's
837
- * environment as getters or setters on the new object that is passed
838
- * in as |this| can significantly increase fan-out below the property
839
- * tree root -- see bug 335700 for details.
840
- */
841
- entry = NULL;
842
- sprop = parent->kids;
843
- if (sprop) {
844
- if (KIDS_IS_CHUNKY(sprop)) {
845
- chunk = KIDS_TO_CHUNK(sprop);
846
-
847
- table = chunk->table;
848
- if (table) {
849
- JS_LOCK_GC(rt);
850
- entry = (JSPropertyTreeEntry *)
851
- JS_DHashTableOperate(table, child, JS_DHASH_LOOKUP);
852
- sprop = entry->child;
853
- if (sprop) {
854
- JS_UNLOCK_GC(rt);
855
- return sprop;
856
- }
857
- goto locked_not_found;
858
- }
859
-
860
- n = 0;
861
- do {
862
- for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
863
- sprop = chunk->kids[i];
864
- if (!sprop) {
865
- n += i;
866
- if (n >= CHUNK_HASH_THRESHOLD) {
867
- chunk = KIDS_TO_CHUNK(parent->kids);
868
- if (!chunk->table) {
869
- table = HashChunks(chunk, n);
870
- JS_LOCK_GC(rt);
871
- if (!table)
872
- goto out_of_memory;
873
- if (chunk->table)
874
- JS_DHashTableDestroy(table);
875
- else
876
- chunk->table = table;
877
- goto locked_not_found;
878
- }
879
- }
880
- goto not_found;
881
- }
882
-
883
- if (SPROP_MATCH(sprop, child))
884
- return sprop;
885
- }
886
- n += MAX_KIDS_PER_CHUNK;
887
- } while ((chunk = chunk->next) != NULL);
888
- } else {
889
- if (SPROP_MATCH(sprop, child))
890
- return sprop;
891
- }
892
- }
893
-
894
- not_found:
895
- JS_LOCK_GC(rt);
896
- }
897
-
898
- locked_not_found:
899
- /*
900
- * Call js_GenerateShape before the allocation to prevent collecting the
901
- * new property when the shape generation triggers the GC.
902
- */
903
- shape = js_GenerateShape(cx, JS_TRUE, NULL);
904
-
905
- sprop = NewScopeProperty(rt);
906
- if (!sprop)
907
- goto out_of_memory;
908
-
909
- sprop->id = child->id;
910
- sprop->getter = child->getter;
911
- sprop->setter = child->setter;
912
- sprop->slot = child->slot;
913
- sprop->attrs = child->attrs;
914
- sprop->flags = child->flags;
915
- sprop->shortid = child->shortid;
916
- sprop->parent = sprop->kids = NULL;
917
- sprop->shape = shape;
918
-
919
- if (!parent) {
920
- entry->child = sprop;
921
- } else {
922
- if (!InsertPropertyTreeChild(rt, parent, sprop, NULL))
923
- goto out_of_memory;
924
- }
925
-
926
- out:
927
- JS_UNLOCK_GC(rt);
928
- return sprop;
929
-
930
- out_of_memory:
931
- JS_UNLOCK_GC(rt);
932
- JS_ReportOutOfMemory(cx);
933
- return NULL;
934
- }
935
-
936
- #ifdef DEBUG_notbrendan
937
- #define CHECK_ANCESTOR_LINE(scope, sparse) \
938
- JS_BEGIN_MACRO \
939
- if ((scope)->table) CheckAncestorLine(scope, sparse); \
940
- JS_END_MACRO
941
-
942
- static void
943
- CheckAncestorLine(JSScope *scope, JSBool sparse)
944
- {
945
- uint32 size;
946
- JSScopeProperty **spp, **start, **end, *ancestorLine, *sprop, *aprop;
947
- uint32 entryCount, ancestorCount;
948
-
949
- ancestorLine = SCOPE_LAST_PROP(scope);
950
- if (ancestorLine)
951
- JS_ASSERT(SCOPE_HAS_PROPERTY(scope, ancestorLine));
952
-
953
- entryCount = 0;
954
- size = SCOPE_CAPACITY(scope);
955
- start = scope->table;
956
- for (spp = start, end = start + size; spp < end; spp++) {
957
- sprop = SPROP_FETCH(spp);
958
- if (sprop) {
959
- entryCount++;
960
- for (aprop = ancestorLine; aprop; aprop = aprop->parent) {
961
- if (aprop == sprop)
962
- break;
963
- }
964
- JS_ASSERT(aprop);
965
- }
966
- }
967
- JS_ASSERT(entryCount == scope->entryCount);
968
-
969
- ancestorCount = 0;
970
- for (sprop = ancestorLine; sprop; sprop = sprop->parent) {
971
- if (SCOPE_HAD_MIDDLE_DELETE(scope) &&
972
- !SCOPE_HAS_PROPERTY(scope, sprop)) {
973
- JS_ASSERT(sparse);
974
- continue;
975
- }
976
- ancestorCount++;
977
- }
978
- JS_ASSERT(ancestorCount == scope->entryCount);
979
- }
980
- #else
981
- #define CHECK_ANCESTOR_LINE(scope, sparse) /* nothing */
982
- #endif
983
-
984
- static void
985
- ReportReadOnlyScope(JSContext *cx, JSScope *scope)
986
- {
987
- JSString *str;
988
- const char *bytes;
989
-
990
- str = js_ValueToString(cx, OBJECT_TO_JSVAL(scope->object));
991
- if (!str)
992
- return;
993
- bytes = js_GetStringBytes(cx, str);
994
- if (!bytes)
995
- return;
996
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_READ_ONLY, bytes);
997
- }
998
-
999
- JSScopeProperty *
1000
- js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
1001
- JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
1002
- uintN attrs, uintN flags, intN shortid)
1003
- {
1004
- JSScopeProperty **spp, *sprop, *overwriting, **spvec, **spp2, child;
1005
- uint32 size, splen, i;
1006
- int change;
1007
- JSTempValueRooter tvr;
1008
-
1009
- JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope));
1010
- CHECK_ANCESTOR_LINE(scope, JS_TRUE);
1011
-
1012
- /*
1013
- * You can't add properties to a sealed scope. But note well that you can
1014
- * change property attributes in a sealed scope, even though that replaces
1015
- * a JSScopeProperty * in the scope's hash table -- but no id is added, so
1016
- * the scope remains sealed.
1017
- */
1018
- if (SCOPE_IS_SEALED(scope)) {
1019
- ReportReadOnlyScope(cx, scope);
1020
- return NULL;
1021
- }
1022
-
1023
- /*
1024
- * Normalize stub getter and setter values for faster is-stub testing in
1025
- * the SPROP_CALL_[GS]ETTER macros.
1026
- */
1027
- if (getter == JS_PropertyStub)
1028
- getter = NULL;
1029
- if (setter == JS_PropertyStub)
1030
- setter = NULL;
1031
-
1032
- /*
1033
- * Search for id in order to claim its entry, allocating a property tree
1034
- * node if one doesn't already exist for our parameters.
1035
- */
1036
- spp = js_SearchScope(scope, id, JS_TRUE);
1037
- sprop = overwriting = SPROP_FETCH(spp);
1038
- if (!sprop) {
1039
- JS_COUNT_OPERATION(cx, JSOW_NEW_PROPERTY);
1040
-
1041
- /* Check whether we need to grow, if the load factor is >= .75. */
1042
- size = SCOPE_CAPACITY(scope);
1043
- if (scope->entryCount + scope->removedCount >= size - (size >> 2)) {
1044
- if (scope->removedCount >= size >> 2) {
1045
- METER(compresses);
1046
- change = 0;
1047
- } else {
1048
- METER(grows);
1049
- change = 1;
1050
- }
1051
- if (!ChangeScope(cx, scope, change) &&
1052
- scope->entryCount + scope->removedCount == size - 1) {
1053
- METER(addFailures);
1054
- return NULL;
1055
- }
1056
- spp = js_SearchScope(scope, id, JS_TRUE);
1057
- JS_ASSERT(!SPROP_FETCH(spp));
1058
- }
1059
- } else {
1060
- /* Property exists: js_SearchScope must have returned a valid entry. */
1061
- JS_ASSERT(!SPROP_IS_REMOVED(*spp));
1062
-
1063
- /*
1064
- * If all property members match, this is a redundant add and we can
1065
- * return early. If the caller wants to allocate a slot, but doesn't
1066
- * care which slot, copy sprop->slot into slot so we can match sprop,
1067
- * if all other members match.
1068
- */
1069
- if (!(attrs & JSPROP_SHARED) &&
1070
- slot == SPROP_INVALID_SLOT &&
1071
- SPROP_HAS_VALID_SLOT(sprop, scope)) {
1072
- slot = sprop->slot;
1073
- }
1074
- if (SPROP_MATCH_PARAMS_AFTER_ID(sprop, getter, setter, slot, attrs,
1075
- flags, shortid)) {
1076
- METER(redundantAdds);
1077
- return sprop;
1078
- }
1079
-
1080
- /*
1081
- * If we are clearing sprop to force an existing property to be
1082
- * overwritten (apart from a duplicate formal parameter), we must
1083
- * unlink it from the ancestor line at scope->lastProp, lazily if
1084
- * sprop is not lastProp. And we must remove the entry at *spp,
1085
- * precisely so the lazy "middle delete" fixup code further below
1086
- * won't find sprop in scope->table, in spite of sprop being on
1087
- * the ancestor line.
1088
- *
1089
- * When we finally succeed in finding or creating a new sprop
1090
- * and storing its pointer at *spp, we'll use the |overwriting|
1091
- * local saved when we first looked up id to decide whether we're
1092
- * indeed creating a new entry, or merely overwriting an existing
1093
- * property.
1094
- */
1095
- if (sprop == SCOPE_LAST_PROP(scope)) {
1096
- do {
1097
- SCOPE_REMOVE_LAST_PROP(scope);
1098
- if (!SCOPE_HAD_MIDDLE_DELETE(scope))
1099
- break;
1100
- sprop = SCOPE_LAST_PROP(scope);
1101
- } while (sprop && !SCOPE_HAS_PROPERTY(scope, sprop));
1102
- } else if (!SCOPE_HAD_MIDDLE_DELETE(scope)) {
1103
- /*
1104
- * If we have no hash table yet, we need one now. The middle
1105
- * delete code is simple-minded that way!
1106
- */
1107
- if (!scope->table) {
1108
- if (!CreateScopeTable(cx, scope, JS_TRUE))
1109
- return NULL;
1110
- spp = js_SearchScope(scope, id, JS_TRUE);
1111
- sprop = overwriting = SPROP_FETCH(spp);
1112
- }
1113
- SCOPE_SET_MIDDLE_DELETE(scope);
1114
- }
1115
- SCOPE_MAKE_UNIQUE_SHAPE(cx, scope);
1116
-
1117
- /*
1118
- * If we fail later on trying to find or create a new sprop, we will
1119
- * goto fail_overwrite and restore *spp from |overwriting|. Note that
1120
- * we don't bother to keep scope->removedCount in sync, because we'll
1121
- * fix up *spp and scope->entryCount shortly, no matter how control
1122
- * flow returns from this function.
1123
- */
1124
- if (scope->table)
1125
- SPROP_STORE_PRESERVING_COLLISION(spp, NULL);
1126
- scope->entryCount--;
1127
- CHECK_ANCESTOR_LINE(scope, JS_TRUE);
1128
- sprop = NULL;
1129
- }
1130
-
1131
- if (!sprop) {
1132
- /*
1133
- * If properties were deleted from the middle of the list starting at
1134
- * scope->lastProp, we may need to fork the property tree and squeeze
1135
- * all deleted properties out of scope's ancestor line. Otherwise we
1136
- * risk adding a node with the same id as a "middle" node, violating
1137
- * the rule that properties along an ancestor line have distinct ids.
1138
- */
1139
- if (SCOPE_HAD_MIDDLE_DELETE(scope)) {
1140
- JS_ASSERT(scope->table);
1141
- CHECK_ANCESTOR_LINE(scope, JS_TRUE);
1142
-
1143
- splen = scope->entryCount;
1144
- if (splen == 0) {
1145
- JS_ASSERT(scope->lastProp == NULL);
1146
- } else {
1147
- /*
1148
- * Enumerate live entries in scope->table using a temporary
1149
- * vector, by walking the (possibly sparse, due to deletions)
1150
- * ancestor line from scope->lastProp.
1151
- */
1152
- spvec = (JSScopeProperty **)
1153
- JS_malloc(cx, SCOPE_TABLE_NBYTES(splen));
1154
- if (!spvec)
1155
- goto fail_overwrite;
1156
- i = splen;
1157
- sprop = SCOPE_LAST_PROP(scope);
1158
- JS_ASSERT(sprop);
1159
- do {
1160
- /*
1161
- * NB: test SCOPE_GET_PROPERTY, not SCOPE_HAS_PROPERTY --
1162
- * the latter insists that sprop->id maps to sprop, while
1163
- * the former simply tests whether sprop->id is bound in
1164
- * scope. We must allow for duplicate formal parameters
1165
- * along the ancestor line, and fork them as needed.
1166
- */
1167
- if (!SCOPE_GET_PROPERTY(scope, sprop->id))
1168
- continue;
1169
-
1170
- JS_ASSERT(sprop != overwriting);
1171
- if (i == 0) {
1172
- /*
1173
- * If our original splen estimate, scope->entryCount,
1174
- * is less than the ancestor line height, there must
1175
- * be duplicate formal parameters in this (function
1176
- * object) scope. Count remaining ancestors in order
1177
- * to realloc spvec.
1178
- */
1179
- JSScopeProperty *tmp = sprop;
1180
- do {
1181
- if (SCOPE_GET_PROPERTY(scope, tmp->id))
1182
- i++;
1183
- } while ((tmp = tmp->parent) != NULL);
1184
- spp2 = (JSScopeProperty **)
1185
- JS_realloc(cx, spvec, SCOPE_TABLE_NBYTES(splen+i));
1186
- if (!spp2) {
1187
- JS_free(cx, spvec);
1188
- goto fail_overwrite;
1189
- }
1190
-
1191
- spvec = spp2;
1192
- memmove(spvec + i, spvec, SCOPE_TABLE_NBYTES(splen));
1193
- splen += i;
1194
- }
1195
-
1196
- spvec[--i] = sprop;
1197
- } while ((sprop = sprop->parent) != NULL);
1198
- JS_ASSERT(i == 0);
1199
-
1200
- /*
1201
- * Now loop forward through spvec, forking the property tree
1202
- * whenever we see a "parent gap" due to deletions from scope.
1203
- * NB: sprop is null on first entry to the loop body.
1204
- */
1205
- do {
1206
- if (spvec[i]->parent == sprop) {
1207
- sprop = spvec[i];
1208
- } else {
1209
- sprop = GetPropertyTreeChild(cx, sprop, spvec[i]);
1210
- if (!sprop) {
1211
- JS_free(cx, spvec);
1212
- goto fail_overwrite;
1213
- }
1214
-
1215
- spp2 = js_SearchScope(scope, sprop->id, JS_FALSE);
1216
- JS_ASSERT(SPROP_FETCH(spp2) == spvec[i]);
1217
- SPROP_STORE_PRESERVING_COLLISION(spp2, sprop);
1218
- }
1219
- } while (++i < splen);
1220
- JS_free(cx, spvec);
1221
-
1222
- /*
1223
- * Now sprop points to the last property in scope, where the
1224
- * ancestor line from sprop to the root is dense w.r.t. scope:
1225
- * it contains no nodes not mapped by scope->table, apart from
1226
- * any stinking ECMA-mandated duplicate formal parameters.
1227
- */
1228
- scope->lastProp = sprop;
1229
- CHECK_ANCESTOR_LINE(scope, JS_FALSE);
1230
- JS_RUNTIME_METER(cx->runtime, middleDeleteFixups);
1231
- }
1232
-
1233
- SCOPE_CLR_MIDDLE_DELETE(scope);
1234
- }
1235
-
1236
- /*
1237
- * Aliases share another property's slot, passed in the |slot| param.
1238
- * Shared properties have no slot. Unshared properties that do not
1239
- * alias another property's slot get one here, but may lose it due to
1240
- * a JS_ClearScope call.
1241
- */
1242
- if (!(flags & SPROP_IS_ALIAS)) {
1243
- if (attrs & JSPROP_SHARED) {
1244
- slot = SPROP_INVALID_SLOT;
1245
- } else {
1246
- /*
1247
- * We may have set slot from a nearly-matching sprop, above.
1248
- * If so, we're overwriting that nearly-matching sprop, so we
1249
- * can reuse its slot -- we don't need to allocate a new one.
1250
- * Similarly, we use a specific slot if provided by the caller.
1251
- */
1252
- if (slot == SPROP_INVALID_SLOT &&
1253
- !js_AllocSlot(cx, scope->object, &slot)) {
1254
- goto fail_overwrite;
1255
- }
1256
- }
1257
- }
1258
-
1259
- /*
1260
- * Check for a watchpoint on a deleted property; if one exists, change
1261
- * setter to js_watch_set.
1262
- * XXXbe this could get expensive with lots of watchpoints...
1263
- */
1264
- if (!JS_CLIST_IS_EMPTY(&cx->runtime->watchPointList) &&
1265
- js_FindWatchPoint(cx->runtime, scope, id)) {
1266
- if (overwriting)
1267
- JS_PUSH_TEMP_ROOT_SPROP(cx, overwriting, &tvr);
1268
- setter = js_WrapWatchedSetter(cx, id, attrs, setter);
1269
- if (overwriting)
1270
- JS_POP_TEMP_ROOT(cx, &tvr);
1271
- if (!setter)
1272
- goto fail_overwrite;
1273
- }
1274
-
1275
- /* Find or create a property tree node labeled by our arguments. */
1276
- child.id = id;
1277
- child.getter = getter;
1278
- child.setter = setter;
1279
- child.slot = slot;
1280
- child.attrs = attrs;
1281
- child.flags = flags;
1282
- child.shortid = shortid;
1283
- sprop = GetPropertyTreeChild(cx, scope->lastProp, &child);
1284
- if (!sprop)
1285
- goto fail_overwrite;
1286
-
1287
- /*
1288
- * The scope's shape defaults to its last property's shape, but may
1289
- * be regenerated later as the scope diverges (from the property cache
1290
- * point of view) from the structural type associated with sprop.
1291
- */
1292
- SCOPE_EXTEND_SHAPE(cx, scope, sprop);
1293
-
1294
- /* Store the tree node pointer in the table entry for id. */
1295
- if (scope->table)
1296
- SPROP_STORE_PRESERVING_COLLISION(spp, sprop);
1297
- scope->entryCount++;
1298
- scope->lastProp = sprop;
1299
- CHECK_ANCESTOR_LINE(scope, JS_FALSE);
1300
- #ifdef DEBUG
1301
- if (!overwriting) {
1302
- LIVE_SCOPE_METER(cx, ++cx->runtime->liveScopeProps);
1303
- JS_RUNTIME_METER(cx->runtime, totalScopeProps);
1304
- }
1305
- #endif
1306
-
1307
- /*
1308
- * If we reach the hashing threshold, try to allocate scope->table.
1309
- * If we can't (a rare event, preceded by swapping to death on most
1310
- * modern OSes), stick with linear search rather than whining about
1311
- * this little set-back. Therefore we must test !scope->table and
1312
- * scope->entryCount >= SCOPE_HASH_THRESHOLD, not merely whether the
1313
- * entry count just reached the threshold.
1314
- */
1315
- if (!scope->table && scope->entryCount >= SCOPE_HASH_THRESHOLD)
1316
- (void) CreateScopeTable(cx, scope, JS_FALSE);
1317
- }
1318
-
1319
- METER(adds);
1320
- return sprop;
1321
-
1322
- fail_overwrite:
1323
- if (overwriting) {
1324
- /*
1325
- * We may or may not have forked overwriting out of scope's ancestor
1326
- * line, so we must check (the alternative is to set a flag above, but
1327
- * that hurts the common, non-error case). If we did fork overwriting
1328
- * out, we'll add it back at scope->lastProp. This means enumeration
1329
- * order can change due to a failure to overwrite an id.
1330
- * XXXbe very minor incompatibility
1331
- */
1332
- for (sprop = SCOPE_LAST_PROP(scope); ; sprop = sprop->parent) {
1333
- if (!sprop) {
1334
- sprop = SCOPE_LAST_PROP(scope);
1335
- if (overwriting->parent == sprop) {
1336
- scope->lastProp = overwriting;
1337
- } else {
1338
- sprop = GetPropertyTreeChild(cx, sprop, overwriting);
1339
- if (sprop) {
1340
- JS_ASSERT(sprop != overwriting);
1341
- scope->lastProp = sprop;
1342
- }
1343
- overwriting = sprop;
1344
- }
1345
- break;
1346
- }
1347
- if (sprop == overwriting)
1348
- break;
1349
- }
1350
- if (overwriting) {
1351
- if (scope->table)
1352
- SPROP_STORE_PRESERVING_COLLISION(spp, overwriting);
1353
- scope->entryCount++;
1354
- }
1355
- CHECK_ANCESTOR_LINE(scope, JS_TRUE);
1356
- }
1357
- METER(addFailures);
1358
- return NULL;
1359
- }
1360
-
1361
- JSScopeProperty *
1362
- js_ChangeScopePropertyAttrs(JSContext *cx, JSScope *scope,
1363
- JSScopeProperty *sprop, uintN attrs, uintN mask,
1364
- JSPropertyOp getter, JSPropertyOp setter)
1365
- {
1366
- JSScopeProperty child, *newsprop, **spp;
1367
-
1368
- CHECK_ANCESTOR_LINE(scope, JS_TRUE);
1369
-
1370
- /* Allow only shared (slot-less) => unshared (slot-full) transition. */
1371
- attrs |= sprop->attrs & mask;
1372
- JS_ASSERT(!((attrs ^ sprop->attrs) & JSPROP_SHARED) ||
1373
- !(attrs & JSPROP_SHARED));
1374
- if (getter == JS_PropertyStub)
1375
- getter = NULL;
1376
- if (setter == JS_PropertyStub)
1377
- setter = NULL;
1378
- if (sprop->attrs == attrs &&
1379
- sprop->getter == getter &&
1380
- sprop->setter == setter) {
1381
- return sprop;
1382
- }
1383
-
1384
- child.id = sprop->id;
1385
- child.getter = getter;
1386
- child.setter = setter;
1387
- child.slot = sprop->slot;
1388
- child.attrs = attrs;
1389
- child.flags = sprop->flags;
1390
- child.shortid = sprop->shortid;
1391
-
1392
- if (SCOPE_LAST_PROP(scope) == sprop) {
1393
- /*
1394
- * Optimize the case where the last property added to scope is changed
1395
- * to have a different attrs, getter, or setter. In the last property
1396
- * case, we need not fork the property tree. But since we do not call
1397
- * js_AddScopeProperty, we may need to allocate a new slot directly.
1398
- */
1399
- if ((sprop->attrs & JSPROP_SHARED) && !(attrs & JSPROP_SHARED)) {
1400
- JS_ASSERT(child.slot == SPROP_INVALID_SLOT);
1401
- if (!js_AllocSlot(cx, scope->object, &child.slot))
1402
- return NULL;
1403
- }
1404
-
1405
- newsprop = GetPropertyTreeChild(cx, sprop->parent, &child);
1406
- if (newsprop) {
1407
- spp = js_SearchScope(scope, sprop->id, JS_FALSE);
1408
- JS_ASSERT(SPROP_FETCH(spp) == sprop);
1409
-
1410
- if (scope->table)
1411
- SPROP_STORE_PRESERVING_COLLISION(spp, newsprop);
1412
- scope->lastProp = newsprop;
1413
- CHECK_ANCESTOR_LINE(scope, JS_TRUE);
1414
- }
1415
- } else {
1416
- /*
1417
- * Let js_AddScopeProperty handle this |overwriting| case, including
1418
- * the conservation of sprop->slot (if it's valid). We must not call
1419
- * js_RemoveScopeProperty here, it will free a valid sprop->slot and
1420
- * js_AddScopeProperty won't re-allocate it.
1421
- */
1422
- newsprop = js_AddScopeProperty(cx, scope, child.id,
1423
- child.getter, child.setter, child.slot,
1424
- child.attrs, child.flags, child.shortid);
1425
- }
1426
-
1427
- if (newsprop) {
1428
- if (scope->shape == sprop->shape)
1429
- scope->shape = newsprop->shape;
1430
- else
1431
- SCOPE_MAKE_UNIQUE_SHAPE(cx, scope);
1432
- }
1433
- #ifdef JS_DUMP_PROPTREE_STATS
1434
- else
1435
- METER(changeFailures);
1436
- #endif
1437
- return newsprop;
1438
- }
1439
-
1440
- JSBool
1441
- js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id)
1442
- {
1443
- JSScopeProperty **spp, *stored, *sprop;
1444
- uint32 size;
1445
-
1446
- JS_ASSERT(JS_IS_SCOPE_LOCKED(cx, scope));
1447
- CHECK_ANCESTOR_LINE(scope, JS_TRUE);
1448
- if (SCOPE_IS_SEALED(scope)) {
1449
- ReportReadOnlyScope(cx, scope);
1450
- return JS_FALSE;
1451
- }
1452
- METER(removes);
1453
-
1454
- spp = js_SearchScope(scope, id, JS_FALSE);
1455
- stored = *spp;
1456
- sprop = SPROP_CLEAR_COLLISION(stored);
1457
- if (!sprop) {
1458
- METER(uselessRemoves);
1459
- return JS_TRUE;
1460
- }
1461
-
1462
- /* Convert from a list to a hash so we can handle "middle deletes". */
1463
- if (!scope->table && sprop != scope->lastProp) {
1464
- if (!CreateScopeTable(cx, scope, JS_TRUE))
1465
- return JS_FALSE;
1466
- spp = js_SearchScope(scope, id, JS_FALSE);
1467
- stored = *spp;
1468
- sprop = SPROP_CLEAR_COLLISION(stored);
1469
- }
1470
-
1471
- /* First, if sprop is unshared and not cleared, free its slot number. */
1472
- if (SPROP_HAS_VALID_SLOT(sprop, scope)) {
1473
- js_FreeSlot(cx, scope->object, sprop->slot);
1474
- JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals);
1475
- }
1476
-
1477
- /* Next, remove id by setting its entry to a removed or free sentinel. */
1478
- if (SPROP_HAD_COLLISION(stored)) {
1479
- JS_ASSERT(scope->table);
1480
- *spp = SPROP_REMOVED;
1481
- scope->removedCount++;
1482
- } else {
1483
- METER(removeFrees);
1484
- if (scope->table)
1485
- *spp = NULL;
1486
- }
1487
- scope->entryCount--;
1488
- LIVE_SCOPE_METER(cx, --cx->runtime->liveScopeProps);
1489
-
1490
- /* Update scope->lastProp directly, or set its deferred update flag. */
1491
- if (sprop == SCOPE_LAST_PROP(scope)) {
1492
- do {
1493
- SCOPE_REMOVE_LAST_PROP(scope);
1494
- if (!SCOPE_HAD_MIDDLE_DELETE(scope))
1495
- break;
1496
- sprop = SCOPE_LAST_PROP(scope);
1497
- } while (sprop && !SCOPE_HAS_PROPERTY(scope, sprop));
1498
- } else if (!SCOPE_HAD_MIDDLE_DELETE(scope)) {
1499
- SCOPE_SET_MIDDLE_DELETE(scope);
1500
- }
1501
- SCOPE_MAKE_UNIQUE_SHAPE(cx, scope);
1502
- CHECK_ANCESTOR_LINE(scope, JS_TRUE);
1503
-
1504
- /* Last, consider shrinking scope's table if its load factor is <= .25. */
1505
- size = SCOPE_CAPACITY(scope);
1506
- if (size > MIN_SCOPE_SIZE && scope->entryCount <= size >> 2) {
1507
- METER(shrinks);
1508
- (void) ChangeScope(cx, scope, -1);
1509
- }
1510
-
1511
- return JS_TRUE;
1512
- }
1513
-
1514
- void
1515
- js_ClearScope(JSContext *cx, JSScope *scope)
1516
- {
1517
- CHECK_ANCESTOR_LINE(scope, JS_TRUE);
1518
- LIVE_SCOPE_METER(cx, cx->runtime->liveScopeProps -= scope->entryCount);
1519
-
1520
- if (scope->table)
1521
- free(scope->table);
1522
- SCOPE_CLR_MIDDLE_DELETE(scope);
1523
- InitMinimalScope(scope);
1524
- JS_ATOMIC_INCREMENT(&cx->runtime->propertyRemovals);
1525
- }
1526
-
1527
- void
1528
- js_TraceId(JSTracer *trc, jsid id)
1529
- {
1530
- jsval v;
1531
-
1532
- v = ID_TO_VALUE(id);
1533
- JS_CALL_VALUE_TRACER(trc, v, "id");
1534
- }
1535
-
1536
- #ifdef DEBUG
1537
- static void
1538
- PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize)
1539
- {
1540
- JSScopeProperty *sprop;
1541
- jsid id;
1542
- size_t n;
1543
- const char *name;
1544
-
1545
- JS_ASSERT(trc->debugPrinter == PrintPropertyGetterOrSetter);
1546
- sprop = (JSScopeProperty *)trc->debugPrintArg;
1547
- id = sprop->id;
1548
- name = trc->debugPrintIndex ? js_setter_str : js_getter_str;
1549
-
1550
- if (JSID_IS_ATOM(id)) {
1551
- n = js_PutEscapedString(buf, bufsize - 1,
1552
- ATOM_TO_STRING(JSID_TO_ATOM(id)), 0);
1553
- if (n < bufsize - 1)
1554
- JS_snprintf(buf + n, bufsize - n, " %s", name);
1555
- } else if (JSID_IS_INT(sprop->id)) {
1556
- JS_snprintf(buf, bufsize, "%d %s", JSID_TO_INT(id), name);
1557
- } else {
1558
- JS_snprintf(buf, bufsize, "<object> %s", name);
1559
- }
1560
- }
1561
- #endif
1562
-
1563
-
1564
- void
1565
- js_TraceScopeProperty(JSTracer *trc, JSScopeProperty *sprop)
1566
- {
1567
- if (IS_GC_MARKING_TRACER(trc))
1568
- sprop->flags |= SPROP_MARK;
1569
- TRACE_ID(trc, sprop->id);
1570
-
1571
- #if JS_HAS_GETTER_SETTER
1572
- if (sprop->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
1573
- if (sprop->attrs & JSPROP_GETTER) {
1574
- JS_ASSERT(JSVAL_IS_OBJECT((jsval) sprop->getter));
1575
- JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, sprop, 0);
1576
- JS_CallTracer(trc, JSVAL_TO_OBJECT((jsval) sprop->getter),
1577
- JSTRACE_OBJECT);
1578
- }
1579
- if (sprop->attrs & JSPROP_SETTER) {
1580
- JS_ASSERT(JSVAL_IS_OBJECT((jsval) sprop->setter));
1581
- JS_SET_TRACING_DETAILS(trc, PrintPropertyGetterOrSetter, sprop, 1);
1582
- JS_CallTracer(trc, JSVAL_TO_OBJECT((jsval) sprop->setter),
1583
- JSTRACE_OBJECT);
1584
- }
1585
- }
1586
- #endif /* JS_HAS_GETTER_SETTER */
1587
- }
1588
-
1589
- #ifdef JS_DUMP_PROPTREE_STATS
1590
-
1591
- #include <stdio.h>
1592
-
1593
- static void
1594
- MeterKidCount(JSBasicStats *bs, uintN nkids)
1595
- {
1596
- JS_BASIC_STATS_ACCUM(bs, nkids);
1597
- bs->hist[JS_MIN(nkids, 10)]++;
1598
- }
1599
-
1600
- static void
1601
- MeterPropertyTree(JSBasicStats *bs, JSScopeProperty *node)
1602
- {
1603
- uintN i, nkids;
1604
- JSScopeProperty *kids, *kid;
1605
- PropTreeKidsChunk *chunk;
1606
-
1607
- nkids = 0;
1608
- kids = node->kids;
1609
- if (kids) {
1610
- if (KIDS_IS_CHUNKY(kids)) {
1611
- for (chunk = KIDS_TO_CHUNK(kids); chunk; chunk = chunk->next) {
1612
- for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
1613
- kid = chunk->kids[i];
1614
- if (!kid)
1615
- break;
1616
- MeterPropertyTree(bs, kid);
1617
- nkids++;
1618
- }
1619
- }
1620
- } else {
1621
- MeterPropertyTree(bs, kids);
1622
- nkids = 1;
1623
- }
1624
- }
1625
-
1626
- MeterKidCount(bs, nkids);
1627
- }
1628
-
1629
- JS_STATIC_DLL_CALLBACK(JSDHashOperator)
1630
- js_MeterPropertyTree(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 number,
1631
- void *arg)
1632
- {
1633
- JSPropertyTreeEntry *entry = (JSPropertyTreeEntry *)hdr;
1634
- JSBasicStats *bs = (JSBasicStats *)arg;
1635
-
1636
- MeterPropertyTree(bs, entry->child);
1637
- return JS_DHASH_NEXT;
1638
- }
1639
-
1640
- static void
1641
- DumpSubtree(JSContext *cx, JSScopeProperty *sprop, int level, FILE *fp)
1642
- {
1643
- jsval v;
1644
- JSString *str;
1645
- JSScopeProperty *kids, *kid;
1646
- PropTreeKidsChunk *chunk;
1647
- uintN i;
1648
-
1649
- fprintf(fp, "%*sid ", level, "");
1650
- v = ID_TO_VALUE(sprop->id);
1651
- if (JSID_IS_INT(sprop->id)) {
1652
- fprintf(fp, "%d", JSVAL_TO_INT(v));
1653
- } else {
1654
- if (JSID_IS_ATOM(sprop->id)) {
1655
- str = JSVAL_TO_STRING(v);
1656
- } else {
1657
- JS_ASSERT(JSID_IS_OBJECT(sprop->id));
1658
- str = js_ValueToString(cx, v);
1659
- fputs("object ", fp);
1660
- }
1661
- if (!str)
1662
- fputs("<error>", fp);
1663
- else
1664
- js_FileEscapedString(fp, str, '"');
1665
- }
1666
-
1667
- fprintf(fp, " g/s %p/%p slot %u attrs %x flags %x shortid %d\n",
1668
- (void *) sprop->getter, (void *) sprop->setter, sprop->slot,
1669
- sprop->attrs, sprop->flags, sprop->shortid);
1670
- kids = sprop->kids;
1671
- if (kids) {
1672
- ++level;
1673
- if (KIDS_IS_CHUNKY(kids)) {
1674
- chunk = KIDS_TO_CHUNK(kids);
1675
- do {
1676
- for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
1677
- kid = chunk->kids[i];
1678
- if (!kid)
1679
- break;
1680
- JS_ASSERT(kid->parent == sprop);
1681
- DumpSubtree(cx, kid, level, fp);
1682
- }
1683
- } while ((chunk = chunk->next) != NULL);
1684
- } else {
1685
- kid = kids;
1686
- DumpSubtree(cx, kid, level, fp);
1687
- }
1688
- }
1689
- }
1690
-
1691
- #endif /* JS_DUMP_PROPTREE_STATS */
1692
-
1693
- void
1694
- js_SweepScopeProperties(JSContext *cx)
1695
- {
1696
- JSRuntime *rt = cx->runtime;
1697
- JSArena **ap, *a;
1698
- JSScopeProperty *limit, *sprop, *parent, *kids, *kid;
1699
- uintN liveCount;
1700
- PropTreeKidsChunk *chunk, *nextChunk, *freeChunk;
1701
- uintN i;
1702
-
1703
- #ifdef JS_DUMP_PROPTREE_STATS
1704
- JSBasicStats bs;
1705
- uint32 livePropCapacity = 0, totalLiveCount = 0;
1706
- static FILE *logfp;
1707
- if (!logfp)
1708
- logfp = fopen("/tmp/proptree.stats", "w");
1709
-
1710
- JS_BASIC_STATS_INIT(&bs);
1711
- MeterKidCount(&bs, rt->propertyTreeHash.entryCount);
1712
- JS_DHashTableEnumerate(&rt->propertyTreeHash, js_MeterPropertyTree, &bs);
1713
-
1714
- {
1715
- double props, nodes, mean, sigma;
1716
-
1717
- props = rt->liveScopePropsPreSweep;
1718
- nodes = rt->livePropTreeNodes;
1719
- JS_ASSERT(nodes == bs.sum);
1720
- mean = JS_MeanAndStdDevBS(&bs, &sigma);
1721
-
1722
- fprintf(logfp,
1723
- "props %g nodes %g beta %g meankids %g sigma %g max %u\n",
1724
- props, nodes, nodes / props, mean, sigma, bs.max);
1725
- }
1726
-
1727
- JS_DumpHistogram(&bs, logfp);
1728
- #endif
1729
-
1730
- ap = &rt->propertyArenaPool.first.next;
1731
- while ((a = *ap) != NULL) {
1732
- limit = (JSScopeProperty *) a->avail;
1733
- liveCount = 0;
1734
- for (sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++) {
1735
- /* If the id is null, sprop is already on the freelist. */
1736
- if (sprop->id == JSVAL_NULL)
1737
- continue;
1738
-
1739
- /*
1740
- * If the mark bit is set, sprop is alive, so clear the mark bit
1741
- * and continue the while loop.
1742
- *
1743
- * Regenerate sprop->shape if it hasn't already been refreshed
1744
- * during the mark phase, when live scopes' lastProp members are
1745
- * followed to update both scope->shape and lastProp->shape.
1746
- */
1747
- if (sprop->flags & SPROP_MARK) {
1748
- sprop->flags &= ~SPROP_MARK;
1749
- if (sprop->flags & SPROP_FLAG_SHAPE_REGEN) {
1750
- sprop->flags &= ~SPROP_FLAG_SHAPE_REGEN;
1751
- } else {
1752
- sprop->shape = ++cx->runtime->shapeGen;
1753
- JS_ASSERT(sprop->shape != 0);
1754
- }
1755
- liveCount++;
1756
- continue;
1757
- }
1758
-
1759
- /* Ok, sprop is garbage to collect: unlink it from its parent. */
1760
- freeChunk = RemovePropertyTreeChild(rt, sprop);
1761
-
1762
- /*
1763
- * Take care to reparent all sprop's kids to their grandparent.
1764
- * InsertPropertyTreeChild can potentially fail for two reasons:
1765
- *
1766
- * 1. If parent is null, insertion into the root property hash
1767
- * table may fail. We are forced to leave the kid out of the
1768
- * table (as can already happen with duplicates) but ensure
1769
- * that the kid's parent pointer is set to null.
1770
- *
1771
- * 2. If parent is non-null, allocation of a new KidsChunk can
1772
- * fail. To prevent this from happening, we allow sprops's own
1773
- * chunks to be reused by the grandparent, which removes the
1774
- * need for InsertPropertyTreeChild to malloc a new KidsChunk.
1775
- *
1776
- * If sprop does not have chunky kids, then we rely on the
1777
- * RemovePropertyTreeChild call above (which removed sprop from
1778
- * its parent) either leaving one free entry, or else returning
1779
- * the now-unused chunk to us so we can reuse it.
1780
- *
1781
- * We also require the grandparent to have either no kids or else
1782
- * chunky kids. A single non-chunky kid would force a new chunk to
1783
- * be malloced in some cases (if sprop had a single non-chunky
1784
- * kid, or a multiple of MAX_KIDS_PER_CHUNK kids). Note that
1785
- * RemovePropertyTreeChild never converts a single-entry chunky
1786
- * kid back to a non-chunky kid, so we are assured of correct
1787
- * behaviour.
1788
- */
1789
- kids = sprop->kids;
1790
- if (kids) {
1791
- sprop->kids = NULL;
1792
- parent = sprop->parent;
1793
-
1794
- /* Assert that grandparent has no kids or chunky kids. */
1795
- JS_ASSERT(!parent || !parent->kids ||
1796
- KIDS_IS_CHUNKY(parent->kids));
1797
- if (KIDS_IS_CHUNKY(kids)) {
1798
- chunk = KIDS_TO_CHUNK(kids);
1799
- do {
1800
- nextChunk = chunk->next;
1801
- chunk->next = NULL;
1802
- for (i = 0; i < MAX_KIDS_PER_CHUNK; i++) {
1803
- kid = chunk->kids[i];
1804
- if (!kid)
1805
- break;
1806
- JS_ASSERT(kid->parent == sprop);
1807
-
1808
- /*
1809
- * Clear a space in the kids array for possible
1810
- * re-use by InsertPropertyTreeChild.
1811
- */
1812
- chunk->kids[i] = NULL;
1813
- if (!InsertPropertyTreeChild(rt, parent, kid,
1814
- chunk)) {
1815
- /*
1816
- * This can happen only if we failed to add an
1817
- * entry to the root property hash table.
1818
- */
1819
- JS_ASSERT(!parent);
1820
- kid->parent = NULL;
1821
- }
1822
- }
1823
- if (!chunk->kids[0]) {
1824
- /* The chunk wasn't reused, so we must free it. */
1825
- DestroyPropTreeKidsChunk(rt, chunk);
1826
- }
1827
- } while ((chunk = nextChunk) != NULL);
1828
- } else {
1829
- kid = kids;
1830
- if (!InsertPropertyTreeChild(rt, parent, kid, freeChunk)) {
1831
- /*
1832
- * This can happen only if we failed to add an entry
1833
- * to the root property hash table.
1834
- */
1835
- JS_ASSERT(!parent);
1836
- kid->parent = NULL;
1837
- }
1838
- }
1839
- }
1840
-
1841
- if (freeChunk && !freeChunk->kids[0]) {
1842
- /* The chunk wasn't reused, so we must free it. */
1843
- DestroyPropTreeKidsChunk(rt, freeChunk);
1844
- }
1845
-
1846
- /* Clear id so we know (above) that sprop is on the freelist. */
1847
- sprop->id = JSVAL_NULL;
1848
- FREENODE_INSERT(rt->propertyFreeList, sprop);
1849
- JS_RUNTIME_UNMETER(rt, livePropTreeNodes);
1850
- }
1851
-
1852
- /* If a contains no live properties, return it to the malloc heap. */
1853
- if (liveCount == 0) {
1854
- for (sprop = (JSScopeProperty *) a->base; sprop < limit; sprop++)
1855
- FREENODE_REMOVE(sprop);
1856
- JS_ARENA_DESTROY(&rt->propertyArenaPool, a, ap);
1857
- } else {
1858
- #ifdef JS_DUMP_PROPTREE_STATS
1859
- livePropCapacity += limit - (JSScopeProperty *) a->base;
1860
- totalLiveCount += liveCount;
1861
- #endif
1862
- ap = &a->next;
1863
- }
1864
- }
1865
-
1866
- #ifdef JS_DUMP_PROPTREE_STATS
1867
- fprintf(logfp, "arenautil %g%%\n",
1868
- (totalLiveCount && livePropCapacity)
1869
- ? (totalLiveCount * 100.0) / livePropCapacity
1870
- : 0.0);
1871
-
1872
- #define RATE(f1, f2) (((double)js_scope_stats.f1 / js_scope_stats.f2) * 100.0)
1873
-
1874
- fprintf(logfp, "Scope search stats:\n"
1875
- " searches: %6u\n"
1876
- " hits: %6u %5.2f%% of searches\n"
1877
- " misses: %6u %5.2f%%\n"
1878
- " hashes: %6u %5.2f%%\n"
1879
- " steps: %6u %5.2f%% %5.2f%% of hashes\n"
1880
- " stepHits: %6u %5.2f%% %5.2f%%\n"
1881
- " stepMisses: %6u %5.2f%% %5.2f%%\n"
1882
- " adds: %6u\n"
1883
- " redundantAdds: %6u\n"
1884
- " addFailures: %6u\n"
1885
- " changeFailures: %6u\n"
1886
- " compresses: %6u\n"
1887
- " grows: %6u\n"
1888
- " removes: %6u\n"
1889
- " removeFrees: %6u\n"
1890
- " uselessRemoves: %6u\n"
1891
- " shrinks: %6u\n",
1892
- js_scope_stats.searches,
1893
- js_scope_stats.hits, RATE(hits, searches),
1894
- js_scope_stats.misses, RATE(misses, searches),
1895
- js_scope_stats.hashes, RATE(hashes, searches),
1896
- js_scope_stats.steps, RATE(steps, searches), RATE(steps, hashes),
1897
- js_scope_stats.stepHits,
1898
- RATE(stepHits, searches), RATE(stepHits, hashes),
1899
- js_scope_stats.stepMisses,
1900
- RATE(stepMisses, searches), RATE(stepMisses, hashes),
1901
- js_scope_stats.adds,
1902
- js_scope_stats.redundantAdds,
1903
- js_scope_stats.addFailures,
1904
- js_scope_stats.changeFailures,
1905
- js_scope_stats.compresses,
1906
- js_scope_stats.grows,
1907
- js_scope_stats.removes,
1908
- js_scope_stats.removeFrees,
1909
- js_scope_stats.uselessRemoves,
1910
- js_scope_stats.shrinks);
1911
-
1912
- #undef RATE
1913
-
1914
- fflush(logfp);
1915
- #endif
1916
-
1917
- #ifdef DUMP_PROPERTY_TREE
1918
- {
1919
- FILE *dumpfp = fopen("/tmp/proptree.dump", "w");
1920
- if (dumpfp) {
1921
- JSPropertyTreeEntry *pte, *end;
1922
-
1923
- pte = (JSPropertyTreeEntry *) rt->propertyTreeHash.entryStore;
1924
- end = pte + JS_DHASH_TABLE_SIZE(&rt->propertyTreeHash);
1925
- while (pte < end) {
1926
- if (pte->child)
1927
- DumpSubtree(cx, pte->child, 0, dumpfp);
1928
- pte++;
1929
- }
1930
- fclose(dumpfp);
1931
- }
1932
- }
1933
- #endif
1934
- }
1935
-
1936
- JSBool
1937
- js_InitPropertyTree(JSRuntime *rt)
1938
- {
1939
- if (!JS_DHashTableInit(&rt->propertyTreeHash, &PropertyTreeHashOps, NULL,
1940
- sizeof(JSPropertyTreeEntry), JS_DHASH_MIN_SIZE)) {
1941
- rt->propertyTreeHash.ops = NULL;
1942
- return JS_FALSE;
1943
- }
1944
- JS_INIT_ARENA_POOL(&rt->propertyArenaPool, "properties",
1945
- 256 * sizeof(JSScopeProperty), sizeof(void *), NULL);
1946
- return JS_TRUE;
1947
- }
1948
-
1949
- void
1950
- js_FinishPropertyTree(JSRuntime *rt)
1951
- {
1952
- if (rt->propertyTreeHash.ops) {
1953
- JS_DHashTableFinish(&rt->propertyTreeHash);
1954
- rt->propertyTreeHash.ops = NULL;
1955
- }
1956
- JS_FinishArenaPool(&rt->propertyArenaPool);
1957
- }