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,56 @@
1
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
+ *
3
+ * ***** BEGIN LICENSE BLOCK *****
4
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
+ *
6
+ * The contents of this file are subject to the Mozilla Public License Version
7
+ * 1.1 (the "License"); you may not use this file except in compliance with
8
+ * the License. You may obtain a copy of the License at
9
+ * http://www.mozilla.org/MPL/
10
+ *
11
+ * Software distributed under the License is distributed on an "AS IS" basis,
12
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
+ * for the specific language governing rights and limitations under the
14
+ * License.
15
+ *
16
+ * The Original Code is Mozilla Communicator client code, released
17
+ * March 31, 1998.
18
+ *
19
+ * The Initial Developer of the Original Code is
20
+ * Netscape Communications Corporation.
21
+ * Portions created by the Initial Developer are Copyright (C) 1998
22
+ * the Initial Developer. All Rights Reserved.
23
+ *
24
+ * Contributor(s):
25
+ *
26
+ * Alternatively, the contents of this file may be used under the terms of
27
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
28
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29
+ * in which case the provisions of the GPL or the LGPL are applicable instead
30
+ * of those above. If you wish to allow use of your version of this file only
31
+ * under the terms of either the GPL or the LGPL, and not to allow others to
32
+ * use your version of this file under the terms of the MPL, indicate your
33
+ * decision by deleting the provisions above and replace them with the notice
34
+ * and other provisions required by the GPL or the LGPL. If you do not delete
35
+ * the provisions above, a recipient may use your version of this file under
36
+ * the terms of any one of the MPL, the GPL or the LGPL.
37
+ *
38
+ * ***** END LICENSE BLOCK ***** */
39
+
40
+ #ifndef _jsfile_h__
41
+ #define _jsfile_h__
42
+
43
+ #if JS_HAS_FILE_OBJECT
44
+
45
+ #include "jsobj.h"
46
+
47
+ extern JS_PUBLIC_API(JSObject*)
48
+ js_InitFileClass(JSContext *cx, JSObject* obj);
49
+
50
+ extern JS_PUBLIC_API(JSObject*)
51
+ js_NewFileObject(JSContext *cx, char *bytes);
52
+
53
+ extern JSClass js_FileClass;
54
+
55
+ #endif /* JS_HAS_FILE_OBJECT */
56
+ #endif /* _jsfile_h__ */
@@ -0,0 +1,90 @@
1
+ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2
+ *
3
+ * ***** BEGIN LICENSE BLOCK *****
4
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
+ *
6
+ * The contents of this file are subject to the Mozilla Public License Version
7
+ * 1.1 (the "License"); you may not use this file except in compliance with
8
+ * the License. You may obtain a copy of the License at
9
+ * http://www.mozilla.org/MPL/
10
+ *
11
+ * Software distributed under the License is distributed on an "AS IS" basis,
12
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
+ * for the specific language governing rights and limitations under the
14
+ * License.
15
+ *
16
+ * The Original Code is Mozilla Communicator client code, released
17
+ * March 31, 1998.
18
+ *
19
+ * The Initial Developer of the Original Code is
20
+ * Netscape Communications Corporation.
21
+ * Portions created by the Initial Developer are Copyright (C) 1998
22
+ * the Initial Developer. All Rights Reserved.
23
+ *
24
+ * Contributor(s):
25
+ *
26
+ * Alternatively, the contents of this file may be used under the terms of
27
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
28
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29
+ * in which case the provisions of the GPL or the LGPL are applicable instead
30
+ * of those above. If you wish to allow use of your version of this file only
31
+ * under the terms of either the GPL or the LGPL, and not to allow others to
32
+ * use your version of this file under the terms of the MPL, indicate your
33
+ * decision by deleting the provisions above and replace them with the notice
34
+ * and other provisions required by the GPL or the LGPL. If you do not delete
35
+ * the provisions above, a recipient may use your version of this file under
36
+ * the terms of any one of the MPL, the GPL or the LGPL.
37
+ *
38
+ * ***** END LICENSE BLOCK ***** */
39
+
40
+ /*
41
+ Error messages for jsfile.c. See js.msg for format specification.
42
+ */
43
+
44
+ MSG_DEF(JSFILEMSG_NOT_AN_ERROR, 0, 0, JSEXN_NONE, "<Error #0 is reserved>")
45
+ MSG_DEF(JSFILEMSG_FILE_CONSTRUCTOR_UNDEFINED_ERROR, 1, 0, JSEXN_NONE, "File constructor is undefined")
46
+ MSG_DEF(JSFILEMSG_FILE_CURRENTDIR_UNDEFINED_ERROR, 2, 0, JSEXN_NONE, "File.currentDir is undefined")
47
+ MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_OPEN_NOT_STRING_ERROR, 3, 1, JSEXN_NONE, "The first argument {0} to file.open must be a string")
48
+ MSG_DEF(JSFILEMSG_SECOND_ARGUMENT_OPEN_NOT_STRING_ERROR, 4, 0, JSEXN_NONE, "The second argument to file.open must be a string")
49
+ MSG_DEF(JSFILEMSG_CANNOT_COPY_FILE_OPEN_FOR_WRITING_ERROR, 5, 1, JSEXN_NONE, "Cannot copy file {0} open for writing")
50
+ MSG_DEF(JSFILEMSG_CANNOT_ACCESS_FILE_INFO_ERROR, 6, 1, JSEXN_NONE, "Cannot access file information for {0}")
51
+ MSG_DEF(JSFILEMSG_COPY_READ_ERROR, 7, 1, JSEXN_NONE, "An error occured while attempting to read a file {0} to copy")
52
+ MSG_DEF(JSFILEMSG_COPY_WRITE_ERROR, 8, 1, JSEXN_NONE, "An error occured while attempting to copy into file {0}")
53
+ MSG_DEF(JSFILEMSG_EXPECTS_ONE_ARG_ERROR, 9, 0, JSEXN_NONE, "Operation {0} expects one argument, not {1}")
54
+ MSG_DEF(JSFILEMSG_CANNOT_FLUSH_CLOSE_FILE_ERROR, 10, 1, JSEXN_NONE, "Cannot flush closed file {0}")
55
+ MSG_DEF(JSFILEMSG_CANNOT_OPEN_WRITING_ERROR, 11, 1, JSEXN_NONE, "Cannot open file {0} for writing")
56
+ MSG_DEF(JSFILEMSG_WRITEALL_EXPECTS_ONE_ARG_ERROR, 12, 0, JSEXN_NONE, "writeAll expects one argument")
57
+ MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_WRITEALL_NOT_ARRAY_ERROR, 13, 0, JSEXN_NONE, "writeAll expects an array as an argument")
58
+ MSG_DEF(JSFILEMSG_UNUSED0, 14, 0, JSEXN_NONE, "Unused error message slot")
59
+ MSG_DEF(JSFILEMSG_CANNOT_OPEN_FILE_ERROR, 15, 1, JSEXN_NONE, "Cannot open file {0}")
60
+ MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_CONSTRUCTOR_NOT_STRING_ERROR, 16, 1, JSEXN_NONE, "The argument to the File constructor {0} must be a string")
61
+ MSG_DEF(JSFILEMSG_BIDIRECTIONAL_PIPE_NOT_SUPPORTED, 17, 0, JSEXN_NONE, "Bidirectional pipes are not supported")
62
+ MSG_DEF(JSFILEMSG_OPEN_MODE_NOT_SUPPORTED_WITH_PIPES, 18, 2, JSEXN_NONE, "The opening mode you have chosen {0} is not supported by the pipe you are trying to open: {1}")
63
+ MSG_DEF(JSFILEMSG_OPEN_FAILED, 19, 1, JSEXN_NONE, "open on file {0} failed")
64
+ MSG_DEF(JSFILEMSG_CLOSE_FAILED, 20, 1, JSEXN_NONE, "close on file {0} failed")
65
+ MSG_DEF(JSFILEMSG_PCLOSE_FAILED, 21, 1, JSEXN_NONE, "pclose on file {0} failed")
66
+ MSG_DEF(JSFILEMSG_REMOVE_FAILED, 22, 1, JSEXN_NONE, "remove on file {0} failed")
67
+ MSG_DEF(JSFILEMSG_CANNOT_ACCESS_FILE_STATUS, 23, 1, JSEXN_NONE, "Cannot access file status for {0}")
68
+ MSG_DEF(JSFILEMSG_RENAME_FAILED, 24, 2, JSEXN_NONE, "Cannot rename {0} to {1}")
69
+ MSG_DEF(JSFILEMSG_WRITE_FAILED, 25, 1, JSEXN_NONE, "Write failed on file {0}")
70
+ MSG_DEF(JSFILEMSG_READ_FAILED, 26, 1, JSEXN_NONE, "Read failed on file {0}")
71
+ MSG_DEF(JSFILEMSG_SKIP_FAILED, 27, 1, JSEXN_NONE, "Skip failed on file {0}")
72
+ MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_FUNCTION_OR_REGEX, 28, 1, JSEXN_NONE, "The first argument to file.list must be a function or a regex")
73
+ MSG_DEF(JSFILEMSG_CANNOT_DO_LIST_ON_A_FILE, 29, 1, JSEXN_NONE, "{0} must be a directory, cannot do list")
74
+ MSG_DEF(JSFILEMSG_NATIVE_OPERATION_IS_NOT_SUPPORTED, 30, 2, JSEXN_NONE, "Native operation {0} is not supported on {1}")
75
+ MSG_DEF(JSFILEMSG_CANNOT_SET_PRIVATE_FILE, 31, 1, JSEXN_NONE, "Cannot set private data for file {0}")
76
+ MSG_DEF(JSFILEMSG_FIRST_ARGUMENT_MUST_BE_A_NUMBER, 32, 2, JSEXN_NONE, "First argument to {0} must be a number, not {1}")
77
+ MSG_DEF(JSFILEMSG_CANNOT_WRITE, 33, 1, JSEXN_NONE, "Cannot write to {0}, file mode is different")
78
+ MSG_DEF(JSFILEMSG_CANNOT_READ, 34, 1, JSEXN_NONE, "Cannot read from {0}, file mode is different")
79
+ MSG_DEF(JSFILEMSG_CANNOT_FLUSH, 35, 1, JSEXN_NONE, "Flush failed on {0}")
80
+ MSG_DEF(JSFILEMSG_OP_FAILED, 36, 1, JSEXN_NONE, "File operation {0} failed")
81
+ MSG_DEF(JSFILEMSG_FILE_MUST_BE_OPEN, 37, 1, JSEXN_NONE, "File must be open for {0}")
82
+ MSG_DEF(JSFILEMSG_FILE_MUST_BE_CLOSED, 38, 1, JSEXN_NONE, "File must be closed for {0}")
83
+ MSG_DEF(JSFILEMSG_NO_RANDOM_ACCESS, 39, 1, JSEXN_NONE, "File {0} doesn't allow random access")
84
+ MSG_DEF(JSFILEMSG_OBJECT_CREATION_FAILED, 40, 1, JSEXN_NONE, "Couldn't create {0}")
85
+ MSG_DEF(JSFILEMSG_CANNOT_OPEN_DIR, 41, 1, JSEXN_NONE, "Couldn't open directory {0}")
86
+ MSG_DEF(JSFILEMSG_CANNOT_REPORT_POSITION, 42, 1, JSEXN_NONE, "Couldn't report position for {0}")
87
+ MSG_DEF(JSFILEMSG_CANNOT_SET_POSITION, 43, 1, JSEXN_NONE, "Couldn't set position for {0}")
88
+ MSG_DEF(JSFILEMSG_INIT_FAILED, 44, 0, JSEXN_NONE, "File class initialization failed")
89
+
90
+
@@ -0,0 +1,2634 @@
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 function support.
43
+ */
44
+ #include "jsstddef.h"
45
+ #include <string.h>
46
+ #include "jstypes.h"
47
+ #include "jsbit.h"
48
+ #include "jsutil.h" /* Added by JSIFY */
49
+ #include "jsapi.h"
50
+ #include "jsarray.h"
51
+ #include "jsatom.h"
52
+ #include "jscntxt.h"
53
+ #include "jsconfig.h"
54
+ #include "jsdbgapi.h"
55
+ #include "jsfun.h"
56
+ #include "jsgc.h"
57
+ #include "jsinterp.h"
58
+ #include "jslock.h"
59
+ #include "jsnum.h"
60
+ #include "jsobj.h"
61
+ #include "jsopcode.h"
62
+ #include "jsparse.h"
63
+ #include "jsscan.h"
64
+ #include "jsscope.h"
65
+ #include "jsscript.h"
66
+ #include "jsstr.h"
67
+ #include "jsexn.h"
68
+
69
+ #if JS_HAS_GENERATORS
70
+ # include "jsiter.h"
71
+ #endif
72
+
73
+ #if JS_HAS_XDR
74
+ # include "jsxdrapi.h"
75
+ #endif
76
+
77
+ /* Generic function/call/arguments tinyids -- also reflected bit numbers. */
78
+ enum {
79
+ CALL_ARGUMENTS = -1, /* predefined arguments local variable */
80
+ ARGS_LENGTH = -2, /* number of actual args, arity if inactive */
81
+ ARGS_CALLEE = -3, /* reference from arguments to active funobj */
82
+ FUN_ARITY = -4, /* number of formal parameters; desired argc */
83
+ FUN_NAME = -5, /* function name, "" if anonymous */
84
+ FUN_CALLER = -6 /* Function.prototype.caller, backward compat */
85
+ };
86
+
87
+ #if JSFRAME_OVERRIDE_BITS < 8
88
+ # error "not enough override bits in JSStackFrame.flags!"
89
+ #endif
90
+
91
+ #define TEST_OVERRIDE_BIT(fp, tinyid) \
92
+ ((fp)->flags & JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
93
+
94
+ #define SET_OVERRIDE_BIT(fp, tinyid) \
95
+ ((fp)->flags |= JS_BIT(JSFRAME_OVERRIDE_SHIFT - ((tinyid) + 1)))
96
+
97
+ JSBool
98
+ js_GetArgsValue(JSContext *cx, JSStackFrame *fp, jsval *vp)
99
+ {
100
+ JSObject *argsobj;
101
+
102
+ if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
103
+ JS_ASSERT(fp->callobj);
104
+ return OBJ_GET_PROPERTY(cx, fp->callobj,
105
+ ATOM_TO_JSID(cx->runtime->atomState
106
+ .argumentsAtom),
107
+ vp);
108
+ }
109
+ argsobj = js_GetArgsObject(cx, fp);
110
+ if (!argsobj)
111
+ return JS_FALSE;
112
+ *vp = OBJECT_TO_JSVAL(argsobj);
113
+ return JS_TRUE;
114
+ }
115
+
116
+ static JSBool
117
+ MarkArgDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
118
+ {
119
+ JSObject *argsobj;
120
+ jsval bmapval, bmapint;
121
+ size_t nbits, nbytes;
122
+ jsbitmap *bitmap;
123
+
124
+ argsobj = fp->argsobj;
125
+ (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
126
+ nbits = fp->argc;
127
+ JS_ASSERT(slot < nbits);
128
+ if (JSVAL_IS_VOID(bmapval)) {
129
+ if (nbits <= JSVAL_INT_BITS) {
130
+ bmapint = 0;
131
+ bitmap = (jsbitmap *) &bmapint;
132
+ } else {
133
+ nbytes = JS_HOWMANY(nbits, JS_BITS_PER_WORD) * sizeof(jsbitmap);
134
+ bitmap = (jsbitmap *) JS_malloc(cx, nbytes);
135
+ if (!bitmap)
136
+ return JS_FALSE;
137
+ memset(bitmap, 0, nbytes);
138
+ bmapval = PRIVATE_TO_JSVAL(bitmap);
139
+ JS_SetReservedSlot(cx, argsobj, 0, bmapval);
140
+ }
141
+ } else {
142
+ if (nbits <= JSVAL_INT_BITS) {
143
+ bmapint = JSVAL_TO_INT(bmapval);
144
+ bitmap = (jsbitmap *) &bmapint;
145
+ } else {
146
+ bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval);
147
+ }
148
+ }
149
+ JS_SET_BIT(bitmap, slot);
150
+ if (bitmap == (jsbitmap *) &bmapint) {
151
+ bmapval = INT_TO_JSVAL(bmapint);
152
+ JS_SetReservedSlot(cx, argsobj, 0, bmapval);
153
+ }
154
+ return JS_TRUE;
155
+ }
156
+
157
+ /* NB: Infallible predicate, false does not mean error/exception. */
158
+ static JSBool
159
+ ArgWasDeleted(JSContext *cx, JSStackFrame *fp, uintN slot)
160
+ {
161
+ JSObject *argsobj;
162
+ jsval bmapval, bmapint;
163
+ jsbitmap *bitmap;
164
+
165
+ argsobj = fp->argsobj;
166
+ (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
167
+ if (JSVAL_IS_VOID(bmapval))
168
+ return JS_FALSE;
169
+ if (fp->argc <= JSVAL_INT_BITS) {
170
+ bmapint = JSVAL_TO_INT(bmapval);
171
+ bitmap = (jsbitmap *) &bmapint;
172
+ } else {
173
+ bitmap = (jsbitmap *) JSVAL_TO_PRIVATE(bmapval);
174
+ }
175
+ return JS_TEST_BIT(bitmap, slot) != 0;
176
+ }
177
+
178
+ JSBool
179
+ js_GetArgsProperty(JSContext *cx, JSStackFrame *fp, jsid id, jsval *vp)
180
+ {
181
+ jsval val;
182
+ JSObject *obj;
183
+ uintN slot;
184
+
185
+ if (TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
186
+ JS_ASSERT(fp->callobj);
187
+ if (!OBJ_GET_PROPERTY(cx, fp->callobj,
188
+ ATOM_TO_JSID(cx->runtime->atomState
189
+ .argumentsAtom),
190
+ &val)) {
191
+ return JS_FALSE;
192
+ }
193
+ if (JSVAL_IS_PRIMITIVE(val)) {
194
+ obj = js_ValueToNonNullObject(cx, val);
195
+ if (!obj)
196
+ return JS_FALSE;
197
+ } else {
198
+ obj = JSVAL_TO_OBJECT(val);
199
+ }
200
+ return OBJ_GET_PROPERTY(cx, obj, id, vp);
201
+ }
202
+
203
+ *vp = JSVAL_VOID;
204
+ if (JSID_IS_INT(id)) {
205
+ slot = (uintN) JSID_TO_INT(id);
206
+ if (slot < fp->argc) {
207
+ if (fp->argsobj && ArgWasDeleted(cx, fp, slot))
208
+ return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
209
+ *vp = fp->argv[slot];
210
+ } else {
211
+ /*
212
+ * Per ECMA-262 Ed. 3, 10.1.8, last bulleted item, do not share
213
+ * storage between the formal parameter and arguments[k] for all
214
+ * fp->argc <= k && k < fp->fun->nargs. For example, in
215
+ *
216
+ * function f(x) { x = 42; return arguments[0]; }
217
+ * f();
218
+ *
219
+ * the call to f should return undefined, not 42. If fp->argsobj
220
+ * is null at this point, as it would be in the example, return
221
+ * undefined in *vp.
222
+ */
223
+ if (fp->argsobj)
224
+ return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
225
+ }
226
+ } else {
227
+ if (id == ATOM_TO_JSID(cx->runtime->atomState.lengthAtom)) {
228
+ if (fp->argsobj && TEST_OVERRIDE_BIT(fp, ARGS_LENGTH))
229
+ return OBJ_GET_PROPERTY(cx, fp->argsobj, id, vp);
230
+ *vp = INT_TO_JSVAL((jsint) fp->argc);
231
+ }
232
+ }
233
+ return JS_TRUE;
234
+ }
235
+
236
+ JSObject *
237
+ js_GetArgsObject(JSContext *cx, JSStackFrame *fp)
238
+ {
239
+ JSObject *argsobj, *global, *parent;
240
+
241
+ /*
242
+ * We must be in a function activation; the function must be lightweight
243
+ * or else fp must have a variable object.
244
+ */
245
+ JS_ASSERT(fp->fun && (!(fp->fun->flags & JSFUN_HEAVYWEIGHT) || fp->varobj));
246
+
247
+ /* Skip eval and debugger frames. */
248
+ while (fp->flags & JSFRAME_SPECIAL)
249
+ fp = fp->down;
250
+
251
+ /* Create an arguments object for fp only if it lacks one. */
252
+ argsobj = fp->argsobj;
253
+ if (argsobj)
254
+ return argsobj;
255
+
256
+ /* Link the new object to fp so it can get actual argument values. */
257
+ argsobj = js_NewObject(cx, &js_ArgumentsClass, NULL, NULL, 0);
258
+ if (!argsobj || !JS_SetPrivate(cx, argsobj, fp)) {
259
+ cx->weakRoots.newborn[GCX_OBJECT] = NULL;
260
+ return NULL;
261
+ }
262
+
263
+ /*
264
+ * Give arguments an intrinsic scope chain link to fp's global object.
265
+ * Since the arguments object lacks a prototype because js_ArgumentsClass
266
+ * is not initialized, js_NewObject won't assign a default parent to it.
267
+ *
268
+ * Therefore if arguments is used as the head of an eval scope chain (via
269
+ * a direct or indirect call to eval(program, arguments)), any reference
270
+ * to a standard class object in the program will fail to resolve due to
271
+ * js_GetClassPrototype not being able to find a global object containing
272
+ * the standard prototype by starting from arguments and following parent.
273
+ */
274
+ global = fp->scopeChain;
275
+ while ((parent = OBJ_GET_PARENT(cx, global)) != NULL)
276
+ global = parent;
277
+ STOBJ_SET_PARENT(argsobj, global);
278
+ fp->argsobj = argsobj;
279
+ return argsobj;
280
+ }
281
+
282
+ static JSBool
283
+ args_enumerate(JSContext *cx, JSObject *obj);
284
+
285
+ JS_FRIEND_API(JSBool)
286
+ js_PutArgsObject(JSContext *cx, JSStackFrame *fp)
287
+ {
288
+ JSObject *argsobj;
289
+ jsval bmapval, rval;
290
+ JSBool ok;
291
+ JSRuntime *rt;
292
+
293
+ /*
294
+ * Reuse args_enumerate here to reflect fp's actual arguments as indexed
295
+ * elements of argsobj. Do this first, before clearing and freeing the
296
+ * deleted argument slot bitmap, because args_enumerate depends on that.
297
+ */
298
+ argsobj = fp->argsobj;
299
+ ok = args_enumerate(cx, argsobj);
300
+
301
+ /*
302
+ * Now clear the deleted argument number bitmap slot and free the bitmap,
303
+ * if one was actually created due to 'delete arguments[0]' or similar.
304
+ */
305
+ (void) JS_GetReservedSlot(cx, argsobj, 0, &bmapval);
306
+ if (!JSVAL_IS_VOID(bmapval)) {
307
+ JS_SetReservedSlot(cx, argsobj, 0, JSVAL_VOID);
308
+ if (fp->argc > JSVAL_INT_BITS)
309
+ JS_free(cx, JSVAL_TO_PRIVATE(bmapval));
310
+ }
311
+
312
+ /*
313
+ * Now get the prototype properties so we snapshot fp->fun and fp->argc
314
+ * before fp goes away.
315
+ */
316
+ rt = cx->runtime;
317
+ ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom),
318
+ &rval);
319
+ ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.calleeAtom),
320
+ &rval);
321
+ ok &= js_GetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom),
322
+ &rval);
323
+ ok &= js_SetProperty(cx, argsobj, ATOM_TO_JSID(rt->atomState.lengthAtom),
324
+ &rval);
325
+
326
+ /*
327
+ * Clear the private pointer to fp, which is about to go away (js_Invoke).
328
+ * Do this last because the args_enumerate and js_GetProperty calls above
329
+ * need to follow the private slot to find fp.
330
+ */
331
+ ok &= JS_SetPrivate(cx, argsobj, NULL);
332
+ fp->argsobj = NULL;
333
+ return ok;
334
+ }
335
+
336
+ static JSBool
337
+ args_delProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
338
+ {
339
+ jsint slot;
340
+ JSStackFrame *fp;
341
+
342
+ if (!JSVAL_IS_INT(id))
343
+ return JS_TRUE;
344
+ fp = (JSStackFrame *)
345
+ JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
346
+ if (!fp)
347
+ return JS_TRUE;
348
+ JS_ASSERT(fp->argsobj);
349
+
350
+ slot = JSVAL_TO_INT(id);
351
+ switch (slot) {
352
+ case ARGS_CALLEE:
353
+ case ARGS_LENGTH:
354
+ SET_OVERRIDE_BIT(fp, slot);
355
+ break;
356
+
357
+ default:
358
+ if ((uintN)slot < fp->argc && !MarkArgDeleted(cx, fp, slot))
359
+ return JS_FALSE;
360
+ break;
361
+ }
362
+ return JS_TRUE;
363
+ }
364
+
365
+ static JSBool
366
+ args_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
367
+ {
368
+ jsint slot;
369
+ JSStackFrame *fp;
370
+
371
+ if (!JSVAL_IS_INT(id))
372
+ return JS_TRUE;
373
+ fp = (JSStackFrame *)
374
+ JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
375
+ if (!fp)
376
+ return JS_TRUE;
377
+ JS_ASSERT(fp->argsobj);
378
+
379
+ slot = JSVAL_TO_INT(id);
380
+ switch (slot) {
381
+ case ARGS_CALLEE:
382
+ if (!TEST_OVERRIDE_BIT(fp, slot))
383
+ *vp = OBJECT_TO_JSVAL(fp->callee);
384
+ break;
385
+
386
+ case ARGS_LENGTH:
387
+ if (!TEST_OVERRIDE_BIT(fp, slot))
388
+ *vp = INT_TO_JSVAL((jsint)fp->argc);
389
+ break;
390
+
391
+ default:
392
+ if ((uintN)slot < fp->argc && !ArgWasDeleted(cx, fp, slot))
393
+ *vp = fp->argv[slot];
394
+ break;
395
+ }
396
+ return JS_TRUE;
397
+ }
398
+
399
+ static JSBool
400
+ args_setProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
401
+ {
402
+ JSStackFrame *fp;
403
+ jsint slot;
404
+
405
+ if (!JSVAL_IS_INT(id))
406
+ return JS_TRUE;
407
+ fp = (JSStackFrame *)
408
+ JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
409
+ if (!fp)
410
+ return JS_TRUE;
411
+ JS_ASSERT(fp->argsobj);
412
+
413
+ slot = JSVAL_TO_INT(id);
414
+ switch (slot) {
415
+ case ARGS_CALLEE:
416
+ case ARGS_LENGTH:
417
+ SET_OVERRIDE_BIT(fp, slot);
418
+ break;
419
+
420
+ default:
421
+ if (FUN_INTERPRETED(fp->fun) &&
422
+ (uintN)slot < fp->argc &&
423
+ !ArgWasDeleted(cx, fp, slot)) {
424
+ fp->argv[slot] = *vp;
425
+ }
426
+ break;
427
+ }
428
+ return JS_TRUE;
429
+ }
430
+
431
+ static JSBool
432
+ args_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
433
+ JSObject **objp)
434
+ {
435
+ JSStackFrame *fp;
436
+ uintN slot;
437
+ JSString *str;
438
+ JSAtom *atom;
439
+ intN tinyid;
440
+ jsval value;
441
+
442
+ *objp = NULL;
443
+ fp = (JSStackFrame *)
444
+ JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
445
+ if (!fp)
446
+ return JS_TRUE;
447
+ JS_ASSERT(fp->argsobj);
448
+
449
+ if (JSVAL_IS_INT(id)) {
450
+ slot = JSVAL_TO_INT(id);
451
+ if (slot < fp->argc && !ArgWasDeleted(cx, fp, slot)) {
452
+ /* XXX ECMA specs DontEnum, contrary to other array-like objects */
453
+ if (!js_DefineProperty(cx, obj, INT_JSVAL_TO_JSID(id),
454
+ fp->argv[slot],
455
+ args_getProperty, args_setProperty,
456
+ 0, NULL)) {
457
+ return JS_FALSE;
458
+ }
459
+ *objp = obj;
460
+ }
461
+ } else {
462
+ str = JSVAL_TO_STRING(id);
463
+ atom = cx->runtime->atomState.lengthAtom;
464
+ if (str == ATOM_TO_STRING(atom)) {
465
+ tinyid = ARGS_LENGTH;
466
+ value = INT_TO_JSVAL(fp->argc);
467
+ } else {
468
+ atom = cx->runtime->atomState.calleeAtom;
469
+ if (str == ATOM_TO_STRING(atom)) {
470
+ tinyid = ARGS_CALLEE;
471
+ value = OBJECT_TO_JSVAL(fp->callee);
472
+ } else {
473
+ atom = NULL;
474
+
475
+ /* Quell GCC overwarnings. */
476
+ tinyid = 0;
477
+ value = JSVAL_NULL;
478
+ }
479
+ }
480
+
481
+ if (atom && !TEST_OVERRIDE_BIT(fp, tinyid)) {
482
+ if (!js_DefineNativeProperty(cx, obj, ATOM_TO_JSID(atom), value,
483
+ args_getProperty, args_setProperty, 0,
484
+ SPROP_HAS_SHORTID, tinyid, NULL)) {
485
+ return JS_FALSE;
486
+ }
487
+ *objp = obj;
488
+ }
489
+ }
490
+
491
+ return JS_TRUE;
492
+ }
493
+
494
+ static JSBool
495
+ args_enumerate(JSContext *cx, JSObject *obj)
496
+ {
497
+ JSStackFrame *fp;
498
+ JSObject *pobj;
499
+ JSProperty *prop;
500
+ uintN slot, argc;
501
+
502
+ fp = (JSStackFrame *)
503
+ JS_GetInstancePrivate(cx, obj, &js_ArgumentsClass, NULL);
504
+ if (!fp)
505
+ return JS_TRUE;
506
+ JS_ASSERT(fp->argsobj);
507
+
508
+ /*
509
+ * Trigger reflection with value snapshot in args_resolve using a series
510
+ * of js_LookupProperty calls. We handle length, callee, and the indexed
511
+ * argument properties. We know that args_resolve covers all these cases
512
+ * and creates direct properties of obj, but that it may fail to resolve
513
+ * length or callee if overridden.
514
+ */
515
+ if (!js_LookupProperty(cx, obj,
516
+ ATOM_TO_JSID(cx->runtime->atomState.lengthAtom),
517
+ &pobj, &prop)) {
518
+ return JS_FALSE;
519
+ }
520
+ if (prop)
521
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
522
+
523
+ if (!js_LookupProperty(cx, obj,
524
+ ATOM_TO_JSID(cx->runtime->atomState.calleeAtom),
525
+ &pobj, &prop)) {
526
+ return JS_FALSE;
527
+ }
528
+ if (prop)
529
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
530
+
531
+ argc = fp->argc;
532
+ for (slot = 0; slot < argc; slot++) {
533
+ if (!js_LookupProperty(cx, obj, INT_TO_JSID((jsint)slot), &pobj, &prop))
534
+ return JS_FALSE;
535
+ if (prop)
536
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
537
+ }
538
+ return JS_TRUE;
539
+ }
540
+
541
+ #if JS_HAS_GENERATORS
542
+ /*
543
+ * If a generator-iterator's arguments or call object escapes, it needs to
544
+ * mark its generator object.
545
+ */
546
+ static void
547
+ args_or_call_trace(JSTracer *trc, JSObject *obj)
548
+ {
549
+ JSStackFrame *fp;
550
+
551
+ fp = (JSStackFrame *) JS_GetPrivate(trc->context, obj);
552
+ if (fp && (fp->flags & JSFRAME_GENERATOR)) {
553
+ JS_CALL_OBJECT_TRACER(trc, FRAME_TO_GENERATOR(fp)->obj,
554
+ "FRAME_TO_GENERATOR(fp)->obj");
555
+ }
556
+ }
557
+ #else
558
+ # define args_or_call_trace NULL
559
+ #endif
560
+
561
+ /*
562
+ * The Arguments class is not initialized via JS_InitClass, and must not be,
563
+ * because its name is "Object". Per ECMA, that causes instances of it to
564
+ * delegate to the object named by Object.prototype. It also ensures that
565
+ * arguments.toString() returns "[object Object]".
566
+ *
567
+ * The JSClass functions below collaborate to lazily reflect and synchronize
568
+ * actual argument values, argument count, and callee function object stored
569
+ * in a JSStackFrame with their corresponding property values in the frame's
570
+ * arguments object.
571
+ */
572
+ JSClass js_ArgumentsClass = {
573
+ js_Object_str,
574
+ JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(1) |
575
+ JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
576
+ JS_PropertyStub, args_delProperty,
577
+ args_getProperty, args_setProperty,
578
+ args_enumerate, (JSResolveOp) args_resolve,
579
+ JS_ConvertStub, JS_FinalizeStub,
580
+ NULL, NULL,
581
+ NULL, NULL,
582
+ NULL, NULL,
583
+ JS_CLASS_TRACE(args_or_call_trace), NULL
584
+ };
585
+
586
+ JSObject *
587
+ js_GetCallObject(JSContext *cx, JSStackFrame *fp, JSObject *parent)
588
+ {
589
+ JSObject *callobj, *funobj;
590
+
591
+ /* Create a call object for fp only if it lacks one. */
592
+ JS_ASSERT(fp->fun);
593
+ callobj = fp->callobj;
594
+ if (callobj)
595
+ return callobj;
596
+
597
+ /* The default call parent is its function's parent (static link). */
598
+ if (!parent) {
599
+ funobj = fp->callee;
600
+ if (funobj)
601
+ parent = OBJ_GET_PARENT(cx, funobj);
602
+ }
603
+
604
+ /* Create the call object and link it to its stack frame. */
605
+ callobj = js_NewObject(cx, &js_CallClass, NULL, parent, 0);
606
+ if (!callobj || !JS_SetPrivate(cx, callobj, fp)) {
607
+ cx->weakRoots.newborn[GCX_OBJECT] = NULL;
608
+ return NULL;
609
+ }
610
+ fp->callobj = callobj;
611
+
612
+ /* Make callobj be the scope chain and the variables object. */
613
+ JS_ASSERT(fp->scopeChain == parent);
614
+ fp->scopeChain = callobj;
615
+ fp->varobj = callobj;
616
+ return callobj;
617
+ }
618
+
619
+ static JSBool
620
+ call_enumerate(JSContext *cx, JSObject *obj);
621
+
622
+ JS_FRIEND_API(JSBool)
623
+ js_PutCallObject(JSContext *cx, JSStackFrame *fp)
624
+ {
625
+ JSObject *callobj;
626
+ JSBool ok;
627
+ jsid argsid;
628
+ jsval aval;
629
+
630
+ /*
631
+ * Reuse call_enumerate here to reflect all actual args and vars into the
632
+ * call object from fp.
633
+ */
634
+ callobj = fp->callobj;
635
+ if (!callobj)
636
+ return JS_TRUE;
637
+ ok = call_enumerate(cx, callobj);
638
+
639
+ /*
640
+ * Get the arguments object to snapshot fp's actual argument values.
641
+ */
642
+ if (fp->argsobj) {
643
+ if (!TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
644
+ argsid = ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom);
645
+ aval = OBJECT_TO_JSVAL(fp->argsobj);
646
+ ok &= js_SetProperty(cx, callobj, argsid, &aval);
647
+ }
648
+ ok &= js_PutArgsObject(cx, fp);
649
+ }
650
+
651
+ /*
652
+ * Clear the private pointer to fp, which is about to go away (js_Invoke).
653
+ * Do this last because the call_enumerate and js_GetProperty calls above
654
+ * need to follow the private slot to find fp.
655
+ */
656
+ ok &= JS_SetPrivate(cx, callobj, NULL);
657
+ fp->callobj = NULL;
658
+ return ok;
659
+ }
660
+
661
+ static JSBool
662
+ call_enumerate(JSContext *cx, JSObject *obj)
663
+ {
664
+ JSStackFrame *fp;
665
+ JSFunction *fun;
666
+ uintN n, i, slot;
667
+ void *mark;
668
+ jsuword *names;
669
+ JSBool ok;
670
+ JSAtom *name;
671
+ JSObject *pobj;
672
+ JSProperty *prop;
673
+ jsval v;
674
+
675
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
676
+ if (!fp)
677
+ return JS_TRUE;
678
+ JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee) == fp->fun);
679
+
680
+ /*
681
+ * Reflect actual args from fp->argv for formal parameters, and local vars
682
+ * and functions in fp->vars for declared variables and nested-at-top-level
683
+ * local functions.
684
+ */
685
+ fun = fp->fun;
686
+ n = JS_GET_LOCAL_NAME_COUNT(fun);
687
+ if (n == 0)
688
+ return JS_TRUE;
689
+
690
+ mark = JS_ARENA_MARK(&cx->tempPool);
691
+
692
+ /* From this point the control must flow through the label out. */
693
+ names = js_GetLocalNameArray(cx, fun, &cx->tempPool);
694
+ if (!names) {
695
+ ok = JS_FALSE;
696
+ goto out;
697
+ }
698
+
699
+ for (i = 0; i != n; ++i) {
700
+ name = JS_LOCAL_NAME_TO_ATOM(names[i]);
701
+ if (!name)
702
+ continue;
703
+
704
+ /*
705
+ * Trigger reflection by looking up the name of the argument or
706
+ * variable.
707
+ */
708
+ ok = js_LookupProperty(cx, obj, ATOM_TO_JSID(name), &pobj, &prop);
709
+ if (!ok)
710
+ goto out;
711
+
712
+ /*
713
+ * At this point the call object always has a property corresponding
714
+ * to the local name because call_resolve creates the property using
715
+ * JSPROP_PERMANENT.
716
+ */
717
+ JS_ASSERT(prop && pobj == obj);
718
+ slot = ((JSScopeProperty *) prop)->slot;
719
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
720
+
721
+ v = (i < fun->nargs) ? fp->argv[i] : fp->vars[i - fun->nargs];
722
+ LOCKED_OBJ_SET_SLOT(obj, slot, v);
723
+ }
724
+ ok = JS_TRUE;
725
+
726
+ out:
727
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
728
+ return ok;
729
+ }
730
+
731
+ typedef enum JSCallPropertyKind {
732
+ JSCPK_ARGUMENTS,
733
+ JSCPK_ARG,
734
+ JSCPK_VAR
735
+ } JSCallPropertyKind;
736
+
737
+ static JSBool
738
+ CallPropertyOp(JSContext *cx, JSObject *obj, jsid id, jsval *vp,
739
+ JSCallPropertyKind kind, JSBool setter)
740
+ {
741
+ JSStackFrame *fp;
742
+ JSFunction *fun;
743
+ uintN i;
744
+ jsval *array;
745
+
746
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
747
+ if (!fp)
748
+ return JS_TRUE;
749
+ fun = fp->fun;
750
+ JS_ASSERT(fun && FUN_INTERPRETED(fun));
751
+
752
+ if (kind == JSCPK_ARGUMENTS) {
753
+ if (setter) {
754
+ SET_OVERRIDE_BIT(fp, CALL_ARGUMENTS);
755
+ } else if (!TEST_OVERRIDE_BIT(fp, CALL_ARGUMENTS)) {
756
+ JSObject *argsobj;
757
+
758
+ argsobj = js_GetArgsObject(cx, fp);
759
+ if (!argsobj)
760
+ return JS_FALSE;
761
+ *vp = OBJECT_TO_JSVAL(argsobj);
762
+ }
763
+ return JS_TRUE;
764
+ }
765
+
766
+ JS_ASSERT((int16) JSVAL_TO_INT(id) == JSVAL_TO_INT(id));
767
+ i = (uint16) JSVAL_TO_INT(id);
768
+ JS_ASSERT_IF(kind == JSCPK_ARG, i < fun->nargs);
769
+ JS_ASSERT_IF(kind == JSCPK_VAR, i < fun->u.i.nvars);
770
+
771
+ JS_ASSERT(fun->u.i.nvars == fp->nvars);
772
+ if (kind == JSCPK_ARG) {
773
+ array = fp->argv;
774
+ } else {
775
+ JS_ASSERT(kind == JSCPK_VAR);
776
+ array = fp->vars;
777
+ }
778
+ if (setter)
779
+ array[i] = *vp;
780
+ else
781
+ *vp = array[i];
782
+ return JS_TRUE;
783
+ }
784
+
785
+ static JSBool
786
+ GetCallArguments(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
787
+ {
788
+ return CallPropertyOp(cx, obj, id, vp, JSCPK_ARGUMENTS, JS_FALSE);
789
+ }
790
+
791
+ static JSBool
792
+ SetCallArguments(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
793
+ {
794
+ return CallPropertyOp(cx, obj, id, vp, JSCPK_ARGUMENTS, JS_TRUE);
795
+ }
796
+
797
+ JSBool
798
+ js_GetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
799
+ {
800
+ return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, JS_FALSE);
801
+ }
802
+
803
+ static JSBool
804
+ SetCallArg(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
805
+ {
806
+ return CallPropertyOp(cx, obj, id, vp, JSCPK_ARG, JS_TRUE);
807
+ }
808
+
809
+ JSBool
810
+ js_GetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
811
+ {
812
+ return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_FALSE);
813
+ }
814
+
815
+ static JSBool
816
+ SetCallVar(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
817
+ {
818
+ return CallPropertyOp(cx, obj, id, vp, JSCPK_VAR, JS_TRUE);
819
+ }
820
+
821
+ static JSBool
822
+ call_resolve(JSContext *cx, JSObject *obj, jsval idval, uintN flags,
823
+ JSObject **objp)
824
+ {
825
+ JSStackFrame *fp;
826
+ JSFunction *fun;
827
+ jsid id;
828
+ JSLocalKind localKind;
829
+ JSPropertyOp getter, setter;
830
+ uintN slot, attrs;
831
+ jsval *vp;
832
+
833
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
834
+ if (!fp)
835
+ return JS_TRUE;
836
+ fun = fp->fun;
837
+ JS_ASSERT(fun);
838
+ JS_ASSERT(GET_FUNCTION_PRIVATE(cx, fp->callee) == fun);
839
+
840
+ if (!JSVAL_IS_STRING(idval))
841
+ return JS_TRUE;
842
+
843
+ if (!js_ValueToStringId(cx, idval, &id))
844
+ return JS_FALSE;
845
+
846
+ localKind = js_LookupLocal(cx, fun, JSID_TO_ATOM(id), &slot);
847
+ if (localKind != JSLOCAL_NONE) {
848
+ JS_ASSERT((uint16) slot == slot);
849
+ if (localKind == JSLOCAL_ARG) {
850
+ JS_ASSERT(slot < fun->nargs);
851
+ vp = fp->argv;
852
+ getter = js_GetCallArg;
853
+ setter = SetCallArg;
854
+ attrs = JSPROP_PERMANENT;
855
+ } else {
856
+ JS_ASSERT(localKind == JSLOCAL_VAR || localKind == JSLOCAL_CONST);
857
+ JS_ASSERT(fun->u.i.nvars == fp->nvars);
858
+ JS_ASSERT(slot < fun->u.i.nvars);
859
+ vp = fp->vars;
860
+ getter = js_GetCallVar;
861
+ setter = SetCallVar;
862
+ attrs = (localKind == JSLOCAL_CONST)
863
+ ? JSPROP_PERMANENT | JSPROP_READONLY
864
+ : JSPROP_PERMANENT;
865
+ }
866
+ if (!js_DefineNativeProperty(cx, obj, id, vp[slot], getter, setter,
867
+ attrs, SPROP_HAS_SHORTID, (int16) slot,
868
+ NULL)) {
869
+ return JS_FALSE;
870
+ }
871
+ *objp = obj;
872
+ return JS_TRUE;
873
+ }
874
+
875
+ /*
876
+ * Resolve arguments so that we never store a particular Call object's
877
+ * arguments object reference in a Call prototype's |arguments| slot.
878
+ */
879
+ if (id == ATOM_TO_JSID(cx->runtime->atomState.argumentsAtom)) {
880
+ if (!js_DefineNativeProperty(cx, obj, id, JSVAL_VOID,
881
+ GetCallArguments, SetCallArguments,
882
+ JSPROP_PERMANENT, 0, 0, NULL)) {
883
+ return JS_FALSE;
884
+ }
885
+ *objp = obj;
886
+ return JS_TRUE;
887
+ }
888
+ return JS_TRUE;
889
+ }
890
+
891
+ static JSBool
892
+ call_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
893
+ {
894
+ JSStackFrame *fp;
895
+
896
+ if (type == JSTYPE_FUNCTION) {
897
+ fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
898
+ if (fp) {
899
+ JS_ASSERT(fp->fun);
900
+ *vp = OBJECT_TO_JSVAL(fp->callee);
901
+ }
902
+ }
903
+ return JS_TRUE;
904
+ }
905
+
906
+ JS_FRIEND_DATA(JSClass) js_CallClass = {
907
+ js_Call_str,
908
+ JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_IS_ANONYMOUS |
909
+ JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Call),
910
+ JS_PropertyStub, JS_PropertyStub,
911
+ JS_PropertyStub, JS_PropertyStub,
912
+ call_enumerate, (JSResolveOp)call_resolve,
913
+ call_convert, JS_FinalizeStub,
914
+ NULL, NULL,
915
+ NULL, NULL,
916
+ NULL, NULL,
917
+ JS_CLASS_TRACE(args_or_call_trace), NULL,
918
+ };
919
+
920
+ /*
921
+ * ECMA-262 specifies that length is a property of function object instances,
922
+ * but we can avoid that space cost by delegating to a prototype property that
923
+ * is JSPROP_PERMANENT and JSPROP_SHARED. Each fun_getProperty call computes
924
+ * a fresh length value based on the arity of the individual function object's
925
+ * private data.
926
+ *
927
+ * The extensions below other than length, i.e., the ones not in ECMA-262,
928
+ * are neither JSPROP_READONLY nor JSPROP_SHARED, because for compatibility
929
+ * with ECMA we must allow a delegating object to override them. Therefore to
930
+ * avoid entraining garbage in Function.prototype slots, they must be resolved
931
+ * in non-prototype function objects, wherefore the lazy_function_props table
932
+ * and fun_resolve's use of it.
933
+ */
934
+ #define LENGTH_PROP_ATTRS (JSPROP_READONLY|JSPROP_PERMANENT|JSPROP_SHARED)
935
+
936
+ static JSPropertySpec function_props[] = {
937
+ {js_length_str, ARGS_LENGTH, LENGTH_PROP_ATTRS, 0,0},
938
+ {0,0,0,0,0}
939
+ };
940
+
941
+ typedef struct LazyFunctionProp {
942
+ uint16 atomOffset;
943
+ int8 tinyid;
944
+ uint8 attrs;
945
+ } LazyFunctionProp;
946
+
947
+ /* NB: no sentinel at the end -- use JS_ARRAY_LENGTH to bound loops. */
948
+ static LazyFunctionProp lazy_function_props[] = {
949
+ {ATOM_OFFSET(arguments), CALL_ARGUMENTS, JSPROP_PERMANENT},
950
+ {ATOM_OFFSET(arity), FUN_ARITY, JSPROP_PERMANENT},
951
+ {ATOM_OFFSET(caller), FUN_CALLER, JSPROP_PERMANENT},
952
+ {ATOM_OFFSET(name), FUN_NAME, JSPROP_PERMANENT},
953
+ };
954
+
955
+ static JSBool
956
+ fun_getProperty(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
957
+ {
958
+ jsint slot;
959
+ JSFunction *fun;
960
+ JSStackFrame *fp;
961
+
962
+ if (!JSVAL_IS_INT(id))
963
+ return JS_TRUE;
964
+ slot = JSVAL_TO_INT(id);
965
+
966
+ /*
967
+ * Loop because getter and setter can be delegated from another class,
968
+ * but loop only for ARGS_LENGTH because we must pretend that f.length
969
+ * is in each function instance f, per ECMA-262, instead of only in the
970
+ * Function.prototype object (we use JSPROP_PERMANENT with JSPROP_SHARED
971
+ * to make it appear so).
972
+ *
973
+ * This code couples tightly to the attributes for the function_props[]
974
+ * initializers above, and to js_SetProperty and js_HasOwnPropertyHelper.
975
+ *
976
+ * It's important to allow delegating objects, even though they inherit
977
+ * this getter (fun_getProperty), to override arguments, arity, caller,
978
+ * and name. If we didn't return early for slot != ARGS_LENGTH, we would
979
+ * clobber *vp with the native property value, instead of letting script
980
+ * override that value in delegating objects.
981
+ *
982
+ * Note how that clobbering is what simulates JSPROP_READONLY for all of
983
+ * the non-standard properties when the directly addressed object (obj)
984
+ * is a function object (i.e., when this loop does not iterate).
985
+ */
986
+ while (!(fun = (JSFunction *)
987
+ JS_GetInstancePrivate(cx, obj, &js_FunctionClass, NULL))) {
988
+ if (slot != ARGS_LENGTH)
989
+ return JS_TRUE;
990
+ obj = OBJ_GET_PROTO(cx, obj);
991
+ if (!obj)
992
+ return JS_TRUE;
993
+ }
994
+
995
+ /* Find fun's top-most activation record. */
996
+ for (fp = cx->fp; fp && (fp->fun != fun || (fp->flags & JSFRAME_SPECIAL));
997
+ fp = fp->down) {
998
+ continue;
999
+ }
1000
+
1001
+ switch (slot) {
1002
+ case CALL_ARGUMENTS:
1003
+ /* Warn if strict about f.arguments or equivalent unqualified uses. */
1004
+ if (!JS_ReportErrorFlagsAndNumber(cx,
1005
+ JSREPORT_WARNING | JSREPORT_STRICT,
1006
+ js_GetErrorMessage, NULL,
1007
+ JSMSG_DEPRECATED_USAGE,
1008
+ js_arguments_str)) {
1009
+ return JS_FALSE;
1010
+ }
1011
+ if (fp) {
1012
+ if (!js_GetArgsValue(cx, fp, vp))
1013
+ return JS_FALSE;
1014
+ } else {
1015
+ *vp = JSVAL_NULL;
1016
+ }
1017
+ break;
1018
+
1019
+ case ARGS_LENGTH:
1020
+ case FUN_ARITY:
1021
+ *vp = INT_TO_JSVAL((jsint)fun->nargs);
1022
+ break;
1023
+
1024
+ case FUN_NAME:
1025
+ *vp = fun->atom
1026
+ ? ATOM_KEY(fun->atom)
1027
+ : STRING_TO_JSVAL(cx->runtime->emptyString);
1028
+ break;
1029
+
1030
+ case FUN_CALLER:
1031
+ if (fp && fp->down && fp->down->fun)
1032
+ *vp = OBJECT_TO_JSVAL(fp->down->callee);
1033
+ else
1034
+ *vp = JSVAL_NULL;
1035
+ if (!JSVAL_IS_PRIMITIVE(*vp) && cx->runtime->checkObjectAccess) {
1036
+ id = ATOM_KEY(cx->runtime->atomState.callerAtom);
1037
+ if (!cx->runtime->checkObjectAccess(cx, obj, id, JSACC_READ, vp))
1038
+ return JS_FALSE;
1039
+ }
1040
+ break;
1041
+
1042
+ default:
1043
+ /* XXX fun[0] and fun.arguments[0] are equivalent. */
1044
+ if (fp && fp->fun && (uintN)slot < fp->fun->nargs)
1045
+ *vp = fp->argv[slot];
1046
+ break;
1047
+ }
1048
+
1049
+ return JS_TRUE;
1050
+ }
1051
+
1052
+ static JSBool
1053
+ fun_enumerate(JSContext *cx, JSObject *obj)
1054
+ {
1055
+ jsid prototypeId;
1056
+ JSObject *pobj;
1057
+ JSProperty *prop;
1058
+
1059
+ prototypeId = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
1060
+ if (!OBJ_LOOKUP_PROPERTY(cx, obj, prototypeId, &pobj, &prop))
1061
+ return JS_FALSE;
1062
+ if (prop)
1063
+ OBJ_DROP_PROPERTY(cx, pobj, prop);
1064
+ return JS_TRUE;
1065
+ }
1066
+
1067
+ static JSBool
1068
+ fun_resolve(JSContext *cx, JSObject *obj, jsval id, uintN flags,
1069
+ JSObject **objp)
1070
+ {
1071
+ JSFunction *fun;
1072
+ JSAtom *atom;
1073
+ uintN i;
1074
+
1075
+ if (!JSVAL_IS_STRING(id))
1076
+ return JS_TRUE;
1077
+
1078
+ fun = GET_FUNCTION_PRIVATE(cx, obj);
1079
+
1080
+ /*
1081
+ * No need to reflect fun.prototype in 'fun.prototype = ... '.
1082
+ *
1083
+ * This is not just an optimization, because we must not resolve when
1084
+ * defining hidden properties during compilation. The setup code for the
1085
+ * prototype and the lazy properties below eventually calls the property
1086
+ * hooks for the function object. That in turn calls fun_reserveSlots to
1087
+ * get the number of the reserved slots which is just the number of
1088
+ * regular expressions literals in the function. When compiling, that
1089
+ * number is not yet ready so we must make sure that fun_resolve does
1090
+ * nothing until the code for the function is generated.
1091
+ */
1092
+ if (flags & JSRESOLVE_ASSIGNING)
1093
+ return JS_TRUE;
1094
+
1095
+ /*
1096
+ * Ok, check whether id is 'prototype' and bootstrap the function object's
1097
+ * prototype property.
1098
+ */
1099
+ atom = cx->runtime->atomState.classPrototypeAtom;
1100
+ if (id == ATOM_KEY(atom)) {
1101
+ JSObject *proto;
1102
+
1103
+ /*
1104
+ * Beware of the wacky case of a user function named Object -- trying
1105
+ * to find a prototype for that will recur back here _ad perniciem_.
1106
+ */
1107
+ if (fun->atom == CLASS_ATOM(cx, Object))
1108
+ return JS_TRUE;
1109
+
1110
+ /*
1111
+ * Make the prototype object to have the same parent as the function
1112
+ * object itself.
1113
+ */
1114
+ proto = js_NewObject(cx, &js_ObjectClass, NULL, OBJ_GET_PARENT(cx, obj),
1115
+ 0);
1116
+ if (!proto)
1117
+ return JS_FALSE;
1118
+
1119
+ /*
1120
+ * ECMA (15.3.5.2) says that constructor.prototype is DontDelete for
1121
+ * user-defined functions, but DontEnum | ReadOnly | DontDelete for
1122
+ * native "system" constructors such as Object or Function. So lazily
1123
+ * set the former here in fun_resolve, but eagerly define the latter
1124
+ * in JS_InitClass, with the right attributes.
1125
+ */
1126
+ if (!js_SetClassPrototype(cx, obj, proto,
1127
+ JSPROP_ENUMERATE | JSPROP_PERMANENT)) {
1128
+ cx->weakRoots.newborn[GCX_OBJECT] = NULL;
1129
+ return JS_FALSE;
1130
+ }
1131
+ *objp = obj;
1132
+ return JS_TRUE;
1133
+ }
1134
+
1135
+ for (i = 0; i < JS_ARRAY_LENGTH(lazy_function_props); i++) {
1136
+ LazyFunctionProp *lfp = &lazy_function_props[i];
1137
+
1138
+ atom = OFFSET_TO_ATOM(cx->runtime, lfp->atomOffset);
1139
+ if (id == ATOM_KEY(atom)) {
1140
+ if (!js_DefineNativeProperty(cx, obj,
1141
+ ATOM_TO_JSID(atom), JSVAL_VOID,
1142
+ NULL, NULL, lfp->attrs,
1143
+ SPROP_HAS_SHORTID, lfp->tinyid,
1144
+ NULL)) {
1145
+ return JS_FALSE;
1146
+ }
1147
+ *objp = obj;
1148
+ return JS_TRUE;
1149
+ }
1150
+ }
1151
+
1152
+ return JS_TRUE;
1153
+ }
1154
+
1155
+ static JSBool
1156
+ fun_convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
1157
+ {
1158
+ switch (type) {
1159
+ case JSTYPE_FUNCTION:
1160
+ *vp = OBJECT_TO_JSVAL(obj);
1161
+ return JS_TRUE;
1162
+ default:
1163
+ return js_TryValueOf(cx, obj, type, vp);
1164
+ }
1165
+ }
1166
+
1167
+ #if JS_HAS_XDR
1168
+
1169
+ /* XXX store parent and proto, if defined */
1170
+ static JSBool
1171
+ fun_xdrObject(JSXDRState *xdr, JSObject **objp)
1172
+ {
1173
+ JSContext *cx;
1174
+ JSFunction *fun;
1175
+ uint32 nullAtom; /* flag to indicate if fun->atom is NULL */
1176
+ uintN nargs, nvars, n;
1177
+ uint32 localsword; /* word to xdr argument and variable counts */
1178
+ uint32 flagsword; /* originally only flags was JS_XDRUint8'd */
1179
+ JSTempValueRooter tvr;
1180
+ JSBool ok;
1181
+
1182
+ cx = xdr->cx;
1183
+ if (xdr->mode == JSXDR_ENCODE) {
1184
+ fun = GET_FUNCTION_PRIVATE(cx, *objp);
1185
+ if (!FUN_INTERPRETED(fun)) {
1186
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1187
+ JSMSG_NOT_SCRIPTED_FUNCTION,
1188
+ JS_GetFunctionName(fun));
1189
+ return JS_FALSE;
1190
+ }
1191
+ nullAtom = !fun->atom;
1192
+ nargs = fun->nargs;
1193
+ nvars = fun->u.i.nvars;
1194
+ localsword = (nargs << 16) | nvars;
1195
+ flagsword = fun->flags;
1196
+ } else {
1197
+ fun = js_NewFunction(cx, NULL, NULL, 0, JSFUN_INTERPRETED, NULL, NULL);
1198
+ if (!fun)
1199
+ return JS_FALSE;
1200
+ STOBJ_SET_PARENT(FUN_OBJECT(fun), NULL);
1201
+ STOBJ_SET_PROTO(FUN_OBJECT(fun), NULL);
1202
+ #ifdef __GNUC__
1203
+ nvars = nargs = 0; /* quell GCC uninitialized warning */
1204
+ #endif
1205
+ }
1206
+
1207
+ /* From here on, control flow must flow through label out. */
1208
+ JS_PUSH_TEMP_ROOT_OBJECT(cx, FUN_OBJECT(fun), &tvr);
1209
+ ok = JS_TRUE;
1210
+
1211
+ if (!JS_XDRUint32(xdr, &nullAtom))
1212
+ goto bad;
1213
+ if (!nullAtom && !js_XDRStringAtom(xdr, &fun->atom))
1214
+ goto bad;
1215
+ if (!JS_XDRUint32(xdr, &localsword) ||
1216
+ !JS_XDRUint32(xdr, &flagsword)) {
1217
+ goto bad;
1218
+ }
1219
+
1220
+ if (xdr->mode == JSXDR_DECODE) {
1221
+ nargs = localsword >> 16;
1222
+ nvars = localsword & JS_BITMASK(16);
1223
+ JS_ASSERT(flagsword | JSFUN_INTERPRETED);
1224
+ fun->flags = (uint16) flagsword;
1225
+ }
1226
+
1227
+ /* do arguments and local vars */
1228
+ n = nargs + nvars;
1229
+ if (n != 0) {
1230
+ void *mark;
1231
+ uintN i;
1232
+ uintN bitmapLength;
1233
+ uint32 *bitmap;
1234
+ jsuword *names;
1235
+ JSAtom *name;
1236
+ JSLocalKind localKind;
1237
+
1238
+ mark = JS_ARENA_MARK(&xdr->cx->tempPool);
1239
+
1240
+ /*
1241
+ * From this point the control must flow via the label release_mark.
1242
+ *
1243
+ * To xdr the names we prefix the names with a bitmap descriptor and
1244
+ * then xdr the names as strings. For argument names (indexes below
1245
+ * nargs) the corresponding bit in the bitmap is unset when the name
1246
+ * is null. Such null names are not encoded or decoded. For variable
1247
+ * names (indexes starting from nargs) bitmap's bit is set when the
1248
+ * name is declared as const, not as ordinary var.
1249
+ * */
1250
+ bitmapLength = JS_HOWMANY(n, JS_BITS_PER_UINT32);
1251
+ JS_ARENA_ALLOCATE_CAST(bitmap, uint32 *, &xdr->cx->tempPool,
1252
+ bitmapLength * sizeof *bitmap);
1253
+ if (!bitmap) {
1254
+ js_ReportOutOfScriptQuota(xdr->cx);
1255
+ ok = JS_FALSE;
1256
+ goto release_mark;
1257
+ }
1258
+ if (xdr->mode == JSXDR_ENCODE) {
1259
+ names = js_GetLocalNameArray(xdr->cx, fun, &xdr->cx->tempPool);
1260
+ if (!names) {
1261
+ ok = JS_FALSE;
1262
+ goto release_mark;
1263
+ }
1264
+ memset(bitmap, 0, bitmapLength * sizeof *bitmap);
1265
+ for (i = 0; i != n; ++i) {
1266
+ if (i < fun->nargs
1267
+ ? JS_LOCAL_NAME_TO_ATOM(names[i]) != NULL
1268
+ : JS_LOCAL_NAME_IS_CONST(names[i])) {
1269
+ bitmap[i >> JS_BITS_PER_UINT32_LOG2] |=
1270
+ JS_BIT(i & (JS_BITS_PER_UINT32 - 1));
1271
+ }
1272
+ }
1273
+ }
1274
+ #ifdef __GNUC__
1275
+ else {
1276
+ names = NULL; /* quell GCC uninitialized warning */
1277
+ }
1278
+ #endif
1279
+ for (i = 0; i != bitmapLength; ++i) {
1280
+ ok = JS_XDRUint32(xdr, &bitmap[i]);
1281
+ if (!ok)
1282
+ goto release_mark;
1283
+ }
1284
+ for (i = 0; i != n; ++i) {
1285
+ if (i < nargs &&
1286
+ !(bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
1287
+ JS_BIT(i & (JS_BITS_PER_UINT32 - 1)))) {
1288
+ if (xdr->mode == JSXDR_DECODE) {
1289
+ ok = js_AddLocal(xdr->cx, fun, NULL, JSLOCAL_ARG);
1290
+ if (!ok)
1291
+ goto release_mark;
1292
+ } else {
1293
+ JS_ASSERT(!JS_LOCAL_NAME_TO_ATOM(names[i]));
1294
+ }
1295
+ continue;
1296
+ }
1297
+ if (xdr->mode == JSXDR_ENCODE)
1298
+ name = JS_LOCAL_NAME_TO_ATOM(names[i]);
1299
+ ok = js_XDRStringAtom(xdr, &name);
1300
+ if (!ok)
1301
+ goto release_mark;
1302
+ if (xdr->mode == JSXDR_DECODE) {
1303
+ localKind = (i < nargs)
1304
+ ? JSLOCAL_ARG
1305
+ : bitmap[i >> JS_BITS_PER_UINT32_LOG2] &
1306
+ JS_BIT(i & (JS_BITS_PER_UINT32 - 1))
1307
+ ? JSLOCAL_CONST
1308
+ : JSLOCAL_VAR;
1309
+ ok = js_AddLocal(xdr->cx, fun, name, localKind);
1310
+ if (!ok)
1311
+ goto release_mark;
1312
+ }
1313
+ }
1314
+ ok = JS_TRUE;
1315
+
1316
+ release_mark:
1317
+ JS_ARENA_RELEASE(&xdr->cx->tempPool, mark);
1318
+ if (!ok)
1319
+ goto out;
1320
+
1321
+ if (xdr->mode == JSXDR_DECODE)
1322
+ js_FreezeLocalNames(cx, fun);
1323
+ }
1324
+
1325
+ if (!js_XDRScript(xdr, &fun->u.i.script, NULL))
1326
+ goto bad;
1327
+
1328
+ if (xdr->mode == JSXDR_DECODE) {
1329
+ *objp = FUN_OBJECT(fun);
1330
+ #ifdef CHECK_SCRIPT_OWNER
1331
+ fun->u.i.script->owner = NULL;
1332
+ #endif
1333
+ js_CallNewScriptHook(cx, fun->u.i.script, fun);
1334
+ }
1335
+
1336
+ out:
1337
+ JS_POP_TEMP_ROOT(cx, &tvr);
1338
+ return ok;
1339
+
1340
+ bad:
1341
+ ok = JS_FALSE;
1342
+ goto out;
1343
+ }
1344
+
1345
+ #else /* !JS_HAS_XDR */
1346
+
1347
+ #define fun_xdrObject NULL
1348
+
1349
+ #endif /* !JS_HAS_XDR */
1350
+
1351
+ /*
1352
+ * [[HasInstance]] internal method for Function objects: fetch the .prototype
1353
+ * property of its 'this' parameter, and walks the prototype chain of v (only
1354
+ * if v is an object) returning true if .prototype is found.
1355
+ */
1356
+ static JSBool
1357
+ fun_hasInstance(JSContext *cx, JSObject *obj, jsval v, JSBool *bp)
1358
+ {
1359
+ jsval pval;
1360
+
1361
+ if (!OBJ_GET_PROPERTY(cx, obj,
1362
+ ATOM_TO_JSID(cx->runtime->atomState
1363
+ .classPrototypeAtom),
1364
+ &pval)) {
1365
+ return JS_FALSE;
1366
+ }
1367
+
1368
+ if (JSVAL_IS_PRIMITIVE(pval)) {
1369
+ /*
1370
+ * Throw a runtime error if instanceof is called on a function that
1371
+ * has a non-object as its .prototype value.
1372
+ */
1373
+ js_ReportValueError(cx, JSMSG_BAD_PROTOTYPE,
1374
+ -1, OBJECT_TO_JSVAL(obj), NULL);
1375
+ return JS_FALSE;
1376
+ }
1377
+
1378
+ return js_IsDelegate(cx, JSVAL_TO_OBJECT(pval), v, bp);
1379
+ }
1380
+
1381
+ static void
1382
+ TraceLocalNames(JSTracer *trc, JSFunction *fun);
1383
+
1384
+ static void
1385
+ DestroyLocalNames(JSContext *cx, JSFunction *fun);
1386
+
1387
+ static void
1388
+ fun_trace(JSTracer *trc, JSObject *obj)
1389
+ {
1390
+ JSFunction *fun;
1391
+
1392
+ /* A newborn function object may have a not yet initialized private slot. */
1393
+ fun = (JSFunction *) JS_GetPrivate(trc->context, obj);
1394
+ if (!fun)
1395
+ return;
1396
+
1397
+ if (FUN_OBJECT(fun) != obj) {
1398
+ /* obj is cloned function object, trace the original. */
1399
+ JS_CALL_TRACER(trc, FUN_OBJECT(fun), JSTRACE_OBJECT, "private");
1400
+ return;
1401
+ }
1402
+ if (fun->atom)
1403
+ JS_CALL_STRING_TRACER(trc, ATOM_TO_STRING(fun->atom), "atom");
1404
+ if (FUN_INTERPRETED(fun)) {
1405
+ if (fun->u.i.script)
1406
+ js_TraceScript(trc, fun->u.i.script);
1407
+ TraceLocalNames(trc, fun);
1408
+ }
1409
+ }
1410
+
1411
+ static void
1412
+ fun_finalize(JSContext *cx, JSObject *obj)
1413
+ {
1414
+ JSFunction *fun;
1415
+
1416
+ /* Ignore newborn and cloned function objects. */
1417
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
1418
+ if (!fun || FUN_OBJECT(fun) != obj)
1419
+ return;
1420
+
1421
+ /*
1422
+ * Null-check of u.i.script is required since the parser sets interpreted
1423
+ * very early.
1424
+ */
1425
+ if (FUN_INTERPRETED(fun)) {
1426
+ if (fun->u.i.script)
1427
+ js_DestroyScript(cx, fun->u.i.script);
1428
+ DestroyLocalNames(cx, fun);
1429
+ }
1430
+ }
1431
+
1432
+ static uint32
1433
+ fun_reserveSlots(JSContext *cx, JSObject *obj)
1434
+ {
1435
+ JSFunction *fun;
1436
+
1437
+ /*
1438
+ * We use JS_GetPrivate and not GET_FUNCTION_PRIVATE because during
1439
+ * js_InitFunctionClass invocation the function is called before the
1440
+ * private slot of the function object is set.
1441
+ */
1442
+ fun = (JSFunction *) JS_GetPrivate(cx, obj);
1443
+ return (fun && FUN_INTERPRETED(fun) &&
1444
+ fun->u.i.script && fun->u.i.script->regexpsOffset != 0)
1445
+ ? JS_SCRIPT_REGEXPS(fun->u.i.script)->length
1446
+ : 0;
1447
+ }
1448
+
1449
+ /*
1450
+ * Reserve two slots in all function objects for XPConnect. Note that this
1451
+ * does not bloat every instance, only those on which reserved slots are set,
1452
+ * and those on which ad-hoc properties are defined.
1453
+ */
1454
+ JS_FRIEND_DATA(JSClass) js_FunctionClass = {
1455
+ js_Function_str,
1456
+ JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(2) |
1457
+ JSCLASS_MARK_IS_TRACE | JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
1458
+ JS_PropertyStub, JS_PropertyStub,
1459
+ fun_getProperty, JS_PropertyStub,
1460
+ fun_enumerate, (JSResolveOp)fun_resolve,
1461
+ fun_convert, fun_finalize,
1462
+ NULL, NULL,
1463
+ NULL, NULL,
1464
+ fun_xdrObject, fun_hasInstance,
1465
+ JS_CLASS_TRACE(fun_trace), fun_reserveSlots
1466
+ };
1467
+
1468
+ static JSBool
1469
+ fun_toStringHelper(JSContext *cx, uint32 indent, uintN argc, jsval *vp)
1470
+ {
1471
+ jsval fval;
1472
+ JSObject *obj;
1473
+ JSFunction *fun;
1474
+ JSString *str;
1475
+
1476
+ fval = JS_THIS(cx, vp);
1477
+ if (JSVAL_IS_NULL(fval))
1478
+ return JS_FALSE;
1479
+
1480
+ if (!VALUE_IS_FUNCTION(cx, fval)) {
1481
+ /*
1482
+ * If we don't have a function to start off with, try converting the
1483
+ * object to a function. If that doesn't work, complain.
1484
+ */
1485
+ if (!JSVAL_IS_PRIMITIVE(fval)) {
1486
+ obj = JSVAL_TO_OBJECT(fval);
1487
+ if (!OBJ_GET_CLASS(cx, obj)->convert(cx, obj, JSTYPE_FUNCTION,
1488
+ &fval)) {
1489
+ return JS_FALSE;
1490
+ }
1491
+ vp[1] = fval;
1492
+ }
1493
+ if (!VALUE_IS_FUNCTION(cx, fval)) {
1494
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1495
+ JSMSG_INCOMPATIBLE_PROTO,
1496
+ js_Function_str, js_toString_str,
1497
+ JS_GetTypeName(cx, JS_TypeOfValue(cx, fval)));
1498
+ return JS_FALSE;
1499
+ }
1500
+ }
1501
+
1502
+ obj = JSVAL_TO_OBJECT(fval);
1503
+ if (argc != 0) {
1504
+ indent = js_ValueToECMAUint32(cx, &vp[2]);
1505
+ if (JSVAL_IS_NULL(vp[2]))
1506
+ return JS_FALSE;
1507
+ }
1508
+
1509
+ JS_ASSERT(JS_ObjectIsFunction(cx, obj));
1510
+ fun = GET_FUNCTION_PRIVATE(cx, obj);
1511
+ if (!fun)
1512
+ return JS_TRUE;
1513
+ str = JS_DecompileFunction(cx, fun, (uintN)indent);
1514
+ if (!str)
1515
+ return JS_FALSE;
1516
+ *vp = STRING_TO_JSVAL(str);
1517
+ return JS_TRUE;
1518
+ }
1519
+
1520
+ static JSBool
1521
+ fun_toString(JSContext *cx, uintN argc, jsval *vp)
1522
+ {
1523
+ return fun_toStringHelper(cx, 0, argc, vp);
1524
+ }
1525
+
1526
+ #if JS_HAS_TOSOURCE
1527
+ static JSBool
1528
+ fun_toSource(JSContext *cx, uintN argc, jsval *vp)
1529
+ {
1530
+ return fun_toStringHelper(cx, JS_DONT_PRETTY_PRINT, argc, vp);
1531
+ }
1532
+ #endif
1533
+
1534
+ static const char call_str[] = "call";
1535
+
1536
+ static JSBool
1537
+ fun_call(JSContext *cx, uintN argc, jsval *vp)
1538
+ {
1539
+ JSObject *obj;
1540
+ jsval fval, *argv, *invokevp;
1541
+ JSString *str;
1542
+ void *mark;
1543
+ JSBool ok;
1544
+
1545
+ obj = JS_THIS_OBJECT(cx, vp);
1546
+ if (!obj || !OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1]))
1547
+ return JS_FALSE;
1548
+ fval = vp[1];
1549
+
1550
+ if (!VALUE_IS_FUNCTION(cx, fval)) {
1551
+ str = JS_ValueToString(cx, fval);
1552
+ if (str) {
1553
+ const char *bytes = js_GetStringBytes(cx, str);
1554
+
1555
+ if (bytes) {
1556
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1557
+ JSMSG_INCOMPATIBLE_PROTO,
1558
+ js_Function_str, call_str,
1559
+ bytes);
1560
+ }
1561
+ }
1562
+ return JS_FALSE;
1563
+ }
1564
+
1565
+ argv = vp + 2;
1566
+ if (argc == 0) {
1567
+ /* Call fun with its global object as the 'this' param if no args. */
1568
+ obj = NULL;
1569
+ } else {
1570
+ /* Otherwise convert the first arg to 'this' and skip over it. */
1571
+ if (!JSVAL_IS_PRIMITIVE(argv[0]))
1572
+ obj = JSVAL_TO_OBJECT(argv[0]);
1573
+ else if (!js_ValueToObject(cx, argv[0], &obj))
1574
+ return JS_FALSE;
1575
+ argc--;
1576
+ argv++;
1577
+ }
1578
+
1579
+ /* Allocate stack space for fval, obj, and the args. */
1580
+ invokevp = js_AllocStack(cx, 2 + argc, &mark);
1581
+ if (!invokevp)
1582
+ return JS_FALSE;
1583
+
1584
+ /* Push fval, obj, and the args. */
1585
+ invokevp[0] = fval;
1586
+ invokevp[1] = OBJECT_TO_JSVAL(obj);
1587
+ memcpy(invokevp + 2, argv, argc * sizeof *argv);
1588
+
1589
+ ok = js_Invoke(cx, argc, invokevp, 0);
1590
+ *vp = *invokevp;
1591
+ js_FreeStack(cx, mark);
1592
+ return ok;
1593
+ }
1594
+
1595
+ static JSBool
1596
+ fun_apply(JSContext *cx, uintN argc, jsval *vp)
1597
+ {
1598
+ JSObject *obj, *aobj;
1599
+ jsval fval, *invokevp, *sp;
1600
+ JSString *str;
1601
+ jsuint length;
1602
+ JSBool arraylike, ok;
1603
+ void *mark;
1604
+ uintN i;
1605
+
1606
+ if (argc == 0) {
1607
+ /* Will get globalObject as 'this' and no other arguments. */
1608
+ return fun_call(cx, argc, vp);
1609
+ }
1610
+
1611
+ obj = JS_THIS_OBJECT(cx, vp);
1612
+ if (!obj || !OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &vp[1]))
1613
+ return JS_FALSE;
1614
+ fval = vp[1];
1615
+
1616
+ if (!VALUE_IS_FUNCTION(cx, fval)) {
1617
+ str = JS_ValueToString(cx, fval);
1618
+ if (str) {
1619
+ const char *bytes = js_GetStringBytes(cx, str);
1620
+
1621
+ if (bytes) {
1622
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1623
+ JSMSG_INCOMPATIBLE_PROTO,
1624
+ js_Function_str, "apply",
1625
+ bytes);
1626
+ }
1627
+ }
1628
+ return JS_FALSE;
1629
+ }
1630
+
1631
+ /* Quell GCC overwarnings. */
1632
+ aobj = NULL;
1633
+ length = 0;
1634
+
1635
+ if (argc >= 2) {
1636
+ /* If the 2nd arg is null or void, call the function with 0 args. */
1637
+ if (JSVAL_IS_NULL(vp[3]) || JSVAL_IS_VOID(vp[3])) {
1638
+ argc = 0;
1639
+ } else {
1640
+ /* The second arg must be an array (or arguments object). */
1641
+ arraylike = JS_FALSE;
1642
+ if (!JSVAL_IS_PRIMITIVE(vp[3])) {
1643
+ aobj = JSVAL_TO_OBJECT(vp[3]);
1644
+ if (!js_IsArrayLike(cx, aobj, &arraylike, &length))
1645
+ return JS_FALSE;
1646
+ }
1647
+ if (!arraylike) {
1648
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1649
+ JSMSG_BAD_APPLY_ARGS, "apply");
1650
+ return JS_FALSE;
1651
+ }
1652
+ }
1653
+ }
1654
+
1655
+ /* Convert the first arg to 'this' and skip over it. */
1656
+ if (!JSVAL_IS_PRIMITIVE(vp[2]))
1657
+ obj = JSVAL_TO_OBJECT(vp[2]);
1658
+ else if (!js_ValueToObject(cx, vp[2], &obj))
1659
+ return JS_FALSE;
1660
+
1661
+ /* Allocate stack space for fval, obj, and the args. */
1662
+ argc = (uintN)JS_MIN(length, ARRAY_INIT_LIMIT - 1);
1663
+ invokevp = js_AllocStack(cx, 2 + argc, &mark);
1664
+ if (!invokevp)
1665
+ return JS_FALSE;
1666
+
1667
+ /* Push fval, obj, and aobj's elements as args. */
1668
+ sp = invokevp;
1669
+ *sp++ = fval;
1670
+ *sp++ = OBJECT_TO_JSVAL(obj);
1671
+ for (i = 0; i < argc; i++) {
1672
+ ok = JS_GetElement(cx, aobj, (jsint)i, sp);
1673
+ if (!ok)
1674
+ goto out;
1675
+ sp++;
1676
+ }
1677
+
1678
+ ok = js_Invoke(cx, argc, invokevp, 0);
1679
+ *vp = *invokevp;
1680
+ out:
1681
+ js_FreeStack(cx, mark);
1682
+ return ok;
1683
+ }
1684
+
1685
+ #ifdef NARCISSUS
1686
+ static JSBool
1687
+ fun_applyConstructor(JSContext *cx, uintN argc, jsval *vp)
1688
+ {
1689
+ JSObject *aobj;
1690
+ uintN length, i;
1691
+ void *mark;
1692
+ jsval *invokevp, *sp;
1693
+ JSBool ok;
1694
+
1695
+ if (JSVAL_IS_PRIMITIVE(vp[2]) ||
1696
+ (aobj = JSVAL_TO_OBJECT(vp[2]),
1697
+ OBJ_GET_CLASS(cx, aobj) != &js_ArrayClass &&
1698
+ OBJ_GET_CLASS(cx, aobj) != &js_ArgumentsClass)) {
1699
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1700
+ JSMSG_BAD_APPLY_ARGS, "__applyConstruct__");
1701
+ return JS_FALSE;
1702
+ }
1703
+
1704
+ if (!js_GetLengthProperty(cx, aobj, &length))
1705
+ return JS_FALSE;
1706
+
1707
+ if (length >= ARRAY_INIT_LIMIT)
1708
+ length = ARRAY_INIT_LIMIT - 1;
1709
+ invokevp = js_AllocStack(cx, 2 + length, &mark);
1710
+ if (!invokevp)
1711
+ return JS_FALSE;
1712
+
1713
+ sp = invokevp;
1714
+ *sp++ = vp[1];
1715
+ *sp++ = JSVAL_NULL; /* this is filled automagically */
1716
+ for (i = 0; i < length; i++) {
1717
+ ok = JS_GetElement(cx, aobj, (jsint)i, sp);
1718
+ if (!ok)
1719
+ goto out;
1720
+ sp++;
1721
+ }
1722
+
1723
+ ok = js_InvokeConstructor(cx, length, invokevp);
1724
+ *vp = *invokevp;
1725
+ out:
1726
+ js_FreeStack(cx, mark);
1727
+ return ok;
1728
+ }
1729
+ #endif
1730
+
1731
+ static JSFunctionSpec function_methods[] = {
1732
+ #if JS_HAS_TOSOURCE
1733
+ JS_FN(js_toSource_str, fun_toSource, 0,0,0),
1734
+ #endif
1735
+ JS_FN(js_toString_str, fun_toString, 0,0,0),
1736
+ JS_FN("apply", fun_apply, 0,2,0),
1737
+ JS_FN(call_str, fun_call, 0,1,0),
1738
+ #ifdef NARCISSUS
1739
+ JS_FN("__applyConstructor__", fun_applyConstructor, 0,1,0),
1740
+ #endif
1741
+ JS_FS_END
1742
+ };
1743
+
1744
+ static JSBool
1745
+ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
1746
+ {
1747
+ JSStackFrame *fp, *caller;
1748
+ JSFunction *fun;
1749
+ JSObject *parent;
1750
+ uintN i, n, lineno;
1751
+ JSAtom *atom;
1752
+ const char *filename;
1753
+ JSBool ok;
1754
+ JSString *str, *arg;
1755
+ JSTokenStream ts;
1756
+ JSPrincipals *principals;
1757
+ jschar *collected_args, *cp;
1758
+ void *mark;
1759
+ size_t arg_length, args_length, old_args_length;
1760
+ JSTokenType tt;
1761
+
1762
+ fp = cx->fp;
1763
+ if (!(fp->flags & JSFRAME_CONSTRUCTING)) {
1764
+ obj = js_NewObject(cx, &js_FunctionClass, NULL, NULL, 0);
1765
+ if (!obj)
1766
+ return JS_FALSE;
1767
+ *rval = OBJECT_TO_JSVAL(obj);
1768
+ } else {
1769
+ /*
1770
+ * The constructor is called before the private slot is initialized so
1771
+ * we must use JS_GetPrivate, not GET_FUNCTION_PRIVATE here.
1772
+ */
1773
+ if (JS_GetPrivate(cx, obj))
1774
+ return JS_TRUE;
1775
+ }
1776
+
1777
+ /*
1778
+ * NB: (new Function) is not lexically closed by its caller, it's just an
1779
+ * anonymous function in the top-level scope that its constructor inhabits.
1780
+ * Thus 'var x = 42; f = new Function("return x"); print(f())' prints 42,
1781
+ * and so would a call to f from another top-level's script or function.
1782
+ *
1783
+ * In older versions, before call objects, a new Function was adopted by
1784
+ * its running context's globalObject, which might be different from the
1785
+ * top-level reachable from scopeChain (in HTML frames, e.g.).
1786
+ */
1787
+ parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(argv[-2]));
1788
+
1789
+ fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
1790
+ parent, cx->runtime->atomState.anonymousAtom);
1791
+
1792
+ if (!fun)
1793
+ return JS_FALSE;
1794
+
1795
+ /*
1796
+ * Function is static and not called directly by other functions in this
1797
+ * file, therefore it is callable only as a native function by js_Invoke.
1798
+ * Find the scripted caller, possibly skipping other native frames such as
1799
+ * are built for Function.prototype.call or .apply activations that invoke
1800
+ * Function indirectly from a script.
1801
+ */
1802
+ JS_ASSERT(!fp->script && fp->fun && fp->fun->u.n.native == Function);
1803
+ caller = JS_GetScriptedCaller(cx, fp);
1804
+ if (caller) {
1805
+ principals = JS_EvalFramePrincipals(cx, fp, caller);
1806
+ filename = js_ComputeFilename(cx, caller, principals, &lineno);
1807
+ } else {
1808
+ filename = NULL;
1809
+ lineno = 0;
1810
+ principals = NULL;
1811
+ }
1812
+
1813
+ /* Belt-and-braces: check that the caller has access to parent. */
1814
+ if (!js_CheckPrincipalsAccess(cx, parent, principals,
1815
+ CLASS_ATOM(cx, Function))) {
1816
+ return JS_FALSE;
1817
+ }
1818
+
1819
+ n = argc ? argc - 1 : 0;
1820
+ if (n > 0) {
1821
+ enum { OK, BAD, BAD_FORMAL } state;
1822
+
1823
+ /*
1824
+ * Collect the function-argument arguments into one string, separated
1825
+ * by commas, then make a tokenstream from that string, and scan it to
1826
+ * get the arguments. We need to throw the full scanner at the
1827
+ * problem, because the argument string can legitimately contain
1828
+ * comments and linefeeds. XXX It might be better to concatenate
1829
+ * everything up into a function definition and pass it to the
1830
+ * compiler, but doing it this way is less of a delta from the old
1831
+ * code. See ECMA 15.3.2.1.
1832
+ */
1833
+ state = BAD_FORMAL;
1834
+ args_length = 0;
1835
+ for (i = 0; i < n; i++) {
1836
+ /* Collect the lengths for all the function-argument arguments. */
1837
+ arg = js_ValueToString(cx, argv[i]);
1838
+ if (!arg)
1839
+ return JS_FALSE;
1840
+ argv[i] = STRING_TO_JSVAL(arg);
1841
+
1842
+ /*
1843
+ * Check for overflow. The < test works because the maximum
1844
+ * JSString length fits in 2 fewer bits than size_t has.
1845
+ */
1846
+ old_args_length = args_length;
1847
+ args_length = old_args_length + JSSTRING_LENGTH(arg);
1848
+ if (args_length < old_args_length) {
1849
+ js_ReportAllocationOverflow(cx);
1850
+ return JS_FALSE;
1851
+ }
1852
+ }
1853
+
1854
+ /* Add 1 for each joining comma and check for overflow (two ways). */
1855
+ old_args_length = args_length;
1856
+ args_length = old_args_length + n - 1;
1857
+ if (args_length < old_args_length ||
1858
+ args_length >= ~(size_t)0 / sizeof(jschar)) {
1859
+ js_ReportAllocationOverflow(cx);
1860
+ return JS_FALSE;
1861
+ }
1862
+
1863
+ /*
1864
+ * Allocate a string to hold the concatenated arguments, including room
1865
+ * for a terminating 0. Mark cx->tempPool for later release, to free
1866
+ * collected_args and its tokenstream in one swoop.
1867
+ */
1868
+ mark = JS_ARENA_MARK(&cx->tempPool);
1869
+ JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
1870
+ (args_length+1) * sizeof(jschar));
1871
+ if (!cp) {
1872
+ js_ReportOutOfScriptQuota(cx);
1873
+ return JS_FALSE;
1874
+ }
1875
+ collected_args = cp;
1876
+
1877
+ /*
1878
+ * Concatenate the arguments into the new string, separated by commas.
1879
+ */
1880
+ for (i = 0; i < n; i++) {
1881
+ arg = JSVAL_TO_STRING(argv[i]);
1882
+ arg_length = JSSTRING_LENGTH(arg);
1883
+ (void) js_strncpy(cp, JSSTRING_CHARS(arg), arg_length);
1884
+ cp += arg_length;
1885
+
1886
+ /* Add separating comma or terminating 0. */
1887
+ *cp++ = (i + 1 < n) ? ',' : 0;
1888
+ }
1889
+
1890
+ /* Initialize a tokenstream that reads from the given string. */
1891
+ if (!js_InitTokenStream(cx, &ts, collected_args, args_length,
1892
+ NULL, filename, lineno)) {
1893
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
1894
+ return JS_FALSE;
1895
+ }
1896
+
1897
+ /* The argument string may be empty or contain no tokens. */
1898
+ tt = js_GetToken(cx, &ts);
1899
+ if (tt != TOK_EOF) {
1900
+ for (;;) {
1901
+ /*
1902
+ * Check that it's a name. This also implicitly guards against
1903
+ * TOK_ERROR, which was already reported.
1904
+ */
1905
+ if (tt != TOK_NAME)
1906
+ goto after_args;
1907
+
1908
+ /*
1909
+ * Get the atom corresponding to the name from the token
1910
+ * stream; we're assured at this point that it's a valid
1911
+ * identifier.
1912
+ */
1913
+ atom = CURRENT_TOKEN(&ts).t_atom;
1914
+
1915
+ /* Check for a duplicate parameter name. */
1916
+ if (js_LookupLocal(cx, fun, atom, NULL) != JSLOCAL_NONE) {
1917
+ const char *name;
1918
+
1919
+ name = js_AtomToPrintableString(cx, atom);
1920
+ ok = name &&
1921
+ js_ReportCompileErrorNumber(cx, &ts, NULL,
1922
+ JSREPORT_WARNING |
1923
+ JSREPORT_STRICT,
1924
+ JSMSG_DUPLICATE_FORMAL,
1925
+ name);
1926
+ if (!ok)
1927
+ goto after_args;
1928
+ }
1929
+ if (!js_AddLocal(cx, fun, atom, JSLOCAL_ARG))
1930
+ goto after_args;
1931
+
1932
+ /*
1933
+ * Get the next token. Stop on end of stream. Otherwise
1934
+ * insist on a comma, get another name, and iterate.
1935
+ */
1936
+ tt = js_GetToken(cx, &ts);
1937
+ if (tt == TOK_EOF)
1938
+ break;
1939
+ if (tt != TOK_COMMA)
1940
+ goto after_args;
1941
+ tt = js_GetToken(cx, &ts);
1942
+ }
1943
+ }
1944
+
1945
+ state = OK;
1946
+ after_args:
1947
+ if (state == BAD_FORMAL && !(ts.flags & TSF_ERROR)) {
1948
+ /*
1949
+ * Report "malformed formal parameter" iff no illegal char or
1950
+ * similar scanner error was already reported.
1951
+ */
1952
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
1953
+ JSMSG_BAD_FORMAL);
1954
+ }
1955
+ js_CloseTokenStream(cx, &ts);
1956
+ JS_ARENA_RELEASE(&cx->tempPool, mark);
1957
+ if (state != OK)
1958
+ return JS_FALSE;
1959
+ }
1960
+
1961
+ if (argc) {
1962
+ str = js_ValueToString(cx, argv[argc-1]);
1963
+ if (!str)
1964
+ return JS_FALSE;
1965
+ argv[argc-1] = STRING_TO_JSVAL(str);
1966
+ } else {
1967
+ str = cx->runtime->emptyString;
1968
+ }
1969
+
1970
+ return js_CompileFunctionBody(cx, fun, principals,
1971
+ JSSTRING_CHARS(str), JSSTRING_LENGTH(str),
1972
+ filename, lineno);
1973
+ }
1974
+
1975
+ JSObject *
1976
+ js_InitFunctionClass(JSContext *cx, JSObject *obj)
1977
+ {
1978
+ JSObject *proto;
1979
+ JSFunction *fun;
1980
+
1981
+ proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,
1982
+ function_props, function_methods, NULL, NULL);
1983
+ if (!proto)
1984
+ return NULL;
1985
+ fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL);
1986
+ if (!fun)
1987
+ goto bad;
1988
+ fun->u.i.script = js_NewScript(cx, 1, 0, 0, 0, 0, 0);
1989
+ if (!fun->u.i.script)
1990
+ goto bad;
1991
+ fun->u.i.script->code[0] = JSOP_STOP;
1992
+ #ifdef CHECK_SCRIPT_OWNER
1993
+ fun->u.i.script->owner = NULL;
1994
+ #endif
1995
+ return proto;
1996
+
1997
+ bad:
1998
+ cx->weakRoots.newborn[GCX_OBJECT] = NULL;
1999
+ return NULL;
2000
+ }
2001
+
2002
+ JSObject *
2003
+ js_InitCallClass(JSContext *cx, JSObject *obj)
2004
+ {
2005
+ JSObject *proto;
2006
+
2007
+ proto = JS_InitClass(cx, obj, NULL, &js_CallClass, NULL, 0,
2008
+ NULL, NULL, NULL, NULL);
2009
+ if (!proto)
2010
+ return NULL;
2011
+
2012
+ /*
2013
+ * Null Call.prototype's proto slot so that Object.prototype.* does not
2014
+ * pollute the scope of heavyweight functions.
2015
+ */
2016
+ OBJ_SET_PROTO(cx, proto, NULL);
2017
+ return proto;
2018
+ }
2019
+
2020
+ JSFunction *
2021
+ js_NewFunction(JSContext *cx, JSObject *funobj, JSNative native, uintN nargs,
2022
+ uintN flags, JSObject *parent, JSAtom *atom)
2023
+ {
2024
+ JSFunction *fun;
2025
+
2026
+ if (funobj) {
2027
+ JS_ASSERT(HAS_FUNCTION_CLASS(funobj));
2028
+ OBJ_SET_PARENT(cx, funobj, parent);
2029
+ } else {
2030
+ funobj = js_NewObject(cx, &js_FunctionClass, NULL, parent, 0);
2031
+ if (!funobj)
2032
+ return NULL;
2033
+ }
2034
+ JS_ASSERT(funobj->fslots[JSSLOT_PRIVATE] == JSVAL_VOID);
2035
+ fun = (JSFunction *) funobj;
2036
+
2037
+ /* Initialize all function members. */
2038
+ fun->nargs = nargs;
2039
+ fun->flags = flags & (JSFUN_FLAGS_MASK | JSFUN_INTERPRETED);
2040
+ if (flags & JSFUN_INTERPRETED) {
2041
+ JS_ASSERT(!native);
2042
+ JS_ASSERT(nargs == 0);
2043
+ fun->u.i.nvars = 0;
2044
+ fun->u.i.spare = 0;
2045
+ fun->u.i.script = NULL;
2046
+ #ifdef DEBUG
2047
+ fun->u.i.names.taggedAtom = 0;
2048
+ #endif
2049
+ } else {
2050
+ fun->u.n.native = native;
2051
+ fun->u.n.extra = 0;
2052
+ fun->u.n.minargs = 0;
2053
+ fun->u.n.clasp = NULL;
2054
+ }
2055
+ fun->atom = atom;
2056
+
2057
+ /* Set private to self to indicate non-cloned fully initialized function. */
2058
+ FUN_OBJECT(fun)->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
2059
+ return fun;
2060
+ }
2061
+
2062
+ JSObject *
2063
+ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent)
2064
+ {
2065
+ JSObject *clone;
2066
+
2067
+ /*
2068
+ * The cloned function object does not need the extra fields beyond
2069
+ * JSObject as it points to fun via the private slot.
2070
+ */
2071
+ clone = js_NewObject(cx, &js_FunctionClass, NULL, parent,
2072
+ sizeof(JSObject));
2073
+ if (!clone)
2074
+ return NULL;
2075
+ clone->fslots[JSSLOT_PRIVATE] = PRIVATE_TO_JSVAL(fun);
2076
+ return clone;
2077
+ }
2078
+
2079
+ JSFunction *
2080
+ js_DefineFunction(JSContext *cx, JSObject *obj, JSAtom *atom, JSNative native,
2081
+ uintN nargs, uintN attrs)
2082
+ {
2083
+ JSFunction *fun;
2084
+ JSPropertyOp gsop;
2085
+
2086
+ fun = js_NewFunction(cx, NULL, native, nargs, attrs, obj, atom);
2087
+ if (!fun)
2088
+ return NULL;
2089
+ gsop = (attrs & JSFUN_STUB_GSOPS) ? JS_PropertyStub : NULL;
2090
+ if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom),
2091
+ OBJECT_TO_JSVAL(FUN_OBJECT(fun)),
2092
+ gsop, gsop,
2093
+ attrs & ~JSFUN_FLAGS_MASK, NULL)) {
2094
+ return NULL;
2095
+ }
2096
+ return fun;
2097
+ }
2098
+
2099
+ #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)
2100
+ # error "JSINVOKE_CONSTRUCT and JSV2F_SEARCH_STACK are not disjoint!"
2101
+ #endif
2102
+
2103
+ JSFunction *
2104
+ js_ValueToFunction(JSContext *cx, jsval *vp, uintN flags)
2105
+ {
2106
+ jsval v;
2107
+ JSObject *obj;
2108
+
2109
+ v = *vp;
2110
+ obj = NULL;
2111
+ if (JSVAL_IS_OBJECT(v)) {
2112
+ obj = JSVAL_TO_OBJECT(v);
2113
+ if (obj && OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
2114
+ if (!OBJ_DEFAULT_VALUE(cx, obj, JSTYPE_FUNCTION, &v))
2115
+ return NULL;
2116
+ obj = VALUE_IS_FUNCTION(cx, v) ? JSVAL_TO_OBJECT(v) : NULL;
2117
+ }
2118
+ }
2119
+ if (!obj) {
2120
+ js_ReportIsNotFunction(cx, vp, flags);
2121
+ return NULL;
2122
+ }
2123
+ return GET_FUNCTION_PRIVATE(cx, obj);
2124
+ }
2125
+
2126
+ JSObject *
2127
+ js_ValueToFunctionObject(JSContext *cx, jsval *vp, uintN flags)
2128
+ {
2129
+ JSFunction *fun;
2130
+ JSStackFrame *caller;
2131
+ JSPrincipals *principals;
2132
+
2133
+ if (VALUE_IS_FUNCTION(cx, *vp))
2134
+ return JSVAL_TO_OBJECT(*vp);
2135
+
2136
+ fun = js_ValueToFunction(cx, vp, flags);
2137
+ if (!fun)
2138
+ return NULL;
2139
+ *vp = OBJECT_TO_JSVAL(FUN_OBJECT(fun));
2140
+
2141
+ caller = JS_GetScriptedCaller(cx, cx->fp);
2142
+ if (caller) {
2143
+ principals = JS_StackFramePrincipals(cx, caller);
2144
+ } else {
2145
+ /* No scripted caller, don't allow access. */
2146
+ principals = NULL;
2147
+ }
2148
+
2149
+ if (!js_CheckPrincipalsAccess(cx, FUN_OBJECT(fun), principals,
2150
+ fun->atom
2151
+ ? fun->atom
2152
+ : cx->runtime->atomState.anonymousAtom)) {
2153
+ return NULL;
2154
+ }
2155
+ return FUN_OBJECT(fun);
2156
+ }
2157
+
2158
+ JSObject *
2159
+ js_ValueToCallableObject(JSContext *cx, jsval *vp, uintN flags)
2160
+ {
2161
+ JSObject *callable;
2162
+
2163
+ callable = JSVAL_IS_PRIMITIVE(*vp) ? NULL : JSVAL_TO_OBJECT(*vp);
2164
+ if (callable &&
2165
+ ((callable->map->ops == &js_ObjectOps)
2166
+ ? OBJ_GET_CLASS(cx, callable)->call
2167
+ : callable->map->ops->call)) {
2168
+ *vp = OBJECT_TO_JSVAL(callable);
2169
+ } else {
2170
+ callable = js_ValueToFunctionObject(cx, vp, flags);
2171
+ }
2172
+ return callable;
2173
+ }
2174
+
2175
+ void
2176
+ js_ReportIsNotFunction(JSContext *cx, jsval *vp, uintN flags)
2177
+ {
2178
+ JSStackFrame *fp;
2179
+ uintN error;
2180
+ const char *name, *source;
2181
+ JSTempValueRooter tvr;
2182
+
2183
+ for (fp = cx->fp; fp && !fp->regs; fp = fp->down)
2184
+ continue;
2185
+ name = source = NULL;
2186
+ JS_PUSH_TEMP_ROOT_STRING(cx, NULL, &tvr);
2187
+ if (flags & JSV2F_ITERATOR) {
2188
+ error = JSMSG_BAD_ITERATOR;
2189
+ name = js_iterator_str;
2190
+ tvr.u.string = js_ValueToSource(cx, *vp);
2191
+ if (!tvr.u.string)
2192
+ goto out;
2193
+ tvr.u.string = js_QuoteString(cx, tvr.u.string, 0);
2194
+ if (!tvr.u.string)
2195
+ goto out;
2196
+ source = js_GetStringBytes(cx, tvr.u.string);
2197
+ if (!source)
2198
+ goto out;
2199
+ } else if (flags & JSV2F_CONSTRUCT) {
2200
+ error = JSMSG_NOT_CONSTRUCTOR;
2201
+ } else {
2202
+ error = JSMSG_NOT_FUNCTION;
2203
+ }
2204
+
2205
+ js_ReportValueError3(cx, error,
2206
+ (fp && fp->regs &&
2207
+ fp->spbase <= vp && vp < fp->regs->sp)
2208
+ ? vp - fp->regs->sp
2209
+ : (flags & JSV2F_SEARCH_STACK)
2210
+ ? JSDVG_SEARCH_STACK
2211
+ : JSDVG_IGNORE_STACK,
2212
+ *vp, NULL,
2213
+ name, source);
2214
+
2215
+ out:
2216
+ JS_POP_TEMP_ROOT(cx, &tvr);
2217
+ }
2218
+
2219
+ /*
2220
+ * When a function has between 2 and MAX_ARRAY_LOCALS arguments and variables,
2221
+ * their name are stored as the JSLocalNames.array.
2222
+ */
2223
+ #define MAX_ARRAY_LOCALS 8
2224
+
2225
+ JS_STATIC_ASSERT(2 <= MAX_ARRAY_LOCALS);
2226
+ JS_STATIC_ASSERT(MAX_ARRAY_LOCALS < JS_BITMASK(16));
2227
+
2228
+ /*
2229
+ * We use the lowest bit of the string atom to distinguish const from var
2230
+ * name when there is only single name or when names are stored as an array.
2231
+ */
2232
+ JS_STATIC_ASSERT((JSVAL_STRING & 1) == 0);
2233
+
2234
+ /*
2235
+ * When we use a hash table to store the local names, we use a singly linked
2236
+ * list to record the indexes of duplicated parameter names to preserve the
2237
+ * duplicates for the decompiler.
2238
+ */
2239
+ typedef struct JSNameIndexPair JSNameIndexPair;
2240
+
2241
+ struct JSNameIndexPair {
2242
+ JSAtom *name;
2243
+ uint16 index;
2244
+ JSNameIndexPair *link;
2245
+ };
2246
+
2247
+ struct JSLocalNameMap {
2248
+ JSDHashTable names;
2249
+ JSNameIndexPair *lastdup;
2250
+ };
2251
+
2252
+ typedef struct JSLocalNameHashEntry {
2253
+ JSDHashEntryHdr hdr;
2254
+ JSAtom *name;
2255
+ uint16 index;
2256
+ uint8 localKind;
2257
+ } JSLocalNameHashEntry;
2258
+
2259
+ static void
2260
+ FreeLocalNameHash(JSContext *cx, JSLocalNameMap *map)
2261
+ {
2262
+ JSNameIndexPair *dup, *next;
2263
+
2264
+ for (dup = map->lastdup; dup; dup = next) {
2265
+ next = dup->link;
2266
+ JS_free(cx, dup);
2267
+ }
2268
+ JS_DHashTableFinish(&map->names);
2269
+ JS_free(cx, map);
2270
+ }
2271
+
2272
+ static JSBool
2273
+ HashLocalName(JSContext *cx, JSLocalNameMap *map, JSAtom *name,
2274
+ JSLocalKind localKind, uintN index)
2275
+ {
2276
+ JSLocalNameHashEntry *entry;
2277
+ JSNameIndexPair *dup;
2278
+
2279
+ JS_ASSERT(index <= JS_BITMASK(16));
2280
+ #if JS_HAS_DESTRUCTURING
2281
+ if (!name) {
2282
+ /* A destructuring pattern does not need a hash entry. */
2283
+ JS_ASSERT(localKind == JSLOCAL_ARG);
2284
+ return JS_TRUE;
2285
+ }
2286
+ #endif
2287
+ JS_ASSERT(ATOM_IS_STRING(name));
2288
+ entry = (JSLocalNameHashEntry *)
2289
+ JS_DHashTableOperate(&map->names, name, JS_DHASH_ADD);
2290
+ if (!entry) {
2291
+ JS_ReportOutOfMemory(cx);
2292
+ return JS_FALSE;
2293
+ }
2294
+ if (entry->name) {
2295
+ JS_ASSERT(entry->name == name);
2296
+ JS_ASSERT(entry->localKind == JSLOCAL_ARG);
2297
+ dup = (JSNameIndexPair *) JS_malloc(cx, sizeof *dup);
2298
+ if (!dup)
2299
+ return JS_FALSE;
2300
+ dup->name = entry->name;
2301
+ dup->index = entry->index;
2302
+ dup->link = map->lastdup;
2303
+ map->lastdup = dup;
2304
+ }
2305
+ entry->name = name;
2306
+ entry->index = (uint16) index;
2307
+ entry->localKind = (uint8) localKind;
2308
+ return JS_TRUE;
2309
+ }
2310
+
2311
+ JSBool
2312
+ js_AddLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, JSLocalKind kind)
2313
+ {
2314
+ jsuword taggedAtom;
2315
+ uint16 *indexp;
2316
+ uintN n, i;
2317
+ jsuword *array;
2318
+ JSLocalNameMap *map;
2319
+
2320
+ JS_ASSERT(FUN_INTERPRETED(fun));
2321
+ JS_ASSERT(!fun->u.i.script);
2322
+ JS_ASSERT(((jsuword) atom & 1) == 0);
2323
+ taggedAtom = (jsuword) atom;
2324
+ if (kind == JSLOCAL_ARG) {
2325
+ indexp = &fun->nargs;
2326
+ } else {
2327
+ indexp = &fun->u.i.nvars;
2328
+ if (kind == JSLOCAL_CONST)
2329
+ taggedAtom |= 1;
2330
+ else
2331
+ JS_ASSERT(kind == JSLOCAL_VAR);
2332
+ }
2333
+ n = JS_GET_LOCAL_NAME_COUNT(fun);
2334
+ if (n == 0) {
2335
+ JS_ASSERT(fun->u.i.names.taggedAtom == 0);
2336
+ fun->u.i.names.taggedAtom = taggedAtom;
2337
+ } else if (n < MAX_ARRAY_LOCALS) {
2338
+ if (n > 1) {
2339
+ array = fun->u.i.names.array;
2340
+ } else {
2341
+ array = (jsuword *) JS_malloc(cx, MAX_ARRAY_LOCALS * sizeof *array);
2342
+ if (!array)
2343
+ return JS_FALSE;
2344
+ array[0] = fun->u.i.names.taggedAtom;
2345
+ fun->u.i.names.array = array;
2346
+ }
2347
+ if (kind == JSLOCAL_ARG) {
2348
+ /*
2349
+ * A destructuring argument pattern adds variables, not arguments,
2350
+ * so for the following arguments nvars != 0.
2351
+ */
2352
+ #if JS_HAS_DESTRUCTURING
2353
+ if (fun->u.i.nvars != 0) {
2354
+ memmove(array + fun->nargs + 1, array + fun->nargs,
2355
+ fun->u.i.nvars * sizeof *array);
2356
+ }
2357
+ #else
2358
+ JS_ASSERT(fun->u.i.nvars == 0);
2359
+ #endif
2360
+ array[fun->nargs] = taggedAtom;
2361
+ } else {
2362
+ array[n] = taggedAtom;
2363
+ }
2364
+ } else if (n == MAX_ARRAY_LOCALS) {
2365
+ array = fun->u.i.names.array;
2366
+ map = (JSLocalNameMap *) JS_malloc(cx, sizeof *map);
2367
+ if (!map)
2368
+ return JS_FALSE;
2369
+ if (!JS_DHashTableInit(&map->names, JS_DHashGetStubOps(),
2370
+ NULL, sizeof(JSLocalNameHashEntry),
2371
+ JS_DHASH_DEFAULT_CAPACITY(MAX_ARRAY_LOCALS
2372
+ * 2))) {
2373
+ JS_ReportOutOfMemory(cx);
2374
+ JS_free(cx, map);
2375
+ return JS_FALSE;
2376
+ }
2377
+
2378
+ map->lastdup = NULL;
2379
+ for (i = 0; i != MAX_ARRAY_LOCALS; ++i) {
2380
+ taggedAtom = array[i];
2381
+ if (!HashLocalName(cx, map, (JSAtom *) (taggedAtom & ~1),
2382
+ (i < fun->nargs)
2383
+ ? JSLOCAL_ARG
2384
+ : (taggedAtom & 1) ? JSLOCAL_CONST : JSLOCAL_VAR,
2385
+ (i < fun->nargs) ? i : i - fun->nargs)) {
2386
+ FreeLocalNameHash(cx, map);
2387
+ return JS_FALSE;
2388
+ }
2389
+ }
2390
+ if (!HashLocalName(cx, map, atom, kind, *indexp)) {
2391
+ FreeLocalNameHash(cx, map);
2392
+ return JS_FALSE;
2393
+ }
2394
+
2395
+ /*
2396
+ * At this point the entry is added and we cannot fail. It is time
2397
+ * to replace fun->u.i.names with the built map.
2398
+ */
2399
+ fun->u.i.names.map = map;
2400
+ JS_free(cx, array);
2401
+ } else {
2402
+ if (*indexp == JS_BITMASK(16)) {
2403
+ JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
2404
+ (kind == JSLOCAL_ARG)
2405
+ ? JSMSG_TOO_MANY_FUN_ARGS
2406
+ : JSMSG_TOO_MANY_FUN_VARS);
2407
+ return JS_FALSE;
2408
+ }
2409
+ if (!HashLocalName(cx, fun->u.i.names.map, atom, kind, *indexp))
2410
+ return JS_FALSE;
2411
+ }
2412
+
2413
+ /* Update the argument or variable counter. */
2414
+ ++*indexp;
2415
+ return JS_TRUE;
2416
+ }
2417
+
2418
+ JSLocalKind
2419
+ js_LookupLocal(JSContext *cx, JSFunction *fun, JSAtom *atom, uintN *indexp)
2420
+ {
2421
+ uintN n, i;
2422
+ jsuword *array;
2423
+ JSLocalNameHashEntry *entry;
2424
+
2425
+ JS_ASSERT(FUN_INTERPRETED(fun));
2426
+ n = JS_GET_LOCAL_NAME_COUNT(fun);
2427
+ if (n == 0)
2428
+ return JSLOCAL_NONE;
2429
+ if (n <= MAX_ARRAY_LOCALS) {
2430
+ array = (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array;
2431
+
2432
+ /* Search from the tail to pick up the last duplicated name. */
2433
+ i = n;
2434
+ do {
2435
+ --i;
2436
+ if (atom == JS_LOCAL_NAME_TO_ATOM(array[i])) {
2437
+ if (i < fun->nargs) {
2438
+ if (indexp)
2439
+ *indexp = i;
2440
+ return JSLOCAL_ARG;
2441
+ }
2442
+ if (indexp)
2443
+ *indexp = i - fun->nargs;
2444
+ return JS_LOCAL_NAME_IS_CONST(array[i])
2445
+ ? JSLOCAL_CONST
2446
+ : JSLOCAL_VAR;
2447
+ }
2448
+ } while (i != 0);
2449
+ } else {
2450
+ entry = (JSLocalNameHashEntry *)
2451
+ JS_DHashTableOperate(&fun->u.i.names.map->names, atom,
2452
+ JS_DHASH_LOOKUP);
2453
+ if (JS_DHASH_ENTRY_IS_BUSY(&entry->hdr)) {
2454
+ JS_ASSERT(entry->localKind != JSLOCAL_NONE);
2455
+ if (indexp)
2456
+ *indexp = entry->index;
2457
+ return (JSLocalKind) entry->localKind;
2458
+ }
2459
+ }
2460
+ return JSLOCAL_NONE;
2461
+ }
2462
+
2463
+ typedef struct JSLocalNameEnumeratorArgs {
2464
+ JSFunction *fun;
2465
+ jsuword *names;
2466
+ #ifdef DEBUG
2467
+ uintN nCopiedArgs;
2468
+ uintN nCopiedVars;
2469
+ #endif
2470
+ } JSLocalNameEnumeratorArgs;
2471
+
2472
+ JS_STATIC_DLL_CALLBACK(JSDHashOperator)
2473
+ get_local_names_enumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
2474
+ uint32 number, void *arg)
2475
+ {
2476
+ JSLocalNameHashEntry *entry;
2477
+ JSLocalNameEnumeratorArgs *args;
2478
+ uint i;
2479
+ jsuword constFlag;
2480
+
2481
+ entry = (JSLocalNameHashEntry *) hdr;
2482
+ args = (JSLocalNameEnumeratorArgs *) arg;
2483
+ JS_ASSERT(entry->name);
2484
+ if (entry->localKind == JSLOCAL_ARG) {
2485
+ JS_ASSERT(entry->index < args->fun->nargs);
2486
+ JS_ASSERT(args->nCopiedArgs++ < args->fun->nargs);
2487
+ i = entry->index;
2488
+ constFlag = 0;
2489
+ } else {
2490
+ JS_ASSERT(entry->localKind == JSLOCAL_VAR ||
2491
+ entry->localKind == JSLOCAL_CONST);
2492
+ JS_ASSERT(entry->index < args->fun->u.i.nvars);
2493
+ JS_ASSERT(args->nCopiedVars++ < args->fun->u.i.nvars);
2494
+ i = args->fun->nargs + entry->index;
2495
+ constFlag = (entry->localKind == JSLOCAL_CONST);
2496
+ }
2497
+ args->names[i] = (jsuword) entry->name | constFlag;
2498
+ return JS_DHASH_NEXT;
2499
+ }
2500
+
2501
+ jsuword *
2502
+ js_GetLocalNameArray(JSContext *cx, JSFunction *fun, JSArenaPool *pool)
2503
+ {
2504
+ uintN n;
2505
+ jsuword *names;
2506
+ JSLocalNameMap *map;
2507
+ JSLocalNameEnumeratorArgs args;
2508
+ JSNameIndexPair *dup;
2509
+
2510
+ JS_ASSERT(FUN_INTERPRETED(fun));
2511
+ n = JS_GET_LOCAL_NAME_COUNT(fun);
2512
+ JS_ASSERT(n != 0);
2513
+
2514
+ if (n <= MAX_ARRAY_LOCALS)
2515
+ return (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array;
2516
+
2517
+ /*
2518
+ * No need to check for overflow of the allocation size as we are making a
2519
+ * copy of already allocated data. As such it must fit size_t.
2520
+ */
2521
+ JS_ARENA_ALLOCATE_CAST(names, jsuword *, pool, (size_t) n * sizeof *names);
2522
+ if (!names) {
2523
+ js_ReportOutOfScriptQuota(cx);
2524
+ return NULL;
2525
+ }
2526
+
2527
+ #if JS_HAS_DESTRUCTURING
2528
+ /* Some parameter names can be NULL due to destructuring patterns. */
2529
+ memset(names, 0, fun->nargs * sizeof *names);
2530
+ #endif
2531
+ map = fun->u.i.names.map;
2532
+ args.fun = fun;
2533
+ args.names = names;
2534
+ #ifdef DEBUG
2535
+ args.nCopiedArgs = 0;
2536
+ args.nCopiedVars = 0;
2537
+ #endif
2538
+ JS_DHashTableEnumerate(&map->names, get_local_names_enumerator, &args);
2539
+ for (dup = map->lastdup; dup; dup = dup->link) {
2540
+ JS_ASSERT(dup->index < fun->nargs);
2541
+ JS_ASSERT(args.nCopiedArgs++ < fun->nargs);
2542
+ names[dup->index] = (jsuword) dup->name;
2543
+ }
2544
+ #if !JS_HAS_DESTRUCTURING
2545
+ JS_ASSERT(args.nCopiedArgs == fun->nargs);
2546
+ #endif
2547
+ JS_ASSERT(args.nCopiedVars == fun->u.i.nvars);
2548
+
2549
+ return names;
2550
+ }
2551
+
2552
+ JS_STATIC_DLL_CALLBACK(JSDHashOperator)
2553
+ trace_local_names_enumerator(JSDHashTable *table, JSDHashEntryHdr *hdr,
2554
+ uint32 number, void *arg)
2555
+ {
2556
+ JSLocalNameHashEntry *entry;
2557
+ JSTracer *trc;
2558
+
2559
+ entry = (JSLocalNameHashEntry *) hdr;
2560
+ JS_ASSERT(entry->name);
2561
+ trc = (JSTracer *) arg;
2562
+ JS_SET_TRACING_INDEX(trc,
2563
+ entry->localKind == JSLOCAL_ARG ? "arg" : "var",
2564
+ entry->index);
2565
+ JS_CallTracer(trc, ATOM_TO_STRING(entry->name), JSTRACE_STRING);
2566
+ return JS_DHASH_NEXT;
2567
+ }
2568
+
2569
+ static void
2570
+ TraceLocalNames(JSTracer *trc, JSFunction *fun)
2571
+ {
2572
+ uintN n, i;
2573
+ JSAtom *atom;
2574
+ jsuword *array;
2575
+
2576
+ JS_ASSERT(FUN_INTERPRETED(fun));
2577
+ n = JS_GET_LOCAL_NAME_COUNT(fun);
2578
+ if (n == 0)
2579
+ return;
2580
+ if (n <= MAX_ARRAY_LOCALS) {
2581
+ array = (n == 1) ? &fun->u.i.names.taggedAtom : fun->u.i.names.array;
2582
+ i = n;
2583
+ do {
2584
+ --i;
2585
+ atom = (JSAtom *) (array[i] & ~1);
2586
+ if (atom) {
2587
+ JS_SET_TRACING_INDEX(trc,
2588
+ i < fun->nargs ? "arg" : "var",
2589
+ i < fun->nargs ? i : i - fun->nargs);
2590
+ JS_CallTracer(trc, ATOM_TO_STRING(atom), JSTRACE_STRING);
2591
+ }
2592
+ } while (i != 0);
2593
+ } else {
2594
+ JS_DHashTableEnumerate(&fun->u.i.names.map->names,
2595
+ trace_local_names_enumerator, trc);
2596
+
2597
+ /*
2598
+ * No need to trace the list of duplicates in map->lastdup as the
2599
+ * names there are traced when enumerating the hash table.
2600
+ */
2601
+ }
2602
+ }
2603
+
2604
+ void
2605
+ DestroyLocalNames(JSContext *cx, JSFunction *fun)
2606
+ {
2607
+ uintN n;
2608
+
2609
+ n = fun->nargs + fun->u.i.nvars;
2610
+ if (n <= 1)
2611
+ return;
2612
+ if (n <= MAX_ARRAY_LOCALS)
2613
+ JS_free(cx, fun->u.i.names.array);
2614
+ else
2615
+ FreeLocalNameHash(cx, fun->u.i.names.map);
2616
+ }
2617
+
2618
+ void
2619
+ js_FreezeLocalNames(JSContext *cx, JSFunction *fun)
2620
+ {
2621
+ uintN n;
2622
+ jsuword *array;
2623
+
2624
+ JS_ASSERT(FUN_INTERPRETED(fun));
2625
+ JS_ASSERT(!fun->u.i.script);
2626
+ n = fun->nargs + fun->u.i.nvars;
2627
+ if (2 <= n && n < MAX_ARRAY_LOCALS) {
2628
+ /* Shrink over-allocated array ignoring realloc failures. */
2629
+ array = (jsuword *) JS_realloc(cx, fun->u.i.names.array,
2630
+ n * sizeof *array);
2631
+ if (array)
2632
+ fun->u.i.names.array = array;
2633
+ }
2634
+ }