johnson 2.0.0.pre1 → 2.0.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
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
- }