jbarnette-johnson 1.0.0.200806240111 → 1.0.0.200807291507

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. data/MANIFEST +1 -0
  2. data/Rakefile +3 -10
  3. data/bin/johnson +2 -1
  4. data/ext/spidermonkey/context.c +3 -4
  5. data/ext/spidermonkey/context.h +1 -1
  6. data/ext/spidermonkey/conversions.c +39 -33
  7. data/ext/spidermonkey/debugger.c +5 -5
  8. data/ext/spidermonkey/immutable_node.c.erb +11 -11
  9. data/ext/spidermonkey/jroot.h +4 -4
  10. data/ext/spidermonkey/js_land_proxy.c +9 -8
  11. data/ext/spidermonkey/ruby_land_proxy.c +5 -4
  12. data/ext/spidermonkey/runtime.c +1 -1
  13. data/johnson.gemspec +36 -0
  14. data/lib/hoe.rb +0 -7
  15. data/lib/johnson/cli/options.rb +10 -4
  16. data/lib/johnson/spidermonkey/runtime.rb +2 -2
  17. data/lib/johnson/version.rb +4 -2
  18. data/lib/johnson.rb +1 -0
  19. data/test/johnson/runtime_test.rb +11 -0
  20. data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +6 -0
  21. data/vendor/spidermonkey/.cvsignore +9 -0
  22. data/vendor/spidermonkey/Makefile.in +462 -0
  23. data/vendor/spidermonkey/Makefile.ref +364 -0
  24. data/vendor/spidermonkey/README.html +820 -0
  25. data/vendor/spidermonkey/SpiderMonkey.rsp +12 -0
  26. data/vendor/spidermonkey/Y.js +19 -0
  27. data/vendor/spidermonkey/build.mk +43 -0
  28. data/vendor/spidermonkey/config/AIX4.1.mk +65 -0
  29. data/vendor/spidermonkey/config/AIX4.2.mk +64 -0
  30. data/vendor/spidermonkey/config/AIX4.3.mk +65 -0
  31. data/vendor/spidermonkey/config/Darwin.mk +83 -0
  32. data/vendor/spidermonkey/config/Darwin1.3.mk +81 -0
  33. data/vendor/spidermonkey/config/Darwin1.4.mk +41 -0
  34. data/vendor/spidermonkey/config/Darwin5.2.mk +81 -0
  35. data/vendor/spidermonkey/config/Darwin5.3.mk +81 -0
  36. data/vendor/spidermonkey/config/HP-UXB.10.10.mk +77 -0
  37. data/vendor/spidermonkey/config/HP-UXB.10.20.mk +77 -0
  38. data/vendor/spidermonkey/config/HP-UXB.11.00.mk +80 -0
  39. data/vendor/spidermonkey/config/IRIX.mk +87 -0
  40. data/vendor/spidermonkey/config/IRIX5.3.mk +44 -0
  41. data/vendor/spidermonkey/config/IRIX6.1.mk +44 -0
  42. data/vendor/spidermonkey/config/IRIX6.2.mk +44 -0
  43. data/vendor/spidermonkey/config/IRIX6.3.mk +44 -0
  44. data/vendor/spidermonkey/config/IRIX6.5.mk +44 -0
  45. data/vendor/spidermonkey/config/Linux_All.mk +103 -0
  46. data/vendor/spidermonkey/config/Mac_OS10.0.mk +82 -0
  47. data/vendor/spidermonkey/config/OSF1V4.0.mk +72 -0
  48. data/vendor/spidermonkey/config/OSF1V5.0.mk +69 -0
  49. data/vendor/spidermonkey/config/SunOS4.1.4.mk +101 -0
  50. data/vendor/spidermonkey/config/SunOS5.10.mk +50 -0
  51. data/vendor/spidermonkey/config/SunOS5.3.mk +91 -0
  52. data/vendor/spidermonkey/config/SunOS5.4.mk +92 -0
  53. data/vendor/spidermonkey/config/SunOS5.5.1.mk +44 -0
  54. data/vendor/spidermonkey/config/SunOS5.5.mk +87 -0
  55. data/vendor/spidermonkey/config/SunOS5.6.mk +89 -0
  56. data/vendor/spidermonkey/config/SunOS5.7.mk +44 -0
  57. data/vendor/spidermonkey/config/SunOS5.8.mk +44 -0
  58. data/vendor/spidermonkey/config/SunOS5.9.mk +44 -0
  59. data/vendor/spidermonkey/config/WINNT4.0.mk +117 -0
  60. data/vendor/spidermonkey/config/WINNT5.0.mk +117 -0
  61. data/vendor/spidermonkey/config/WINNT5.1.mk +117 -0
  62. data/vendor/spidermonkey/config/WINNT5.2.mk +117 -0
  63. data/vendor/spidermonkey/config/WINNT6.0.mk +117 -0
  64. data/vendor/spidermonkey/config/dgux.mk +64 -0
  65. data/vendor/spidermonkey/config.mk +192 -0
  66. data/vendor/spidermonkey/editline/Makefile.ref +144 -0
  67. data/vendor/spidermonkey/editline/README +83 -0
  68. data/vendor/spidermonkey/editline/editline.3 +175 -0
  69. data/vendor/spidermonkey/editline/editline.c +1369 -0
  70. data/vendor/spidermonkey/editline/editline.h +135 -0
  71. data/vendor/spidermonkey/editline/sysunix.c +182 -0
  72. data/vendor/spidermonkey/editline/unix.h +82 -0
  73. data/vendor/spidermonkey/fdlibm/.cvsignore +7 -0
  74. data/vendor/spidermonkey/fdlibm/Makefile.in +127 -0
  75. data/vendor/spidermonkey/fdlibm/Makefile.ref +192 -0
  76. data/vendor/spidermonkey/fdlibm/e_acos.c +147 -0
  77. data/vendor/spidermonkey/fdlibm/e_acosh.c +105 -0
  78. data/vendor/spidermonkey/fdlibm/e_asin.c +156 -0
  79. data/vendor/spidermonkey/fdlibm/e_atan2.c +165 -0
  80. data/vendor/spidermonkey/fdlibm/e_atanh.c +110 -0
  81. data/vendor/spidermonkey/fdlibm/e_cosh.c +133 -0
  82. data/vendor/spidermonkey/fdlibm/e_exp.c +202 -0
  83. data/vendor/spidermonkey/fdlibm/e_fmod.c +184 -0
  84. data/vendor/spidermonkey/fdlibm/e_gamma.c +71 -0
  85. data/vendor/spidermonkey/fdlibm/e_gamma_r.c +70 -0
  86. data/vendor/spidermonkey/fdlibm/e_hypot.c +173 -0
  87. data/vendor/spidermonkey/fdlibm/e_j0.c +524 -0
  88. data/vendor/spidermonkey/fdlibm/e_j1.c +523 -0
  89. data/vendor/spidermonkey/fdlibm/e_jn.c +315 -0
  90. data/vendor/spidermonkey/fdlibm/e_lgamma.c +71 -0
  91. data/vendor/spidermonkey/fdlibm/e_lgamma_r.c +347 -0
  92. data/vendor/spidermonkey/fdlibm/e_log.c +184 -0
  93. data/vendor/spidermonkey/fdlibm/e_log10.c +134 -0
  94. data/vendor/spidermonkey/fdlibm/e_pow.c +386 -0
  95. data/vendor/spidermonkey/fdlibm/e_rem_pio2.c +222 -0
  96. data/vendor/spidermonkey/fdlibm/e_remainder.c +120 -0
  97. data/vendor/spidermonkey/fdlibm/e_scalb.c +89 -0
  98. data/vendor/spidermonkey/fdlibm/e_sinh.c +122 -0
  99. data/vendor/spidermonkey/fdlibm/e_sqrt.c +497 -0
  100. data/vendor/spidermonkey/fdlibm/fdlibm.h +273 -0
  101. data/vendor/spidermonkey/fdlibm/fdlibm.mak +1453 -0
  102. data/vendor/spidermonkey/fdlibm/fdlibm.mdp +0 -0
  103. data/vendor/spidermonkey/fdlibm/k_cos.c +135 -0
  104. data/vendor/spidermonkey/fdlibm/k_rem_pio2.c +354 -0
  105. data/vendor/spidermonkey/fdlibm/k_sin.c +114 -0
  106. data/vendor/spidermonkey/fdlibm/k_standard.c +785 -0
  107. data/vendor/spidermonkey/fdlibm/k_tan.c +170 -0
  108. data/vendor/spidermonkey/fdlibm/s_asinh.c +101 -0
  109. data/vendor/spidermonkey/fdlibm/s_atan.c +175 -0
  110. data/vendor/spidermonkey/fdlibm/s_cbrt.c +133 -0
  111. data/vendor/spidermonkey/fdlibm/s_ceil.c +120 -0
  112. data/vendor/spidermonkey/fdlibm/s_copysign.c +72 -0
  113. data/vendor/spidermonkey/fdlibm/s_cos.c +118 -0
  114. data/vendor/spidermonkey/fdlibm/s_erf.c +356 -0
  115. data/vendor/spidermonkey/fdlibm/s_expm1.c +267 -0
  116. data/vendor/spidermonkey/fdlibm/s_fabs.c +70 -0
  117. data/vendor/spidermonkey/fdlibm/s_finite.c +71 -0
  118. data/vendor/spidermonkey/fdlibm/s_floor.c +121 -0
  119. data/vendor/spidermonkey/fdlibm/s_frexp.c +99 -0
  120. data/vendor/spidermonkey/fdlibm/s_ilogb.c +85 -0
  121. data/vendor/spidermonkey/fdlibm/s_isnan.c +74 -0
  122. data/vendor/spidermonkey/fdlibm/s_ldexp.c +66 -0
  123. data/vendor/spidermonkey/fdlibm/s_lib_version.c +73 -0
  124. data/vendor/spidermonkey/fdlibm/s_log1p.c +211 -0
  125. data/vendor/spidermonkey/fdlibm/s_logb.c +79 -0
  126. data/vendor/spidermonkey/fdlibm/s_matherr.c +64 -0
  127. data/vendor/spidermonkey/fdlibm/s_modf.c +132 -0
  128. data/vendor/spidermonkey/fdlibm/s_nextafter.c +124 -0
  129. data/vendor/spidermonkey/fdlibm/s_rint.c +131 -0
  130. data/vendor/spidermonkey/fdlibm/s_scalbn.c +107 -0
  131. data/vendor/spidermonkey/fdlibm/s_signgam.c +40 -0
  132. data/vendor/spidermonkey/fdlibm/s_significand.c +68 -0
  133. data/vendor/spidermonkey/fdlibm/s_sin.c +118 -0
  134. data/vendor/spidermonkey/fdlibm/s_tan.c +112 -0
  135. data/vendor/spidermonkey/fdlibm/s_tanh.c +122 -0
  136. data/vendor/spidermonkey/fdlibm/w_acos.c +78 -0
  137. data/vendor/spidermonkey/fdlibm/w_acosh.c +78 -0
  138. data/vendor/spidermonkey/fdlibm/w_asin.c +80 -0
  139. data/vendor/spidermonkey/fdlibm/w_atan2.c +79 -0
  140. data/vendor/spidermonkey/fdlibm/w_atanh.c +81 -0
  141. data/vendor/spidermonkey/fdlibm/w_cosh.c +77 -0
  142. data/vendor/spidermonkey/fdlibm/w_exp.c +88 -0
  143. data/vendor/spidermonkey/fdlibm/w_fmod.c +78 -0
  144. data/vendor/spidermonkey/fdlibm/w_gamma.c +85 -0
  145. data/vendor/spidermonkey/fdlibm/w_gamma_r.c +81 -0
  146. data/vendor/spidermonkey/fdlibm/w_hypot.c +78 -0
  147. data/vendor/spidermonkey/fdlibm/w_j0.c +105 -0
  148. data/vendor/spidermonkey/fdlibm/w_j1.c +106 -0
  149. data/vendor/spidermonkey/fdlibm/w_jn.c +128 -0
  150. data/vendor/spidermonkey/fdlibm/w_lgamma.c +85 -0
  151. data/vendor/spidermonkey/fdlibm/w_lgamma_r.c +81 -0
  152. data/vendor/spidermonkey/fdlibm/w_log.c +78 -0
  153. data/vendor/spidermonkey/fdlibm/w_log10.c +81 -0
  154. data/vendor/spidermonkey/fdlibm/w_pow.c +99 -0
  155. data/vendor/spidermonkey/fdlibm/w_remainder.c +77 -0
  156. data/vendor/spidermonkey/fdlibm/w_scalb.c +95 -0
  157. data/vendor/spidermonkey/fdlibm/w_sinh.c +77 -0
  158. data/vendor/spidermonkey/fdlibm/w_sqrt.c +77 -0
  159. data/vendor/spidermonkey/javascript-trace.d +73 -0
  160. data/vendor/spidermonkey/js.c +3951 -0
  161. data/vendor/spidermonkey/js.mak +4438 -0
  162. data/vendor/spidermonkey/js.mdp +0 -0
  163. data/vendor/spidermonkey/js.msg +307 -0
  164. data/vendor/spidermonkey/js.pkg +2 -0
  165. data/vendor/spidermonkey/js3240.rc +79 -0
  166. data/vendor/spidermonkey/jsOS240.def +654 -0
  167. data/vendor/spidermonkey/jsapi.c +5836 -0
  168. data/vendor/spidermonkey/jsapi.h +2624 -0
  169. data/vendor/spidermonkey/jsarena.c +450 -0
  170. data/vendor/spidermonkey/jsarena.h +318 -0
  171. data/vendor/spidermonkey/jsarray.c +2988 -0
  172. data/vendor/spidermonkey/jsarray.h +124 -0
  173. data/vendor/spidermonkey/jsatom.c +1045 -0
  174. data/vendor/spidermonkey/jsatom.h +442 -0
  175. data/vendor/spidermonkey/jsbit.h +253 -0
  176. data/vendor/spidermonkey/jsbool.c +176 -0
  177. data/vendor/spidermonkey/jsbool.h +73 -0
  178. data/vendor/spidermonkey/jsclist.h +139 -0
  179. data/vendor/spidermonkey/jscntxt.c +1348 -0
  180. data/vendor/spidermonkey/jscntxt.h +1120 -0
  181. data/vendor/spidermonkey/jscompat.h +57 -0
  182. data/vendor/spidermonkey/jsconfig.h +248 -0
  183. data/vendor/spidermonkey/jsconfig.mk +181 -0
  184. data/vendor/spidermonkey/jscpucfg.c +383 -0
  185. data/vendor/spidermonkey/jscpucfg.h +212 -0
  186. data/vendor/spidermonkey/jsdate.c +2398 -0
  187. data/vendor/spidermonkey/jsdate.h +124 -0
  188. data/vendor/spidermonkey/jsdbgapi.c +1799 -0
  189. data/vendor/spidermonkey/jsdbgapi.h +464 -0
  190. data/vendor/spidermonkey/jsdhash.c +868 -0
  191. data/vendor/spidermonkey/jsdhash.h +592 -0
  192. data/vendor/spidermonkey/jsdtoa.c +3167 -0
  193. data/vendor/spidermonkey/jsdtoa.h +130 -0
  194. data/vendor/spidermonkey/jsdtracef.c +317 -0
  195. data/vendor/spidermonkey/jsdtracef.h +77 -0
  196. data/vendor/spidermonkey/jsemit.c +6909 -0
  197. data/vendor/spidermonkey/jsemit.h +741 -0
  198. data/vendor/spidermonkey/jsexn.c +1371 -0
  199. data/vendor/spidermonkey/jsexn.h +96 -0
  200. data/vendor/spidermonkey/jsfile.c +2736 -0
  201. data/vendor/spidermonkey/jsfile.h +56 -0
  202. data/vendor/spidermonkey/jsfile.msg +90 -0
  203. data/vendor/spidermonkey/jsfun.c +2634 -0
  204. data/vendor/spidermonkey/jsfun.h +254 -0
  205. data/vendor/spidermonkey/jsgc.c +3554 -0
  206. data/vendor/spidermonkey/jsgc.h +403 -0
  207. data/vendor/spidermonkey/jshash.c +476 -0
  208. data/vendor/spidermonkey/jshash.h +151 -0
  209. data/vendor/spidermonkey/jsify.pl +485 -0
  210. data/vendor/spidermonkey/jsinterp.c +6981 -0
  211. data/vendor/spidermonkey/jsinterp.h +521 -0
  212. data/vendor/spidermonkey/jsinvoke.c +43 -0
  213. data/vendor/spidermonkey/jsiter.c +1067 -0
  214. data/vendor/spidermonkey/jsiter.h +122 -0
  215. data/vendor/spidermonkey/jskeyword.tbl +124 -0
  216. data/vendor/spidermonkey/jskwgen.c +460 -0
  217. data/vendor/spidermonkey/jslibmath.h +266 -0
  218. data/vendor/spidermonkey/jslock.c +1309 -0
  219. data/vendor/spidermonkey/jslock.h +313 -0
  220. data/vendor/spidermonkey/jslocko.asm +60 -0
  221. data/vendor/spidermonkey/jslog2.c +94 -0
  222. data/vendor/spidermonkey/jslong.c +264 -0
  223. data/vendor/spidermonkey/jslong.h +412 -0
  224. data/vendor/spidermonkey/jsmath.c +568 -0
  225. data/vendor/spidermonkey/jsmath.h +57 -0
  226. data/vendor/spidermonkey/jsnum.c +1228 -0
  227. data/vendor/spidermonkey/jsnum.h +283 -0
  228. data/vendor/spidermonkey/jsobj.c +5266 -0
  229. data/vendor/spidermonkey/jsobj.h +709 -0
  230. data/vendor/spidermonkey/jsopcode.c +5245 -0
  231. data/vendor/spidermonkey/jsopcode.h +394 -0
  232. data/vendor/spidermonkey/jsopcode.tbl +523 -0
  233. data/vendor/spidermonkey/jsotypes.h +202 -0
  234. data/vendor/spidermonkey/jsparse.c +6680 -0
  235. data/vendor/spidermonkey/jsparse.h +511 -0
  236. data/vendor/spidermonkey/jsprf.c +1262 -0
  237. data/vendor/spidermonkey/jsprf.h +150 -0
  238. data/vendor/spidermonkey/jsproto.tbl +128 -0
  239. data/vendor/spidermonkey/jsprvtd.h +267 -0
  240. data/vendor/spidermonkey/jspubtd.h +744 -0
  241. data/vendor/spidermonkey/jsregexp.c +4352 -0
  242. data/vendor/spidermonkey/jsregexp.h +183 -0
  243. data/vendor/spidermonkey/jsreops.tbl +145 -0
  244. data/vendor/spidermonkey/jsscan.c +2003 -0
  245. data/vendor/spidermonkey/jsscan.h +387 -0
  246. data/vendor/spidermonkey/jsscope.c +1948 -0
  247. data/vendor/spidermonkey/jsscope.h +418 -0
  248. data/vendor/spidermonkey/jsscript.c +1832 -0
  249. data/vendor/spidermonkey/jsscript.h +287 -0
  250. data/vendor/spidermonkey/jsshell.msg +50 -0
  251. data/vendor/spidermonkey/jsstddef.h +83 -0
  252. data/vendor/spidermonkey/jsstr.c +5004 -0
  253. data/vendor/spidermonkey/jsstr.h +641 -0
  254. data/vendor/spidermonkey/jstypes.h +475 -0
  255. data/vendor/spidermonkey/jsutil.c +345 -0
  256. data/vendor/spidermonkey/jsutil.h +157 -0
  257. data/vendor/spidermonkey/jsxdrapi.c +800 -0
  258. data/vendor/spidermonkey/jsxdrapi.h +218 -0
  259. data/vendor/spidermonkey/jsxml.c +8471 -0
  260. data/vendor/spidermonkey/jsxml.h +349 -0
  261. data/vendor/spidermonkey/lock_SunOS.s +119 -0
  262. data/vendor/spidermonkey/perfect.js +39 -0
  263. data/vendor/spidermonkey/plify_jsdhash.sed +36 -0
  264. data/vendor/spidermonkey/prmjtime.c +846 -0
  265. data/vendor/spidermonkey/prmjtime.h +103 -0
  266. data/vendor/spidermonkey/resource.h +15 -0
  267. data/vendor/spidermonkey/rules.mk +197 -0
  268. data/vendor/spidermonkey/win32.order +384 -0
  269. metadata +4 -3
@@ -0,0 +1,266 @@
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
+ * IBM Corp.
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
+ * By default all math calls go to fdlibm. The defines for each platform
43
+ * remap the math calls to native routines.
44
+ */
45
+
46
+ #ifndef _LIBMATH_H
47
+ #define _LIBMATH_H
48
+
49
+ #include <math.h>
50
+ #include "jsconfig.h"
51
+
52
+ /*
53
+ * Define on which platforms to use fdlibm. Not used by default under
54
+ * assumption that native math library works unless proved guilty.
55
+ * Plus there can be problems with endian-ness and such in fdlibm itself.
56
+ *
57
+ * fdlibm compatibility notes:
58
+ * - fdlibm broken on OSF1/alpha
59
+ */
60
+
61
+ #ifndef JS_USE_FDLIBM_MATH
62
+ #define JS_USE_FDLIBM_MATH 0
63
+ #endif
64
+
65
+ #if !JS_USE_FDLIBM_MATH
66
+
67
+ /*
68
+ * Use system provided math routines.
69
+ */
70
+
71
+ #define fd_acos acos
72
+ #define fd_asin asin
73
+ #define fd_atan atan
74
+ #define fd_atan2 atan2
75
+ #define fd_ceil ceil
76
+
77
+ /* The right copysign function is not always named the same thing. */
78
+ #if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
79
+ #define fd_copysign __builtin_copysign
80
+ #elif defined WINCE
81
+ #define fd_copysign _copysign
82
+ #elif defined _WIN32
83
+ #if _MSC_VER < 1400
84
+ /* Try to work around apparent _copysign bustage in VC6 and VC7. */
85
+ #define fd_copysign js_copysign
86
+ extern double js_copysign(double, double);
87
+ #else
88
+ #define fd_copysign _copysign
89
+ #endif
90
+ #else
91
+ #define fd_copysign copysign
92
+ #endif
93
+
94
+ #define fd_cos cos
95
+ #define fd_exp exp
96
+ #define fd_fabs fabs
97
+ #define fd_floor floor
98
+ #define fd_fmod fmod
99
+ #define fd_log log
100
+ #define fd_pow pow
101
+ #define fd_sin sin
102
+ #define fd_sqrt sqrt
103
+ #define fd_tan tan
104
+
105
+ #else
106
+
107
+ /*
108
+ * Use math routines in fdlibm.
109
+ */
110
+
111
+ #undef __P
112
+ #ifdef __STDC__
113
+ #define __P(p) p
114
+ #else
115
+ #define __P(p) ()
116
+ #endif
117
+
118
+ #if defined _WIN32 && !defined WINCE
119
+
120
+ #define fd_acos acos
121
+ #define fd_asin asin
122
+ #define fd_atan atan
123
+ #define fd_cos cos
124
+ #define fd_sin sin
125
+ #define fd_tan tan
126
+ #define fd_exp exp
127
+ #define fd_log log
128
+ #define fd_sqrt sqrt
129
+ #define fd_ceil ceil
130
+ #define fd_fabs fabs
131
+ #define fd_floor floor
132
+ #define fd_fmod fmod
133
+
134
+ extern double fd_atan2 __P((double, double));
135
+ extern double fd_copysign __P((double, double));
136
+ extern double fd_pow __P((double, double));
137
+
138
+ #elif defined IRIX
139
+
140
+ #define fd_acos acos
141
+ #define fd_asin asin
142
+ #define fd_atan atan
143
+ #define fd_exp exp
144
+ #define fd_log log
145
+ #define fd_log10 log10
146
+ #define fd_sqrt sqrt
147
+ #define fd_fabs fabs
148
+ #define fd_floor floor
149
+ #define fd_fmod fmod
150
+
151
+ extern double fd_cos __P((double));
152
+ extern double fd_sin __P((double));
153
+ extern double fd_tan __P((double));
154
+ extern double fd_atan2 __P((double, double));
155
+ extern double fd_pow __P((double, double));
156
+ extern double fd_ceil __P((double));
157
+ extern double fd_copysign __P((double, double));
158
+
159
+ #elif defined SOLARIS
160
+
161
+ #define fd_atan atan
162
+ #define fd_cos cos
163
+ #define fd_sin sin
164
+ #define fd_tan tan
165
+ #define fd_exp exp
166
+ #define fd_sqrt sqrt
167
+ #define fd_ceil ceil
168
+ #define fd_fabs fabs
169
+ #define fd_floor floor
170
+ #define fd_fmod fmod
171
+
172
+ extern double fd_acos __P((double));
173
+ extern double fd_asin __P((double));
174
+ extern double fd_log __P((double));
175
+ extern double fd_atan2 __P((double, double));
176
+ extern double fd_pow __P((double, double));
177
+ extern double fd_copysign __P((double, double));
178
+
179
+ #elif defined HPUX
180
+
181
+ #define fd_cos cos
182
+ #define fd_sin sin
183
+ #define fd_exp exp
184
+ #define fd_sqrt sqrt
185
+ #define fd_fabs fabs
186
+ #define fd_floor floor
187
+ #define fd_fmod fmod
188
+
189
+ extern double fd_ceil __P((double));
190
+ extern double fd_acos __P((double));
191
+ extern double fd_log __P((double));
192
+ extern double fd_atan2 __P((double, double));
193
+ extern double fd_tan __P((double));
194
+ extern double fd_pow __P((double, double));
195
+ extern double fd_asin __P((double));
196
+ extern double fd_atan __P((double));
197
+ extern double fd_copysign __P((double, double));
198
+
199
+ #elif defined(OSF1)
200
+
201
+ #define fd_acos acos
202
+ #define fd_asin asin
203
+ #define fd_atan atan
204
+ #define fd_copysign copysign
205
+ #define fd_cos cos
206
+ #define fd_exp exp
207
+ #define fd_fabs fabs
208
+ #define fd_fmod fmod
209
+ #define fd_sin sin
210
+ #define fd_sqrt sqrt
211
+ #define fd_tan tan
212
+
213
+ extern double fd_atan2 __P((double, double));
214
+ extern double fd_ceil __P((double));
215
+ extern double fd_floor __P((double));
216
+ extern double fd_log __P((double));
217
+ extern double fd_pow __P((double, double));
218
+
219
+ #elif defined(AIX)
220
+
221
+ #define fd_acos acos
222
+ #define fd_asin asin
223
+ #define fd_atan2 atan2
224
+ #define fd_copysign copysign
225
+ #define fd_cos cos
226
+ #define fd_exp exp
227
+ #define fd_fabs fabs
228
+ #define fd_floor floor
229
+ #define fd_fmod fmod
230
+ #define fd_log log
231
+ #define fd_sin sin
232
+ #define fd_sqrt sqrt
233
+
234
+ extern double fd_atan __P((double));
235
+ extern double fd_ceil __P((double));
236
+ extern double fd_pow __P((double,double));
237
+ extern double fd_tan __P((double));
238
+
239
+ #else /* other platform.. generic paranoid slow fdlibm */
240
+
241
+ extern double fd_acos __P((double));
242
+ extern double fd_asin __P((double));
243
+ extern double fd_atan __P((double));
244
+ extern double fd_cos __P((double));
245
+ extern double fd_sin __P((double));
246
+ extern double fd_tan __P((double));
247
+
248
+ extern double fd_exp __P((double));
249
+ extern double fd_log __P((double));
250
+ extern double fd_sqrt __P((double));
251
+
252
+ extern double fd_ceil __P((double));
253
+ extern double fd_fabs __P((double));
254
+ extern double fd_floor __P((double));
255
+ extern double fd_fmod __P((double, double));
256
+
257
+ extern double fd_atan2 __P((double, double));
258
+ extern double fd_pow __P((double, double));
259
+ extern double fd_copysign __P((double, double));
260
+
261
+ #endif
262
+
263
+ #endif /* JS_USE_FDLIBM_MATH */
264
+
265
+ #endif /* _LIBMATH_H */
266
+
@@ -0,0 +1,1309 @@
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
+ #ifdef JS_THREADSAFE
41
+
42
+ /*
43
+ * JS locking stubs.
44
+ */
45
+ #include "jsstddef.h"
46
+ #include <stdlib.h>
47
+ #include <string.h>
48
+ #include "jspubtd.h"
49
+ #include "jsutil.h" /* Added by JSIFY */
50
+ #include "jstypes.h"
51
+ #include "jsbit.h"
52
+ #include "jscntxt.h"
53
+ #include "jsdtoa.h"
54
+ #include "jsgc.h"
55
+ #include "jsfun.h" /* for VALUE_IS_FUNCTION used by *_WRITE_BARRIER */
56
+ #include "jslock.h"
57
+ #include "jsscope.h"
58
+ #include "jsstr.h"
59
+
60
+ #define ReadWord(W) (W)
61
+
62
+ #ifndef NSPR_LOCK
63
+
64
+ #include <memory.h>
65
+
66
+ static PRLock **global_locks;
67
+ static uint32 global_lock_count = 1;
68
+ static uint32 global_locks_log2 = 0;
69
+ static uint32 global_locks_mask = 0;
70
+
71
+ #define GLOBAL_LOCK_INDEX(id) (((uint32)(id) >> 2) & global_locks_mask)
72
+
73
+ static void
74
+ js_LockGlobal(void *id)
75
+ {
76
+ uint32 i = GLOBAL_LOCK_INDEX(id);
77
+ PR_Lock(global_locks[i]);
78
+ }
79
+
80
+ static void
81
+ js_UnlockGlobal(void *id)
82
+ {
83
+ uint32 i = GLOBAL_LOCK_INDEX(id);
84
+ PR_Unlock(global_locks[i]);
85
+ }
86
+
87
+ /* Exclude Alpha NT. */
88
+ #if defined(_WIN32) && defined(_M_IX86)
89
+ #pragma warning( disable : 4035 )
90
+ JS_BEGIN_EXTERN_C
91
+ extern long __cdecl
92
+ _InterlockedCompareExchange(long *volatile dest, long exchange, long comp);
93
+ JS_END_EXTERN_C
94
+ #pragma intrinsic(_InterlockedCompareExchange)
95
+
96
+ static JS_INLINE int
97
+ js_CompareAndSwapHelper(jsword *w, jsword ov, jsword nv)
98
+ {
99
+ _InterlockedCompareExchange(w, nv, ov);
100
+ __asm {
101
+ sete al
102
+ }
103
+ }
104
+
105
+ static JS_INLINE int
106
+ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
107
+ {
108
+ return (js_CompareAndSwapHelper(w, ov, nv) & 1);
109
+ }
110
+
111
+ #elif defined(XP_MACOSX) || defined(DARWIN)
112
+
113
+ #include <libkern/OSAtomic.h>
114
+
115
+ static JS_INLINE int
116
+ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
117
+ {
118
+ /* Details on these functions available in the manpage for atomic */
119
+ #if JS_BYTES_PER_WORD == 8 && JS_BYTES_PER_LONG != 8
120
+ return OSAtomicCompareAndSwap64Barrier(ov, nv, (int64_t*) w);
121
+ #else
122
+ return OSAtomicCompareAndSwap32Barrier(ov, nv, (int32_t*) w);
123
+ #endif
124
+ }
125
+
126
+ #elif defined(__GNUC__) && defined(__i386__)
127
+
128
+ /* Note: This fails on 386 cpus, cmpxchgl is a >= 486 instruction */
129
+ static JS_INLINE int
130
+ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
131
+ {
132
+ unsigned int res;
133
+
134
+ __asm__ __volatile__ (
135
+ "lock\n"
136
+ "cmpxchgl %2, (%1)\n"
137
+ "sete %%al\n"
138
+ "andl $1, %%eax\n"
139
+ : "=a" (res)
140
+ : "r" (w), "r" (nv), "a" (ov)
141
+ : "cc", "memory");
142
+ return (int)res;
143
+ }
144
+
145
+ #elif defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC)
146
+
147
+ static JS_INLINE int
148
+ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
149
+ {
150
+ #if defined(__GNUC__)
151
+ unsigned int res;
152
+ JS_ASSERT(ov != nv);
153
+ asm volatile ("\
154
+ stbar\n\
155
+ cas [%1],%2,%3\n\
156
+ cmp %2,%3\n\
157
+ be,a 1f\n\
158
+ mov 1,%0\n\
159
+ mov 0,%0\n\
160
+ 1:"
161
+ : "=r" (res)
162
+ : "r" (w), "r" (ov), "r" (nv));
163
+ return (int)res;
164
+ #else /* !__GNUC__ */
165
+ extern int compare_and_swap(jsword*, jsword, jsword);
166
+ JS_ASSERT(ov != nv);
167
+ return compare_and_swap(w, ov, nv);
168
+ #endif
169
+ }
170
+
171
+ #elif defined(AIX)
172
+
173
+ #include <sys/atomic_op.h>
174
+
175
+ static JS_INLINE int
176
+ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
177
+ {
178
+ return !_check_lock((atomic_p)w, ov, nv);
179
+ }
180
+
181
+ #else
182
+
183
+ #error "Define NSPR_LOCK if your platform lacks a compare-and-swap instruction."
184
+
185
+ #endif /* arch-tests */
186
+
187
+ #endif /* !NSPR_LOCK */
188
+
189
+ void
190
+ js_InitLock(JSThinLock *tl)
191
+ {
192
+ #ifdef NSPR_LOCK
193
+ tl->owner = 0;
194
+ tl->fat = (JSFatLock*)JS_NEW_LOCK();
195
+ #else
196
+ memset(tl, 0, sizeof(JSThinLock));
197
+ #endif
198
+ }
199
+
200
+ void
201
+ js_FinishLock(JSThinLock *tl)
202
+ {
203
+ #ifdef NSPR_LOCK
204
+ tl->owner = 0xdeadbeef;
205
+ if (tl->fat)
206
+ JS_DESTROY_LOCK(((JSLock*)tl->fat));
207
+ #else
208
+ JS_ASSERT(tl->owner == 0);
209
+ JS_ASSERT(tl->fat == NULL);
210
+ #endif
211
+ }
212
+
213
+ #ifndef NSPR_LOCK
214
+ static void js_Dequeue(JSThinLock *);
215
+ #endif
216
+
217
+ #ifdef DEBUG_SCOPE_COUNT
218
+
219
+ #include <stdio.h>
220
+ #include "jsdhash.h"
221
+
222
+ static FILE *logfp;
223
+ static JSDHashTable logtbl;
224
+
225
+ typedef struct logentry {
226
+ JSDHashEntryStub stub;
227
+ char op;
228
+ const char *file;
229
+ int line;
230
+ } logentry;
231
+
232
+ static void
233
+ logit(JSScope *scope, char op, const char *file, int line)
234
+ {
235
+ logentry *entry;
236
+
237
+ if (!logfp) {
238
+ logfp = fopen("/tmp/scope.log", "w");
239
+ if (!logfp)
240
+ return;
241
+ setvbuf(logfp, NULL, _IONBF, 0);
242
+ }
243
+ fprintf(logfp, "%p %c %s %d\n", scope, op, file, line);
244
+
245
+ if (!logtbl.entryStore &&
246
+ !JS_DHashTableInit(&logtbl, JS_DHashGetStubOps(), NULL,
247
+ sizeof(logentry), 100)) {
248
+ return;
249
+ }
250
+ entry = (logentry *) JS_DHashTableOperate(&logtbl, scope, JS_DHASH_ADD);
251
+ if (!entry)
252
+ return;
253
+ entry->stub.key = scope;
254
+ entry->op = op;
255
+ entry->file = file;
256
+ entry->line = line;
257
+ }
258
+
259
+ void
260
+ js_unlog_scope(JSScope *scope)
261
+ {
262
+ if (!logtbl.entryStore)
263
+ return;
264
+ (void) JS_DHashTableOperate(&logtbl, scope, JS_DHASH_REMOVE);
265
+ }
266
+
267
+ # define LOGIT(scope,op) logit(scope, op, __FILE__, __LINE__)
268
+
269
+ #else
270
+
271
+ # define LOGIT(scope,op) /* nothing */
272
+
273
+ #endif /* DEBUG_SCOPE_COUNT */
274
+
275
+ /*
276
+ * Return true if scope's ownercx, or the ownercx of a single-threaded scope
277
+ * for which ownercx is waiting to become multi-threaded and shared, is cx.
278
+ * That condition implies deadlock in ClaimScope if cx's thread were to wait
279
+ * to share scope.
280
+ *
281
+ * (i) rt->gcLock held
282
+ */
283
+ static JSBool
284
+ WillDeadlock(JSTitle *title, JSContext *cx)
285
+ {
286
+ JSContext *ownercx;
287
+
288
+ do {
289
+ ownercx = title->ownercx;
290
+ if (ownercx == cx) {
291
+ JS_RUNTIME_METER(cx->runtime, deadlocksAvoided);
292
+ return JS_TRUE;
293
+ }
294
+ } while (ownercx && (title = ownercx->titleToShare) != NULL);
295
+ return JS_FALSE;
296
+ }
297
+
298
+ /*
299
+ * Make title multi-threaded, i.e. share its ownership among contexts in rt
300
+ * using a "thin" or (if necessary due to contention) "fat" lock. Called only
301
+ * from ClaimTitle, immediately below, when we detect deadlock were we to wait
302
+ * for title's lock, because its ownercx is waiting on a title owned by the
303
+ * calling cx.
304
+ *
305
+ * (i) rt->gcLock held
306
+ */
307
+ static void
308
+ ShareTitle(JSContext *cx, JSTitle *title)
309
+ {
310
+ JSRuntime *rt;
311
+ JSTitle **todop;
312
+
313
+ rt = cx->runtime;
314
+ if (title->u.link) {
315
+ for (todop = &rt->titleSharingTodo; *todop != title;
316
+ todop = &(*todop)->u.link) {
317
+ JS_ASSERT(*todop != NO_TITLE_SHARING_TODO);
318
+ }
319
+ *todop = title->u.link;
320
+ title->u.link = NULL; /* null u.link for sanity ASAP */
321
+ JS_NOTIFY_ALL_CONDVAR(rt->titleSharingDone);
322
+ }
323
+ js_InitLock(&title->lock);
324
+ title->u.count = 0;
325
+ js_FinishSharingTitle(cx, title);
326
+ }
327
+
328
+ /*
329
+ * js_FinishSharingTitle is the tail part of ShareTitle, split out to become a
330
+ * subroutine of JS_EndRequest too. The bulk of the work here involves making
331
+ * mutable strings in the title's object's slots be immutable. We have to do
332
+ * this because such strings will soon be available to multiple threads, so
333
+ * their buffers can't be realloc'd any longer in js_ConcatStrings, and their
334
+ * members can't be modified by js_ConcatStrings, js_MinimizeDependentStrings,
335
+ * or js_UndependString.
336
+ *
337
+ * The last bit of work done by js_FinishSharingTitle nulls title->ownercx and
338
+ * updates rt->sharedTitles.
339
+ */
340
+
341
+ void
342
+ js_FinishSharingTitle(JSContext *cx, JSTitle *title)
343
+ {
344
+ JSObjectMap *map;
345
+ JSScope *scope;
346
+ JSObject *obj;
347
+ uint32 nslots, i;
348
+ jsval v;
349
+
350
+ map = TITLE_TO_MAP(title);
351
+ if (!MAP_IS_NATIVE(map))
352
+ return;
353
+ scope = (JSScope *)map;
354
+
355
+ obj = scope->object;
356
+ nslots = scope->map.freeslot;
357
+ for (i = 0; i != nslots; ++i) {
358
+ v = STOBJ_GET_SLOT(obj, i);
359
+ if (JSVAL_IS_STRING(v) &&
360
+ !js_MakeStringImmutable(cx, JSVAL_TO_STRING(v))) {
361
+ /*
362
+ * FIXME bug 363059: The following error recovery changes runtime
363
+ * execution semantics, arbitrarily and silently ignoring errors
364
+ * except out-of-memory, which should have been reported through
365
+ * JS_ReportOutOfMemory at this point.
366
+ */
367
+ STOBJ_SET_SLOT(obj, i, JSVAL_VOID);
368
+ }
369
+ }
370
+
371
+ title->ownercx = NULL; /* NB: set last, after lock init */
372
+ JS_RUNTIME_METER(cx->runtime, sharedTitles);
373
+ }
374
+
375
+ /*
376
+ * Given a title with apparently non-null ownercx different from cx, try to
377
+ * set ownercx to cx, claiming exclusive (single-threaded) ownership of title.
378
+ * If we claim ownership, return true. Otherwise, we wait for ownercx to be
379
+ * set to null (indicating that title is multi-threaded); or if waiting would
380
+ * deadlock, we set ownercx to null ourselves via ShareTitle. In any case,
381
+ * once ownercx is null we return false.
382
+ */
383
+ static JSBool
384
+ ClaimTitle(JSTitle *title, JSContext *cx)
385
+ {
386
+ JSRuntime *rt;
387
+ JSContext *ownercx;
388
+ jsrefcount saveDepth;
389
+ PRStatus stat;
390
+
391
+ rt = cx->runtime;
392
+ JS_RUNTIME_METER(rt, claimAttempts);
393
+ JS_LOCK_GC(rt);
394
+
395
+ /* Reload in case ownercx went away while we blocked on the lock. */
396
+ while ((ownercx = title->ownercx) != NULL) {
397
+ /*
398
+ * Avoid selflock if ownercx is dead, or is not running a request, or
399
+ * has the same thread as cx. Set title->ownercx to cx so that the
400
+ * matching JS_UNLOCK_SCOPE or JS_UNLOCK_OBJ macro call will take the
401
+ * fast path around the corresponding js_UnlockTitle or js_UnlockObj
402
+ * function call.
403
+ *
404
+ * If title->u.link is non-null, title has already been inserted on
405
+ * the rt->titleSharingTodo list, because another thread's context
406
+ * already wanted to lock title while ownercx was running a request.
407
+ * We can't claim any title whose u.link is non-null at this point,
408
+ * even if ownercx->requestDepth is 0 (see below where we suspend our
409
+ * request before waiting on rt->titleSharingDone).
410
+ */
411
+ if (!title->u.link &&
412
+ (!js_ValidContextPointer(rt, ownercx) ||
413
+ !ownercx->requestDepth ||
414
+ ownercx->thread == cx->thread)) {
415
+ JS_ASSERT(title->u.count == 0);
416
+ title->ownercx = cx;
417
+ JS_UNLOCK_GC(rt);
418
+ JS_RUNTIME_METER(rt, claimedTitles);
419
+ return JS_TRUE;
420
+ }
421
+
422
+ /*
423
+ * Avoid deadlock if title's owner context is waiting on a title that
424
+ * we own, by revoking title's ownership. This approach to deadlock
425
+ * avoidance works because the engine never nests title locks.
426
+ *
427
+ * If cx could hold locks on ownercx->titleToShare, or if ownercx could
428
+ * hold locks on title, we would need to keep reentrancy counts for all
429
+ * such "flyweight" (ownercx != NULL) locks, so that control would
430
+ * unwind properly once these locks became "thin" or "fat". The engine
431
+ * promotes a title from exclusive to shared access only when locking,
432
+ * never when holding or unlocking.
433
+ *
434
+ * Avoid deadlock before any of this title/context cycle detection if
435
+ * cx is on the active GC's thread, because in that case, no requests
436
+ * will run until the GC completes. Any title wanted by the GC (from
437
+ * a finalizer) that can't be claimed must become shared.
438
+ */
439
+ if (rt->gcThread == cx->thread ||
440
+ (ownercx->titleToShare &&
441
+ WillDeadlock(ownercx->titleToShare, cx))) {
442
+ ShareTitle(cx, title);
443
+ break;
444
+ }
445
+
446
+ /*
447
+ * Thanks to the non-zero NO_TITLE_SHARING_TODO link terminator, we
448
+ * can decide whether title is on rt->titleSharingTodo with a single
449
+ * non-null test, and avoid double-insertion bugs.
450
+ */
451
+ if (!title->u.link) {
452
+ title->u.link = rt->titleSharingTodo;
453
+ rt->titleSharingTodo = title;
454
+ js_HoldObjectMap(cx, TITLE_TO_MAP(title));
455
+ }
456
+
457
+ /*
458
+ * Inline JS_SuspendRequest before we wait on rt->titleSharingDone,
459
+ * saving and clearing cx->requestDepth so we don't deadlock if the
460
+ * GC needs to run on ownercx.
461
+ *
462
+ * Unlike JS_SuspendRequest and JS_EndRequest, we must take care not
463
+ * to decrement rt->requestCount if cx is active on the GC's thread,
464
+ * because the GC has already reduced rt->requestCount to exclude all
465
+ * such such contexts.
466
+ */
467
+ saveDepth = cx->requestDepth;
468
+ if (saveDepth) {
469
+ cx->requestDepth = 0;
470
+ if (rt->gcThread != cx->thread) {
471
+ JS_ASSERT(rt->requestCount > 0);
472
+ rt->requestCount--;
473
+ if (rt->requestCount == 0)
474
+ JS_NOTIFY_REQUEST_DONE(rt);
475
+ }
476
+ }
477
+
478
+ /*
479
+ * We know that some other thread's context owns title, which is now
480
+ * linked onto rt->titleSharingTodo, awaiting the end of that other
481
+ * thread's request. So it is safe to wait on rt->titleSharingDone.
482
+ */
483
+ cx->titleToShare = title;
484
+ stat = PR_WaitCondVar(rt->titleSharingDone, PR_INTERVAL_NO_TIMEOUT);
485
+ JS_ASSERT(stat != PR_FAILURE);
486
+
487
+ /*
488
+ * Inline JS_ResumeRequest after waiting on rt->titleSharingDone,
489
+ * restoring cx->requestDepth. Same note as above for the inlined,
490
+ * specialized JS_SuspendRequest code: beware rt->gcThread.
491
+ */
492
+ if (saveDepth) {
493
+ if (rt->gcThread != cx->thread) {
494
+ while (rt->gcLevel > 0)
495
+ JS_AWAIT_GC_DONE(rt);
496
+ rt->requestCount++;
497
+ }
498
+ cx->requestDepth = saveDepth;
499
+ }
500
+
501
+ /*
502
+ * Don't clear cx->titleToShare until after we're through waiting on
503
+ * all condition variables protected by rt->gcLock -- that includes
504
+ * rt->titleSharingDone *and* rt->gcDone (hidden in JS_AWAIT_GC_DONE,
505
+ * in the inlined JS_ResumeRequest code immediately above).
506
+ *
507
+ * Otherwise, the GC could easily deadlock with another thread that
508
+ * owns a title wanted by a finalizer. By keeping cx->titleToShare
509
+ * set till here, we ensure that such deadlocks are detected, which
510
+ * results in the finalized object's title being shared (it must, of
511
+ * course, have other, live objects sharing it).
512
+ */
513
+ cx->titleToShare = NULL;
514
+ }
515
+
516
+ JS_UNLOCK_GC(rt);
517
+ return JS_FALSE;
518
+ }
519
+
520
+ /* Exported to js.c, which calls it via OBJ_GET_* and JSVAL_IS_* macros. */
521
+ JS_FRIEND_API(jsval)
522
+ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
523
+ {
524
+ jsval v;
525
+ JSScope *scope;
526
+ JSTitle *title;
527
+ #ifndef NSPR_LOCK
528
+ JSThinLock *tl;
529
+ jsword me;
530
+ #endif
531
+
532
+ /*
533
+ * We handle non-native objects via JSObjectOps.getRequiredSlot, treating
534
+ * all slots starting from 0 as required slots. A property definition or
535
+ * some prior arrangement must have allocated slot.
536
+ *
537
+ * Note once again (see jspubtd.h, before JSGetRequiredSlotOp's typedef)
538
+ * the crucial distinction between a |required slot number| that's passed
539
+ * to the get/setRequiredSlot JSObjectOps, and a |reserved slot index|
540
+ * passed to the JS_Get/SetReservedSlot APIs.
541
+ */
542
+ if (!OBJ_IS_NATIVE(obj))
543
+ return OBJ_GET_REQUIRED_SLOT(cx, obj, slot);
544
+
545
+ /*
546
+ * Native object locking is inlined here to optimize the single-threaded
547
+ * and contention-free multi-threaded cases.
548
+ */
549
+ scope = OBJ_SCOPE(obj);
550
+ title = &scope->title;
551
+ JS_ASSERT(title->ownercx != cx);
552
+ JS_ASSERT(slot < obj->map->freeslot);
553
+
554
+ /*
555
+ * Avoid locking if called from the GC. Also avoid locking an object
556
+ * owning a sealed scope. If neither of those special cases applies, try
557
+ * to claim scope's flyweight lock from whatever context may have had it in
558
+ * an earlier request.
559
+ */
560
+ if (CX_THREAD_IS_RUNNING_GC(cx) ||
561
+ (SCOPE_IS_SEALED(scope) && scope->object == obj) ||
562
+ (title->ownercx && ClaimTitle(title, cx))) {
563
+ return STOBJ_GET_SLOT(obj, slot);
564
+ }
565
+
566
+ #ifndef NSPR_LOCK
567
+ tl = &title->lock;
568
+ me = CX_THINLOCK_ID(cx);
569
+ JS_ASSERT(CURRENT_THREAD_IS_ME(me));
570
+ if (js_CompareAndSwap(&tl->owner, 0, me)) {
571
+ /*
572
+ * Got the lock with one compare-and-swap. Even so, someone else may
573
+ * have mutated obj so it now has its own scope and lock, which would
574
+ * require either a restart from the top of this routine, or a thin
575
+ * lock release followed by fat lock acquisition.
576
+ */
577
+ if (scope == OBJ_SCOPE(obj)) {
578
+ v = STOBJ_GET_SLOT(obj, slot);
579
+ if (!js_CompareAndSwap(&tl->owner, me, 0)) {
580
+ /* Assert that scope locks never revert to flyweight. */
581
+ JS_ASSERT(title->ownercx != cx);
582
+ LOGIT(scope, '1');
583
+ title->u.count = 1;
584
+ js_UnlockObj(cx, obj);
585
+ }
586
+ return v;
587
+ }
588
+ if (!js_CompareAndSwap(&tl->owner, me, 0))
589
+ js_Dequeue(tl);
590
+ }
591
+ else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) {
592
+ return STOBJ_GET_SLOT(obj, slot);
593
+ }
594
+ #endif
595
+
596
+ js_LockObj(cx, obj);
597
+ v = STOBJ_GET_SLOT(obj, slot);
598
+
599
+ /*
600
+ * Test whether cx took ownership of obj's scope during js_LockObj.
601
+ *
602
+ * This does not mean that a given scope reverted to flyweight from "thin"
603
+ * or "fat" -- it does mean that obj's map pointer changed due to another
604
+ * thread setting a property, requiring obj to cease sharing a prototype
605
+ * object's scope (whose lock was not flyweight, else we wouldn't be here
606
+ * in the first place!).
607
+ */
608
+ title = &OBJ_SCOPE(obj)->title;
609
+ if (title->ownercx != cx)
610
+ js_UnlockTitle(cx, title);
611
+ return v;
612
+ }
613
+
614
+ void
615
+ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
616
+ {
617
+ JSTitle *title;
618
+ JSScope *scope;
619
+ #ifndef NSPR_LOCK
620
+ JSThinLock *tl;
621
+ jsword me;
622
+ #endif
623
+
624
+ /* Any string stored in a thread-safe object must be immutable. */
625
+ if (JSVAL_IS_STRING(v) &&
626
+ !js_MakeStringImmutable(cx, JSVAL_TO_STRING(v))) {
627
+ /* FIXME bug 363059: See comments in js_FinishSharingScope. */
628
+ v = JSVAL_NULL;
629
+ }
630
+
631
+ /*
632
+ * We handle non-native objects via JSObjectOps.setRequiredSlot, as above
633
+ * for the Get case.
634
+ */
635
+ if (!OBJ_IS_NATIVE(obj)) {
636
+ OBJ_SET_REQUIRED_SLOT(cx, obj, slot, v);
637
+ return;
638
+ }
639
+
640
+ /*
641
+ * Native object locking is inlined here to optimize the single-threaded
642
+ * and contention-free multi-threaded cases.
643
+ */
644
+ scope = OBJ_SCOPE(obj);
645
+ title = &scope->title;
646
+ JS_ASSERT(title->ownercx != cx);
647
+ JS_ASSERT(slot < obj->map->freeslot);
648
+
649
+ /*
650
+ * Avoid locking if called from the GC. Also avoid locking an object
651
+ * owning a sealed scope. If neither of those special cases applies, try
652
+ * to claim scope's flyweight lock from whatever context may have had it in
653
+ * an earlier request.
654
+ */
655
+ if (CX_THREAD_IS_RUNNING_GC(cx) ||
656
+ (SCOPE_IS_SEALED(scope) && scope->object == obj) ||
657
+ (title->ownercx && ClaimTitle(title, cx))) {
658
+ LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, v);
659
+ return;
660
+ }
661
+
662
+ #ifndef NSPR_LOCK
663
+ tl = &title->lock;
664
+ me = CX_THINLOCK_ID(cx);
665
+ JS_ASSERT(CURRENT_THREAD_IS_ME(me));
666
+ if (js_CompareAndSwap(&tl->owner, 0, me)) {
667
+ if (scope == OBJ_SCOPE(obj)) {
668
+ LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, v);
669
+ if (!js_CompareAndSwap(&tl->owner, me, 0)) {
670
+ /* Assert that scope locks never revert to flyweight. */
671
+ JS_ASSERT(title->ownercx != cx);
672
+ LOGIT(scope, '1');
673
+ title->u.count = 1;
674
+ js_UnlockObj(cx, obj);
675
+ }
676
+ return;
677
+ }
678
+ if (!js_CompareAndSwap(&tl->owner, me, 0))
679
+ js_Dequeue(tl);
680
+ }
681
+ else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) {
682
+ LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, v);
683
+ return;
684
+ }
685
+ #endif
686
+
687
+ js_LockObj(cx, obj);
688
+ LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, v);
689
+
690
+ /*
691
+ * Same drill as above, in js_GetSlotThreadSafe.
692
+ */
693
+ title = &OBJ_SCOPE(obj)->title;
694
+ if (title->ownercx != cx)
695
+ js_UnlockTitle(cx, title);
696
+ }
697
+
698
+ #ifndef NSPR_LOCK
699
+
700
+ static JSFatLock *
701
+ NewFatlock()
702
+ {
703
+ JSFatLock *fl = (JSFatLock *)malloc(sizeof(JSFatLock)); /* for now */
704
+ if (!fl) return NULL;
705
+ fl->susp = 0;
706
+ fl->next = NULL;
707
+ fl->prevp = NULL;
708
+ fl->slock = PR_NewLock();
709
+ fl->svar = PR_NewCondVar(fl->slock);
710
+ return fl;
711
+ }
712
+
713
+ static void
714
+ DestroyFatlock(JSFatLock *fl)
715
+ {
716
+ PR_DestroyLock(fl->slock);
717
+ PR_DestroyCondVar(fl->svar);
718
+ free(fl);
719
+ }
720
+
721
+ static JSFatLock *
722
+ ListOfFatlocks(int listc)
723
+ {
724
+ JSFatLock *m;
725
+ JSFatLock *m0;
726
+ int i;
727
+
728
+ JS_ASSERT(listc>0);
729
+ m0 = m = NewFatlock();
730
+ for (i=1; i<listc; i++) {
731
+ m->next = NewFatlock();
732
+ m = m->next;
733
+ }
734
+ return m0;
735
+ }
736
+
737
+ static void
738
+ DeleteListOfFatlocks(JSFatLock *m)
739
+ {
740
+ JSFatLock *m0;
741
+ for (; m; m=m0) {
742
+ m0 = m->next;
743
+ DestroyFatlock(m);
744
+ }
745
+ }
746
+
747
+ static JSFatLockTable *fl_list_table = NULL;
748
+ static uint32 fl_list_table_len = 0;
749
+ static uint32 fl_list_chunk_len = 0;
750
+
751
+ static JSFatLock *
752
+ GetFatlock(void *id)
753
+ {
754
+ JSFatLock *m;
755
+
756
+ uint32 i = GLOBAL_LOCK_INDEX(id);
757
+ if (fl_list_table[i].free == NULL) {
758
+ #ifdef DEBUG
759
+ if (fl_list_table[i].taken)
760
+ printf("Ran out of fat locks!\n");
761
+ #endif
762
+ fl_list_table[i].free = ListOfFatlocks(fl_list_chunk_len);
763
+ }
764
+ m = fl_list_table[i].free;
765
+ fl_list_table[i].free = m->next;
766
+ m->susp = 0;
767
+ m->next = fl_list_table[i].taken;
768
+ m->prevp = &fl_list_table[i].taken;
769
+ if (fl_list_table[i].taken)
770
+ fl_list_table[i].taken->prevp = &m->next;
771
+ fl_list_table[i].taken = m;
772
+ return m;
773
+ }
774
+
775
+ static void
776
+ PutFatlock(JSFatLock *m, void *id)
777
+ {
778
+ uint32 i;
779
+ if (m == NULL)
780
+ return;
781
+
782
+ /* Unlink m from fl_list_table[i].taken. */
783
+ *m->prevp = m->next;
784
+ if (m->next)
785
+ m->next->prevp = m->prevp;
786
+
787
+ /* Insert m in fl_list_table[i].free. */
788
+ i = GLOBAL_LOCK_INDEX(id);
789
+ m->next = fl_list_table[i].free;
790
+ fl_list_table[i].free = m;
791
+ }
792
+
793
+ #endif /* !NSPR_LOCK */
794
+
795
+ JSBool
796
+ js_SetupLocks(int listc, int globc)
797
+ {
798
+ #ifndef NSPR_LOCK
799
+ uint32 i;
800
+
801
+ if (global_locks)
802
+ return JS_TRUE;
803
+ #ifdef DEBUG
804
+ if (listc > 10000 || listc < 0) /* listc == fat lock list chunk length */
805
+ printf("Bad number %d in js_SetupLocks()!\n", listc);
806
+ if (globc > 100 || globc < 0) /* globc == number of global locks */
807
+ printf("Bad number %d in js_SetupLocks()!\n", listc);
808
+ #endif
809
+ global_locks_log2 = JS_CeilingLog2(globc);
810
+ global_locks_mask = JS_BITMASK(global_locks_log2);
811
+ global_lock_count = JS_BIT(global_locks_log2);
812
+ global_locks = (PRLock **) malloc(global_lock_count * sizeof(PRLock*));
813
+ if (!global_locks)
814
+ return JS_FALSE;
815
+ for (i = 0; i < global_lock_count; i++) {
816
+ global_locks[i] = PR_NewLock();
817
+ if (!global_locks[i]) {
818
+ global_lock_count = i;
819
+ js_CleanupLocks();
820
+ return JS_FALSE;
821
+ }
822
+ }
823
+ fl_list_table = (JSFatLockTable *) malloc(i * sizeof(JSFatLockTable));
824
+ if (!fl_list_table) {
825
+ js_CleanupLocks();
826
+ return JS_FALSE;
827
+ }
828
+ fl_list_table_len = global_lock_count;
829
+ for (i = 0; i < global_lock_count; i++)
830
+ fl_list_table[i].free = fl_list_table[i].taken = NULL;
831
+ fl_list_chunk_len = listc;
832
+ #endif /* !NSPR_LOCK */
833
+ return JS_TRUE;
834
+ }
835
+
836
+ void
837
+ js_CleanupLocks()
838
+ {
839
+ #ifndef NSPR_LOCK
840
+ uint32 i;
841
+
842
+ if (global_locks) {
843
+ for (i = 0; i < global_lock_count; i++)
844
+ PR_DestroyLock(global_locks[i]);
845
+ free(global_locks);
846
+ global_locks = NULL;
847
+ global_lock_count = 1;
848
+ global_locks_log2 = 0;
849
+ global_locks_mask = 0;
850
+ }
851
+ if (fl_list_table) {
852
+ for (i = 0; i < fl_list_table_len; i++) {
853
+ DeleteListOfFatlocks(fl_list_table[i].free);
854
+ fl_list_table[i].free = NULL;
855
+ DeleteListOfFatlocks(fl_list_table[i].taken);
856
+ fl_list_table[i].taken = NULL;
857
+ }
858
+ free(fl_list_table);
859
+ fl_list_table = NULL;
860
+ fl_list_table_len = 0;
861
+ }
862
+ #endif /* !NSPR_LOCK */
863
+ }
864
+
865
+ #ifndef NSPR_LOCK
866
+
867
+ /*
868
+ * Fast locking and unlocking is implemented by delaying the allocation of a
869
+ * system lock (fat lock) until contention. As long as a locking thread A
870
+ * runs uncontended, the lock is represented solely by storing A's identity in
871
+ * the object being locked.
872
+ *
873
+ * If another thread B tries to lock the object currently locked by A, B is
874
+ * enqueued into a fat lock structure (which might have to be allocated and
875
+ * pointed to by the object), and suspended using NSPR conditional variables
876
+ * (wait). A wait bit (Bacon bit) is set in the lock word of the object,
877
+ * signalling to A that when releasing the lock, B must be dequeued and
878
+ * notified.
879
+ *
880
+ * The basic operation of the locking primitives (js_Lock, js_Unlock,
881
+ * js_Enqueue, and js_Dequeue) is compare-and-swap. Hence, when locking into
882
+ * the word pointed at by p, compare-and-swap(p, 0, A) success implies that p
883
+ * is unlocked. Similarly, when unlocking p, if compare-and-swap(p, A, 0)
884
+ * succeeds this implies that p is uncontended (no one is waiting because the
885
+ * wait bit is not set).
886
+ *
887
+ * When dequeueing, the lock is released, and one of the threads suspended on
888
+ * the lock is notified. If other threads still are waiting, the wait bit is
889
+ * kept (in js_Enqueue), and if not, the fat lock is deallocated.
890
+ *
891
+ * The functions js_Enqueue, js_Dequeue, js_SuspendThread, and js_ResumeThread
892
+ * are serialized using a global lock. For scalability, a hashtable of global
893
+ * locks is used, which is indexed modulo the thin lock pointer.
894
+ */
895
+
896
+ /*
897
+ * Invariants:
898
+ * (i) global lock is held
899
+ * (ii) fl->susp >= 0
900
+ */
901
+ static int
902
+ js_SuspendThread(JSThinLock *tl)
903
+ {
904
+ JSFatLock *fl;
905
+ PRStatus stat;
906
+
907
+ if (tl->fat == NULL)
908
+ fl = tl->fat = GetFatlock(tl);
909
+ else
910
+ fl = tl->fat;
911
+ JS_ASSERT(fl->susp >= 0);
912
+ fl->susp++;
913
+ PR_Lock(fl->slock);
914
+ js_UnlockGlobal(tl);
915
+ stat = PR_WaitCondVar(fl->svar, PR_INTERVAL_NO_TIMEOUT);
916
+ JS_ASSERT(stat != PR_FAILURE);
917
+ PR_Unlock(fl->slock);
918
+ js_LockGlobal(tl);
919
+ fl->susp--;
920
+ if (fl->susp == 0) {
921
+ PutFatlock(fl, tl);
922
+ tl->fat = NULL;
923
+ }
924
+ return tl->fat == NULL;
925
+ }
926
+
927
+ /*
928
+ * (i) global lock is held
929
+ * (ii) fl->susp > 0
930
+ */
931
+ static void
932
+ js_ResumeThread(JSThinLock *tl)
933
+ {
934
+ JSFatLock *fl = tl->fat;
935
+ PRStatus stat;
936
+
937
+ JS_ASSERT(fl != NULL);
938
+ JS_ASSERT(fl->susp > 0);
939
+ PR_Lock(fl->slock);
940
+ js_UnlockGlobal(tl);
941
+ stat = PR_NotifyCondVar(fl->svar);
942
+ JS_ASSERT(stat != PR_FAILURE);
943
+ PR_Unlock(fl->slock);
944
+ }
945
+
946
+ static void
947
+ js_Enqueue(JSThinLock *tl, jsword me)
948
+ {
949
+ jsword o, n;
950
+
951
+ js_LockGlobal(tl);
952
+ for (;;) {
953
+ o = ReadWord(tl->owner);
954
+ n = Thin_SetWait(o);
955
+ if (o != 0 && js_CompareAndSwap(&tl->owner, o, n)) {
956
+ if (js_SuspendThread(tl))
957
+ me = Thin_RemoveWait(me);
958
+ else
959
+ me = Thin_SetWait(me);
960
+ }
961
+ else if (js_CompareAndSwap(&tl->owner, 0, me)) {
962
+ js_UnlockGlobal(tl);
963
+ return;
964
+ }
965
+ }
966
+ }
967
+
968
+ static void
969
+ js_Dequeue(JSThinLock *tl)
970
+ {
971
+ jsword o;
972
+
973
+ js_LockGlobal(tl);
974
+ o = ReadWord(tl->owner);
975
+ JS_ASSERT(Thin_GetWait(o) != 0);
976
+ JS_ASSERT(tl->fat != NULL);
977
+ if (!js_CompareAndSwap(&tl->owner, o, 0)) /* release it */
978
+ JS_ASSERT(0);
979
+ js_ResumeThread(tl);
980
+ }
981
+
982
+ JS_INLINE void
983
+ js_Lock(JSThinLock *tl, jsword me)
984
+ {
985
+ JS_ASSERT(CURRENT_THREAD_IS_ME(me));
986
+ if (js_CompareAndSwap(&tl->owner, 0, me))
987
+ return;
988
+ if (Thin_RemoveWait(ReadWord(tl->owner)) != me)
989
+ js_Enqueue(tl, me);
990
+ #ifdef DEBUG
991
+ else
992
+ JS_ASSERT(0);
993
+ #endif
994
+ }
995
+
996
+ JS_INLINE void
997
+ js_Unlock(JSThinLock *tl, jsword me)
998
+ {
999
+ JS_ASSERT(CURRENT_THREAD_IS_ME(me));
1000
+
1001
+ /*
1002
+ * Since we can race with the CompareAndSwap in js_Enqueue, we need
1003
+ * to use a C_A_S here as well -- Arjan van de Ven 30/1/08
1004
+ */
1005
+ if (js_CompareAndSwap(&tl->owner, me, 0))
1006
+ return;
1007
+
1008
+ JS_ASSERT(Thin_GetWait(tl->owner));
1009
+ if (Thin_RemoveWait(ReadWord(tl->owner)) == me)
1010
+ js_Dequeue(tl);
1011
+ #ifdef DEBUG
1012
+ else
1013
+ JS_ASSERT(0); /* unbalanced unlock */
1014
+ #endif
1015
+ }
1016
+
1017
+ #endif /* !NSPR_LOCK */
1018
+
1019
+ void
1020
+ js_LockRuntime(JSRuntime *rt)
1021
+ {
1022
+ PR_Lock(rt->rtLock);
1023
+ #ifdef DEBUG
1024
+ rt->rtLockOwner = js_CurrentThreadId();
1025
+ #endif
1026
+ }
1027
+
1028
+ void
1029
+ js_UnlockRuntime(JSRuntime *rt)
1030
+ {
1031
+ #ifdef DEBUG
1032
+ rt->rtLockOwner = 0;
1033
+ #endif
1034
+ PR_Unlock(rt->rtLock);
1035
+ }
1036
+
1037
+ void
1038
+ js_LockTitle(JSContext *cx, JSTitle *title)
1039
+ {
1040
+ jsword me = CX_THINLOCK_ID(cx);
1041
+
1042
+ JS_ASSERT(CURRENT_THREAD_IS_ME(me));
1043
+ JS_ASSERT(title->ownercx != cx);
1044
+ if (CX_THREAD_IS_RUNNING_GC(cx))
1045
+ return;
1046
+ if (title->ownercx && ClaimTitle(title, cx))
1047
+ return;
1048
+
1049
+ if (Thin_RemoveWait(ReadWord(title->lock.owner)) == me) {
1050
+ JS_ASSERT(title->u.count > 0);
1051
+ LOGIT(scope, '+');
1052
+ title->u.count++;
1053
+ } else {
1054
+ JSThinLock *tl = &title->lock;
1055
+ JS_LOCK0(tl, me);
1056
+ JS_ASSERT(title->u.count == 0);
1057
+ LOGIT(scope, '1');
1058
+ title->u.count = 1;
1059
+ }
1060
+ }
1061
+
1062
+ void
1063
+ js_UnlockTitle(JSContext *cx, JSTitle *title)
1064
+ {
1065
+ jsword me = CX_THINLOCK_ID(cx);
1066
+
1067
+ /* We hope compilers use me instead of reloading cx->thread in the macro. */
1068
+ if (CX_THREAD_IS_RUNNING_GC(cx))
1069
+ return;
1070
+ if (cx->lockedSealedTitle == title) {
1071
+ cx->lockedSealedTitle = NULL;
1072
+ return;
1073
+ }
1074
+
1075
+ /*
1076
+ * If title->ownercx is not null, it's likely that two contexts not using
1077
+ * requests nested locks for title. The first context, cx here, claimed
1078
+ * title; the second, title->ownercx here, re-claimed it because the first
1079
+ * was not in a request, or was on the same thread. We don't want to keep
1080
+ * track of such nesting, because it penalizes the common non-nested case.
1081
+ * Instead of asserting here and silently coping, we simply re-claim title
1082
+ * for cx and return.
1083
+ *
1084
+ * See http://bugzilla.mozilla.org/show_bug.cgi?id=229200 for a real world
1085
+ * case where an asymmetric thread model (Mozilla's main thread is known
1086
+ * to be the only thread that runs the GC) combined with multiple contexts
1087
+ * per thread has led to such request-less nesting.
1088
+ */
1089
+ if (title->ownercx) {
1090
+ JS_ASSERT(title->u.count == 0);
1091
+ JS_ASSERT(title->lock.owner == 0);
1092
+ title->ownercx = cx;
1093
+ return;
1094
+ }
1095
+
1096
+ JS_ASSERT(title->u.count > 0);
1097
+ if (Thin_RemoveWait(ReadWord(title->lock.owner)) != me) {
1098
+ JS_ASSERT(0); /* unbalanced unlock */
1099
+ return;
1100
+ }
1101
+ LOGIT(scope, '-');
1102
+ if (--title->u.count == 0) {
1103
+ JSThinLock *tl = &title->lock;
1104
+ JS_UNLOCK0(tl, me);
1105
+ }
1106
+ }
1107
+
1108
+ /*
1109
+ * NB: oldtitle may be null if our caller is js_GetMutableScope and it just
1110
+ * dropped the last reference to oldtitle.
1111
+ */
1112
+ void
1113
+ js_TransferTitle(JSContext *cx, JSTitle *oldtitle, JSTitle *newtitle)
1114
+ {
1115
+ jsword me;
1116
+ JSThinLock *tl;
1117
+
1118
+ JS_ASSERT(JS_IS_TITLE_LOCKED(cx, newtitle));
1119
+
1120
+ /*
1121
+ * If the last reference to oldtitle went away, newtitle needs no lock
1122
+ * state update.
1123
+ */
1124
+ if (!oldtitle)
1125
+ return;
1126
+ JS_ASSERT(JS_IS_TITLE_LOCKED(cx, oldtitle));
1127
+
1128
+ /*
1129
+ * Special case in js_LockTitle and js_UnlockTitle for the GC calling
1130
+ * code that locks, unlocks, or mutates. Nothing to do in these cases,
1131
+ * because title and newtitle were "locked" by the GC thread, so neither
1132
+ * was actually locked.
1133
+ */
1134
+ if (CX_THREAD_IS_RUNNING_GC(cx))
1135
+ return;
1136
+
1137
+ /*
1138
+ * Special case in js_LockObj and js_UnlockTitle for locking the sealed
1139
+ * scope of an object that owns that scope (the prototype or mutated obj
1140
+ * for which OBJ_SCOPE(obj)->object == obj), and unlocking it.
1141
+ */
1142
+ JS_ASSERT(cx->lockedSealedTitle != newtitle);
1143
+ if (cx->lockedSealedTitle == oldtitle) {
1144
+ JS_ASSERT(newtitle->ownercx == cx ||
1145
+ (!newtitle->ownercx && newtitle->u.count == 1));
1146
+ cx->lockedSealedTitle = NULL;
1147
+ return;
1148
+ }
1149
+
1150
+ /*
1151
+ * If oldtitle is single-threaded, there's nothing to do.
1152
+ */
1153
+ if (oldtitle->ownercx) {
1154
+ JS_ASSERT(oldtitle->ownercx == cx);
1155
+ JS_ASSERT(newtitle->ownercx == cx ||
1156
+ (!newtitle->ownercx && newtitle->u.count == 1));
1157
+ return;
1158
+ }
1159
+
1160
+ /*
1161
+ * We transfer oldtitle->u.count only if newtitle is not single-threaded.
1162
+ * Flow unwinds from here through some number of JS_UNLOCK_TITLE and/or
1163
+ * JS_UNLOCK_OBJ macro calls, which will decrement newtitle->u.count only
1164
+ * if they find newtitle->ownercx != cx.
1165
+ */
1166
+ if (newtitle->ownercx != cx) {
1167
+ JS_ASSERT(!newtitle->ownercx);
1168
+ newtitle->u.count = oldtitle->u.count;
1169
+ }
1170
+
1171
+ /*
1172
+ * Reset oldtitle's lock state so that it is completely unlocked.
1173
+ */
1174
+ LOGIT(oldscope, '0');
1175
+ oldtitle->u.count = 0;
1176
+ tl = &oldtitle->lock;
1177
+ me = CX_THINLOCK_ID(cx);
1178
+ JS_UNLOCK0(tl, me);
1179
+ }
1180
+
1181
+ void
1182
+ js_LockObj(JSContext *cx, JSObject *obj)
1183
+ {
1184
+ JSScope *scope;
1185
+ JSTitle *title;
1186
+
1187
+ JS_ASSERT(OBJ_IS_NATIVE(obj));
1188
+
1189
+ /*
1190
+ * We must test whether the GC is calling and return without mutating any
1191
+ * state, especially cx->lockedSealedScope. Note asymmetry with respect to
1192
+ * js_UnlockObj, which is a thin-layer on top of js_UnlockTitle.
1193
+ */
1194
+ if (CX_THREAD_IS_RUNNING_GC(cx))
1195
+ return;
1196
+
1197
+ for (;;) {
1198
+ scope = OBJ_SCOPE(obj);
1199
+ title = &scope->title;
1200
+ if (SCOPE_IS_SEALED(scope) && scope->object == obj &&
1201
+ !cx->lockedSealedTitle) {
1202
+ cx->lockedSealedTitle = title;
1203
+ return;
1204
+ }
1205
+
1206
+ js_LockTitle(cx, title);
1207
+
1208
+ /* If obj still has this scope, we're done. */
1209
+ if (scope == OBJ_SCOPE(obj))
1210
+ return;
1211
+
1212
+ /* Lost a race with a mutator; retry with obj's new scope. */
1213
+ js_UnlockTitle(cx, title);
1214
+ }
1215
+ }
1216
+
1217
+ void
1218
+ js_UnlockObj(JSContext *cx, JSObject *obj)
1219
+ {
1220
+ JS_ASSERT(OBJ_IS_NATIVE(obj));
1221
+ js_UnlockTitle(cx, &OBJ_SCOPE(obj)->title);
1222
+ }
1223
+
1224
+ void
1225
+ js_InitTitle(JSContext *cx, JSTitle *title)
1226
+ {
1227
+ #ifdef JS_THREADSAFE
1228
+ title->ownercx = cx;
1229
+ memset(&title->lock, 0, sizeof title->lock);
1230
+
1231
+ /*
1232
+ * Set u.link = NULL, not u.count = 0, in case the target architecture's
1233
+ * null pointer has a non-zero integer representation.
1234
+ */
1235
+ title->u.link = NULL;
1236
+
1237
+ #ifdef JS_DEBUG_TITLE_LOCKS
1238
+ title->file[0] = title->file[1] = title->file[2] = title->file[3] = NULL;
1239
+ title->line[0] = title->line[1] = title->line[2] = title->line[3] = 0;
1240
+ #endif
1241
+ #endif
1242
+ }
1243
+
1244
+ void
1245
+ js_FinishTitle(JSContext *cx, JSTitle *title)
1246
+ {
1247
+ #ifdef JS_THREADSAFE
1248
+ /* Title must be single-threaded at this point, so set ownercx. */
1249
+ JS_ASSERT(title->u.count == 0);
1250
+ title->ownercx = cx;
1251
+ js_FinishLock(&title->lock);
1252
+ #endif
1253
+ }
1254
+
1255
+ #ifdef DEBUG
1256
+
1257
+ JSBool
1258
+ js_IsRuntimeLocked(JSRuntime *rt)
1259
+ {
1260
+ return js_CurrentThreadId() == rt->rtLockOwner;
1261
+ }
1262
+
1263
+ JSBool
1264
+ js_IsObjLocked(JSContext *cx, JSObject *obj)
1265
+ {
1266
+ JSScope *scope = OBJ_SCOPE(obj);
1267
+
1268
+ return MAP_IS_NATIVE(&scope->map) && js_IsTitleLocked(cx, &scope->title);
1269
+ }
1270
+
1271
+ JSBool
1272
+ js_IsTitleLocked(JSContext *cx, JSTitle *title)
1273
+ {
1274
+ /* Special case: the GC locking any object's title, see js_LockTitle. */
1275
+ if (CX_THREAD_IS_RUNNING_GC(cx))
1276
+ return JS_TRUE;
1277
+
1278
+ /* Special case: locked object owning a sealed scope, see js_LockObj. */
1279
+ if (cx->lockedSealedTitle == title)
1280
+ return JS_TRUE;
1281
+
1282
+ /*
1283
+ * General case: the title is either exclusively owned (by cx), or it has
1284
+ * a thin or fat lock to cope with shared (concurrent) ownership.
1285
+ */
1286
+ if (title->ownercx) {
1287
+ JS_ASSERT(title->ownercx == cx || title->ownercx->thread == cx->thread);
1288
+ return JS_TRUE;
1289
+ }
1290
+ return js_CurrentThreadId() ==
1291
+ ((JSThread *)Thin_RemoveWait(ReadWord(title->lock.owner)))->id;
1292
+ }
1293
+
1294
+ #ifdef JS_DEBUG_TITLE_LOCKS
1295
+ void
1296
+ js_SetScopeInfo(JSScope *scope, const char *file, int line)
1297
+ {
1298
+ JSTitle *title = &scope->title;
1299
+ if (!title->ownercx) {
1300
+ jsrefcount count = title->u.count;
1301
+ JS_ASSERT_IF(!SCOPE_IS_SEALED(scope), count > 0);
1302
+ JS_ASSERT(count <= 4);
1303
+ title->file[count - 1] = file;
1304
+ title->line[count - 1] = line;
1305
+ }
1306
+ }
1307
+ #endif /* JS_DEBUG_TITLE_LOCKS */
1308
+ #endif /* DEBUG */
1309
+ #endif /* JS_THREADSAFE */