johnson 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (371) hide show
  1. data/.autotest +14 -0
  2. data/CHANGELOG.rdoc +11 -0
  3. data/Manifest.txt +370 -0
  4. data/README.rdoc +60 -0
  5. data/Rakefile +42 -0
  6. data/bin/johnson +108 -0
  7. data/docs/MINGW32.mk +124 -0
  8. data/docs/cross-compile.txt +38 -0
  9. data/ext/spidermonkey/context.c +115 -0
  10. data/ext/spidermonkey/context.h +19 -0
  11. data/ext/spidermonkey/conversions.c +320 -0
  12. data/ext/spidermonkey/conversions.h +18 -0
  13. data/ext/spidermonkey/debugger.c +226 -0
  14. data/ext/spidermonkey/debugger.h +9 -0
  15. data/ext/spidermonkey/extconf.rb +30 -0
  16. data/ext/spidermonkey/extensions.c +37 -0
  17. data/ext/spidermonkey/extensions.h +12 -0
  18. data/ext/spidermonkey/global.c +40 -0
  19. data/ext/spidermonkey/global.h +11 -0
  20. data/ext/spidermonkey/idhash.c +16 -0
  21. data/ext/spidermonkey/idhash.h +8 -0
  22. data/ext/spidermonkey/immutable_node.c +1153 -0
  23. data/ext/spidermonkey/immutable_node.c.erb +523 -0
  24. data/ext/spidermonkey/immutable_node.h +22 -0
  25. data/ext/spidermonkey/jroot.h +187 -0
  26. data/ext/spidermonkey/js_land_proxy.c +610 -0
  27. data/ext/spidermonkey/js_land_proxy.h +20 -0
  28. data/ext/spidermonkey/ruby_land_proxy.c +543 -0
  29. data/ext/spidermonkey/ruby_land_proxy.h +17 -0
  30. data/ext/spidermonkey/runtime.c +330 -0
  31. data/ext/spidermonkey/runtime.h +25 -0
  32. data/ext/spidermonkey/spidermonkey.c +20 -0
  33. data/ext/spidermonkey/spidermonkey.h +29 -0
  34. data/johnson.gemspec +44 -0
  35. data/js/johnson/cli.js +30 -0
  36. data/js/johnson/prelude.js +80 -0
  37. data/lib/johnson.rb +55 -0
  38. data/lib/johnson/cli.rb +7 -0
  39. data/lib/johnson/cli/options.rb +67 -0
  40. data/lib/johnson/error.rb +4 -0
  41. data/lib/johnson/nodes.rb +7 -0
  42. data/lib/johnson/nodes/binary_node.rb +65 -0
  43. data/lib/johnson/nodes/for.rb +14 -0
  44. data/lib/johnson/nodes/for_in.rb +12 -0
  45. data/lib/johnson/nodes/function.rb +13 -0
  46. data/lib/johnson/nodes/list.rb +28 -0
  47. data/lib/johnson/nodes/node.rb +68 -0
  48. data/lib/johnson/nodes/ternary_node.rb +20 -0
  49. data/lib/johnson/parser.rb +21 -0
  50. data/lib/johnson/parser/syntax_error.rb +13 -0
  51. data/lib/johnson/runtime.rb +63 -0
  52. data/lib/johnson/spidermonkey/context.rb +10 -0
  53. data/lib/johnson/spidermonkey/debugger.rb +67 -0
  54. data/lib/johnson/spidermonkey/immutable_node.rb +282 -0
  55. data/lib/johnson/spidermonkey/js_land_proxy.rb +62 -0
  56. data/lib/johnson/spidermonkey/mutable_tree_visitor.rb +242 -0
  57. data/lib/johnson/spidermonkey/ruby_land_proxy.rb +54 -0
  58. data/lib/johnson/spidermonkey/runtime.rb +103 -0
  59. data/lib/johnson/version.rb +3 -0
  60. data/lib/johnson/visitable.rb +16 -0
  61. data/lib/johnson/visitors.rb +5 -0
  62. data/lib/johnson/visitors/dot_visitor.rb +169 -0
  63. data/lib/johnson/visitors/ecma_visitor.rb +323 -0
  64. data/lib/johnson/visitors/enumerating_visitor.rb +15 -0
  65. data/lib/johnson/visitors/sexp_visitor.rb +174 -0
  66. data/lib/johnson/visitors/visitor.rb +91 -0
  67. data/lib/rails/init.rb +37 -0
  68. data/lib/tasks/gem.rake +9 -0
  69. data/lib/tasks/parsing.rake +37 -0
  70. data/lib/tasks/testing.rake +36 -0
  71. data/lib/tasks/vendor.rake +20 -0
  72. data/test/helper.rb +55 -0
  73. data/test/johnson/browser_test.rb +43 -0
  74. data/test/johnson/conversions/array_test.rb +32 -0
  75. data/test/johnson/conversions/boolean_test.rb +17 -0
  76. data/test/johnson/conversions/callable_test.rb +34 -0
  77. data/test/johnson/conversions/file_test.rb +15 -0
  78. data/test/johnson/conversions/nil_test.rb +20 -0
  79. data/test/johnson/conversions/number_test.rb +34 -0
  80. data/test/johnson/conversions/regexp_test.rb +24 -0
  81. data/test/johnson/conversions/string_test.rb +26 -0
  82. data/test/johnson/conversions/struct_test.rb +15 -0
  83. data/test/johnson/conversions/symbol_test.rb +19 -0
  84. data/test/johnson/conversions/thread_test.rb +24 -0
  85. data/test/johnson/error_test.rb +9 -0
  86. data/test/johnson/extensions_test.rb +56 -0
  87. data/test/johnson/nodes/array_literal_test.rb +57 -0
  88. data/test/johnson/nodes/array_node_test.rb +26 -0
  89. data/test/johnson/nodes/binary_node_test.rb +61 -0
  90. data/test/johnson/nodes/bracket_access_test.rb +16 -0
  91. data/test/johnson/nodes/delete_test.rb +11 -0
  92. data/test/johnson/nodes/do_while_test.rb +12 -0
  93. data/test/johnson/nodes/dot_accessor_test.rb +15 -0
  94. data/test/johnson/nodes/export_test.rb +9 -0
  95. data/test/johnson/nodes/for_test.rb +54 -0
  96. data/test/johnson/nodes/function_test.rb +71 -0
  97. data/test/johnson/nodes/if_test.rb +41 -0
  98. data/test/johnson/nodes/import_test.rb +13 -0
  99. data/test/johnson/nodes/label_test.rb +19 -0
  100. data/test/johnson/nodes/let_test.rb +31 -0
  101. data/test/johnson/nodes/object_literal_test.rb +110 -0
  102. data/test/johnson/nodes/return_test.rb +16 -0
  103. data/test/johnson/nodes/semi_test.rb +8 -0
  104. data/test/johnson/nodes/switch_test.rb +55 -0
  105. data/test/johnson/nodes/ternary_test.rb +25 -0
  106. data/test/johnson/nodes/throw_test.rb +9 -0
  107. data/test/johnson/nodes/try_node_test.rb +59 -0
  108. data/test/johnson/nodes/typeof_test.rb +11 -0
  109. data/test/johnson/nodes/unary_node_test.rb +23 -0
  110. data/test/johnson/nodes/void_test.rb +11 -0
  111. data/test/johnson/nodes/while_test.rb +26 -0
  112. data/test/johnson/nodes/with_test.rb +10 -0
  113. data/test/johnson/prelude_test.rb +56 -0
  114. data/test/johnson/runtime_test.rb +64 -0
  115. data/test/johnson/spidermonkey/context_test.rb +21 -0
  116. data/test/johnson/spidermonkey/immutable_node_test.rb +34 -0
  117. data/test/johnson/spidermonkey/js_land_proxy_test.rb +236 -0
  118. data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +240 -0
  119. data/test/johnson/spidermonkey/runtime_test.rb +17 -0
  120. data/test/johnson/version_test.rb +13 -0
  121. data/test/johnson/visitors/dot_visitor_test.rb +39 -0
  122. data/test/johnson/visitors/enumerating_visitor_test.rb +12 -0
  123. data/test/johnson_test.rb +16 -0
  124. data/test/parser_test.rb +276 -0
  125. data/vendor/spidermonkey/.cvsignore +9 -0
  126. data/vendor/spidermonkey/Makefile.in +449 -0
  127. data/vendor/spidermonkey/Makefile.ref +365 -0
  128. data/vendor/spidermonkey/README.html +820 -0
  129. data/vendor/spidermonkey/SpiderMonkey.rsp +12 -0
  130. data/vendor/spidermonkey/Y.js +19 -0
  131. data/vendor/spidermonkey/build.mk +43 -0
  132. data/vendor/spidermonkey/config.mk +192 -0
  133. data/vendor/spidermonkey/config/AIX4.1.mk +65 -0
  134. data/vendor/spidermonkey/config/AIX4.2.mk +64 -0
  135. data/vendor/spidermonkey/config/AIX4.3.mk +65 -0
  136. data/vendor/spidermonkey/config/Darwin.mk +83 -0
  137. data/vendor/spidermonkey/config/Darwin1.3.mk +81 -0
  138. data/vendor/spidermonkey/config/Darwin1.4.mk +41 -0
  139. data/vendor/spidermonkey/config/Darwin5.2.mk +81 -0
  140. data/vendor/spidermonkey/config/Darwin5.3.mk +81 -0
  141. data/vendor/spidermonkey/config/HP-UXB.10.10.mk +77 -0
  142. data/vendor/spidermonkey/config/HP-UXB.10.20.mk +77 -0
  143. data/vendor/spidermonkey/config/HP-UXB.11.00.mk +80 -0
  144. data/vendor/spidermonkey/config/IRIX.mk +87 -0
  145. data/vendor/spidermonkey/config/IRIX5.3.mk +44 -0
  146. data/vendor/spidermonkey/config/IRIX6.1.mk +44 -0
  147. data/vendor/spidermonkey/config/IRIX6.2.mk +44 -0
  148. data/vendor/spidermonkey/config/IRIX6.3.mk +44 -0
  149. data/vendor/spidermonkey/config/IRIX6.5.mk +44 -0
  150. data/vendor/spidermonkey/config/Linux_All.mk +103 -0
  151. data/vendor/spidermonkey/config/Mac_OS10.0.mk +82 -0
  152. data/vendor/spidermonkey/config/OSF1V4.0.mk +72 -0
  153. data/vendor/spidermonkey/config/OSF1V5.0.mk +69 -0
  154. data/vendor/spidermonkey/config/SunOS4.1.4.mk +101 -0
  155. data/vendor/spidermonkey/config/SunOS5.10.mk +50 -0
  156. data/vendor/spidermonkey/config/SunOS5.3.mk +91 -0
  157. data/vendor/spidermonkey/config/SunOS5.4.mk +92 -0
  158. data/vendor/spidermonkey/config/SunOS5.5.1.mk +44 -0
  159. data/vendor/spidermonkey/config/SunOS5.5.mk +87 -0
  160. data/vendor/spidermonkey/config/SunOS5.6.mk +89 -0
  161. data/vendor/spidermonkey/config/SunOS5.7.mk +44 -0
  162. data/vendor/spidermonkey/config/SunOS5.8.mk +44 -0
  163. data/vendor/spidermonkey/config/SunOS5.9.mk +44 -0
  164. data/vendor/spidermonkey/config/WINNT4.0.mk +117 -0
  165. data/vendor/spidermonkey/config/WINNT5.0.mk +117 -0
  166. data/vendor/spidermonkey/config/WINNT5.1.mk +117 -0
  167. data/vendor/spidermonkey/config/WINNT5.2.mk +117 -0
  168. data/vendor/spidermonkey/config/WINNT6.0.mk +117 -0
  169. data/vendor/spidermonkey/config/dgux.mk +64 -0
  170. data/vendor/spidermonkey/editline/Makefile.ref +144 -0
  171. data/vendor/spidermonkey/editline/README +83 -0
  172. data/vendor/spidermonkey/editline/editline.3 +175 -0
  173. data/vendor/spidermonkey/editline/editline.c +1369 -0
  174. data/vendor/spidermonkey/editline/editline.h +135 -0
  175. data/vendor/spidermonkey/editline/sysunix.c +182 -0
  176. data/vendor/spidermonkey/editline/unix.h +82 -0
  177. data/vendor/spidermonkey/fdlibm/.cvsignore +7 -0
  178. data/vendor/spidermonkey/fdlibm/Makefile.in +127 -0
  179. data/vendor/spidermonkey/fdlibm/Makefile.ref +192 -0
  180. data/vendor/spidermonkey/fdlibm/e_acos.c +147 -0
  181. data/vendor/spidermonkey/fdlibm/e_acosh.c +105 -0
  182. data/vendor/spidermonkey/fdlibm/e_asin.c +156 -0
  183. data/vendor/spidermonkey/fdlibm/e_atan2.c +165 -0
  184. data/vendor/spidermonkey/fdlibm/e_atanh.c +110 -0
  185. data/vendor/spidermonkey/fdlibm/e_cosh.c +133 -0
  186. data/vendor/spidermonkey/fdlibm/e_exp.c +202 -0
  187. data/vendor/spidermonkey/fdlibm/e_fmod.c +184 -0
  188. data/vendor/spidermonkey/fdlibm/e_gamma.c +71 -0
  189. data/vendor/spidermonkey/fdlibm/e_gamma_r.c +70 -0
  190. data/vendor/spidermonkey/fdlibm/e_hypot.c +173 -0
  191. data/vendor/spidermonkey/fdlibm/e_j0.c +524 -0
  192. data/vendor/spidermonkey/fdlibm/e_j1.c +523 -0
  193. data/vendor/spidermonkey/fdlibm/e_jn.c +315 -0
  194. data/vendor/spidermonkey/fdlibm/e_lgamma.c +71 -0
  195. data/vendor/spidermonkey/fdlibm/e_lgamma_r.c +347 -0
  196. data/vendor/spidermonkey/fdlibm/e_log.c +184 -0
  197. data/vendor/spidermonkey/fdlibm/e_log10.c +134 -0
  198. data/vendor/spidermonkey/fdlibm/e_pow.c +386 -0
  199. data/vendor/spidermonkey/fdlibm/e_rem_pio2.c +222 -0
  200. data/vendor/spidermonkey/fdlibm/e_remainder.c +120 -0
  201. data/vendor/spidermonkey/fdlibm/e_scalb.c +89 -0
  202. data/vendor/spidermonkey/fdlibm/e_sinh.c +122 -0
  203. data/vendor/spidermonkey/fdlibm/e_sqrt.c +497 -0
  204. data/vendor/spidermonkey/fdlibm/fdlibm.h +273 -0
  205. data/vendor/spidermonkey/fdlibm/fdlibm.mak +1453 -0
  206. data/vendor/spidermonkey/fdlibm/fdlibm.mdp +0 -0
  207. data/vendor/spidermonkey/fdlibm/k_cos.c +135 -0
  208. data/vendor/spidermonkey/fdlibm/k_rem_pio2.c +354 -0
  209. data/vendor/spidermonkey/fdlibm/k_sin.c +114 -0
  210. data/vendor/spidermonkey/fdlibm/k_standard.c +785 -0
  211. data/vendor/spidermonkey/fdlibm/k_tan.c +170 -0
  212. data/vendor/spidermonkey/fdlibm/s_asinh.c +101 -0
  213. data/vendor/spidermonkey/fdlibm/s_atan.c +175 -0
  214. data/vendor/spidermonkey/fdlibm/s_cbrt.c +133 -0
  215. data/vendor/spidermonkey/fdlibm/s_ceil.c +120 -0
  216. data/vendor/spidermonkey/fdlibm/s_copysign.c +72 -0
  217. data/vendor/spidermonkey/fdlibm/s_cos.c +118 -0
  218. data/vendor/spidermonkey/fdlibm/s_erf.c +356 -0
  219. data/vendor/spidermonkey/fdlibm/s_expm1.c +267 -0
  220. data/vendor/spidermonkey/fdlibm/s_fabs.c +70 -0
  221. data/vendor/spidermonkey/fdlibm/s_finite.c +71 -0
  222. data/vendor/spidermonkey/fdlibm/s_floor.c +121 -0
  223. data/vendor/spidermonkey/fdlibm/s_frexp.c +99 -0
  224. data/vendor/spidermonkey/fdlibm/s_ilogb.c +85 -0
  225. data/vendor/spidermonkey/fdlibm/s_isnan.c +74 -0
  226. data/vendor/spidermonkey/fdlibm/s_ldexp.c +66 -0
  227. data/vendor/spidermonkey/fdlibm/s_lib_version.c +73 -0
  228. data/vendor/spidermonkey/fdlibm/s_log1p.c +211 -0
  229. data/vendor/spidermonkey/fdlibm/s_logb.c +79 -0
  230. data/vendor/spidermonkey/fdlibm/s_matherr.c +64 -0
  231. data/vendor/spidermonkey/fdlibm/s_modf.c +132 -0
  232. data/vendor/spidermonkey/fdlibm/s_nextafter.c +124 -0
  233. data/vendor/spidermonkey/fdlibm/s_rint.c +131 -0
  234. data/vendor/spidermonkey/fdlibm/s_scalbn.c +107 -0
  235. data/vendor/spidermonkey/fdlibm/s_signgam.c +40 -0
  236. data/vendor/spidermonkey/fdlibm/s_significand.c +68 -0
  237. data/vendor/spidermonkey/fdlibm/s_sin.c +118 -0
  238. data/vendor/spidermonkey/fdlibm/s_tan.c +112 -0
  239. data/vendor/spidermonkey/fdlibm/s_tanh.c +122 -0
  240. data/vendor/spidermonkey/fdlibm/w_acos.c +78 -0
  241. data/vendor/spidermonkey/fdlibm/w_acosh.c +78 -0
  242. data/vendor/spidermonkey/fdlibm/w_asin.c +80 -0
  243. data/vendor/spidermonkey/fdlibm/w_atan2.c +79 -0
  244. data/vendor/spidermonkey/fdlibm/w_atanh.c +81 -0
  245. data/vendor/spidermonkey/fdlibm/w_cosh.c +77 -0
  246. data/vendor/spidermonkey/fdlibm/w_exp.c +88 -0
  247. data/vendor/spidermonkey/fdlibm/w_fmod.c +78 -0
  248. data/vendor/spidermonkey/fdlibm/w_gamma.c +85 -0
  249. data/vendor/spidermonkey/fdlibm/w_gamma_r.c +81 -0
  250. data/vendor/spidermonkey/fdlibm/w_hypot.c +78 -0
  251. data/vendor/spidermonkey/fdlibm/w_j0.c +105 -0
  252. data/vendor/spidermonkey/fdlibm/w_j1.c +106 -0
  253. data/vendor/spidermonkey/fdlibm/w_jn.c +128 -0
  254. data/vendor/spidermonkey/fdlibm/w_lgamma.c +85 -0
  255. data/vendor/spidermonkey/fdlibm/w_lgamma_r.c +81 -0
  256. data/vendor/spidermonkey/fdlibm/w_log.c +78 -0
  257. data/vendor/spidermonkey/fdlibm/w_log10.c +81 -0
  258. data/vendor/spidermonkey/fdlibm/w_pow.c +99 -0
  259. data/vendor/spidermonkey/fdlibm/w_remainder.c +77 -0
  260. data/vendor/spidermonkey/fdlibm/w_scalb.c +95 -0
  261. data/vendor/spidermonkey/fdlibm/w_sinh.c +77 -0
  262. data/vendor/spidermonkey/fdlibm/w_sqrt.c +77 -0
  263. data/vendor/spidermonkey/javascript-trace.d +73 -0
  264. data/vendor/spidermonkey/js.c +3951 -0
  265. data/vendor/spidermonkey/js.mdp +0 -0
  266. data/vendor/spidermonkey/js.msg +308 -0
  267. data/vendor/spidermonkey/js3240.rc +79 -0
  268. data/vendor/spidermonkey/jsOS240.def +654 -0
  269. data/vendor/spidermonkey/jsapi.c +5836 -0
  270. data/vendor/spidermonkey/jsapi.h +2624 -0
  271. data/vendor/spidermonkey/jsarena.c +450 -0
  272. data/vendor/spidermonkey/jsarena.h +318 -0
  273. data/vendor/spidermonkey/jsarray.c +2996 -0
  274. data/vendor/spidermonkey/jsarray.h +127 -0
  275. data/vendor/spidermonkey/jsatom.c +1045 -0
  276. data/vendor/spidermonkey/jsatom.h +442 -0
  277. data/vendor/spidermonkey/jsbit.h +253 -0
  278. data/vendor/spidermonkey/jsbool.c +176 -0
  279. data/vendor/spidermonkey/jsbool.h +73 -0
  280. data/vendor/spidermonkey/jsclist.h +139 -0
  281. data/vendor/spidermonkey/jscntxt.c +1348 -0
  282. data/vendor/spidermonkey/jscntxt.h +1120 -0
  283. data/vendor/spidermonkey/jscompat.h +57 -0
  284. data/vendor/spidermonkey/jsconfig.h +248 -0
  285. data/vendor/spidermonkey/jsconfig.mk +181 -0
  286. data/vendor/spidermonkey/jscpucfg.c +396 -0
  287. data/vendor/spidermonkey/jscpucfg.h +212 -0
  288. data/vendor/spidermonkey/jsdate.c +2390 -0
  289. data/vendor/spidermonkey/jsdate.h +124 -0
  290. data/vendor/spidermonkey/jsdbgapi.c +1802 -0
  291. data/vendor/spidermonkey/jsdbgapi.h +464 -0
  292. data/vendor/spidermonkey/jsdhash.c +868 -0
  293. data/vendor/spidermonkey/jsdhash.h +592 -0
  294. data/vendor/spidermonkey/jsdtoa.c +3167 -0
  295. data/vendor/spidermonkey/jsdtoa.h +130 -0
  296. data/vendor/spidermonkey/jsdtracef.c +317 -0
  297. data/vendor/spidermonkey/jsdtracef.h +77 -0
  298. data/vendor/spidermonkey/jsemit.c +6909 -0
  299. data/vendor/spidermonkey/jsemit.h +741 -0
  300. data/vendor/spidermonkey/jsexn.c +1371 -0
  301. data/vendor/spidermonkey/jsexn.h +96 -0
  302. data/vendor/spidermonkey/jsfile.c +2736 -0
  303. data/vendor/spidermonkey/jsfile.h +56 -0
  304. data/vendor/spidermonkey/jsfile.msg +90 -0
  305. data/vendor/spidermonkey/jsfun.c +2634 -0
  306. data/vendor/spidermonkey/jsfun.h +254 -0
  307. data/vendor/spidermonkey/jsgc.c +3562 -0
  308. data/vendor/spidermonkey/jsgc.h +403 -0
  309. data/vendor/spidermonkey/jshash.c +476 -0
  310. data/vendor/spidermonkey/jshash.h +151 -0
  311. data/vendor/spidermonkey/jsify.pl +485 -0
  312. data/vendor/spidermonkey/jsinterp.c +7007 -0
  313. data/vendor/spidermonkey/jsinterp.h +525 -0
  314. data/vendor/spidermonkey/jsinvoke.c +43 -0
  315. data/vendor/spidermonkey/jsiter.c +1067 -0
  316. data/vendor/spidermonkey/jsiter.h +122 -0
  317. data/vendor/spidermonkey/jskeyword.tbl +124 -0
  318. data/vendor/spidermonkey/jskwgen.c +460 -0
  319. data/vendor/spidermonkey/jslibmath.h +266 -0
  320. data/vendor/spidermonkey/jslock.c +1309 -0
  321. data/vendor/spidermonkey/jslock.h +313 -0
  322. data/vendor/spidermonkey/jslocko.asm +60 -0
  323. data/vendor/spidermonkey/jslog2.c +94 -0
  324. data/vendor/spidermonkey/jslong.c +264 -0
  325. data/vendor/spidermonkey/jslong.h +412 -0
  326. data/vendor/spidermonkey/jsmath.c +567 -0
  327. data/vendor/spidermonkey/jsmath.h +57 -0
  328. data/vendor/spidermonkey/jsnum.c +1239 -0
  329. data/vendor/spidermonkey/jsnum.h +283 -0
  330. data/vendor/spidermonkey/jsobj.c +5282 -0
  331. data/vendor/spidermonkey/jsobj.h +709 -0
  332. data/vendor/spidermonkey/jsopcode.c +5245 -0
  333. data/vendor/spidermonkey/jsopcode.h +394 -0
  334. data/vendor/spidermonkey/jsopcode.tbl +523 -0
  335. data/vendor/spidermonkey/jsotypes.h +202 -0
  336. data/vendor/spidermonkey/jsparse.c +6704 -0
  337. data/vendor/spidermonkey/jsparse.h +511 -0
  338. data/vendor/spidermonkey/jsprf.c +1262 -0
  339. data/vendor/spidermonkey/jsprf.h +150 -0
  340. data/vendor/spidermonkey/jsproto.tbl +128 -0
  341. data/vendor/spidermonkey/jsprvtd.h +267 -0
  342. data/vendor/spidermonkey/jspubtd.h +744 -0
  343. data/vendor/spidermonkey/jsregexp.c +4364 -0
  344. data/vendor/spidermonkey/jsregexp.h +183 -0
  345. data/vendor/spidermonkey/jsreops.tbl +145 -0
  346. data/vendor/spidermonkey/jsscan.c +2012 -0
  347. data/vendor/spidermonkey/jsscan.h +387 -0
  348. data/vendor/spidermonkey/jsscope.c +1957 -0
  349. data/vendor/spidermonkey/jsscope.h +418 -0
  350. data/vendor/spidermonkey/jsscript.c +1832 -0
  351. data/vendor/spidermonkey/jsscript.h +287 -0
  352. data/vendor/spidermonkey/jsshell.msg +50 -0
  353. data/vendor/spidermonkey/jsstddef.h +83 -0
  354. data/vendor/spidermonkey/jsstr.c +5005 -0
  355. data/vendor/spidermonkey/jsstr.h +641 -0
  356. data/vendor/spidermonkey/jstypes.h +475 -0
  357. data/vendor/spidermonkey/jsutil.c +345 -0
  358. data/vendor/spidermonkey/jsutil.h +157 -0
  359. data/vendor/spidermonkey/jsxdrapi.c +800 -0
  360. data/vendor/spidermonkey/jsxdrapi.h +218 -0
  361. data/vendor/spidermonkey/jsxml.c +8476 -0
  362. data/vendor/spidermonkey/jsxml.h +349 -0
  363. data/vendor/spidermonkey/lock_SunOS.s +119 -0
  364. data/vendor/spidermonkey/perfect.js +39 -0
  365. data/vendor/spidermonkey/plify_jsdhash.sed +36 -0
  366. data/vendor/spidermonkey/prmjtime.c +846 -0
  367. data/vendor/spidermonkey/prmjtime.h +103 -0
  368. data/vendor/spidermonkey/resource.h +15 -0
  369. data/vendor/spidermonkey/rules.mk +197 -0
  370. data/vendor/spidermonkey/win32.order +384 -0
  371. metadata +513 -0
@@ -0,0 +1,418 @@
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
+ #ifndef jsscope_h___
42
+ #define jsscope_h___
43
+ /*
44
+ * JS symbol tables.
45
+ */
46
+ #include "jstypes.h"
47
+ #include "jslock.h"
48
+ #include "jsobj.h"
49
+ #include "jsprvtd.h"
50
+ #include "jspubtd.h"
51
+
52
+ JS_BEGIN_EXTERN_C
53
+
54
+ /*
55
+ * Given P independent, non-unique properties each of size S words mapped by
56
+ * all scopes in a runtime, construct a property tree of N nodes each of size
57
+ * S+L words (L for tree linkage). A nominal L value is 2 for leftmost-child
58
+ * and right-sibling links. We hope that the N < P by enough that the space
59
+ * overhead of L, and the overhead of scope entries pointing at property tree
60
+ * nodes, is worth it.
61
+ *
62
+ * The tree construction goes as follows. If any empty scope in the runtime
63
+ * has a property X added to it, find or create a node under the tree root
64
+ * labeled X, and set scope->lastProp to point at that node. If any non-empty
65
+ * scope whose most recently added property is labeled Y has another property
66
+ * labeled Z added, find or create a node for Z under the node that was added
67
+ * for Y, and set scope->lastProp to point at that node.
68
+ *
69
+ * A property is labeled by its members' values: id, getter, setter, slot,
70
+ * attributes, tiny or short id, and a field telling for..in order. Note that
71
+ * labels are not unique in the tree, but they are unique among a node's kids
72
+ * (barring rare and benign multi-threaded race condition outcomes, see below)
73
+ * and along any ancestor line from the tree root to a given leaf node (except
74
+ * for the hard case of duplicate formal parameters to a function).
75
+ *
76
+ * Thus the root of the tree represents all empty scopes, and the first ply
77
+ * of the tree represents all scopes containing one property, etc. Each node
78
+ * in the tree can stand for any number of scopes having the same ordered set
79
+ * of properties, where that node was the last added to the scope. (We need
80
+ * not store the root of the tree as a node, and do not -- all we need are
81
+ * links to its kids.)
82
+ *
83
+ * Sidebar on for..in loop order: ECMA requires no particular order, but this
84
+ * implementation has promised and delivered property definition order, and
85
+ * compatibility is king. We could use an order number per property, which
86
+ * would require a sort in js_Enumerate, and an entry order generation number
87
+ * per scope. An order number beats a list, which should be doubly-linked for
88
+ * O(1) delete. An even better scheme is to use a parent link in the property
89
+ * tree, so that the ancestor line can be iterated from scope->lastProp when
90
+ * filling in a JSIdArray from back to front. This parent link also helps the
91
+ * GC to sweep properties iteratively.
92
+ *
93
+ * What if a property Y is deleted from a scope? If Y is the last property in
94
+ * the scope, we simply adjust the scope's lastProp member after we remove the
95
+ * scope's hash-table entry pointing at that property node. The parent link
96
+ * mentioned in the for..in sidebar above makes this adjustment O(1). But if
97
+ * Y comes between X and Z in the scope, then we might have to "fork" the tree
98
+ * at X, leaving X->Y->Z in case other scopes have those properties added in
99
+ * that order; and to finish the fork, we'd add a node labeled Z with the path
100
+ * X->Z, if it doesn't exist. This could lead to lots of extra nodes, and to
101
+ * O(n^2) growth when deleting lots of properties.
102
+ *
103
+ * Rather, for O(1) growth all around, we should share the path X->Y->Z among
104
+ * scopes having those three properties added in that order, and among scopes
105
+ * having only X->Z where Y was deleted. All such scopes have a lastProp that
106
+ * points to the Z child of Y. But a scope in which Y was deleted does not
107
+ * have a table entry for Y, and when iterating that scope by traversing the
108
+ * ancestor line from Z, we will have to test for a table entry for each node,
109
+ * skipping nodes that lack entries.
110
+ *
111
+ * What if we add Y again? X->Y->Z->Y is wrong and we'll enumerate Y twice.
112
+ * Therefore we must fork in such a case, if not earlier. Because delete is
113
+ * "bursty", we should not fork eagerly. Delaying a fork till we are at risk
114
+ * of adding Y after it was deleted already requires a flag in the JSScope, to
115
+ * wit, SCOPE_MIDDLE_DELETE.
116
+ *
117
+ * What about thread safety? If the property tree operations done by requests
118
+ * are find-node and insert-node, then the only hazard is duplicate insertion.
119
+ * This is harmless except for minor bloat. When all requests have ended or
120
+ * been suspended, the GC is free to sweep the tree after marking all nodes
121
+ * reachable from scopes, performing remove-node operations as needed.
122
+ *
123
+ * Is the property tree worth it compared to property storage in each table's
124
+ * entries? To decide, we must find the relation <> between the words used
125
+ * with a property tree and the words required without a tree.
126
+ *
127
+ * Model all scopes as one super-scope of capacity T entries (T a power of 2).
128
+ * Let alpha be the load factor of this double hash-table. With the property
129
+ * tree, each entry in the table is a word-sized pointer to a node that can be
130
+ * shared by many scopes. But all such pointers are overhead compared to the
131
+ * situation without the property tree, where the table stores property nodes
132
+ * directly, as entries each of size S words. With the property tree, we need
133
+ * L=2 extra words per node for siblings and kids pointers. Without the tree,
134
+ * (1-alpha)*S*T words are wasted on free or removed sentinel-entries required
135
+ * by double hashing.
136
+ *
137
+ * Therefore,
138
+ *
139
+ * (property tree) <> (no property tree)
140
+ * N*(S+L) + T <> S*T
141
+ * N*(S+L) + T <> P*S + (1-alpha)*S*T
142
+ * N*(S+L) + alpha*T + (1-alpha)*T <> P*S + (1-alpha)*S*T
143
+ *
144
+ * Note that P is alpha*T by definition, so
145
+ *
146
+ * N*(S+L) + P + (1-alpha)*T <> P*S + (1-alpha)*S*T
147
+ * N*(S+L) <> P*S - P + (1-alpha)*S*T - (1-alpha)*T
148
+ * N*(S+L) <> (P + (1-alpha)*T) * (S-1)
149
+ * N*(S+L) <> (P + (1-alpha)*P/alpha) * (S-1)
150
+ * N*(S+L) <> P * (1/alpha) * (S-1)
151
+ *
152
+ * Let N = P*beta for a compression ratio beta, beta <= 1:
153
+ *
154
+ * P*beta*(S+L) <> P * (1/alpha) * (S-1)
155
+ * beta*(S+L) <> (S-1)/alpha
156
+ * beta <> (S-1)/((S+L)*alpha)
157
+ *
158
+ * For S = 6 (32-bit architectures) and L = 2, the property tree wins iff
159
+ *
160
+ * beta < 5/(8*alpha)
161
+ *
162
+ * We ensure that alpha <= .75, so the property tree wins if beta < .83_. An
163
+ * average beta from recent Mozilla browser startups was around .6.
164
+ *
165
+ * Can we reduce L? Observe that the property tree degenerates into a list of
166
+ * lists if at most one property Y follows X in all scopes. In or near such a
167
+ * case, we waste a word on the right-sibling link outside of the root ply of
168
+ * the tree. Note also that the root ply tends to be large, so O(n^2) growth
169
+ * searching it is likely, indicating the need for hashing (but with increased
170
+ * thread safety costs).
171
+ *
172
+ * If only K out of N nodes in the property tree have more than one child, we
173
+ * could eliminate the sibling link and overlay a children list or hash-table
174
+ * pointer on the leftmost-child link (which would then be either null or an
175
+ * only-child link; the overlay could be tagged in the low bit of the pointer,
176
+ * or flagged elsewhere in the property tree node, although such a flag must
177
+ * not be considered when comparing node labels during tree search).
178
+ *
179
+ * For such a system, L = 1 + (K * averageChildrenTableSize) / N instead of 2.
180
+ * If K << N, L approaches 1 and the property tree wins if beta < .95.
181
+ *
182
+ * We observe that fan-out below the root ply of the property tree appears to
183
+ * have extremely low degree (see the MeterPropertyTree code that histograms
184
+ * child-counts in jsscope.c), so instead of a hash-table we use a linked list
185
+ * of child node pointer arrays ("kid chunks"). The details are isolated in
186
+ * jsscope.c; others must treat JSScopeProperty.kids as opaque. We leave it
187
+ * strongly typed for debug-ability of the common (null or one-kid) cases.
188
+ *
189
+ * One final twist (can you stand it?): the mean number of entries per scope
190
+ * in Mozilla is < 5, with a large standard deviation (~8). Instead of always
191
+ * allocating scope->table, we leave it null while initializing all the other
192
+ * scope members as if it were non-null and minimal-length. Until a property
193
+ * is added that crosses the threshold of 6 or more entries for hashing, or
194
+ * until a "middle delete" occurs, we use linear search from scope->lastProp
195
+ * to find a given id, and save on the space overhead of a hash table.
196
+ */
197
+
198
+ struct JSScope {
199
+ JSObjectMap map; /* base class state */
200
+ #ifdef JS_THREADSAFE
201
+ JSTitle title; /* lock state */
202
+ #endif
203
+ JSObject *object; /* object that owns this scope */
204
+ uint32 shape; /* property cache shape identifier */
205
+ uint8 flags; /* flags, see below */
206
+ int8 hashShift; /* multiplicative hash shift */
207
+ uint16 spare; /* reserved */
208
+ uint32 entryCount; /* number of entries in table */
209
+ uint32 removedCount; /* removed entry sentinels in table */
210
+ JSScopeProperty **table; /* table of ptrs to shared tree nodes */
211
+ JSScopeProperty *lastProp; /* pointer to last property added */
212
+ };
213
+
214
+ #ifdef JS_THREADSAFE
215
+ JS_STATIC_ASSERT(offsetof(JSScope, title) == sizeof(JSObjectMap));
216
+ #endif
217
+
218
+ #define JS_IS_SCOPE_LOCKED(cx, scope) JS_IS_TITLE_LOCKED(cx, &(scope)->title)
219
+
220
+ #define OBJ_SCOPE(obj) ((JSScope *)(obj)->map)
221
+
222
+ #define SCOPE_MAKE_UNIQUE_SHAPE(cx,scope) \
223
+ ((scope)->shape = js_GenerateShape((cx), JS_FALSE, NULL))
224
+
225
+ #define SCOPE_EXTEND_SHAPE(cx,scope,sprop) \
226
+ JS_BEGIN_MACRO \
227
+ if (!(scope)->lastProp || \
228
+ (scope)->shape == (scope)->lastProp->shape) { \
229
+ (scope)->shape = (sprop)->shape; \
230
+ } else { \
231
+ (scope)->shape = js_GenerateShape((cx), JS_FALSE, sprop); \
232
+ } \
233
+ JS_END_MACRO
234
+
235
+ /* By definition, hashShift = JS_DHASH_BITS - log2(capacity). */
236
+ #define SCOPE_CAPACITY(scope) JS_BIT(JS_DHASH_BITS-(scope)->hashShift)
237
+
238
+ /* Scope flags and some macros to hide them from other files than jsscope.c. */
239
+ #define SCOPE_MIDDLE_DELETE 0x0001
240
+ #define SCOPE_SEALED 0x0002
241
+ #define SCOPE_BRANDED 0x0004
242
+
243
+ #define SCOPE_HAD_MIDDLE_DELETE(scope) ((scope)->flags & SCOPE_MIDDLE_DELETE)
244
+ #define SCOPE_SET_MIDDLE_DELETE(scope) ((scope)->flags |= SCOPE_MIDDLE_DELETE)
245
+ #define SCOPE_CLR_MIDDLE_DELETE(scope) ((scope)->flags &= ~SCOPE_MIDDLE_DELETE)
246
+
247
+ #define SCOPE_IS_SEALED(scope) ((scope)->flags & SCOPE_SEALED)
248
+ #define SCOPE_SET_SEALED(scope) ((scope)->flags |= SCOPE_SEALED)
249
+ #if 0
250
+ /*
251
+ * Don't define this, it can't be done safely because JS_LOCK_OBJ will avoid
252
+ * taking the lock if the object owns its scope and the scope is sealed.
253
+ */
254
+ #undef SCOPE_CLR_SEALED(scope) ((scope)->flags &= ~SCOPE_SEALED)
255
+ #endif
256
+
257
+ /*
258
+ * A branded scope's object contains plain old methods (function-valued
259
+ * properties without magic getters and setters), and its scope->shape
260
+ * evolves whenever a function value changes.
261
+ */
262
+ #define SCOPE_IS_BRANDED(scope) ((scope)->flags & SCOPE_BRANDED)
263
+ #define SCOPE_SET_BRANDED(scope) ((scope)->flags |= SCOPE_BRANDED)
264
+ #define SCOPE_CLR_BRANDED(scope) ((scope)->flags &= ~SCOPE_BRANDED)
265
+
266
+ /*
267
+ * A little information hiding for scope->lastProp, in case it ever becomes
268
+ * a tagged pointer again.
269
+ */
270
+ #define SCOPE_LAST_PROP(scope) ((scope)->lastProp)
271
+ #define SCOPE_REMOVE_LAST_PROP(scope) ((scope)->lastProp = \
272
+ (scope)->lastProp->parent)
273
+
274
+ struct JSScopeProperty {
275
+ jsid id; /* int-tagged jsval/untagged JSAtom* */
276
+ JSPropertyOp getter; /* getter and setter hooks or objects */
277
+ JSPropertyOp setter;
278
+ uint32 slot; /* abstract index in object slots */
279
+ uint8 attrs; /* attributes, see jsapi.h JSPROP_* */
280
+ uint8 flags; /* flags, see below for defines */
281
+ int16 shortid; /* tinyid, or local arg/var index */
282
+ JSScopeProperty *parent; /* parent node, reverse for..in order */
283
+ JSScopeProperty *kids; /* null, single child, or a tagged ptr
284
+ to many-kids data structure */
285
+ uint32 shape; /* property cache shape identifier */
286
+ };
287
+
288
+ /* JSScopeProperty pointer tag bit indicating a collision. */
289
+ #define SPROP_COLLISION ((jsuword)1)
290
+ #define SPROP_REMOVED ((JSScopeProperty *) SPROP_COLLISION)
291
+
292
+ /* Macros to get and set sprop pointer values and collision flags. */
293
+ #define SPROP_IS_FREE(sprop) ((sprop) == NULL)
294
+ #define SPROP_IS_REMOVED(sprop) ((sprop) == SPROP_REMOVED)
295
+ #define SPROP_IS_LIVE(sprop) ((sprop) > SPROP_REMOVED)
296
+ #define SPROP_FLAG_COLLISION(spp,sprop) (*(spp) = (JSScopeProperty *) \
297
+ ((jsuword)(sprop) | SPROP_COLLISION))
298
+ #define SPROP_HAD_COLLISION(sprop) ((jsuword)(sprop) & SPROP_COLLISION)
299
+ #define SPROP_FETCH(spp) SPROP_CLEAR_COLLISION(*(spp))
300
+
301
+ #define SPROP_CLEAR_COLLISION(sprop) \
302
+ ((JSScopeProperty *) ((jsuword)(sprop) & ~SPROP_COLLISION))
303
+
304
+ #define SPROP_STORE_PRESERVING_COLLISION(spp, sprop) \
305
+ (*(spp) = (JSScopeProperty *) ((jsuword)(sprop) \
306
+ | SPROP_HAD_COLLISION(*(spp))))
307
+
308
+ /* Bits stored in sprop->flags. */
309
+ #define SPROP_MARK 0x01
310
+ #define SPROP_IS_ALIAS 0x02
311
+ #define SPROP_HAS_SHORTID 0x04
312
+ #define SPROP_FLAG_SHAPE_REGEN 0x08
313
+
314
+ /*
315
+ * If SPROP_HAS_SHORTID is set in sprop->flags, we use sprop->shortid rather
316
+ * than id when calling sprop's getter or setter.
317
+ */
318
+ #define SPROP_USERID(sprop) \
319
+ (((sprop)->flags & SPROP_HAS_SHORTID) ? INT_TO_JSVAL((sprop)->shortid) \
320
+ : ID_TO_VALUE((sprop)->id))
321
+
322
+ #define SPROP_INVALID_SLOT 0xffffffff
323
+
324
+ #define SLOT_IN_SCOPE(slot,scope) ((slot) < (scope)->map.freeslot)
325
+ #define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope)
326
+
327
+ #define SPROP_HAS_STUB_GETTER(sprop) (!(sprop)->getter)
328
+ #define SPROP_HAS_STUB_SETTER(sprop) (!(sprop)->setter)
329
+
330
+ /*
331
+ * NB: SPROP_GET must not be called if SPROP_HAS_STUB_GETTER(sprop).
332
+ */
333
+ #define SPROP_GET(cx,sprop,obj,obj2,vp) \
334
+ (((sprop)->attrs & JSPROP_GETTER) \
335
+ ? js_InternalGetOrSet(cx, obj, (sprop)->id, \
336
+ OBJECT_TO_JSVAL((sprop)->getter), JSACC_READ, \
337
+ 0, 0, vp) \
338
+ : (sprop)->getter(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp))
339
+
340
+ /*
341
+ * NB: SPROP_SET must not be called if (SPROP_HAS_STUB_SETTER(sprop) &&
342
+ * !(sprop->attrs & JSPROP_GETTER)).
343
+ */
344
+ #define SPROP_SET(cx,sprop,obj,obj2,vp) \
345
+ (((sprop)->attrs & JSPROP_SETTER) \
346
+ ? js_InternalGetOrSet(cx, obj, (sprop)->id, \
347
+ OBJECT_TO_JSVAL((sprop)->setter), JSACC_WRITE, \
348
+ 1, vp, vp) \
349
+ : ((sprop)->attrs & JSPROP_GETTER) \
350
+ ? (JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, \
351
+ JSMSG_GETTER_ONLY, NULL), JS_FALSE) \
352
+ : (sprop)->setter(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp))
353
+
354
+ /* Macro for common expression to test for shared permanent attributes. */
355
+ #define SPROP_IS_SHARED_PERMANENT(sprop) \
356
+ ((~(sprop)->attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0)
357
+
358
+ extern JSScope *
359
+ js_GetMutableScope(JSContext *cx, JSObject *obj);
360
+
361
+ extern JSScope *
362
+ js_NewScope(JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp,
363
+ JSObject *obj);
364
+
365
+ extern void
366
+ js_DestroyScope(JSContext *cx, JSScope *scope);
367
+
368
+ extern JS_FRIEND_API(JSScopeProperty **)
369
+ js_SearchScope(JSScope *scope, jsid id, JSBool adding);
370
+
371
+ #define SCOPE_GET_PROPERTY(scope, id) \
372
+ SPROP_FETCH(js_SearchScope(scope, id, JS_FALSE))
373
+
374
+ #define SCOPE_HAS_PROPERTY(scope, sprop) \
375
+ (SCOPE_GET_PROPERTY(scope, (sprop)->id) == (sprop))
376
+
377
+ extern JSScopeProperty *
378
+ js_AddScopeProperty(JSContext *cx, JSScope *scope, jsid id,
379
+ JSPropertyOp getter, JSPropertyOp setter, uint32 slot,
380
+ uintN attrs, uintN flags, intN shortid);
381
+
382
+ extern JSScopeProperty *
383
+ js_ChangeScopePropertyAttrs(JSContext *cx, JSScope *scope,
384
+ JSScopeProperty *sprop, uintN attrs, uintN mask,
385
+ JSPropertyOp getter, JSPropertyOp setter);
386
+
387
+ extern JSBool
388
+ js_RemoveScopeProperty(JSContext *cx, JSScope *scope, jsid id);
389
+
390
+ extern void
391
+ js_ClearScope(JSContext *cx, JSScope *scope);
392
+
393
+ /*
394
+ * These macros used to inline short code sequences, but they grew over time.
395
+ * We retain them for internal backward compatibility, and in case one or both
396
+ * ever shrink to inline-able size.
397
+ */
398
+ #define TRACE_ID(trc, id) js_TraceId(trc, id)
399
+ #define TRACE_SCOPE_PROPERTY(trc, sprop) js_TraceScopeProperty(trc, sprop)
400
+
401
+ extern void
402
+ js_TraceId(JSTracer *trc, jsid id);
403
+
404
+ extern void
405
+ js_TraceScopeProperty(JSTracer *trc, JSScopeProperty *sprop);
406
+
407
+ extern void
408
+ js_SweepScopeProperties(JSContext *cx);
409
+
410
+ extern JSBool
411
+ js_InitPropertyTree(JSRuntime *rt);
412
+
413
+ extern void
414
+ js_FinishPropertyTree(JSRuntime *rt);
415
+
416
+ JS_END_EXTERN_C
417
+
418
+ #endif /* jsscope_h___ */
@@ -0,0 +1,1832 @@
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 script operations.
43
+ */
44
+ #include "jsstddef.h"
45
+ #include <string.h>
46
+ #include "jstypes.h"
47
+ #include "jsutil.h" /* Added by JSIFY */
48
+ #include "jsprf.h"
49
+ #include "jsapi.h"
50
+ #include "jsatom.h"
51
+ #include "jscntxt.h"
52
+ #include "jsconfig.h"
53
+ #include "jsdbgapi.h"
54
+ #include "jsemit.h"
55
+ #include "jsfun.h"
56
+ #include "jsinterp.h"
57
+ #include "jslock.h"
58
+ #include "jsnum.h"
59
+ #include "jsopcode.h"
60
+ #include "jsparse.h"
61
+ #include "jsscript.h"
62
+ #if JS_HAS_XDR
63
+ #include "jsxdrapi.h"
64
+ #endif
65
+
66
+ #if JS_HAS_SCRIPT_OBJECT
67
+
68
+ static const char js_script_exec_str[] = "Script.prototype.exec";
69
+ static const char js_script_compile_str[] = "Script.prototype.compile";
70
+
71
+ /*
72
+ * This routine requires that obj has been locked previously.
73
+ */
74
+ static jsint
75
+ GetScriptExecDepth(JSContext *cx, JSObject *obj)
76
+ {
77
+ jsval v;
78
+
79
+ JS_ASSERT(JS_IS_OBJ_LOCKED(cx, obj));
80
+ v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_START(&js_ScriptClass));
81
+ return JSVAL_TO_INT(v);
82
+ }
83
+
84
+ static void
85
+ AdjustScriptExecDepth(JSContext *cx, JSObject *obj, jsint delta)
86
+ {
87
+ jsint execDepth;
88
+
89
+ JS_LOCK_OBJ(cx, obj);
90
+ execDepth = GetScriptExecDepth(cx, obj);
91
+ LOCKED_OBJ_SET_SLOT(obj, JSSLOT_START(&js_ScriptClass),
92
+ INT_TO_JSVAL(execDepth + delta));
93
+ JS_UNLOCK_OBJ(cx, obj);
94
+ }
95
+
96
+ #if JS_HAS_TOSOURCE
97
+ static JSBool
98
+ script_toSource(JSContext *cx, uintN argc, jsval *vp)
99
+ {
100
+ JSObject *obj;
101
+ uint32 indent;
102
+ JSScript *script;
103
+ size_t i, j, k, n;
104
+ char buf[16];
105
+ jschar *s, *t;
106
+ JSString *str;
107
+
108
+ obj = JS_THIS_OBJECT(cx, vp);
109
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
110
+ return JS_FALSE;
111
+
112
+ indent = 0;
113
+ if (argc != 0) {
114
+ indent = js_ValueToECMAUint32(cx, &vp[2]);
115
+ if (JSVAL_IS_NULL(vp[2]))
116
+ return JS_FALSE;
117
+ }
118
+
119
+ script = (JSScript *) JS_GetPrivate(cx, obj);
120
+
121
+ /* Let n count the source string length, j the "front porch" length. */
122
+ j = JS_snprintf(buf, sizeof buf, "(new %s(", js_ScriptClass.name);
123
+ n = j + 2;
124
+ if (!script) {
125
+ /* Let k count the constructor argument string length. */
126
+ k = 0;
127
+ s = NULL; /* quell GCC overwarning */
128
+ } else {
129
+ str = JS_DecompileScript(cx, script, "Script.prototype.toSource",
130
+ (uintN)indent);
131
+ if (!str)
132
+ return JS_FALSE;
133
+ str = js_QuoteString(cx, str, '\'');
134
+ if (!str)
135
+ return JS_FALSE;
136
+ JSSTRING_CHARS_AND_LENGTH(str, s, k);
137
+ n += k;
138
+ }
139
+
140
+ /* Allocate the source string and copy into it. */
141
+ t = (jschar *) JS_malloc(cx, (n + 1) * sizeof(jschar));
142
+ if (!t)
143
+ return JS_FALSE;
144
+ for (i = 0; i < j; i++)
145
+ t[i] = buf[i];
146
+ for (j = 0; j < k; i++, j++)
147
+ t[i] = s[j];
148
+ t[i++] = ')';
149
+ t[i++] = ')';
150
+ t[i] = 0;
151
+
152
+ /* Create and return a JS string for t. */
153
+ str = JS_NewUCString(cx, t, n);
154
+ if (!str) {
155
+ JS_free(cx, t);
156
+ return JS_FALSE;
157
+ }
158
+ *vp = STRING_TO_JSVAL(str);
159
+ return JS_TRUE;
160
+ }
161
+ #endif /* JS_HAS_TOSOURCE */
162
+
163
+ static JSBool
164
+ script_toString(JSContext *cx, uintN argc, jsval *vp)
165
+ {
166
+ uint32 indent;
167
+ JSObject *obj;
168
+ JSScript *script;
169
+ JSString *str;
170
+
171
+ indent = 0;
172
+ if (argc != 0) {
173
+ indent = js_ValueToECMAUint32(cx, &vp[2]);
174
+ if (JSVAL_IS_NULL(vp[2]))
175
+ return JS_FALSE;
176
+ }
177
+
178
+ obj = JS_THIS_OBJECT(cx, vp);
179
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
180
+ return JS_FALSE;
181
+ script = (JSScript *) JS_GetPrivate(cx, obj);
182
+ if (!script) {
183
+ *vp = STRING_TO_JSVAL(cx->runtime->emptyString);
184
+ return JS_TRUE;
185
+ }
186
+
187
+ str = JS_DecompileScript(cx, script, "Script.prototype.toString",
188
+ (uintN)indent);
189
+ if (!str)
190
+ return JS_FALSE;
191
+ *vp = STRING_TO_JSVAL(str);
192
+ return JS_TRUE;
193
+ }
194
+
195
+ static JSBool
196
+ script_compile_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
197
+ jsval *rval)
198
+ {
199
+ JSString *str;
200
+ JSObject *scopeobj;
201
+ jsval v;
202
+ JSScript *script, *oldscript;
203
+ JSStackFrame *fp, *caller;
204
+ const char *file;
205
+ uintN line;
206
+ JSPrincipals *principals;
207
+ uint32 tcflags;
208
+ jsint execDepth;
209
+
210
+ /* Make sure obj is a Script object. */
211
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
212
+ return JS_FALSE;
213
+
214
+ /* If no args, leave private undefined and return early. */
215
+ if (argc == 0)
216
+ goto out;
217
+
218
+ /* Otherwise, the first arg is the script source to compile. */
219
+ str = js_ValueToString(cx, argv[0]);
220
+ if (!str)
221
+ return JS_FALSE;
222
+ argv[0] = STRING_TO_JSVAL(str);
223
+
224
+ scopeobj = NULL;
225
+ if (argc >= 2) {
226
+ if (!js_ValueToObject(cx, argv[1], &scopeobj))
227
+ return JS_FALSE;
228
+ argv[1] = OBJECT_TO_JSVAL(scopeobj);
229
+ }
230
+
231
+ /* Compile using the caller's scope chain, which js_Invoke passes to fp. */
232
+ fp = cx->fp;
233
+ caller = JS_GetScriptedCaller(cx, fp);
234
+ JS_ASSERT(!caller || fp->scopeChain == caller->scopeChain);
235
+
236
+ if (caller) {
237
+ if (!scopeobj) {
238
+ scopeobj = js_GetScopeChain(cx, caller);
239
+ if (!scopeobj)
240
+ return JS_FALSE;
241
+ fp->scopeChain = scopeobj; /* for the compiler's benefit */
242
+ }
243
+
244
+ principals = JS_EvalFramePrincipals(cx, fp, caller);
245
+ file = js_ComputeFilename(cx, caller, principals, &line);
246
+ } else {
247
+ file = NULL;
248
+ line = 0;
249
+ principals = NULL;
250
+ }
251
+
252
+ /* Ensure we compile this script with the right (inner) principals. */
253
+ scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_compile_str);
254
+ if (!scopeobj)
255
+ return JS_FALSE;
256
+
257
+ /*
258
+ * Compile the new script using the caller's scope chain, a la eval().
259
+ * Unlike jsobj.c:obj_eval, however, we do not pass TCF_COMPILE_N_GO in
260
+ * tcflags, because compilation is here separated from execution, and the
261
+ * run-time scope chain may not match the compile-time. JSFRAME_EVAL is
262
+ * tested in jsemit.c and jsscan.c to optimize based on identity of run-
263
+ * and compile-time scope.
264
+ */
265
+ fp->flags |= JSFRAME_SCRIPT_OBJECT;
266
+ tcflags = 0;
267
+ script = js_CompileScript(cx, scopeobj, principals, tcflags,
268
+ JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
269
+ NULL, file, line);
270
+ if (!script)
271
+ return JS_FALSE;
272
+
273
+ JS_LOCK_OBJ(cx, obj);
274
+ execDepth = GetScriptExecDepth(cx, obj);
275
+
276
+ /*
277
+ * execDepth must be 0 to allow compilation here, otherwise the JSScript
278
+ * struct can be released while running.
279
+ */
280
+ if (execDepth > 0) {
281
+ JS_UNLOCK_OBJ(cx, obj);
282
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
283
+ JSMSG_COMPILE_EXECED_SCRIPT);
284
+ return JS_FALSE;
285
+ }
286
+
287
+ /* Swap script for obj's old script, if any. */
288
+ v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
289
+ oldscript = !JSVAL_IS_VOID(v) ? JSVAL_TO_PRIVATE(v) : NULL;
290
+ LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script));
291
+ JS_UNLOCK_OBJ(cx, obj);
292
+
293
+ if (oldscript)
294
+ js_DestroyScript(cx, oldscript);
295
+
296
+ script->object = obj;
297
+ js_CallNewScriptHook(cx, script, NULL);
298
+
299
+ out:
300
+ /* Return the object. */
301
+ *rval = OBJECT_TO_JSVAL(obj);
302
+ return JS_TRUE;
303
+ }
304
+
305
+ static JSBool
306
+ script_compile(JSContext *cx, uintN argc, jsval *vp)
307
+ {
308
+ return script_compile_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp);
309
+ }
310
+
311
+ static JSBool
312
+ script_exec_sub(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
313
+ jsval *rval)
314
+ {
315
+ JSObject *scopeobj, *parent;
316
+ JSStackFrame *fp, *caller;
317
+ JSPrincipals *principals;
318
+ JSScript *script;
319
+ JSBool ok;
320
+
321
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv))
322
+ return JS_FALSE;
323
+
324
+ scopeobj = NULL;
325
+ if (argc != 0) {
326
+ if (!js_ValueToObject(cx, argv[0], &scopeobj))
327
+ return JS_FALSE;
328
+ argv[0] = OBJECT_TO_JSVAL(scopeobj);
329
+ }
330
+
331
+ /*
332
+ * Emulate eval() by using caller's this, var object, sharp array, etc.,
333
+ * all propagated by js_Execute via a non-null fourth (down) argument to
334
+ * js_Execute. If there is no scripted caller, js_Execute uses its second
335
+ * (chain) argument to set the exec frame's varobj, thisp, and scopeChain.
336
+ *
337
+ * Unlike eval, which the compiler detects, Script.prototype.exec may be
338
+ * called from a lightweight function, or even from native code (in which
339
+ * case fp->varobj and fp->scopeChain are null). If exec is called from
340
+ * a lightweight function, we will need to get a Call object representing
341
+ * its frame, to act as the var object and scope chain head.
342
+ */
343
+ fp = cx->fp;
344
+ caller = JS_GetScriptedCaller(cx, fp);
345
+ if (caller && !caller->varobj) {
346
+ /* Called from a lightweight function. */
347
+ JS_ASSERT(caller->fun && !JSFUN_HEAVYWEIGHT_TEST(caller->fun->flags));
348
+
349
+ /* Scope chain links from Call object to callee's parent. */
350
+ parent = OBJ_GET_PARENT(cx, caller->callee);
351
+ if (!js_GetCallObject(cx, caller, parent))
352
+ return JS_FALSE;
353
+ }
354
+
355
+ if (!scopeobj) {
356
+ /* No scope object passed in: try to use the caller's scope chain. */
357
+ if (caller) {
358
+ /*
359
+ * Load caller->scopeChain after the conditional js_GetCallObject
360
+ * call above, which resets scopeChain as well as varobj.
361
+ */
362
+ scopeobj = js_GetScopeChain(cx, caller);
363
+ if (!scopeobj)
364
+ return JS_FALSE;
365
+ } else {
366
+ /*
367
+ * Called from native code, so we don't know what scope object to
368
+ * use. We could use parent (see above), but Script.prototype.exec
369
+ * might be a shared/sealed "superglobal" method. A more general
370
+ * approach would use cx->globalObject, which will be the same as
371
+ * exec.__parent__ in the non-superglobal case. In the superglobal
372
+ * case it's the right object: the global, not the superglobal.
373
+ */
374
+ scopeobj = cx->globalObject;
375
+ }
376
+ }
377
+
378
+ scopeobj = js_CheckScopeChainValidity(cx, scopeobj, js_script_exec_str);
379
+ if (!scopeobj)
380
+ return JS_FALSE;
381
+
382
+ /* Keep track of nesting depth for the script. */
383
+ AdjustScriptExecDepth(cx, obj, 1);
384
+
385
+ /* Must get to out label after this */
386
+ script = (JSScript *) JS_GetPrivate(cx, obj);
387
+ if (!script) {
388
+ ok = JS_FALSE;
389
+ goto out;
390
+ }
391
+
392
+ /* Belt-and-braces: check that this script object has access to scopeobj. */
393
+ principals = script->principals;
394
+ ok = js_CheckPrincipalsAccess(cx, scopeobj, principals,
395
+ CLASS_ATOM(cx, Script));
396
+ if (!ok)
397
+ goto out;
398
+
399
+ ok = js_Execute(cx, scopeobj, script, caller, JSFRAME_EVAL, rval);
400
+
401
+ out:
402
+ AdjustScriptExecDepth(cx, obj, -1);
403
+ return ok;
404
+ }
405
+
406
+ static JSBool
407
+ script_exec(JSContext *cx, uintN argc, jsval *vp)
408
+ {
409
+ return script_exec_sub(cx, JS_THIS_OBJECT(cx, vp), argc, vp + 2, vp);
410
+ }
411
+
412
+ #endif /* JS_HAS_SCRIPT_OBJECT */
413
+
414
+ #if JS_HAS_XDR
415
+
416
+ JSBool
417
+ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
418
+ {
419
+ JSContext *cx;
420
+ JSScript *script, *oldscript;
421
+ JSBool ok;
422
+ jsbytecode *code;
423
+ uint32 length, lineno, depth, magic;
424
+ uint32 natoms, nsrcnotes, ntrynotes, nobjects, nregexps, i;
425
+ uint32 prologLength, version;
426
+ JSTempValueRooter tvr;
427
+ JSPrincipals *principals;
428
+ uint32 encodeable;
429
+ JSBool filenameWasSaved;
430
+ jssrcnote *notes, *sn;
431
+
432
+ cx = xdr->cx;
433
+ script = *scriptp;
434
+ nsrcnotes = ntrynotes = natoms = nobjects = nregexps = 0;
435
+ filenameWasSaved = JS_FALSE;
436
+ notes = NULL;
437
+
438
+ if (xdr->mode == JSXDR_ENCODE)
439
+ magic = JSXDR_MAGIC_SCRIPT_CURRENT;
440
+ if (!JS_XDRUint32(xdr, &magic))
441
+ return JS_FALSE;
442
+ if (magic != JSXDR_MAGIC_SCRIPT_CURRENT) {
443
+ /* We do not provide binary compatibility with older scripts. */
444
+ if (!hasMagic) {
445
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
446
+ JSMSG_BAD_SCRIPT_MAGIC);
447
+ return JS_FALSE;
448
+ }
449
+ *hasMagic = JS_FALSE;
450
+ return JS_TRUE;
451
+ }
452
+ if (hasMagic)
453
+ *hasMagic = JS_TRUE;
454
+
455
+ if (xdr->mode == JSXDR_ENCODE) {
456
+ length = script->length;
457
+ prologLength = PTRDIFF(script->main, script->code, jsbytecode);
458
+ JS_ASSERT((int16)script->version != JSVERSION_UNKNOWN);
459
+ version = (uint32)script->version | (script->ngvars << 16);
460
+ lineno = (uint32)script->lineno;
461
+ depth = (uint32)script->depth;
462
+ natoms = (uint32)script->atomMap.length;
463
+
464
+ /* Count the srcnotes, keeping notes pointing at the first one. */
465
+ notes = SCRIPT_NOTES(script);
466
+ for (sn = notes; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn))
467
+ continue;
468
+ nsrcnotes = PTRDIFF(sn, notes, jssrcnote);
469
+ nsrcnotes++; /* room for the terminator */
470
+
471
+ if (script->objectsOffset != 0)
472
+ nobjects = JS_SCRIPT_OBJECTS(script)->length;
473
+ if (script->regexpsOffset != 0)
474
+ nregexps = JS_SCRIPT_REGEXPS(script)->length;
475
+ if (script->trynotesOffset != 0)
476
+ ntrynotes = JS_SCRIPT_TRYNOTES(script)->length;
477
+ }
478
+
479
+ if (!JS_XDRUint32(xdr, &length))
480
+ return JS_FALSE;
481
+ if (!JS_XDRUint32(xdr, &prologLength))
482
+ return JS_FALSE;
483
+ if (!JS_XDRUint32(xdr, &version))
484
+ return JS_FALSE;
485
+
486
+ /*
487
+ * To fuse allocations, we need srcnote, atom, objects, regexp and trynote
488
+ * counts early.
489
+ */
490
+ if (!JS_XDRUint32(xdr, &natoms))
491
+ return JS_FALSE;
492
+ if (!JS_XDRUint32(xdr, &nsrcnotes))
493
+ return JS_FALSE;
494
+ if (!JS_XDRUint32(xdr, &ntrynotes))
495
+ return JS_FALSE;
496
+ if (!JS_XDRUint32(xdr, &nobjects))
497
+ return JS_FALSE;
498
+ if (!JS_XDRUint32(xdr, &nregexps))
499
+ return JS_FALSE;
500
+
501
+ if (xdr->mode == JSXDR_DECODE) {
502
+ script = js_NewScript(cx, length, nsrcnotes, natoms, nobjects, nregexps,
503
+ ntrynotes);
504
+ if (!script)
505
+ return JS_FALSE;
506
+
507
+ script->main += prologLength;
508
+ script->version = (JSVersion) (version & 0xffff);
509
+ script->ngvars = (uint16) (version >> 16);
510
+
511
+ /* If we know nsrcnotes, we allocated space for notes in script. */
512
+ notes = SCRIPT_NOTES(script);
513
+ *scriptp = script;
514
+ JS_PUSH_TEMP_ROOT_SCRIPT(cx, script, &tvr);
515
+ }
516
+
517
+ /*
518
+ * Control hereafter must goto error on failure, in order for the
519
+ * DECODE case to destroy script.
520
+ */
521
+ oldscript = xdr->script;
522
+ code = script->code;
523
+ if (xdr->mode == JSXDR_ENCODE) {
524
+ code = js_UntrapScriptCode(cx, script);
525
+ if (!code)
526
+ goto error;
527
+ }
528
+
529
+ xdr->script = script;
530
+ ok = JS_XDRBytes(xdr, (char *) code, length * sizeof(jsbytecode));
531
+
532
+ if (code != script->code)
533
+ JS_free(cx, code);
534
+
535
+ if (!ok)
536
+ goto error;
537
+
538
+ if (!JS_XDRBytes(xdr, (char *)notes, nsrcnotes * sizeof(jssrcnote)) ||
539
+ !JS_XDRCStringOrNull(xdr, (char **)&script->filename) ||
540
+ !JS_XDRUint32(xdr, &lineno) ||
541
+ !JS_XDRUint32(xdr, &depth)) {
542
+ goto error;
543
+ }
544
+
545
+ if (xdr->mode == JSXDR_ENCODE) {
546
+ principals = script->principals;
547
+ encodeable = (cx->runtime->principalsTranscoder != NULL);
548
+ if (!JS_XDRUint32(xdr, &encodeable))
549
+ goto error;
550
+ if (encodeable &&
551
+ !cx->runtime->principalsTranscoder(xdr, &principals)) {
552
+ goto error;
553
+ }
554
+ } else {
555
+ if (!JS_XDRUint32(xdr, &encodeable))
556
+ goto error;
557
+ if (encodeable) {
558
+ if (!cx->runtime->principalsTranscoder) {
559
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
560
+ JSMSG_CANT_DECODE_PRINCIPALS);
561
+ goto error;
562
+ }
563
+ if (!cx->runtime->principalsTranscoder(xdr, &principals))
564
+ goto error;
565
+ script->principals = principals;
566
+ }
567
+ }
568
+
569
+ if (xdr->mode == JSXDR_DECODE) {
570
+ const char *filename = script->filename;
571
+ if (filename) {
572
+ filename = js_SaveScriptFilename(cx, filename);
573
+ if (!filename)
574
+ goto error;
575
+ JS_free(cx, (void *) script->filename);
576
+ script->filename = filename;
577
+ filenameWasSaved = JS_TRUE;
578
+ }
579
+ script->lineno = (uintN)lineno;
580
+ script->depth = (uintN)depth;
581
+ }
582
+
583
+ for (i = 0; i != natoms; ++i) {
584
+ if (!js_XDRAtom(xdr, &script->atomMap.vector[i]))
585
+ goto error;
586
+ }
587
+
588
+ /*
589
+ * Here looping from 0-to-length to xdr objects is essential. It ensures
590
+ * that block objects from the script->objects will be written and
591
+ * restored in the outer-to-inner order. block_xdrObject uses this to
592
+ * restore the parent chain.
593
+ */
594
+ for (i = 0; i != nobjects; ++i) {
595
+ if (!js_XDRObject(xdr, &JS_SCRIPT_OBJECTS(script)->vector[i]))
596
+ goto error;
597
+ }
598
+ for (i = 0; i != nregexps; ++i) {
599
+ if (!js_XDRObject(xdr, &JS_SCRIPT_REGEXPS(script)->vector[i]))
600
+ goto error;
601
+ }
602
+
603
+ if (ntrynotes != 0) {
604
+ /*
605
+ * We combine tn->kind and tn->stackDepth when serializing as XDR is not
606
+ * efficient when serializing small integer types.
607
+ */
608
+ JSTryNote *tn, *tnfirst;
609
+ uint32 kindAndDepth;
610
+ JS_STATIC_ASSERT(sizeof(tn->kind) == sizeof(uint8));
611
+ JS_STATIC_ASSERT(sizeof(tn->stackDepth) == sizeof(uint16));
612
+
613
+ tnfirst = JS_SCRIPT_TRYNOTES(script)->vector;
614
+ JS_ASSERT(JS_SCRIPT_TRYNOTES(script)->length == ntrynotes);
615
+ tn = tnfirst + ntrynotes;
616
+ do {
617
+ --tn;
618
+ if (xdr->mode == JSXDR_ENCODE) {
619
+ kindAndDepth = ((uint32)tn->kind << 16)
620
+ | (uint32)tn->stackDepth;
621
+ }
622
+ if (!JS_XDRUint32(xdr, &kindAndDepth) ||
623
+ !JS_XDRUint32(xdr, &tn->start) ||
624
+ !JS_XDRUint32(xdr, &tn->length)) {
625
+ goto error;
626
+ }
627
+ if (xdr->mode == JSXDR_DECODE) {
628
+ tn->kind = (uint8)(kindAndDepth >> 16);
629
+ tn->stackDepth = (uint16)kindAndDepth;
630
+ }
631
+ } while (tn != tnfirst);
632
+ }
633
+
634
+ xdr->script = oldscript;
635
+ if (xdr->mode == JSXDR_DECODE)
636
+ JS_POP_TEMP_ROOT(cx, &tvr);
637
+ return JS_TRUE;
638
+
639
+ error:
640
+ if (xdr->mode == JSXDR_DECODE) {
641
+ JS_POP_TEMP_ROOT(cx, &tvr);
642
+ if (script->filename && !filenameWasSaved) {
643
+ JS_free(cx, (void *) script->filename);
644
+ script->filename = NULL;
645
+ }
646
+ js_DestroyScript(cx, script);
647
+ *scriptp = NULL;
648
+ }
649
+ xdr->script = oldscript;
650
+ return JS_FALSE;
651
+ }
652
+
653
+ #if JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW
654
+ /*
655
+ * These cannot be exposed to web content, and chrome does not need them, so
656
+ * we take them out of the Mozilla client altogether. Fortunately, there is
657
+ * no way to serialize a native function (see fun_xdrObject in jsfun.c).
658
+ */
659
+
660
+ static JSBool
661
+ script_freeze(JSContext *cx, uintN argc, jsval *vp)
662
+ {
663
+ JSObject *obj;
664
+ JSXDRState *xdr;
665
+ JSScript *script;
666
+ JSBool ok, hasMagic;
667
+ uint32 len;
668
+ void *buf;
669
+ JSString *str;
670
+
671
+ obj = JS_THIS_OBJECT(cx, vp);
672
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
673
+ return JS_FALSE;
674
+ script = (JSScript *) JS_GetPrivate(cx, obj);
675
+ if (!script)
676
+ return JS_TRUE;
677
+
678
+ /* create new XDR */
679
+ xdr = JS_XDRNewMem(cx, JSXDR_ENCODE);
680
+ if (!xdr)
681
+ return JS_FALSE;
682
+
683
+ /* write */
684
+ ok = js_XDRScript(xdr, &script, &hasMagic);
685
+ if (!ok)
686
+ goto out;
687
+ if (!hasMagic) {
688
+ *vp = JSVAL_VOID;
689
+ goto out;
690
+ }
691
+
692
+ buf = JS_XDRMemGetData(xdr, &len);
693
+ if (!buf) {
694
+ ok = JS_FALSE;
695
+ goto out;
696
+ }
697
+
698
+ JS_ASSERT((jsword)buf % sizeof(jschar) == 0);
699
+ len /= sizeof(jschar);
700
+ #if IS_BIG_ENDIAN
701
+ {
702
+ jschar *chars;
703
+ uint32 i;
704
+
705
+ /* Swap bytes in Unichars to keep frozen strings machine-independent. */
706
+ chars = (jschar *)buf;
707
+ for (i = 0; i < len; i++)
708
+ chars[i] = JSXDR_SWAB16(chars[i]);
709
+ }
710
+ #endif
711
+ str = JS_NewUCStringCopyN(cx, (jschar *)buf, len);
712
+ if (!str) {
713
+ ok = JS_FALSE;
714
+ goto out;
715
+ }
716
+
717
+ *vp = STRING_TO_JSVAL(str);
718
+
719
+ out:
720
+ JS_XDRDestroy(xdr);
721
+ return ok;
722
+ }
723
+
724
+ static JSBool
725
+ script_thaw(JSContext *cx, uintN argc, jsval *vp)
726
+ {
727
+ JSObject *obj;
728
+ JSXDRState *xdr;
729
+ JSString *str;
730
+ void *buf;
731
+ uint32 len;
732
+ jsval v;
733
+ JSScript *script, *oldscript;
734
+ JSBool ok, hasMagic;
735
+ jsint execDepth;
736
+
737
+ obj = JS_THIS_OBJECT(cx, vp);
738
+ if (!JS_InstanceOf(cx, obj, &js_ScriptClass, vp + 2))
739
+ return JS_FALSE;
740
+
741
+ if (argc == 0)
742
+ return JS_TRUE;
743
+ str = js_ValueToString(cx, vp[2]);
744
+ if (!str)
745
+ return JS_FALSE;
746
+ vp[2] = STRING_TO_JSVAL(str);
747
+
748
+ /* create new XDR */
749
+ xdr = JS_XDRNewMem(cx, JSXDR_DECODE);
750
+ if (!xdr)
751
+ return JS_FALSE;
752
+
753
+ JSSTRING_CHARS_AND_LENGTH(str, buf, len);
754
+ #if IS_BIG_ENDIAN
755
+ {
756
+ jschar *from, *to;
757
+ uint32 i;
758
+
759
+ /* Swap bytes in Unichars to keep frozen strings machine-independent. */
760
+ from = (jschar *)buf;
761
+ to = (jschar *) JS_malloc(cx, len * sizeof(jschar));
762
+ if (!to) {
763
+ JS_XDRDestroy(xdr);
764
+ return JS_FALSE;
765
+ }
766
+ for (i = 0; i < len; i++)
767
+ to[i] = JSXDR_SWAB16(from[i]);
768
+ buf = (char *)to;
769
+ }
770
+ #endif
771
+ len *= sizeof(jschar);
772
+ JS_XDRMemSetData(xdr, buf, len);
773
+
774
+ /* XXXbe should magic mismatch be error, or false return value? */
775
+ ok = js_XDRScript(xdr, &script, &hasMagic);
776
+ if (!ok)
777
+ goto out;
778
+ if (!hasMagic) {
779
+ *vp = JSVAL_FALSE;
780
+ goto out;
781
+ }
782
+
783
+ JS_LOCK_OBJ(cx, obj);
784
+ execDepth = GetScriptExecDepth(cx, obj);
785
+
786
+ /*
787
+ * execDepth must be 0 to allow compilation here, otherwise the JSScript
788
+ * struct can be released while running.
789
+ */
790
+ if (execDepth > 0) {
791
+ JS_UNLOCK_OBJ(cx, obj);
792
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
793
+ JSMSG_COMPILE_EXECED_SCRIPT);
794
+ goto out;
795
+ }
796
+
797
+ /* Swap script for obj's old script, if any. */
798
+ v = LOCKED_OBJ_GET_SLOT(obj, JSSLOT_PRIVATE);
799
+ oldscript = !JSVAL_IS_VOID(v) ? JSVAL_TO_PRIVATE(v) : NULL;
800
+ LOCKED_OBJ_SET_SLOT(obj, JSSLOT_PRIVATE, PRIVATE_TO_JSVAL(script));
801
+ JS_UNLOCK_OBJ(cx, obj);
802
+
803
+ if (oldscript)
804
+ js_DestroyScript(cx, oldscript);
805
+
806
+ script->object = obj;
807
+ js_CallNewScriptHook(cx, script, NULL);
808
+
809
+ out:
810
+ /*
811
+ * We reset the buffer to be NULL so that it doesn't free the chars
812
+ * memory owned by str (vp[2]).
813
+ */
814
+ JS_XDRMemSetData(xdr, NULL, 0);
815
+ JS_XDRDestroy(xdr);
816
+ #if IS_BIG_ENDIAN
817
+ JS_free(cx, buf);
818
+ #endif
819
+ *vp = JSVAL_TRUE;
820
+ return ok;
821
+ }
822
+
823
+ static const char js_thaw_str[] = "thaw";
824
+
825
+ #endif /* JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW */
826
+ #endif /* JS_HAS_XDR */
827
+
828
+ #if JS_HAS_SCRIPT_OBJECT
829
+
830
+ static JSFunctionSpec script_methods[] = {
831
+ #if JS_HAS_TOSOURCE
832
+ JS_FN(js_toSource_str, script_toSource, 0,0,0),
833
+ #endif
834
+ JS_FN(js_toString_str, script_toString, 0,0,0),
835
+ JS_FN("compile", script_compile, 0,2,0),
836
+ JS_FN("exec", script_exec, 0,1,0),
837
+ #if JS_HAS_XDR_FREEZE_THAW
838
+ JS_FN("freeze", script_freeze, 0,0,0),
839
+ JS_FN(js_thaw_str, script_thaw, 0,1,0),
840
+ #endif /* JS_HAS_XDR_FREEZE_THAW */
841
+ JS_FS_END
842
+ };
843
+
844
+ #endif /* JS_HAS_SCRIPT_OBJECT */
845
+
846
+ static void
847
+ script_finalize(JSContext *cx, JSObject *obj)
848
+ {
849
+ JSScript *script;
850
+
851
+ script = (JSScript *) JS_GetPrivate(cx, obj);
852
+ if (script)
853
+ js_DestroyScript(cx, script);
854
+ }
855
+
856
+ static JSBool
857
+ script_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
858
+ {
859
+ #if JS_HAS_SCRIPT_OBJECT
860
+ return script_exec_sub(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval);
861
+ #else
862
+ return JS_FALSE;
863
+ #endif
864
+ }
865
+
866
+ static void
867
+ script_trace(JSTracer *trc, JSObject *obj)
868
+ {
869
+ JSScript *script;
870
+
871
+ script = (JSScript *) JS_GetPrivate(trc->context, obj);
872
+ if (script)
873
+ js_TraceScript(trc, script);
874
+ }
875
+
876
+ #if !JS_HAS_SCRIPT_OBJECT
877
+ #define JSProto_Script JSProto_Object
878
+ #endif
879
+
880
+ JS_FRIEND_DATA(JSClass) js_ScriptClass = {
881
+ js_Script_str,
882
+ JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) |
883
+ JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Script),
884
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
885
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, script_finalize,
886
+ NULL, NULL, script_call, NULL,/*XXXbe xdr*/
887
+ NULL, NULL, JS_CLASS_TRACE(script_trace), NULL
888
+ };
889
+
890
+ #if JS_HAS_SCRIPT_OBJECT
891
+
892
+ static JSBool
893
+ Script(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
894
+ {
895
+ /* If not constructing, replace obj with a new Script object. */
896
+ if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
897
+ obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
898
+ if (!obj)
899
+ return JS_FALSE;
900
+
901
+ /*
902
+ * script_compile_sub does not use rval to root its temporaries so we
903
+ * can use it to root obj.
904
+ */
905
+ *rval = OBJECT_TO_JSVAL(obj);
906
+ }
907
+
908
+ if (!JS_SetReservedSlot(cx, obj, 0, INT_TO_JSVAL(0)))
909
+ return JS_FALSE;
910
+
911
+ return script_compile_sub(cx, obj, argc, argv, rval);
912
+ }
913
+
914
+ #if JS_HAS_SCRIPT_OBJECT && JS_HAS_XDR_FREEZE_THAW
915
+
916
+ static JSBool
917
+ script_static_thaw(JSContext *cx, uintN argc, jsval *vp)
918
+ {
919
+ JSObject *obj;
920
+
921
+ obj = js_NewObject(cx, &js_ScriptClass, NULL, NULL);
922
+ if (!obj)
923
+ return JS_FALSE;
924
+ vp[1] = OBJECT_TO_JSVAL(obj);
925
+ if (!script_thaw(cx, vp))
926
+ return JS_FALSE;
927
+ *vp = OBJECT_TO_JSVAL(obj);
928
+ return JS_TRUE;
929
+ }
930
+
931
+ static JSFunctionSpec script_static_methods[] = {
932
+ JS_FN(js_thaw_str, script_static_thaw, 1,1,0),
933
+ JS_FS_END
934
+ };
935
+
936
+ #else /* !JS_HAS_SCRIPT_OBJECT || !JS_HAS_XDR_FREEZE_THAW */
937
+
938
+ #define script_static_methods NULL
939
+
940
+ #endif /* !JS_HAS_SCRIPT_OBJECT || !JS_HAS_XDR_FREEZE_THAW */
941
+
942
+ JSObject *
943
+ js_InitScriptClass(JSContext *cx, JSObject *obj)
944
+ {
945
+ return JS_InitClass(cx, obj, NULL, &js_ScriptClass, Script, 1,
946
+ NULL, script_methods, NULL, script_static_methods);
947
+ }
948
+
949
+ #endif /* JS_HAS_SCRIPT_OBJECT */
950
+
951
+ /*
952
+ * Shared script filename management.
953
+ */
954
+ JS_STATIC_DLL_CALLBACK(int)
955
+ js_compare_strings(const void *k1, const void *k2)
956
+ {
957
+ return strcmp((const char *) k1, (const char *) k2) == 0;
958
+ }
959
+
960
+ /* NB: This struct overlays JSHashEntry -- see jshash.h, do not reorganize. */
961
+ typedef struct ScriptFilenameEntry {
962
+ JSHashEntry *next; /* hash chain linkage */
963
+ JSHashNumber keyHash; /* key hash function result */
964
+ const void *key; /* ptr to filename, below */
965
+ uint32 flags; /* user-defined filename prefix flags */
966
+ JSPackedBool mark; /* GC mark flag */
967
+ char filename[3]; /* two or more bytes, NUL-terminated */
968
+ } ScriptFilenameEntry;
969
+
970
+ JS_STATIC_DLL_CALLBACK(void *)
971
+ js_alloc_table_space(void *priv, size_t size)
972
+ {
973
+ return malloc(size);
974
+ }
975
+
976
+ JS_STATIC_DLL_CALLBACK(void)
977
+ js_free_table_space(void *priv, void *item)
978
+ {
979
+ free(item);
980
+ }
981
+
982
+ JS_STATIC_DLL_CALLBACK(JSHashEntry *)
983
+ js_alloc_sftbl_entry(void *priv, const void *key)
984
+ {
985
+ size_t nbytes = offsetof(ScriptFilenameEntry, filename) +
986
+ strlen((const char *) key) + 1;
987
+
988
+ return (JSHashEntry *) malloc(JS_MAX(nbytes, sizeof(JSHashEntry)));
989
+ }
990
+
991
+ JS_STATIC_DLL_CALLBACK(void)
992
+ js_free_sftbl_entry(void *priv, JSHashEntry *he, uintN flag)
993
+ {
994
+ if (flag != HT_FREE_ENTRY)
995
+ return;
996
+ free(he);
997
+ }
998
+
999
+ static JSHashAllocOps sftbl_alloc_ops = {
1000
+ js_alloc_table_space, js_free_table_space,
1001
+ js_alloc_sftbl_entry, js_free_sftbl_entry
1002
+ };
1003
+
1004
+ JSBool
1005
+ js_InitRuntimeScriptState(JSRuntime *rt)
1006
+ {
1007
+ #ifdef JS_THREADSAFE
1008
+ JS_ASSERT(!rt->scriptFilenameTableLock);
1009
+ rt->scriptFilenameTableLock = JS_NEW_LOCK();
1010
+ if (!rt->scriptFilenameTableLock)
1011
+ return JS_FALSE;
1012
+ #endif
1013
+ JS_ASSERT(!rt->scriptFilenameTable);
1014
+ rt->scriptFilenameTable =
1015
+ JS_NewHashTable(16, JS_HashString, js_compare_strings, NULL,
1016
+ &sftbl_alloc_ops, NULL);
1017
+ if (!rt->scriptFilenameTable) {
1018
+ js_FinishRuntimeScriptState(rt); /* free lock if threadsafe */
1019
+ return JS_FALSE;
1020
+ }
1021
+ JS_INIT_CLIST(&rt->scriptFilenamePrefixes);
1022
+ return JS_TRUE;
1023
+ }
1024
+
1025
+ typedef struct ScriptFilenamePrefix {
1026
+ JSCList links; /* circular list linkage for easy deletion */
1027
+ const char *name; /* pointer to pinned ScriptFilenameEntry string */
1028
+ size_t length; /* prefix string length, precomputed */
1029
+ uint32 flags; /* user-defined flags to inherit from this prefix */
1030
+ } ScriptFilenamePrefix;
1031
+
1032
+ void
1033
+ js_FinishRuntimeScriptState(JSRuntime *rt)
1034
+ {
1035
+ if (rt->scriptFilenameTable) {
1036
+ JS_HashTableDestroy(rt->scriptFilenameTable);
1037
+ rt->scriptFilenameTable = NULL;
1038
+ }
1039
+ #ifdef JS_THREADSAFE
1040
+ if (rt->scriptFilenameTableLock) {
1041
+ JS_DESTROY_LOCK(rt->scriptFilenameTableLock);
1042
+ rt->scriptFilenameTableLock = NULL;
1043
+ }
1044
+ #endif
1045
+ }
1046
+
1047
+ void
1048
+ js_FreeRuntimeScriptState(JSRuntime *rt)
1049
+ {
1050
+ ScriptFilenamePrefix *sfp;
1051
+
1052
+ if (!rt->scriptFilenameTable)
1053
+ return;
1054
+
1055
+ while (!JS_CLIST_IS_EMPTY(&rt->scriptFilenamePrefixes)) {
1056
+ sfp = (ScriptFilenamePrefix *) rt->scriptFilenamePrefixes.next;
1057
+ JS_REMOVE_LINK(&sfp->links);
1058
+ free(sfp);
1059
+ }
1060
+ js_FinishRuntimeScriptState(rt);
1061
+ }
1062
+
1063
+ #ifdef DEBUG_brendan
1064
+ #define DEBUG_SFTBL
1065
+ #endif
1066
+ #ifdef DEBUG_SFTBL
1067
+ size_t sftbl_savings = 0;
1068
+ #endif
1069
+
1070
+ static ScriptFilenameEntry *
1071
+ SaveScriptFilename(JSRuntime *rt, const char *filename, uint32 flags)
1072
+ {
1073
+ JSHashTable *table;
1074
+ JSHashNumber hash;
1075
+ JSHashEntry **hep;
1076
+ ScriptFilenameEntry *sfe;
1077
+ size_t length;
1078
+ JSCList *head, *link;
1079
+ ScriptFilenamePrefix *sfp;
1080
+
1081
+ table = rt->scriptFilenameTable;
1082
+ hash = JS_HashString(filename);
1083
+ hep = JS_HashTableRawLookup(table, hash, filename);
1084
+ sfe = (ScriptFilenameEntry *) *hep;
1085
+ #ifdef DEBUG_SFTBL
1086
+ if (sfe)
1087
+ sftbl_savings += strlen(sfe->filename);
1088
+ #endif
1089
+
1090
+ if (!sfe) {
1091
+ sfe = (ScriptFilenameEntry *)
1092
+ JS_HashTableRawAdd(table, hep, hash, filename, NULL);
1093
+ if (!sfe)
1094
+ return NULL;
1095
+ sfe->key = strcpy(sfe->filename, filename);
1096
+ sfe->flags = 0;
1097
+ sfe->mark = JS_FALSE;
1098
+ }
1099
+
1100
+ /* If saving a prefix, add it to the set in rt->scriptFilenamePrefixes. */
1101
+ if (flags != 0) {
1102
+ /* Search in case filename was saved already; we must be idempotent. */
1103
+ sfp = NULL;
1104
+ length = strlen(filename);
1105
+ for (head = link = &rt->scriptFilenamePrefixes;
1106
+ link->next != head;
1107
+ link = link->next) {
1108
+ /* Lag link behind sfp to insert in non-increasing length order. */
1109
+ sfp = (ScriptFilenamePrefix *) link->next;
1110
+ if (!strcmp(sfp->name, filename))
1111
+ break;
1112
+ if (sfp->length <= length) {
1113
+ sfp = NULL;
1114
+ break;
1115
+ }
1116
+ sfp = NULL;
1117
+ }
1118
+
1119
+ if (!sfp) {
1120
+ /* No such prefix: add one now. */
1121
+ sfp = (ScriptFilenamePrefix *) malloc(sizeof(ScriptFilenamePrefix));
1122
+ if (!sfp)
1123
+ return NULL;
1124
+ JS_INSERT_AFTER(&sfp->links, link);
1125
+ sfp->name = sfe->filename;
1126
+ sfp->length = length;
1127
+ sfp->flags = 0;
1128
+ }
1129
+
1130
+ /*
1131
+ * Accumulate flags in both sfe and sfp: sfe for later access from the
1132
+ * JS_GetScriptedCallerFilenameFlags debug-API, and sfp so that longer
1133
+ * filename entries can inherit by prefix.
1134
+ */
1135
+ sfe->flags |= flags;
1136
+ sfp->flags |= flags;
1137
+ }
1138
+
1139
+ return sfe;
1140
+ }
1141
+
1142
+ const char *
1143
+ js_SaveScriptFilename(JSContext *cx, const char *filename)
1144
+ {
1145
+ JSRuntime *rt;
1146
+ ScriptFilenameEntry *sfe;
1147
+ JSCList *head, *link;
1148
+ ScriptFilenamePrefix *sfp;
1149
+
1150
+ rt = cx->runtime;
1151
+ JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock);
1152
+ sfe = SaveScriptFilename(rt, filename, 0);
1153
+ if (!sfe) {
1154
+ JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
1155
+ JS_ReportOutOfMemory(cx);
1156
+ return NULL;
1157
+ }
1158
+
1159
+ /*
1160
+ * Try to inherit flags by prefix. We assume there won't be more than a
1161
+ * few (dozen! ;-) prefixes, so linear search is tolerable.
1162
+ * XXXbe every time I've assumed that in the JS engine, I've been wrong!
1163
+ */
1164
+ for (head = &rt->scriptFilenamePrefixes, link = head->next;
1165
+ link != head;
1166
+ link = link->next) {
1167
+ sfp = (ScriptFilenamePrefix *) link;
1168
+ if (!strncmp(sfp->name, filename, sfp->length)) {
1169
+ sfe->flags |= sfp->flags;
1170
+ break;
1171
+ }
1172
+ }
1173
+ JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
1174
+ return sfe->filename;
1175
+ }
1176
+
1177
+ const char *
1178
+ js_SaveScriptFilenameRT(JSRuntime *rt, const char *filename, uint32 flags)
1179
+ {
1180
+ ScriptFilenameEntry *sfe;
1181
+
1182
+ /* This may be called very early, via the jsdbgapi.h entry point. */
1183
+ if (!rt->scriptFilenameTable && !js_InitRuntimeScriptState(rt))
1184
+ return NULL;
1185
+
1186
+ JS_ACQUIRE_LOCK(rt->scriptFilenameTableLock);
1187
+ sfe = SaveScriptFilename(rt, filename, flags);
1188
+ JS_RELEASE_LOCK(rt->scriptFilenameTableLock);
1189
+ if (!sfe)
1190
+ return NULL;
1191
+
1192
+ return sfe->filename;
1193
+ }
1194
+
1195
+ /*
1196
+ * Back up from a saved filename by its offset within its hash table entry.
1197
+ */
1198
+ #define FILENAME_TO_SFE(fn) \
1199
+ ((ScriptFilenameEntry *) ((fn) - offsetof(ScriptFilenameEntry, filename)))
1200
+
1201
+ /*
1202
+ * The sfe->key member, redundant given sfe->filename but required by the old
1203
+ * jshash.c code, here gives us a useful sanity check. This assertion will
1204
+ * very likely botch if someone tries to mark a string that wasn't allocated
1205
+ * as an sfe->filename.
1206
+ */
1207
+ #define ASSERT_VALID_SFE(sfe) JS_ASSERT((sfe)->key == (sfe)->filename)
1208
+
1209
+ uint32
1210
+ js_GetScriptFilenameFlags(const char *filename)
1211
+ {
1212
+ ScriptFilenameEntry *sfe;
1213
+
1214
+ sfe = FILENAME_TO_SFE(filename);
1215
+ ASSERT_VALID_SFE(sfe);
1216
+ return sfe->flags;
1217
+ }
1218
+
1219
+ void
1220
+ js_MarkScriptFilename(const char *filename)
1221
+ {
1222
+ ScriptFilenameEntry *sfe;
1223
+
1224
+ sfe = FILENAME_TO_SFE(filename);
1225
+ ASSERT_VALID_SFE(sfe);
1226
+ sfe->mark = JS_TRUE;
1227
+ }
1228
+
1229
+ JS_STATIC_DLL_CALLBACK(intN)
1230
+ js_script_filename_marker(JSHashEntry *he, intN i, void *arg)
1231
+ {
1232
+ ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he;
1233
+
1234
+ sfe->mark = JS_TRUE;
1235
+ return HT_ENUMERATE_NEXT;
1236
+ }
1237
+
1238
+ void
1239
+ js_MarkScriptFilenames(JSRuntime *rt, JSBool keepAtoms)
1240
+ {
1241
+ JSCList *head, *link;
1242
+ ScriptFilenamePrefix *sfp;
1243
+
1244
+ if (!rt->scriptFilenameTable)
1245
+ return;
1246
+
1247
+ if (keepAtoms) {
1248
+ JS_HashTableEnumerateEntries(rt->scriptFilenameTable,
1249
+ js_script_filename_marker,
1250
+ rt);
1251
+ }
1252
+ for (head = &rt->scriptFilenamePrefixes, link = head->next;
1253
+ link != head;
1254
+ link = link->next) {
1255
+ sfp = (ScriptFilenamePrefix *) link;
1256
+ js_MarkScriptFilename(sfp->name);
1257
+ }
1258
+ }
1259
+
1260
+ JS_STATIC_DLL_CALLBACK(intN)
1261
+ js_script_filename_sweeper(JSHashEntry *he, intN i, void *arg)
1262
+ {
1263
+ ScriptFilenameEntry *sfe = (ScriptFilenameEntry *) he;
1264
+
1265
+ if (!sfe->mark)
1266
+ return HT_ENUMERATE_REMOVE;
1267
+ sfe->mark = JS_FALSE;
1268
+ return HT_ENUMERATE_NEXT;
1269
+ }
1270
+
1271
+ void
1272
+ js_SweepScriptFilenames(JSRuntime *rt)
1273
+ {
1274
+ if (!rt->scriptFilenameTable)
1275
+ return;
1276
+
1277
+ JS_HashTableEnumerateEntries(rt->scriptFilenameTable,
1278
+ js_script_filename_sweeper,
1279
+ rt);
1280
+ #ifdef DEBUG_notme
1281
+ #ifdef DEBUG_SFTBL
1282
+ printf("script filename table savings so far: %u\n", sftbl_savings);
1283
+ #endif
1284
+ #endif
1285
+ }
1286
+
1287
+ /*
1288
+ * JSScript data structures memory alignment:
1289
+ *
1290
+ * JSScript
1291
+ * JSObjectArray script objects' descriptor if JSScript.objectsOffset != 0,
1292
+ * use JS_SCRIPT_OBJECTS(script) macro to access it.
1293
+ * JSObjectArray script regexps' descriptor if JSScript.regexpsOffset != 0,
1294
+ * use JS_SCRIPT_REGEXPS(script) macro to access it.
1295
+ * JSTryNoteArray script try notes' descriptor if JSScript.tryNotesOffset
1296
+ * != 0, use JS_SCRIPT_TRYNOTES(script) macro to access it.
1297
+ * JSAtom *a[] array of JSScript.atomMap.length atoms pointed by
1298
+ * JSScript.atomMap.vector if any.
1299
+ * JSObject *o[] array of JS_SCRIPT_OBJECTS(script)->length objects if any
1300
+ * pointed by JS_SCRIPT_OBJECTS(script)->vector.
1301
+ * JSObject *r[] array of JS_SCRIPT_REGEXPS(script)->length regexps if any
1302
+ * pointed by JS_SCRIPT_REGEXPS(script)->vector.
1303
+ * JSTryNote t[] array of JS_SCRIPT_TRYNOTES(script)->length try notes if any
1304
+ * pointed by JS_SCRIPT_TRYNOTES(script)->vector.
1305
+ * jsbytecode b[] script bytecode pointed by JSScript.code.
1306
+ * jssrcnote s[] script source notes, use SCRIPT_NOTES(script) to access it
1307
+ *
1308
+ * The alignment avoids gaps between entries as alignment requirement for each
1309
+ * subsequent structure or array is the same or divides the alignment
1310
+ * requirement for the previous one.
1311
+ *
1312
+ * The followings asserts checks that assuming that the alignment requirement
1313
+ * for JSObjectArray and JSTryNoteArray are sizeof(void *) and for JSTryNote
1314
+ * it is sizeof(uint32) as the structure consists of 3 uint32 fields.
1315
+ */
1316
+ JS_STATIC_ASSERT(sizeof(JSScript) % sizeof(void *) == 0);
1317
+ JS_STATIC_ASSERT(sizeof(JSObjectArray) % sizeof(void *) == 0);
1318
+ JS_STATIC_ASSERT(sizeof(JSTryNoteArray) == sizeof(JSObjectArray));
1319
+ JS_STATIC_ASSERT(sizeof(JSAtom *) == sizeof(JSObject *));
1320
+ JS_STATIC_ASSERT(sizeof(JSObject *) % sizeof(uint32) == 0);
1321
+ JS_STATIC_ASSERT(sizeof(JSTryNote) == 3 * sizeof(uint32));
1322
+ JS_STATIC_ASSERT(sizeof(uint32) % sizeof(jsbytecode) == 0);
1323
+ JS_STATIC_ASSERT(sizeof(jsbytecode) % sizeof(jssrcnote) == 0);
1324
+
1325
+ /*
1326
+ * Check that uint8 offset for object, regexp and try note arrays is sufficient.
1327
+ */
1328
+ JS_STATIC_ASSERT(sizeof(JSScript) + 2 * sizeof(JSObjectArray) < JS_BIT(8));
1329
+
1330
+ JSScript *
1331
+ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 natoms,
1332
+ uint32 nobjects, uint32 nregexps, uint32 ntrynotes)
1333
+ {
1334
+ size_t size, vectorSize;
1335
+ JSScript *script;
1336
+ uint8 *cursor;
1337
+
1338
+ size = sizeof(JSScript) +
1339
+ sizeof(JSAtom *) * natoms +
1340
+ length * sizeof(jsbytecode) +
1341
+ nsrcnotes * sizeof(jssrcnote);
1342
+ if (nobjects != 0)
1343
+ size += sizeof(JSObjectArray) + nobjects * sizeof(JSObject *);
1344
+ if (nregexps != 0)
1345
+ size += sizeof(JSObjectArray) + nregexps * sizeof(JSObject *);
1346
+ if (ntrynotes != 0)
1347
+ size += sizeof(JSTryNoteArray) + ntrynotes * sizeof(JSTryNote);
1348
+
1349
+ script = (JSScript *) JS_malloc(cx, size);
1350
+ if (!script)
1351
+ return NULL;
1352
+ memset(script, 0, sizeof(JSScript));
1353
+ script->length = length;
1354
+ script->version = cx->version;
1355
+
1356
+ cursor = (uint8 *)script + sizeof(JSScript);
1357
+ if (nobjects != 0) {
1358
+ script->objectsOffset = (uint8)(cursor - (uint8 *)script);
1359
+ cursor += sizeof(JSObjectArray);
1360
+ }
1361
+ if (nregexps != 0) {
1362
+ script->regexpsOffset = (uint8)(cursor - (uint8 *)script);
1363
+ cursor += sizeof(JSObjectArray);
1364
+ }
1365
+ if (ntrynotes != 0) {
1366
+ script->trynotesOffset = (uint8)(cursor - (uint8 *)script);
1367
+ cursor += sizeof(JSTryNoteArray);
1368
+ }
1369
+
1370
+ if (natoms != 0) {
1371
+ script->atomMap.length = natoms;
1372
+ script->atomMap.vector = (JSAtom **)cursor;
1373
+ vectorSize = natoms * sizeof(script->atomMap.vector[0]);
1374
+
1375
+ /*
1376
+ * Clear object map's vector so the GC tracing can run when not yet
1377
+ * all atoms are copied to the array.
1378
+ */
1379
+ memset(cursor, 0, vectorSize);
1380
+ cursor += vectorSize;
1381
+ }
1382
+ if (nobjects != 0) {
1383
+ JS_SCRIPT_OBJECTS(script)->length = nobjects;
1384
+ JS_SCRIPT_OBJECTS(script)->vector = (JSObject **)cursor;
1385
+ vectorSize = nobjects * sizeof(JS_SCRIPT_OBJECTS(script)->vector[0]);
1386
+ memset(cursor, 0, vectorSize);
1387
+ cursor += vectorSize;
1388
+ }
1389
+ if (nregexps != 0) {
1390
+ JS_SCRIPT_REGEXPS(script)->length = nregexps;
1391
+ JS_SCRIPT_REGEXPS(script)->vector = (JSObject **)cursor;
1392
+ vectorSize = nregexps * sizeof(JS_SCRIPT_REGEXPS(script)->vector[0]);
1393
+ memset(cursor, 0, vectorSize);
1394
+ cursor += vectorSize;
1395
+ }
1396
+ if (ntrynotes != 0) {
1397
+ JS_SCRIPT_TRYNOTES(script)->length = ntrynotes;
1398
+ JS_SCRIPT_TRYNOTES(script)->vector = (JSTryNote *)cursor;
1399
+ vectorSize = ntrynotes * sizeof(JS_SCRIPT_TRYNOTES(script)->vector[0]);
1400
+ #ifdef DEBUG
1401
+ memset(cursor, 0, vectorSize);
1402
+ #endif
1403
+ cursor += vectorSize;
1404
+ }
1405
+
1406
+ script->code = script->main = (jsbytecode *)cursor;
1407
+ JS_ASSERT(cursor +
1408
+ length * sizeof(jsbytecode) +
1409
+ nsrcnotes * sizeof(jssrcnote) ==
1410
+ (uint8 *)script + size);
1411
+
1412
+ #ifdef CHECK_SCRIPT_OWNER
1413
+ script->owner = cx->thread;
1414
+ #endif
1415
+ return script;
1416
+ }
1417
+
1418
+ JSScript *
1419
+ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg)
1420
+ {
1421
+ uint32 mainLength, prologLength, nsrcnotes;
1422
+ JSScript *script;
1423
+ const char *filename;
1424
+ JSFunction *fun;
1425
+
1426
+ /* The counts of indexed things must be checked during code generation. */
1427
+ JS_ASSERT(cg->atomList.count <= INDEX_LIMIT);
1428
+ JS_ASSERT(cg->objectList.length <= INDEX_LIMIT);
1429
+ JS_ASSERT(cg->regexpList.length <= INDEX_LIMIT);
1430
+
1431
+ mainLength = CG_OFFSET(cg);
1432
+ prologLength = CG_PROLOG_OFFSET(cg);
1433
+ CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
1434
+ script = js_NewScript(cx, prologLength + mainLength, nsrcnotes,
1435
+ cg->atomList.count, cg->objectList.length,
1436
+ cg->regexpList.length, cg->ntrynotes);
1437
+ if (!script)
1438
+ return NULL;
1439
+
1440
+ /* Now that we have script, error control flow must go to label bad. */
1441
+ script->main += prologLength;
1442
+ memcpy(script->code, CG_PROLOG_BASE(cg), prologLength * sizeof(jsbytecode));
1443
+ memcpy(script->main, CG_BASE(cg), mainLength * sizeof(jsbytecode));
1444
+ script->ngvars = cg->treeContext.ngvars;
1445
+
1446
+ js_InitAtomMap(cx, &script->atomMap, &cg->atomList);
1447
+
1448
+ filename = cg->treeContext.parseContext->tokenStream.filename;
1449
+ if (filename) {
1450
+ script->filename = js_SaveScriptFilename(cx, filename);
1451
+ if (!script->filename)
1452
+ goto bad;
1453
+ }
1454
+ script->lineno = cg->firstLine;
1455
+ script->depth = cg->maxStackDepth;
1456
+ script->principals = cg->treeContext.parseContext->principals;
1457
+ if (script->principals)
1458
+ JSPRINCIPALS_HOLD(cx, script->principals);
1459
+
1460
+ if (!js_FinishTakingSrcNotes(cx, cg, SCRIPT_NOTES(script)))
1461
+ goto bad;
1462
+ if (cg->ntrynotes != 0)
1463
+ js_FinishTakingTryNotes(cg, JS_SCRIPT_TRYNOTES(script));
1464
+ if (cg->objectList.length != 0)
1465
+ FinishParsedObjects(&cg->objectList, JS_SCRIPT_OBJECTS(script));
1466
+ if (cg->regexpList.length != 0)
1467
+ FinishParsedObjects(&cg->regexpList, JS_SCRIPT_REGEXPS(script));
1468
+
1469
+ /*
1470
+ * We initialize fun->u.script to be the script constructed above
1471
+ * so that the debugger has a valid FUN_SCRIPT(fun).
1472
+ */
1473
+ fun = NULL;
1474
+ if (cg->treeContext.flags & TCF_IN_FUNCTION) {
1475
+ fun = cg->treeContext.fun;
1476
+ JS_ASSERT(FUN_INTERPRETED(fun) && !FUN_SCRIPT(fun));
1477
+ js_FreezeLocalNames(cx, fun);
1478
+ fun->u.i.script = script;
1479
+ #ifdef CHECK_SCRIPT_OWNER
1480
+ script->owner = NULL;
1481
+ #endif
1482
+ if (cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT)
1483
+ fun->flags |= JSFUN_HEAVYWEIGHT;
1484
+ if (fun->flags & JSFUN_HEAVYWEIGHT)
1485
+ ++cg->treeContext.maxScopeDepth;
1486
+ }
1487
+
1488
+ #ifdef JS_SCOPE_DEPTH_METER
1489
+ JS_BASIC_STATS_ACCUM(&cx->runtime->lexicalScopeDepthStats,
1490
+ cg->treeContext.maxScopeDepth);
1491
+ #endif
1492
+
1493
+ /* Tell the debugger about this compiled script. */
1494
+ js_CallNewScriptHook(cx, script, fun);
1495
+ return script;
1496
+
1497
+ bad:
1498
+ js_DestroyScript(cx, script);
1499
+ return NULL;
1500
+ }
1501
+
1502
+ JS_FRIEND_API(void)
1503
+ js_CallNewScriptHook(JSContext *cx, JSScript *script, JSFunction *fun)
1504
+ {
1505
+ JSNewScriptHook hook;
1506
+
1507
+ hook = cx->debugHooks->newScriptHook;
1508
+ if (hook) {
1509
+ JS_KEEP_ATOMS(cx->runtime);
1510
+ hook(cx, script->filename, script->lineno, script, fun,
1511
+ cx->debugHooks->newScriptHookData);
1512
+ JS_UNKEEP_ATOMS(cx->runtime);
1513
+ }
1514
+ }
1515
+
1516
+ JS_FRIEND_API(void)
1517
+ js_CallDestroyScriptHook(JSContext *cx, JSScript *script)
1518
+ {
1519
+ JSDestroyScriptHook hook;
1520
+
1521
+ hook = cx->debugHooks->destroyScriptHook;
1522
+ if (hook)
1523
+ hook(cx, script, cx->debugHooks->destroyScriptHookData);
1524
+ }
1525
+
1526
+ void
1527
+ js_DestroyScript(JSContext *cx, JSScript *script)
1528
+ {
1529
+ js_CallDestroyScriptHook(cx, script);
1530
+ JS_ClearScriptTraps(cx, script);
1531
+
1532
+ if (script->principals)
1533
+ JSPRINCIPALS_DROP(cx, script->principals);
1534
+
1535
+ if (JS_GSN_CACHE(cx).code == script->code)
1536
+ JS_CLEAR_GSN_CACHE(cx);
1537
+
1538
+ /*
1539
+ * The GC flushes all property caches, so no need to purge just the
1540
+ * entries for this script.
1541
+ *
1542
+ * JS_THREADSAFE note: js_FlushPropertyCacheForScript flushes only the
1543
+ * current thread's property cache, so a script not owned by a function
1544
+ * or object, which hands off lifetime management for that script to the
1545
+ * GC, must be used by only one thread over its lifetime.
1546
+ *
1547
+ * This should be an API-compatible change, since a script is never safe
1548
+ * against premature GC if shared among threads without a rooted object
1549
+ * wrapping it to protect the script's mapped atoms against GC. We use
1550
+ * script->owner to enforce this requirement via assertions.
1551
+ */
1552
+ #ifdef CHECK_SCRIPT_OWNER
1553
+ JS_ASSERT_IF(cx->runtime->gcRunning, !script->owner);
1554
+ #endif
1555
+
1556
+ if (!cx->runtime->gcRunning &&
1557
+ !(cx->fp && (cx->fp->flags & JSFRAME_EVAL))) {
1558
+ #ifdef CHECK_SCRIPT_OWNER
1559
+ JS_ASSERT(script->owner == cx->thread);
1560
+ #endif
1561
+ js_FlushPropertyCacheForScript(cx, script);
1562
+ }
1563
+
1564
+ JS_free(cx, script);
1565
+ }
1566
+
1567
+ void
1568
+ js_TraceScript(JSTracer *trc, JSScript *script)
1569
+ {
1570
+ JSAtomMap *map;
1571
+ uintN i, length;
1572
+ JSAtom **vector;
1573
+ jsval v;
1574
+ JSObjectArray *objarray;
1575
+
1576
+ map = &script->atomMap;
1577
+ length = map->length;
1578
+ vector = map->vector;
1579
+ for (i = 0; i < length; i++) {
1580
+ v = ATOM_KEY(vector[i]);
1581
+ if (JSVAL_IS_TRACEABLE(v)) {
1582
+ JS_SET_TRACING_INDEX(trc, "atomMap", i);
1583
+ JS_CallTracer(trc, JSVAL_TO_TRACEABLE(v), JSVAL_TRACE_KIND(v));
1584
+ }
1585
+ }
1586
+
1587
+ if (script->objectsOffset != 0) {
1588
+ objarray = JS_SCRIPT_OBJECTS(script);
1589
+ i = objarray->length;
1590
+ do {
1591
+ --i;
1592
+ if (objarray->vector[i]) {
1593
+ JS_SET_TRACING_INDEX(trc, "objects", i);
1594
+ JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT);
1595
+ }
1596
+ } while (i != 0);
1597
+ }
1598
+
1599
+ if (script->regexpsOffset != 0) {
1600
+ objarray = JS_SCRIPT_REGEXPS(script);
1601
+ i = objarray->length;
1602
+ do {
1603
+ --i;
1604
+ if (objarray->vector[i]) {
1605
+ JS_SET_TRACING_INDEX(trc, "regexps", i);
1606
+ JS_CallTracer(trc, objarray->vector[i], JSTRACE_OBJECT);
1607
+ }
1608
+ } while (i != 0);
1609
+ }
1610
+
1611
+ if (IS_GC_MARKING_TRACER(trc) && script->filename)
1612
+ js_MarkScriptFilename(script->filename);
1613
+ }
1614
+
1615
+ typedef struct GSNCacheEntry {
1616
+ JSDHashEntryHdr hdr;
1617
+ jsbytecode *pc;
1618
+ jssrcnote *sn;
1619
+ } GSNCacheEntry;
1620
+
1621
+ #define GSN_CACHE_THRESHOLD 100
1622
+
1623
+ jssrcnote *
1624
+ js_GetSrcNoteCached(JSContext *cx, JSScript *script, jsbytecode *pc)
1625
+ {
1626
+ ptrdiff_t target, offset;
1627
+ GSNCacheEntry *entry;
1628
+ jssrcnote *sn, *result;
1629
+ uintN nsrcnotes;
1630
+
1631
+
1632
+ target = PTRDIFF(pc, script->code, jsbytecode);
1633
+ if ((uint32)target >= script->length)
1634
+ return NULL;
1635
+
1636
+ if (JS_GSN_CACHE(cx).code == script->code) {
1637
+ JS_METER_GSN_CACHE(cx, hits);
1638
+ entry = (GSNCacheEntry *)
1639
+ JS_DHashTableOperate(&JS_GSN_CACHE(cx).table, pc,
1640
+ JS_DHASH_LOOKUP);
1641
+ return entry->sn;
1642
+ }
1643
+
1644
+ JS_METER_GSN_CACHE(cx, misses);
1645
+ offset = 0;
1646
+ for (sn = SCRIPT_NOTES(script); ; sn = SN_NEXT(sn)) {
1647
+ if (SN_IS_TERMINATOR(sn)) {
1648
+ result = NULL;
1649
+ break;
1650
+ }
1651
+ offset += SN_DELTA(sn);
1652
+ if (offset == target && SN_IS_GETTABLE(sn)) {
1653
+ result = sn;
1654
+ break;
1655
+ }
1656
+ }
1657
+
1658
+ if (JS_GSN_CACHE(cx).code != script->code &&
1659
+ script->length >= GSN_CACHE_THRESHOLD) {
1660
+ JS_CLEAR_GSN_CACHE(cx);
1661
+ nsrcnotes = 0;
1662
+ for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn);
1663
+ sn = SN_NEXT(sn)) {
1664
+ if (SN_IS_GETTABLE(sn))
1665
+ ++nsrcnotes;
1666
+ }
1667
+ if (!JS_DHashTableInit(&JS_GSN_CACHE(cx).table, JS_DHashGetStubOps(),
1668
+ NULL, sizeof(GSNCacheEntry),
1669
+ JS_DHASH_DEFAULT_CAPACITY(nsrcnotes))) {
1670
+ JS_GSN_CACHE(cx).table.ops = NULL;
1671
+ } else {
1672
+ pc = script->code;
1673
+ for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn);
1674
+ sn = SN_NEXT(sn)) {
1675
+ pc += SN_DELTA(sn);
1676
+ if (SN_IS_GETTABLE(sn)) {
1677
+ entry = (GSNCacheEntry *)
1678
+ JS_DHashTableOperate(&JS_GSN_CACHE(cx).table, pc,
1679
+ JS_DHASH_ADD);
1680
+ entry->pc = pc;
1681
+ entry->sn = sn;
1682
+ }
1683
+ }
1684
+ JS_GSN_CACHE(cx).code = script->code;
1685
+ JS_METER_GSN_CACHE(cx, fills);
1686
+ }
1687
+ }
1688
+
1689
+ return result;
1690
+ }
1691
+
1692
+ uintN
1693
+ js_PCToLineNumber(JSContext *cx, JSScript *script, jsbytecode *pc)
1694
+ {
1695
+ JSFunction *fun;
1696
+ uintN lineno;
1697
+ ptrdiff_t offset, target;
1698
+ jssrcnote *sn;
1699
+ JSSrcNoteType type;
1700
+
1701
+ /* Cope with JSStackFrame.pc value prior to entering js_Interpret. */
1702
+ if (!pc)
1703
+ return 0;
1704
+
1705
+ /*
1706
+ * Special case: function definition needs no line number note because
1707
+ * the function's script contains its starting line number.
1708
+ */
1709
+ if (js_CodeSpec[*pc].format & JOF_INDEXBASE)
1710
+ pc += js_CodeSpec[*pc].length;
1711
+ if (*pc == JSOP_DEFFUN) {
1712
+ GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun);
1713
+ return fun->u.i.script->lineno;
1714
+ }
1715
+
1716
+ /*
1717
+ * General case: walk through source notes accumulating their deltas,
1718
+ * keeping track of line-number notes, until we pass the note for pc's
1719
+ * offset within script->code.
1720
+ */
1721
+ lineno = script->lineno;
1722
+ offset = 0;
1723
+ target = PTRDIFF(pc, script->code, jsbytecode);
1724
+ for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
1725
+ offset += SN_DELTA(sn);
1726
+ type = (JSSrcNoteType) SN_TYPE(sn);
1727
+ if (type == SRC_SETLINE) {
1728
+ if (offset <= target)
1729
+ lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
1730
+ } else if (type == SRC_NEWLINE) {
1731
+ if (offset <= target)
1732
+ lineno++;
1733
+ }
1734
+ if (offset > target)
1735
+ break;
1736
+ }
1737
+ return lineno;
1738
+ }
1739
+
1740
+ /* The line number limit is the same as the jssrcnote offset limit. */
1741
+ #define SN_LINE_LIMIT (SN_3BYTE_OFFSET_FLAG << 16)
1742
+
1743
+ jsbytecode *
1744
+ js_LineNumberToPC(JSScript *script, uintN target)
1745
+ {
1746
+ ptrdiff_t offset, best;
1747
+ uintN lineno, bestdiff, diff;
1748
+ jssrcnote *sn;
1749
+ JSSrcNoteType type;
1750
+
1751
+ offset = 0;
1752
+ best = -1;
1753
+ lineno = script->lineno;
1754
+ bestdiff = SN_LINE_LIMIT;
1755
+ for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
1756
+ /*
1757
+ * Exact-match only if offset is not in the prolog; otherwise use
1758
+ * nearest greater-or-equal line number match.
1759
+ */
1760
+ if (lineno == target && script->code + offset >= script->main)
1761
+ goto out;
1762
+ if (lineno >= target) {
1763
+ diff = lineno - target;
1764
+ if (diff < bestdiff) {
1765
+ bestdiff = diff;
1766
+ best = offset;
1767
+ }
1768
+ }
1769
+ offset += SN_DELTA(sn);
1770
+ type = (JSSrcNoteType) SN_TYPE(sn);
1771
+ if (type == SRC_SETLINE) {
1772
+ lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
1773
+ } else if (type == SRC_NEWLINE) {
1774
+ lineno++;
1775
+ }
1776
+ }
1777
+ if (best >= 0)
1778
+ offset = best;
1779
+ out:
1780
+ return script->code + offset;
1781
+ }
1782
+
1783
+ JS_FRIEND_API(uintN)
1784
+ js_GetScriptLineExtent(JSScript *script)
1785
+ {
1786
+ uintN lineno;
1787
+ jssrcnote *sn;
1788
+ JSSrcNoteType type;
1789
+
1790
+ lineno = script->lineno;
1791
+ for (sn = SCRIPT_NOTES(script); !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) {
1792
+ type = (JSSrcNoteType) SN_TYPE(sn);
1793
+ if (type == SRC_SETLINE) {
1794
+ lineno = (uintN) js_GetSrcNoteOffset(sn, 0);
1795
+ } else if (type == SRC_NEWLINE) {
1796
+ lineno++;
1797
+ }
1798
+ }
1799
+ return 1 + lineno - script->lineno;
1800
+ }
1801
+
1802
+ #if JS_HAS_GENERATORS
1803
+
1804
+ JSBool
1805
+ js_IsInsideTryWithFinally(JSScript *script, jsbytecode *pc)
1806
+ {
1807
+ JSTryNoteArray *tarray;
1808
+ JSTryNote *tn, *tnlimit;
1809
+ uint32 off;
1810
+
1811
+ JS_ASSERT(script->code <= pc);
1812
+ JS_ASSERT(pc < script->code + script->length);
1813
+
1814
+ if (!script->trynotesOffset != 0)
1815
+ return JS_FALSE;
1816
+ tarray = JS_SCRIPT_TRYNOTES(script);
1817
+ JS_ASSERT(tarray->length != 0);
1818
+
1819
+ tn = tarray->vector;
1820
+ tnlimit = tn + tarray->length;
1821
+ off = (uint32)(pc - script->main);
1822
+ do {
1823
+ if (off - tn->start < tn->length) {
1824
+ if (tn->kind == JSTN_FINALLY)
1825
+ return JS_TRUE;
1826
+ JS_ASSERT(tn->kind == JSTN_CATCH);
1827
+ }
1828
+ } while (++tn != tnlimit);
1829
+ return JS_FALSE;
1830
+ }
1831
+
1832
+ #endif