johnson 2.0.0.pre1 → 2.0.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +12 -0
- data/Manifest.txt +4 -285
- data/Rakefile +13 -20
- data/ext/tracemonkey/global.cc +4 -1
- data/ext/tracemonkey/js.cc +30 -33
- data/ext/tracemonkey/runtime.cc +96 -6
- data/ext/tracemonkey/split_global.cc +0 -5
- data/ext/tracemonkey/tracemonkey.h +2 -2
- data/lib/johnson.rb +2 -2
- data/lib/johnson/runtime.rb +25 -15
- data/lib/johnson/tracemonkey/runtime.rb +6 -3
- data/vendor/tracemonkey/config/system-headers +1 -3
- data/vendor/tracemonkey/jscntxt.h +5 -2
- data/vendor/tracemonkey/jsdbgapi.cpp +9 -1
- data/vendor/tracemonkey/jsdbgapi.h +4 -0
- data/vendor/tracemonkey/tests/ecma/NativeObjects/browser.js +0 -0
- data/vendor/tracemonkey/tests/ecma/NativeObjects/jstests.list +0 -0
- data/vendor/tracemonkey/tests/ecma_3_1/Object/jstests.list +1 -1
- data/vendor/tracemonkey/tests/js1_3/misc/browser.js +0 -0
- data/vendor/tracemonkey/tests/js1_3/misc/jstests.list +0 -0
- data/vendor/tracemonkey/tests/js1_5/Regress/jstests.list +4 -4
- data/vendor/tracemonkey/tests/js1_5/Scope/jstests.list +1 -1
- data/vendor/tracemonkey/tests/js1_5/decompilation/jstests.list +2 -2
- data/vendor/tracemonkey/tests/js1_7/decompilation/jstests.list +1 -1
- data/vendor/tracemonkey/tests/shell.js +2 -1
- metadata +51 -309
- data/ext/spidermonkey/context.c +0 -116
- data/ext/spidermonkey/context.h +0 -19
- data/ext/spidermonkey/conversions.c +0 -361
- data/ext/spidermonkey/conversions.h +0 -31
- data/ext/spidermonkey/debugger.c +0 -234
- data/ext/spidermonkey/debugger.h +0 -10
- data/ext/spidermonkey/extconf.rb +0 -32
- data/ext/spidermonkey/extensions.c +0 -37
- data/ext/spidermonkey/extensions.h +0 -12
- data/ext/spidermonkey/global.c +0 -40
- data/ext/spidermonkey/global.h +0 -11
- data/ext/spidermonkey/idhash.c +0 -16
- data/ext/spidermonkey/idhash.h +0 -8
- data/ext/spidermonkey/immutable_node.c +0 -1153
- data/ext/spidermonkey/immutable_node.c.erb +0 -523
- data/ext/spidermonkey/immutable_node.h +0 -22
- data/ext/spidermonkey/jroot.h +0 -197
- data/ext/spidermonkey/js_land_proxy.c +0 -620
- data/ext/spidermonkey/js_land_proxy.h +0 -20
- data/ext/spidermonkey/ruby_land_proxy.c +0 -618
- data/ext/spidermonkey/ruby_land_proxy.h +0 -38
- data/ext/spidermonkey/runtime.c +0 -396
- data/ext/spidermonkey/runtime.h +0 -27
- data/ext/spidermonkey/spidermonkey.c +0 -22
- data/ext/spidermonkey/spidermonkey.h +0 -29
- data/lib/johnson/spidermonkey.rb +0 -12
- data/lib/johnson/spidermonkey/context.rb +0 -10
- data/lib/johnson/spidermonkey/debugger.rb +0 -67
- data/lib/johnson/spidermonkey/immutable_node.rb +0 -282
- data/lib/johnson/spidermonkey/js_land_proxy.rb +0 -64
- data/lib/johnson/spidermonkey/mutable_tree_visitor.rb +0 -242
- data/lib/johnson/spidermonkey/ruby_land_proxy.rb +0 -17
- data/lib/johnson/spidermonkey/runtime.rb +0 -74
- data/test/johnson/spidermonkey/context_test.rb +0 -21
- data/test/johnson/spidermonkey/immutable_node_test.rb +0 -34
- data/test/johnson/spidermonkey/js_land_proxy_test.rb +0 -273
- data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +0 -274
- data/test/johnson/spidermonkey/runtime_test.rb +0 -41
- data/vendor/spidermonkey/.cvsignore +0 -9
- data/vendor/spidermonkey/Makefile.in +0 -449
- data/vendor/spidermonkey/Makefile.ref +0 -365
- data/vendor/spidermonkey/README.html +0 -820
- data/vendor/spidermonkey/SpiderMonkey.rsp +0 -12
- data/vendor/spidermonkey/Y.js +0 -19
- data/vendor/spidermonkey/build.mk +0 -43
- data/vendor/spidermonkey/config.mk +0 -192
- data/vendor/spidermonkey/config/AIX4.1.mk +0 -65
- data/vendor/spidermonkey/config/AIX4.2.mk +0 -64
- data/vendor/spidermonkey/config/AIX4.3.mk +0 -65
- data/vendor/spidermonkey/config/Darwin.mk +0 -83
- data/vendor/spidermonkey/config/Darwin1.3.mk +0 -81
- data/vendor/spidermonkey/config/Darwin1.4.mk +0 -41
- data/vendor/spidermonkey/config/Darwin5.2.mk +0 -81
- data/vendor/spidermonkey/config/Darwin5.3.mk +0 -81
- data/vendor/spidermonkey/config/HP-UXB.10.10.mk +0 -77
- data/vendor/spidermonkey/config/HP-UXB.10.20.mk +0 -77
- data/vendor/spidermonkey/config/HP-UXB.11.00.mk +0 -80
- data/vendor/spidermonkey/config/IRIX.mk +0 -87
- data/vendor/spidermonkey/config/IRIX5.3.mk +0 -44
- data/vendor/spidermonkey/config/IRIX6.1.mk +0 -44
- data/vendor/spidermonkey/config/IRIX6.2.mk +0 -44
- data/vendor/spidermonkey/config/IRIX6.3.mk +0 -44
- data/vendor/spidermonkey/config/IRIX6.5.mk +0 -44
- data/vendor/spidermonkey/config/Linux_All.mk +0 -103
- data/vendor/spidermonkey/config/Mac_OS10.0.mk +0 -82
- data/vendor/spidermonkey/config/OSF1V4.0.mk +0 -72
- data/vendor/spidermonkey/config/OSF1V5.0.mk +0 -69
- data/vendor/spidermonkey/config/SunOS4.1.4.mk +0 -101
- data/vendor/spidermonkey/config/SunOS5.10.mk +0 -50
- data/vendor/spidermonkey/config/SunOS5.3.mk +0 -91
- data/vendor/spidermonkey/config/SunOS5.4.mk +0 -92
- data/vendor/spidermonkey/config/SunOS5.5.1.mk +0 -44
- data/vendor/spidermonkey/config/SunOS5.5.mk +0 -87
- data/vendor/spidermonkey/config/SunOS5.6.mk +0 -89
- data/vendor/spidermonkey/config/SunOS5.7.mk +0 -44
- data/vendor/spidermonkey/config/SunOS5.8.mk +0 -44
- data/vendor/spidermonkey/config/SunOS5.9.mk +0 -44
- data/vendor/spidermonkey/config/WINNT4.0.mk +0 -117
- data/vendor/spidermonkey/config/WINNT5.0.mk +0 -117
- data/vendor/spidermonkey/config/WINNT5.1.mk +0 -117
- data/vendor/spidermonkey/config/WINNT5.2.mk +0 -117
- data/vendor/spidermonkey/config/WINNT6.0.mk +0 -117
- data/vendor/spidermonkey/config/dgux.mk +0 -64
- data/vendor/spidermonkey/editline/Makefile.ref +0 -144
- data/vendor/spidermonkey/editline/README +0 -83
- data/vendor/spidermonkey/editline/editline.3 +0 -175
- data/vendor/spidermonkey/editline/editline.c +0 -1369
- data/vendor/spidermonkey/editline/editline.h +0 -135
- data/vendor/spidermonkey/editline/sysunix.c +0 -182
- data/vendor/spidermonkey/editline/unix.h +0 -82
- data/vendor/spidermonkey/fdlibm/.cvsignore +0 -7
- data/vendor/spidermonkey/fdlibm/Makefile.in +0 -127
- data/vendor/spidermonkey/fdlibm/Makefile.ref +0 -192
- data/vendor/spidermonkey/fdlibm/e_acos.c +0 -147
- data/vendor/spidermonkey/fdlibm/e_acosh.c +0 -105
- data/vendor/spidermonkey/fdlibm/e_asin.c +0 -156
- data/vendor/spidermonkey/fdlibm/e_atan2.c +0 -165
- data/vendor/spidermonkey/fdlibm/e_atanh.c +0 -110
- data/vendor/spidermonkey/fdlibm/e_cosh.c +0 -133
- data/vendor/spidermonkey/fdlibm/e_exp.c +0 -202
- data/vendor/spidermonkey/fdlibm/e_fmod.c +0 -184
- data/vendor/spidermonkey/fdlibm/e_gamma.c +0 -71
- data/vendor/spidermonkey/fdlibm/e_gamma_r.c +0 -70
- data/vendor/spidermonkey/fdlibm/e_hypot.c +0 -173
- data/vendor/spidermonkey/fdlibm/e_j0.c +0 -524
- data/vendor/spidermonkey/fdlibm/e_j1.c +0 -523
- data/vendor/spidermonkey/fdlibm/e_jn.c +0 -315
- data/vendor/spidermonkey/fdlibm/e_lgamma.c +0 -71
- data/vendor/spidermonkey/fdlibm/e_lgamma_r.c +0 -347
- data/vendor/spidermonkey/fdlibm/e_log.c +0 -184
- data/vendor/spidermonkey/fdlibm/e_log10.c +0 -134
- data/vendor/spidermonkey/fdlibm/e_pow.c +0 -386
- data/vendor/spidermonkey/fdlibm/e_rem_pio2.c +0 -222
- data/vendor/spidermonkey/fdlibm/e_remainder.c +0 -120
- data/vendor/spidermonkey/fdlibm/e_scalb.c +0 -89
- data/vendor/spidermonkey/fdlibm/e_sinh.c +0 -122
- data/vendor/spidermonkey/fdlibm/e_sqrt.c +0 -497
- data/vendor/spidermonkey/fdlibm/fdlibm.h +0 -273
- data/vendor/spidermonkey/fdlibm/fdlibm.mak +0 -1453
- data/vendor/spidermonkey/fdlibm/fdlibm.mdp +0 -0
- data/vendor/spidermonkey/fdlibm/k_cos.c +0 -135
- data/vendor/spidermonkey/fdlibm/k_rem_pio2.c +0 -354
- data/vendor/spidermonkey/fdlibm/k_sin.c +0 -114
- data/vendor/spidermonkey/fdlibm/k_standard.c +0 -785
- data/vendor/spidermonkey/fdlibm/k_tan.c +0 -170
- data/vendor/spidermonkey/fdlibm/s_asinh.c +0 -101
- data/vendor/spidermonkey/fdlibm/s_atan.c +0 -175
- data/vendor/spidermonkey/fdlibm/s_cbrt.c +0 -133
- data/vendor/spidermonkey/fdlibm/s_ceil.c +0 -120
- data/vendor/spidermonkey/fdlibm/s_copysign.c +0 -72
- data/vendor/spidermonkey/fdlibm/s_cos.c +0 -118
- data/vendor/spidermonkey/fdlibm/s_erf.c +0 -356
- data/vendor/spidermonkey/fdlibm/s_expm1.c +0 -267
- data/vendor/spidermonkey/fdlibm/s_fabs.c +0 -70
- data/vendor/spidermonkey/fdlibm/s_finite.c +0 -71
- data/vendor/spidermonkey/fdlibm/s_floor.c +0 -121
- data/vendor/spidermonkey/fdlibm/s_frexp.c +0 -99
- data/vendor/spidermonkey/fdlibm/s_ilogb.c +0 -85
- data/vendor/spidermonkey/fdlibm/s_isnan.c +0 -74
- data/vendor/spidermonkey/fdlibm/s_ldexp.c +0 -66
- data/vendor/spidermonkey/fdlibm/s_lib_version.c +0 -73
- data/vendor/spidermonkey/fdlibm/s_log1p.c +0 -211
- data/vendor/spidermonkey/fdlibm/s_logb.c +0 -79
- data/vendor/spidermonkey/fdlibm/s_matherr.c +0 -64
- data/vendor/spidermonkey/fdlibm/s_modf.c +0 -132
- data/vendor/spidermonkey/fdlibm/s_nextafter.c +0 -124
- data/vendor/spidermonkey/fdlibm/s_rint.c +0 -131
- data/vendor/spidermonkey/fdlibm/s_scalbn.c +0 -107
- data/vendor/spidermonkey/fdlibm/s_signgam.c +0 -40
- data/vendor/spidermonkey/fdlibm/s_significand.c +0 -68
- data/vendor/spidermonkey/fdlibm/s_sin.c +0 -118
- data/vendor/spidermonkey/fdlibm/s_tan.c +0 -112
- data/vendor/spidermonkey/fdlibm/s_tanh.c +0 -122
- data/vendor/spidermonkey/fdlibm/w_acos.c +0 -78
- data/vendor/spidermonkey/fdlibm/w_acosh.c +0 -78
- data/vendor/spidermonkey/fdlibm/w_asin.c +0 -80
- data/vendor/spidermonkey/fdlibm/w_atan2.c +0 -79
- data/vendor/spidermonkey/fdlibm/w_atanh.c +0 -81
- data/vendor/spidermonkey/fdlibm/w_cosh.c +0 -77
- data/vendor/spidermonkey/fdlibm/w_exp.c +0 -88
- data/vendor/spidermonkey/fdlibm/w_fmod.c +0 -78
- data/vendor/spidermonkey/fdlibm/w_gamma.c +0 -85
- data/vendor/spidermonkey/fdlibm/w_gamma_r.c +0 -81
- data/vendor/spidermonkey/fdlibm/w_hypot.c +0 -78
- data/vendor/spidermonkey/fdlibm/w_j0.c +0 -105
- data/vendor/spidermonkey/fdlibm/w_j1.c +0 -106
- data/vendor/spidermonkey/fdlibm/w_jn.c +0 -128
- data/vendor/spidermonkey/fdlibm/w_lgamma.c +0 -85
- data/vendor/spidermonkey/fdlibm/w_lgamma_r.c +0 -81
- data/vendor/spidermonkey/fdlibm/w_log.c +0 -78
- data/vendor/spidermonkey/fdlibm/w_log10.c +0 -81
- data/vendor/spidermonkey/fdlibm/w_pow.c +0 -99
- data/vendor/spidermonkey/fdlibm/w_remainder.c +0 -77
- data/vendor/spidermonkey/fdlibm/w_scalb.c +0 -95
- data/vendor/spidermonkey/fdlibm/w_sinh.c +0 -77
- data/vendor/spidermonkey/fdlibm/w_sqrt.c +0 -77
- data/vendor/spidermonkey/javascript-trace.d +0 -73
- data/vendor/spidermonkey/js.c +0 -3951
- data/vendor/spidermonkey/js.mdp +0 -0
- data/vendor/spidermonkey/js.msg +0 -308
- data/vendor/spidermonkey/js.pkg +0 -2
- data/vendor/spidermonkey/js3240.rc +0 -79
- data/vendor/spidermonkey/jsOS240.def +0 -654
- data/vendor/spidermonkey/jsapi.c +0 -5836
- data/vendor/spidermonkey/jsapi.h +0 -2624
- data/vendor/spidermonkey/jsarena.c +0 -450
- data/vendor/spidermonkey/jsarena.h +0 -318
- data/vendor/spidermonkey/jsarray.c +0 -2996
- data/vendor/spidermonkey/jsarray.h +0 -127
- data/vendor/spidermonkey/jsatom.c +0 -1045
- data/vendor/spidermonkey/jsatom.h +0 -442
- data/vendor/spidermonkey/jsbit.h +0 -253
- data/vendor/spidermonkey/jsbool.c +0 -176
- data/vendor/spidermonkey/jsbool.h +0 -73
- data/vendor/spidermonkey/jsclist.h +0 -139
- data/vendor/spidermonkey/jscntxt.c +0 -1348
- data/vendor/spidermonkey/jscntxt.h +0 -1120
- data/vendor/spidermonkey/jscompat.h +0 -57
- data/vendor/spidermonkey/jsconfig.h +0 -248
- data/vendor/spidermonkey/jsconfig.mk +0 -181
- data/vendor/spidermonkey/jscpucfg.c +0 -396
- data/vendor/spidermonkey/jscpucfg.h +0 -212
- data/vendor/spidermonkey/jsdate.c +0 -2390
- data/vendor/spidermonkey/jsdate.h +0 -124
- data/vendor/spidermonkey/jsdbgapi.c +0 -1802
- data/vendor/spidermonkey/jsdbgapi.h +0 -464
- data/vendor/spidermonkey/jsdhash.c +0 -868
- data/vendor/spidermonkey/jsdhash.h +0 -592
- data/vendor/spidermonkey/jsdtoa.c +0 -3167
- data/vendor/spidermonkey/jsdtoa.h +0 -130
- data/vendor/spidermonkey/jsdtracef.c +0 -317
- data/vendor/spidermonkey/jsdtracef.h +0 -77
- data/vendor/spidermonkey/jsemit.c +0 -6909
- data/vendor/spidermonkey/jsemit.h +0 -741
- data/vendor/spidermonkey/jsexn.c +0 -1371
- data/vendor/spidermonkey/jsexn.h +0 -96
- data/vendor/spidermonkey/jsfile.c +0 -2736
- data/vendor/spidermonkey/jsfile.h +0 -56
- data/vendor/spidermonkey/jsfile.msg +0 -90
- data/vendor/spidermonkey/jsfun.c +0 -2634
- data/vendor/spidermonkey/jsfun.h +0 -254
- data/vendor/spidermonkey/jsgc.c +0 -3562
- data/vendor/spidermonkey/jsgc.h +0 -403
- data/vendor/spidermonkey/jshash.c +0 -476
- data/vendor/spidermonkey/jshash.h +0 -151
- data/vendor/spidermonkey/jsify.pl +0 -485
- data/vendor/spidermonkey/jsinterp.c +0 -7007
- data/vendor/spidermonkey/jsinterp.h +0 -525
- data/vendor/spidermonkey/jsinvoke.c +0 -43
- data/vendor/spidermonkey/jsiter.c +0 -1067
- data/vendor/spidermonkey/jsiter.h +0 -122
- data/vendor/spidermonkey/jskeyword.tbl +0 -124
- data/vendor/spidermonkey/jskwgen.c +0 -460
- data/vendor/spidermonkey/jslibmath.h +0 -266
- data/vendor/spidermonkey/jslock.c +0 -1309
- data/vendor/spidermonkey/jslock.h +0 -313
- data/vendor/spidermonkey/jslocko.asm +0 -60
- data/vendor/spidermonkey/jslog2.c +0 -94
- data/vendor/spidermonkey/jslong.c +0 -264
- data/vendor/spidermonkey/jslong.h +0 -412
- data/vendor/spidermonkey/jsmath.c +0 -567
- data/vendor/spidermonkey/jsmath.h +0 -57
- data/vendor/spidermonkey/jsnum.c +0 -1239
- data/vendor/spidermonkey/jsnum.h +0 -283
- data/vendor/spidermonkey/jsobj.c +0 -5282
- data/vendor/spidermonkey/jsobj.h +0 -709
- data/vendor/spidermonkey/jsopcode.c +0 -5245
- data/vendor/spidermonkey/jsopcode.h +0 -394
- data/vendor/spidermonkey/jsopcode.tbl +0 -523
- data/vendor/spidermonkey/jsotypes.h +0 -202
- data/vendor/spidermonkey/jsparse.c +0 -6704
- data/vendor/spidermonkey/jsparse.h +0 -511
- data/vendor/spidermonkey/jsprf.c +0 -1264
- data/vendor/spidermonkey/jsprf.h +0 -150
- data/vendor/spidermonkey/jsproto.tbl +0 -128
- data/vendor/spidermonkey/jsprvtd.h +0 -267
- data/vendor/spidermonkey/jspubtd.h +0 -744
- data/vendor/spidermonkey/jsregexp.c +0 -4364
- data/vendor/spidermonkey/jsregexp.h +0 -183
- data/vendor/spidermonkey/jsreops.tbl +0 -145
- data/vendor/spidermonkey/jsscan.c +0 -2012
- data/vendor/spidermonkey/jsscan.h +0 -387
- data/vendor/spidermonkey/jsscope.c +0 -1957
- data/vendor/spidermonkey/jsscope.h +0 -418
- data/vendor/spidermonkey/jsscript.c +0 -1832
- data/vendor/spidermonkey/jsscript.h +0 -287
- data/vendor/spidermonkey/jsshell.msg +0 -50
- data/vendor/spidermonkey/jsstddef.h +0 -83
- data/vendor/spidermonkey/jsstr.c +0 -5005
- data/vendor/spidermonkey/jsstr.h +0 -641
- data/vendor/spidermonkey/jstypes.h +0 -475
- data/vendor/spidermonkey/jsutil.c +0 -345
- data/vendor/spidermonkey/jsutil.h +0 -157
- data/vendor/spidermonkey/jsxdrapi.c +0 -800
- data/vendor/spidermonkey/jsxdrapi.h +0 -218
- data/vendor/spidermonkey/jsxml.c +0 -8476
- data/vendor/spidermonkey/jsxml.h +0 -349
- data/vendor/spidermonkey/lock_SunOS.s +0 -119
- data/vendor/spidermonkey/perfect.js +0 -39
- data/vendor/spidermonkey/plify_jsdhash.sed +0 -36
- data/vendor/spidermonkey/prmjtime.c +0 -846
- data/vendor/spidermonkey/prmjtime.h +0 -103
- data/vendor/spidermonkey/resource.h +0 -15
- data/vendor/spidermonkey/rules.mk +0 -197
- data/vendor/spidermonkey/win32.order +0 -384
@@ -1,868 +0,0 @@
|
|
1
|
-
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
|
-
/* ***** BEGIN LICENSE BLOCK *****
|
3
|
-
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
4
|
-
*
|
5
|
-
* The contents of this file are subject to the Mozilla Public License Version
|
6
|
-
* 1.1 (the "License"); you may not use this file except in compliance with
|
7
|
-
* the License. You may obtain a copy of the License at
|
8
|
-
* http://www.mozilla.org/MPL/
|
9
|
-
*
|
10
|
-
* Software distributed under the License is distributed on an "AS IS" basis,
|
11
|
-
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
12
|
-
* for the specific language governing rights and limitations under the
|
13
|
-
* License.
|
14
|
-
*
|
15
|
-
* The Original Code is Mozilla JavaScript code.
|
16
|
-
*
|
17
|
-
* The Initial Developer of the Original Code is
|
18
|
-
* Netscape Communications Corporation.
|
19
|
-
* Portions created by the Initial Developer are Copyright (C) 1999-2001
|
20
|
-
* the Initial Developer. All Rights Reserved.
|
21
|
-
*
|
22
|
-
* Contributor(s):
|
23
|
-
* Brendan Eich <brendan@mozilla.org> (Original Author)
|
24
|
-
* Chris Waterson <waterson@netscape.com>
|
25
|
-
* L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
|
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
|
-
* Double hashing implementation.
|
43
|
-
*/
|
44
|
-
#include <stdio.h>
|
45
|
-
#include <stdlib.h>
|
46
|
-
#include <string.h>
|
47
|
-
#include "jsbit.h"
|
48
|
-
#include "jsdhash.h"
|
49
|
-
#include "jsutil.h" /* for JS_ASSERT */
|
50
|
-
|
51
|
-
#ifdef JS_DHASHMETER
|
52
|
-
# if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan
|
53
|
-
# include "nsTraceMalloc.h"
|
54
|
-
# endif
|
55
|
-
# define METER(x) x
|
56
|
-
#else
|
57
|
-
# define METER(x) /* nothing */
|
58
|
-
#endif
|
59
|
-
|
60
|
-
/*
|
61
|
-
* The following DEBUG-only code is used to assert that calls to one of
|
62
|
-
* table->ops or to an enumerator do not cause re-entry into a call that
|
63
|
-
* can mutate the table. The recursion level is stored in additional
|
64
|
-
* space allocated at the end of the entry store to avoid changing
|
65
|
-
* JSDHashTable, which could cause issues when mixing DEBUG and
|
66
|
-
* non-DEBUG components.
|
67
|
-
*/
|
68
|
-
#ifdef DEBUG
|
69
|
-
|
70
|
-
#define RECURSION_LEVEL(table_) (*(uint32*)(table_->entryStore + \
|
71
|
-
JS_DHASH_TABLE_SIZE(table_) * \
|
72
|
-
table_->entrySize))
|
73
|
-
|
74
|
-
#define ENTRY_STORE_EXTRA sizeof(uint32)
|
75
|
-
#define INCREMENT_RECURSION_LEVEL(table_) (++RECURSION_LEVEL(table_))
|
76
|
-
#define DECREMENT_RECURSION_LEVEL(table_) (--RECURSION_LEVEL(table_))
|
77
|
-
|
78
|
-
#else
|
79
|
-
|
80
|
-
#define ENTRY_STORE_EXTRA 0
|
81
|
-
#define INCREMENT_RECURSION_LEVEL(table_) ((void)1)
|
82
|
-
#define DECREMENT_RECURSION_LEVEL(table_) ((void)0)
|
83
|
-
|
84
|
-
#endif /* defined(DEBUG) */
|
85
|
-
|
86
|
-
JS_PUBLIC_API(void *)
|
87
|
-
JS_DHashAllocTable(JSDHashTable *table, uint32 nbytes)
|
88
|
-
{
|
89
|
-
return malloc(nbytes);
|
90
|
-
}
|
91
|
-
|
92
|
-
JS_PUBLIC_API(void)
|
93
|
-
JS_DHashFreeTable(JSDHashTable *table, void *ptr)
|
94
|
-
{
|
95
|
-
free(ptr);
|
96
|
-
}
|
97
|
-
|
98
|
-
JS_PUBLIC_API(JSDHashNumber)
|
99
|
-
JS_DHashStringKey(JSDHashTable *table, const void *key)
|
100
|
-
{
|
101
|
-
JSDHashNumber h;
|
102
|
-
const unsigned char *s;
|
103
|
-
|
104
|
-
h = 0;
|
105
|
-
for (s = (const unsigned char *) key; *s != '\0'; s++)
|
106
|
-
h = JS_ROTATE_LEFT32(h, 4) ^ *s;
|
107
|
-
return h;
|
108
|
-
}
|
109
|
-
|
110
|
-
JS_PUBLIC_API(JSDHashNumber)
|
111
|
-
JS_DHashVoidPtrKeyStub(JSDHashTable *table, const void *key)
|
112
|
-
{
|
113
|
-
return (JSDHashNumber)(unsigned long)key >> 2;
|
114
|
-
}
|
115
|
-
|
116
|
-
JS_PUBLIC_API(JSBool)
|
117
|
-
JS_DHashMatchEntryStub(JSDHashTable *table,
|
118
|
-
const JSDHashEntryHdr *entry,
|
119
|
-
const void *key)
|
120
|
-
{
|
121
|
-
const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry;
|
122
|
-
|
123
|
-
return stub->key == key;
|
124
|
-
}
|
125
|
-
|
126
|
-
JS_PUBLIC_API(JSBool)
|
127
|
-
JS_DHashMatchStringKey(JSDHashTable *table,
|
128
|
-
const JSDHashEntryHdr *entry,
|
129
|
-
const void *key)
|
130
|
-
{
|
131
|
-
const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry;
|
132
|
-
|
133
|
-
/* XXX tolerate null keys on account of sloppy Mozilla callers. */
|
134
|
-
return stub->key == key ||
|
135
|
-
(stub->key && key &&
|
136
|
-
strcmp((const char *) stub->key, (const char *) key) == 0);
|
137
|
-
}
|
138
|
-
|
139
|
-
JS_PUBLIC_API(void)
|
140
|
-
JS_DHashMoveEntryStub(JSDHashTable *table,
|
141
|
-
const JSDHashEntryHdr *from,
|
142
|
-
JSDHashEntryHdr *to)
|
143
|
-
{
|
144
|
-
memcpy(to, from, table->entrySize);
|
145
|
-
}
|
146
|
-
|
147
|
-
JS_PUBLIC_API(void)
|
148
|
-
JS_DHashClearEntryStub(JSDHashTable *table, JSDHashEntryHdr *entry)
|
149
|
-
{
|
150
|
-
memset(entry, 0, table->entrySize);
|
151
|
-
}
|
152
|
-
|
153
|
-
JS_PUBLIC_API(void)
|
154
|
-
JS_DHashFreeStringKey(JSDHashTable *table, JSDHashEntryHdr *entry)
|
155
|
-
{
|
156
|
-
const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry;
|
157
|
-
|
158
|
-
free((void *) stub->key);
|
159
|
-
memset(entry, 0, table->entrySize);
|
160
|
-
}
|
161
|
-
|
162
|
-
JS_PUBLIC_API(void)
|
163
|
-
JS_DHashFinalizeStub(JSDHashTable *table)
|
164
|
-
{
|
165
|
-
}
|
166
|
-
|
167
|
-
static const JSDHashTableOps stub_ops = {
|
168
|
-
JS_DHashAllocTable,
|
169
|
-
JS_DHashFreeTable,
|
170
|
-
JS_DHashVoidPtrKeyStub,
|
171
|
-
JS_DHashMatchEntryStub,
|
172
|
-
JS_DHashMoveEntryStub,
|
173
|
-
JS_DHashClearEntryStub,
|
174
|
-
JS_DHashFinalizeStub,
|
175
|
-
NULL
|
176
|
-
};
|
177
|
-
|
178
|
-
JS_PUBLIC_API(const JSDHashTableOps *)
|
179
|
-
JS_DHashGetStubOps(void)
|
180
|
-
{
|
181
|
-
return &stub_ops;
|
182
|
-
}
|
183
|
-
|
184
|
-
JS_PUBLIC_API(JSDHashTable *)
|
185
|
-
JS_NewDHashTable(const JSDHashTableOps *ops, void *data, uint32 entrySize,
|
186
|
-
uint32 capacity)
|
187
|
-
{
|
188
|
-
JSDHashTable *table;
|
189
|
-
|
190
|
-
table = (JSDHashTable *) malloc(sizeof *table);
|
191
|
-
if (!table)
|
192
|
-
return NULL;
|
193
|
-
if (!JS_DHashTableInit(table, ops, data, entrySize, capacity)) {
|
194
|
-
free(table);
|
195
|
-
return NULL;
|
196
|
-
}
|
197
|
-
return table;
|
198
|
-
}
|
199
|
-
|
200
|
-
JS_PUBLIC_API(void)
|
201
|
-
JS_DHashTableDestroy(JSDHashTable *table)
|
202
|
-
{
|
203
|
-
JS_DHashTableFinish(table);
|
204
|
-
free(table);
|
205
|
-
}
|
206
|
-
|
207
|
-
JS_PUBLIC_API(JSBool)
|
208
|
-
JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data,
|
209
|
-
uint32 entrySize, uint32 capacity)
|
210
|
-
{
|
211
|
-
int log2;
|
212
|
-
uint32 nbytes;
|
213
|
-
|
214
|
-
#ifdef DEBUG
|
215
|
-
if (entrySize > 10 * sizeof(void *)) {
|
216
|
-
fprintf(stderr,
|
217
|
-
"jsdhash: for the table at address %p, the given entrySize"
|
218
|
-
" of %lu %s favors chaining over double hashing.\n",
|
219
|
-
(void *) table,
|
220
|
-
(unsigned long) entrySize,
|
221
|
-
(entrySize > 16 * sizeof(void*)) ? "definitely" : "probably");
|
222
|
-
}
|
223
|
-
#endif
|
224
|
-
|
225
|
-
table->ops = ops;
|
226
|
-
table->data = data;
|
227
|
-
if (capacity < JS_DHASH_MIN_SIZE)
|
228
|
-
capacity = JS_DHASH_MIN_SIZE;
|
229
|
-
|
230
|
-
JS_CEILING_LOG2(log2, capacity);
|
231
|
-
|
232
|
-
capacity = JS_BIT(log2);
|
233
|
-
if (capacity >= JS_DHASH_SIZE_LIMIT)
|
234
|
-
return JS_FALSE;
|
235
|
-
table->hashShift = JS_DHASH_BITS - log2;
|
236
|
-
table->maxAlphaFrac = (uint8)(0x100 * JS_DHASH_DEFAULT_MAX_ALPHA);
|
237
|
-
table->minAlphaFrac = (uint8)(0x100 * JS_DHASH_DEFAULT_MIN_ALPHA);
|
238
|
-
table->entrySize = entrySize;
|
239
|
-
table->entryCount = table->removedCount = 0;
|
240
|
-
table->generation = 0;
|
241
|
-
nbytes = capacity * entrySize;
|
242
|
-
|
243
|
-
table->entryStore = (char *) ops->allocTable(table,
|
244
|
-
nbytes + ENTRY_STORE_EXTRA);
|
245
|
-
if (!table->entryStore)
|
246
|
-
return JS_FALSE;
|
247
|
-
memset(table->entryStore, 0, nbytes);
|
248
|
-
METER(memset(&table->stats, 0, sizeof table->stats));
|
249
|
-
|
250
|
-
#ifdef DEBUG
|
251
|
-
RECURSION_LEVEL(table) = 0;
|
252
|
-
#endif
|
253
|
-
|
254
|
-
return JS_TRUE;
|
255
|
-
}
|
256
|
-
|
257
|
-
/*
|
258
|
-
* Compute max and min load numbers (entry counts) from table params.
|
259
|
-
*/
|
260
|
-
#define MAX_LOAD(table, size) (((table)->maxAlphaFrac * (size)) >> 8)
|
261
|
-
#define MIN_LOAD(table, size) (((table)->minAlphaFrac * (size)) >> 8)
|
262
|
-
|
263
|
-
JS_PUBLIC_API(void)
|
264
|
-
JS_DHashTableSetAlphaBounds(JSDHashTable *table,
|
265
|
-
float maxAlpha,
|
266
|
-
float minAlpha)
|
267
|
-
{
|
268
|
-
uint32 size;
|
269
|
-
|
270
|
-
/*
|
271
|
-
* Reject obviously insane bounds, rather than trying to guess what the
|
272
|
-
* buggy caller intended.
|
273
|
-
*/
|
274
|
-
JS_ASSERT(0.5 <= maxAlpha && maxAlpha < 1 && 0 <= minAlpha);
|
275
|
-
if (maxAlpha < 0.5 || 1 <= maxAlpha || minAlpha < 0)
|
276
|
-
return;
|
277
|
-
|
278
|
-
/*
|
279
|
-
* Ensure that at least one entry will always be free. If maxAlpha at
|
280
|
-
* minimum size leaves no entries free, reduce maxAlpha based on minimum
|
281
|
-
* size and the precision limit of maxAlphaFrac's fixed point format.
|
282
|
-
*/
|
283
|
-
JS_ASSERT(JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) >= 1);
|
284
|
-
if (JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) < 1) {
|
285
|
-
maxAlpha = (float)
|
286
|
-
(JS_DHASH_MIN_SIZE - JS_MAX(JS_DHASH_MIN_SIZE / 256, 1))
|
287
|
-
/ JS_DHASH_MIN_SIZE;
|
288
|
-
}
|
289
|
-
|
290
|
-
/*
|
291
|
-
* Ensure that minAlpha is strictly less than half maxAlpha. Take care
|
292
|
-
* not to truncate an entry's worth of alpha when storing in minAlphaFrac
|
293
|
-
* (8-bit fixed point format).
|
294
|
-
*/
|
295
|
-
JS_ASSERT(minAlpha < maxAlpha / 2);
|
296
|
-
if (minAlpha >= maxAlpha / 2) {
|
297
|
-
size = JS_DHASH_TABLE_SIZE(table);
|
298
|
-
minAlpha = (size * maxAlpha - JS_MAX(size / 256, 1)) / (2 * size);
|
299
|
-
}
|
300
|
-
|
301
|
-
table->maxAlphaFrac = (uint8)(maxAlpha * 256);
|
302
|
-
table->minAlphaFrac = (uint8)(minAlpha * 256);
|
303
|
-
}
|
304
|
-
|
305
|
-
/*
|
306
|
-
* Double hashing needs the second hash code to be relatively prime to table
|
307
|
-
* size, so we simply make hash2 odd.
|
308
|
-
*/
|
309
|
-
#define HASH1(hash0, shift) ((hash0) >> (shift))
|
310
|
-
#define HASH2(hash0,log2,shift) ((((hash0) << (log2)) >> (shift)) | 1)
|
311
|
-
|
312
|
-
/*
|
313
|
-
* Reserve keyHash 0 for free entries and 1 for removed-entry sentinels. Note
|
314
|
-
* that a removed-entry sentinel need be stored only if the removed entry had
|
315
|
-
* a colliding entry added after it. Therefore we can use 1 as the collision
|
316
|
-
* flag in addition to the removed-entry sentinel value. Multiplicative hash
|
317
|
-
* uses the high order bits of keyHash, so this least-significant reservation
|
318
|
-
* should not hurt the hash function's effectiveness much.
|
319
|
-
*
|
320
|
-
* If you change any of these magic numbers, also update JS_DHASH_ENTRY_IS_LIVE
|
321
|
-
* in jsdhash.h. It used to be private to jsdhash.c, but then became public to
|
322
|
-
* assist iterator writers who inspect table->entryStore directly.
|
323
|
-
*/
|
324
|
-
#define COLLISION_FLAG ((JSDHashNumber) 1)
|
325
|
-
#define MARK_ENTRY_FREE(entry) ((entry)->keyHash = 0)
|
326
|
-
#define MARK_ENTRY_REMOVED(entry) ((entry)->keyHash = 1)
|
327
|
-
#define ENTRY_IS_REMOVED(entry) ((entry)->keyHash == 1)
|
328
|
-
#define ENTRY_IS_LIVE(entry) JS_DHASH_ENTRY_IS_LIVE(entry)
|
329
|
-
#define ENSURE_LIVE_KEYHASH(hash0) if (hash0 < 2) hash0 -= 2; else (void)0
|
330
|
-
|
331
|
-
/* Match an entry's keyHash against an unstored one computed from a key. */
|
332
|
-
#define MATCH_ENTRY_KEYHASH(entry,hash0) \
|
333
|
-
(((entry)->keyHash & ~COLLISION_FLAG) == (hash0))
|
334
|
-
|
335
|
-
/* Compute the address of the indexed entry in table. */
|
336
|
-
#define ADDRESS_ENTRY(table, index) \
|
337
|
-
((JSDHashEntryHdr *)((table)->entryStore + (index) * (table)->entrySize))
|
338
|
-
|
339
|
-
JS_PUBLIC_API(void)
|
340
|
-
JS_DHashTableFinish(JSDHashTable *table)
|
341
|
-
{
|
342
|
-
char *entryAddr, *entryLimit;
|
343
|
-
uint32 entrySize;
|
344
|
-
JSDHashEntryHdr *entry;
|
345
|
-
|
346
|
-
#ifdef DEBUG_XXXbrendan
|
347
|
-
static FILE *dumpfp = NULL;
|
348
|
-
if (!dumpfp) dumpfp = fopen("/tmp/jsdhash.bigdump", "w");
|
349
|
-
if (dumpfp) {
|
350
|
-
#ifdef MOZILLA_CLIENT
|
351
|
-
NS_TraceStack(1, dumpfp);
|
352
|
-
#endif
|
353
|
-
JS_DHashTableDumpMeter(table, NULL, dumpfp);
|
354
|
-
fputc('\n', dumpfp);
|
355
|
-
}
|
356
|
-
#endif
|
357
|
-
|
358
|
-
INCREMENT_RECURSION_LEVEL(table);
|
359
|
-
|
360
|
-
/* Call finalize before clearing entries, so it can enumerate them. */
|
361
|
-
table->ops->finalize(table);
|
362
|
-
|
363
|
-
/* Clear any remaining live entries. */
|
364
|
-
entryAddr = table->entryStore;
|
365
|
-
entrySize = table->entrySize;
|
366
|
-
entryLimit = entryAddr + JS_DHASH_TABLE_SIZE(table) * entrySize;
|
367
|
-
while (entryAddr < entryLimit) {
|
368
|
-
entry = (JSDHashEntryHdr *)entryAddr;
|
369
|
-
if (ENTRY_IS_LIVE(entry)) {
|
370
|
-
METER(table->stats.removeEnums++);
|
371
|
-
table->ops->clearEntry(table, entry);
|
372
|
-
}
|
373
|
-
entryAddr += entrySize;
|
374
|
-
}
|
375
|
-
|
376
|
-
DECREMENT_RECURSION_LEVEL(table);
|
377
|
-
JS_ASSERT(RECURSION_LEVEL(table) == 0);
|
378
|
-
|
379
|
-
/* Free entry storage last. */
|
380
|
-
table->ops->freeTable(table, table->entryStore);
|
381
|
-
}
|
382
|
-
|
383
|
-
static JSDHashEntryHdr * JS_DHASH_FASTCALL
|
384
|
-
SearchTable(JSDHashTable *table, const void *key, JSDHashNumber keyHash,
|
385
|
-
JSDHashOperator op)
|
386
|
-
{
|
387
|
-
JSDHashNumber hash1, hash2;
|
388
|
-
int hashShift, sizeLog2;
|
389
|
-
JSDHashEntryHdr *entry, *firstRemoved;
|
390
|
-
JSDHashMatchEntry matchEntry;
|
391
|
-
uint32 sizeMask;
|
392
|
-
|
393
|
-
METER(table->stats.searches++);
|
394
|
-
JS_ASSERT(!(keyHash & COLLISION_FLAG));
|
395
|
-
|
396
|
-
/* Compute the primary hash address. */
|
397
|
-
hashShift = table->hashShift;
|
398
|
-
hash1 = HASH1(keyHash, hashShift);
|
399
|
-
entry = ADDRESS_ENTRY(table, hash1);
|
400
|
-
|
401
|
-
/* Miss: return space for a new entry. */
|
402
|
-
if (JS_DHASH_ENTRY_IS_FREE(entry)) {
|
403
|
-
METER(table->stats.misses++);
|
404
|
-
return entry;
|
405
|
-
}
|
406
|
-
|
407
|
-
/* Hit: return entry. */
|
408
|
-
matchEntry = table->ops->matchEntry;
|
409
|
-
if (MATCH_ENTRY_KEYHASH(entry, keyHash) && matchEntry(table, entry, key)) {
|
410
|
-
METER(table->stats.hits++);
|
411
|
-
return entry;
|
412
|
-
}
|
413
|
-
|
414
|
-
/* Collision: double hash. */
|
415
|
-
sizeLog2 = JS_DHASH_BITS - table->hashShift;
|
416
|
-
hash2 = HASH2(keyHash, sizeLog2, hashShift);
|
417
|
-
sizeMask = JS_BITMASK(sizeLog2);
|
418
|
-
|
419
|
-
/* Save the first removed entry pointer so JS_DHASH_ADD can recycle it. */
|
420
|
-
firstRemoved = NULL;
|
421
|
-
|
422
|
-
for (;;) {
|
423
|
-
if (JS_UNLIKELY(ENTRY_IS_REMOVED(entry))) {
|
424
|
-
if (!firstRemoved)
|
425
|
-
firstRemoved = entry;
|
426
|
-
} else {
|
427
|
-
if (op == JS_DHASH_ADD)
|
428
|
-
entry->keyHash |= COLLISION_FLAG;
|
429
|
-
}
|
430
|
-
|
431
|
-
METER(table->stats.steps++);
|
432
|
-
hash1 -= hash2;
|
433
|
-
hash1 &= sizeMask;
|
434
|
-
|
435
|
-
entry = ADDRESS_ENTRY(table, hash1);
|
436
|
-
if (JS_DHASH_ENTRY_IS_FREE(entry)) {
|
437
|
-
METER(table->stats.misses++);
|
438
|
-
return (firstRemoved && op == JS_DHASH_ADD) ? firstRemoved : entry;
|
439
|
-
}
|
440
|
-
|
441
|
-
if (MATCH_ENTRY_KEYHASH(entry, keyHash) &&
|
442
|
-
matchEntry(table, entry, key)) {
|
443
|
-
METER(table->stats.hits++);
|
444
|
-
return entry;
|
445
|
-
}
|
446
|
-
}
|
447
|
-
|
448
|
-
/* NOTREACHED */
|
449
|
-
return NULL;
|
450
|
-
}
|
451
|
-
|
452
|
-
/*
|
453
|
-
* This is a copy of SearchTable, used by ChangeTable, hardcoded to
|
454
|
-
* 1. assume |op == PL_DHASH_ADD|,
|
455
|
-
* 2. assume that |key| will never match an existing entry, and
|
456
|
-
* 3. assume that no entries have been removed from the current table
|
457
|
-
* structure.
|
458
|
-
* Avoiding the need for |key| means we can avoid needing a way to map
|
459
|
-
* entries to keys, which means callers can use complex key types more
|
460
|
-
* easily.
|
461
|
-
*/
|
462
|
-
static JSDHashEntryHdr * JS_DHASH_FASTCALL
|
463
|
-
FindFreeEntry(JSDHashTable *table, JSDHashNumber keyHash)
|
464
|
-
{
|
465
|
-
JSDHashNumber hash1, hash2;
|
466
|
-
int hashShift, sizeLog2;
|
467
|
-
JSDHashEntryHdr *entry;
|
468
|
-
uint32 sizeMask;
|
469
|
-
|
470
|
-
METER(table->stats.searches++);
|
471
|
-
JS_ASSERT(!(keyHash & COLLISION_FLAG));
|
472
|
-
|
473
|
-
/* Compute the primary hash address. */
|
474
|
-
hashShift = table->hashShift;
|
475
|
-
hash1 = HASH1(keyHash, hashShift);
|
476
|
-
entry = ADDRESS_ENTRY(table, hash1);
|
477
|
-
|
478
|
-
/* Miss: return space for a new entry. */
|
479
|
-
if (JS_DHASH_ENTRY_IS_FREE(entry)) {
|
480
|
-
METER(table->stats.misses++);
|
481
|
-
return entry;
|
482
|
-
}
|
483
|
-
|
484
|
-
/* Collision: double hash. */
|
485
|
-
sizeLog2 = JS_DHASH_BITS - table->hashShift;
|
486
|
-
hash2 = HASH2(keyHash, sizeLog2, hashShift);
|
487
|
-
sizeMask = JS_BITMASK(sizeLog2);
|
488
|
-
|
489
|
-
for (;;) {
|
490
|
-
JS_ASSERT(!ENTRY_IS_REMOVED(entry));
|
491
|
-
entry->keyHash |= COLLISION_FLAG;
|
492
|
-
|
493
|
-
METER(table->stats.steps++);
|
494
|
-
hash1 -= hash2;
|
495
|
-
hash1 &= sizeMask;
|
496
|
-
|
497
|
-
entry = ADDRESS_ENTRY(table, hash1);
|
498
|
-
if (JS_DHASH_ENTRY_IS_FREE(entry)) {
|
499
|
-
METER(table->stats.misses++);
|
500
|
-
return entry;
|
501
|
-
}
|
502
|
-
}
|
503
|
-
|
504
|
-
/* NOTREACHED */
|
505
|
-
return NULL;
|
506
|
-
}
|
507
|
-
|
508
|
-
static JSBool
|
509
|
-
ChangeTable(JSDHashTable *table, int deltaLog2)
|
510
|
-
{
|
511
|
-
int oldLog2, newLog2;
|
512
|
-
uint32 oldCapacity, newCapacity;
|
513
|
-
char *newEntryStore, *oldEntryStore, *oldEntryAddr;
|
514
|
-
uint32 entrySize, i, nbytes;
|
515
|
-
JSDHashEntryHdr *oldEntry, *newEntry;
|
516
|
-
JSDHashMoveEntry moveEntry;
|
517
|
-
#ifdef DEBUG
|
518
|
-
uint32 recursionLevel;
|
519
|
-
#endif
|
520
|
-
|
521
|
-
/* Look, but don't touch, until we succeed in getting new entry store. */
|
522
|
-
oldLog2 = JS_DHASH_BITS - table->hashShift;
|
523
|
-
newLog2 = oldLog2 + deltaLog2;
|
524
|
-
oldCapacity = JS_BIT(oldLog2);
|
525
|
-
newCapacity = JS_BIT(newLog2);
|
526
|
-
if (newCapacity >= JS_DHASH_SIZE_LIMIT)
|
527
|
-
return JS_FALSE;
|
528
|
-
entrySize = table->entrySize;
|
529
|
-
nbytes = newCapacity * entrySize;
|
530
|
-
|
531
|
-
newEntryStore = (char *) table->ops->allocTable(table,
|
532
|
-
nbytes + ENTRY_STORE_EXTRA);
|
533
|
-
if (!newEntryStore)
|
534
|
-
return JS_FALSE;
|
535
|
-
|
536
|
-
/* We can't fail from here on, so update table parameters. */
|
537
|
-
#ifdef DEBUG
|
538
|
-
recursionLevel = RECURSION_LEVEL(table);
|
539
|
-
#endif
|
540
|
-
table->hashShift = JS_DHASH_BITS - newLog2;
|
541
|
-
table->removedCount = 0;
|
542
|
-
table->generation++;
|
543
|
-
|
544
|
-
/* Assign the new entry store to table. */
|
545
|
-
memset(newEntryStore, 0, nbytes);
|
546
|
-
oldEntryAddr = oldEntryStore = table->entryStore;
|
547
|
-
table->entryStore = newEntryStore;
|
548
|
-
moveEntry = table->ops->moveEntry;
|
549
|
-
#ifdef DEBUG
|
550
|
-
RECURSION_LEVEL(table) = recursionLevel;
|
551
|
-
#endif
|
552
|
-
|
553
|
-
/* Copy only live entries, leaving removed ones behind. */
|
554
|
-
for (i = 0; i < oldCapacity; i++) {
|
555
|
-
oldEntry = (JSDHashEntryHdr *)oldEntryAddr;
|
556
|
-
if (ENTRY_IS_LIVE(oldEntry)) {
|
557
|
-
oldEntry->keyHash &= ~COLLISION_FLAG;
|
558
|
-
newEntry = FindFreeEntry(table, oldEntry->keyHash);
|
559
|
-
JS_ASSERT(JS_DHASH_ENTRY_IS_FREE(newEntry));
|
560
|
-
moveEntry(table, oldEntry, newEntry);
|
561
|
-
newEntry->keyHash = oldEntry->keyHash;
|
562
|
-
}
|
563
|
-
oldEntryAddr += entrySize;
|
564
|
-
}
|
565
|
-
|
566
|
-
table->ops->freeTable(table, oldEntryStore);
|
567
|
-
return JS_TRUE;
|
568
|
-
}
|
569
|
-
|
570
|
-
JS_PUBLIC_API(JSDHashEntryHdr *) JS_DHASH_FASTCALL
|
571
|
-
JS_DHashTableOperate(JSDHashTable *table, const void *key, JSDHashOperator op)
|
572
|
-
{
|
573
|
-
JSDHashNumber keyHash;
|
574
|
-
JSDHashEntryHdr *entry;
|
575
|
-
uint32 size;
|
576
|
-
int deltaLog2;
|
577
|
-
|
578
|
-
JS_ASSERT(op == JS_DHASH_LOOKUP || RECURSION_LEVEL(table) == 0);
|
579
|
-
INCREMENT_RECURSION_LEVEL(table);
|
580
|
-
|
581
|
-
keyHash = table->ops->hashKey(table, key);
|
582
|
-
keyHash *= JS_DHASH_GOLDEN_RATIO;
|
583
|
-
|
584
|
-
/* Avoid 0 and 1 hash codes, they indicate free and removed entries. */
|
585
|
-
ENSURE_LIVE_KEYHASH(keyHash);
|
586
|
-
keyHash &= ~COLLISION_FLAG;
|
587
|
-
|
588
|
-
switch (op) {
|
589
|
-
case JS_DHASH_LOOKUP:
|
590
|
-
METER(table->stats.lookups++);
|
591
|
-
entry = SearchTable(table, key, keyHash, op);
|
592
|
-
break;
|
593
|
-
|
594
|
-
case JS_DHASH_ADD:
|
595
|
-
/*
|
596
|
-
* If alpha is >= .75, grow or compress the table. If key is already
|
597
|
-
* in the table, we may grow once more than necessary, but only if we
|
598
|
-
* are on the edge of being overloaded.
|
599
|
-
*/
|
600
|
-
size = JS_DHASH_TABLE_SIZE(table);
|
601
|
-
if (table->entryCount + table->removedCount >= MAX_LOAD(table, size)) {
|
602
|
-
/* Compress if a quarter or more of all entries are removed. */
|
603
|
-
if (table->removedCount >= size >> 2) {
|
604
|
-
METER(table->stats.compresses++);
|
605
|
-
deltaLog2 = 0;
|
606
|
-
} else {
|
607
|
-
METER(table->stats.grows++);
|
608
|
-
deltaLog2 = 1;
|
609
|
-
}
|
610
|
-
|
611
|
-
/*
|
612
|
-
* Grow or compress table, returning null if ChangeTable fails and
|
613
|
-
* falling through might claim the last free entry.
|
614
|
-
*/
|
615
|
-
if (!ChangeTable(table, deltaLog2) &&
|
616
|
-
table->entryCount + table->removedCount == size - 1) {
|
617
|
-
METER(table->stats.addFailures++);
|
618
|
-
entry = NULL;
|
619
|
-
break;
|
620
|
-
}
|
621
|
-
}
|
622
|
-
|
623
|
-
/*
|
624
|
-
* Look for entry after possibly growing, so we don't have to add it,
|
625
|
-
* then skip it while growing the table and re-add it after.
|
626
|
-
*/
|
627
|
-
entry = SearchTable(table, key, keyHash, op);
|
628
|
-
if (!ENTRY_IS_LIVE(entry)) {
|
629
|
-
/* Initialize the entry, indicating that it's no longer free. */
|
630
|
-
METER(table->stats.addMisses++);
|
631
|
-
if (ENTRY_IS_REMOVED(entry)) {
|
632
|
-
METER(table->stats.addOverRemoved++);
|
633
|
-
table->removedCount--;
|
634
|
-
keyHash |= COLLISION_FLAG;
|
635
|
-
}
|
636
|
-
if (table->ops->initEntry &&
|
637
|
-
!table->ops->initEntry(table, entry, key)) {
|
638
|
-
/* We haven't claimed entry yet; fail with null return. */
|
639
|
-
memset(entry + 1, 0, table->entrySize - sizeof *entry);
|
640
|
-
entry = NULL;
|
641
|
-
break;
|
642
|
-
}
|
643
|
-
entry->keyHash = keyHash;
|
644
|
-
table->entryCount++;
|
645
|
-
}
|
646
|
-
METER(else table->stats.addHits++);
|
647
|
-
break;
|
648
|
-
|
649
|
-
case JS_DHASH_REMOVE:
|
650
|
-
entry = SearchTable(table, key, keyHash, op);
|
651
|
-
if (ENTRY_IS_LIVE(entry)) {
|
652
|
-
/* Clear this entry and mark it as "removed". */
|
653
|
-
METER(table->stats.removeHits++);
|
654
|
-
JS_DHashTableRawRemove(table, entry);
|
655
|
-
|
656
|
-
/* Shrink if alpha is <= .25 and table isn't too small already. */
|
657
|
-
size = JS_DHASH_TABLE_SIZE(table);
|
658
|
-
if (size > JS_DHASH_MIN_SIZE &&
|
659
|
-
table->entryCount <= MIN_LOAD(table, size)) {
|
660
|
-
METER(table->stats.shrinks++);
|
661
|
-
(void) ChangeTable(table, -1);
|
662
|
-
}
|
663
|
-
}
|
664
|
-
METER(else table->stats.removeMisses++);
|
665
|
-
entry = NULL;
|
666
|
-
break;
|
667
|
-
|
668
|
-
default:
|
669
|
-
JS_ASSERT(0);
|
670
|
-
entry = NULL;
|
671
|
-
}
|
672
|
-
|
673
|
-
DECREMENT_RECURSION_LEVEL(table);
|
674
|
-
|
675
|
-
return entry;
|
676
|
-
}
|
677
|
-
|
678
|
-
JS_PUBLIC_API(void)
|
679
|
-
JS_DHashTableRawRemove(JSDHashTable *table, JSDHashEntryHdr *entry)
|
680
|
-
{
|
681
|
-
JSDHashNumber keyHash; /* load first in case clearEntry goofs it */
|
682
|
-
|
683
|
-
JS_ASSERT(JS_DHASH_ENTRY_IS_LIVE(entry));
|
684
|
-
keyHash = entry->keyHash;
|
685
|
-
table->ops->clearEntry(table, entry);
|
686
|
-
if (keyHash & COLLISION_FLAG) {
|
687
|
-
MARK_ENTRY_REMOVED(entry);
|
688
|
-
table->removedCount++;
|
689
|
-
} else {
|
690
|
-
METER(table->stats.removeFrees++);
|
691
|
-
MARK_ENTRY_FREE(entry);
|
692
|
-
}
|
693
|
-
table->entryCount--;
|
694
|
-
}
|
695
|
-
|
696
|
-
JS_PUBLIC_API(uint32)
|
697
|
-
JS_DHashTableEnumerate(JSDHashTable *table, JSDHashEnumerator etor, void *arg)
|
698
|
-
{
|
699
|
-
char *entryAddr, *entryLimit;
|
700
|
-
uint32 i, capacity, entrySize, ceiling;
|
701
|
-
JSBool didRemove;
|
702
|
-
JSDHashEntryHdr *entry;
|
703
|
-
JSDHashOperator op;
|
704
|
-
|
705
|
-
INCREMENT_RECURSION_LEVEL(table);
|
706
|
-
|
707
|
-
entryAddr = table->entryStore;
|
708
|
-
entrySize = table->entrySize;
|
709
|
-
capacity = JS_DHASH_TABLE_SIZE(table);
|
710
|
-
entryLimit = entryAddr + capacity * entrySize;
|
711
|
-
i = 0;
|
712
|
-
didRemove = JS_FALSE;
|
713
|
-
while (entryAddr < entryLimit) {
|
714
|
-
entry = (JSDHashEntryHdr *)entryAddr;
|
715
|
-
if (ENTRY_IS_LIVE(entry)) {
|
716
|
-
op = etor(table, entry, i++, arg);
|
717
|
-
if (op & JS_DHASH_REMOVE) {
|
718
|
-
METER(table->stats.removeEnums++);
|
719
|
-
JS_DHashTableRawRemove(table, entry);
|
720
|
-
didRemove = JS_TRUE;
|
721
|
-
}
|
722
|
-
if (op & JS_DHASH_STOP)
|
723
|
-
break;
|
724
|
-
}
|
725
|
-
entryAddr += entrySize;
|
726
|
-
}
|
727
|
-
|
728
|
-
JS_ASSERT(!didRemove || RECURSION_LEVEL(table) == 1);
|
729
|
-
|
730
|
-
/*
|
731
|
-
* Shrink or compress if a quarter or more of all entries are removed, or
|
732
|
-
* if the table is underloaded according to the configured minimum alpha,
|
733
|
-
* and is not minimal-size already. Do this only if we removed above, so
|
734
|
-
* non-removing enumerations can count on stable table->entryStore until
|
735
|
-
* the next non-lookup-Operate or removing-Enumerate.
|
736
|
-
*/
|
737
|
-
if (didRemove &&
|
738
|
-
(table->removedCount >= capacity >> 2 ||
|
739
|
-
(capacity > JS_DHASH_MIN_SIZE &&
|
740
|
-
table->entryCount <= MIN_LOAD(table, capacity)))) {
|
741
|
-
METER(table->stats.enumShrinks++);
|
742
|
-
capacity = table->entryCount;
|
743
|
-
capacity += capacity >> 1;
|
744
|
-
if (capacity < JS_DHASH_MIN_SIZE)
|
745
|
-
capacity = JS_DHASH_MIN_SIZE;
|
746
|
-
|
747
|
-
JS_CEILING_LOG2(ceiling, capacity);
|
748
|
-
ceiling -= JS_DHASH_BITS - table->hashShift;
|
749
|
-
|
750
|
-
(void) ChangeTable(table, ceiling);
|
751
|
-
}
|
752
|
-
|
753
|
-
DECREMENT_RECURSION_LEVEL(table);
|
754
|
-
|
755
|
-
return i;
|
756
|
-
}
|
757
|
-
|
758
|
-
#ifdef JS_DHASHMETER
|
759
|
-
#include <math.h>
|
760
|
-
|
761
|
-
JS_PUBLIC_API(void)
|
762
|
-
JS_DHashTableDumpMeter(JSDHashTable *table, JSDHashEnumerator dump, FILE *fp)
|
763
|
-
{
|
764
|
-
char *entryAddr;
|
765
|
-
uint32 entrySize, entryCount;
|
766
|
-
int hashShift, sizeLog2;
|
767
|
-
uint32 i, tableSize, sizeMask, chainLen, maxChainLen, chainCount;
|
768
|
-
JSDHashNumber hash1, hash2, saveHash1, maxChainHash1, maxChainHash2;
|
769
|
-
double sqsum, mean, variance, sigma;
|
770
|
-
JSDHashEntryHdr *entry, *probe;
|
771
|
-
|
772
|
-
entryAddr = table->entryStore;
|
773
|
-
entrySize = table->entrySize;
|
774
|
-
hashShift = table->hashShift;
|
775
|
-
sizeLog2 = JS_DHASH_BITS - hashShift;
|
776
|
-
tableSize = JS_DHASH_TABLE_SIZE(table);
|
777
|
-
sizeMask = JS_BITMASK(sizeLog2);
|
778
|
-
chainCount = maxChainLen = 0;
|
779
|
-
hash2 = 0;
|
780
|
-
sqsum = 0;
|
781
|
-
|
782
|
-
for (i = 0; i < tableSize; i++) {
|
783
|
-
entry = (JSDHashEntryHdr *)entryAddr;
|
784
|
-
entryAddr += entrySize;
|
785
|
-
if (!ENTRY_IS_LIVE(entry))
|
786
|
-
continue;
|
787
|
-
hash1 = HASH1(entry->keyHash & ~COLLISION_FLAG, hashShift);
|
788
|
-
saveHash1 = hash1;
|
789
|
-
probe = ADDRESS_ENTRY(table, hash1);
|
790
|
-
chainLen = 1;
|
791
|
-
if (probe == entry) {
|
792
|
-
/* Start of a (possibly unit-length) chain. */
|
793
|
-
chainCount++;
|
794
|
-
} else {
|
795
|
-
hash2 = HASH2(entry->keyHash & ~COLLISION_FLAG, sizeLog2,
|
796
|
-
hashShift);
|
797
|
-
do {
|
798
|
-
chainLen++;
|
799
|
-
hash1 -= hash2;
|
800
|
-
hash1 &= sizeMask;
|
801
|
-
probe = ADDRESS_ENTRY(table, hash1);
|
802
|
-
} while (probe != entry);
|
803
|
-
}
|
804
|
-
sqsum += chainLen * chainLen;
|
805
|
-
if (chainLen > maxChainLen) {
|
806
|
-
maxChainLen = chainLen;
|
807
|
-
maxChainHash1 = saveHash1;
|
808
|
-
maxChainHash2 = hash2;
|
809
|
-
}
|
810
|
-
}
|
811
|
-
|
812
|
-
entryCount = table->entryCount;
|
813
|
-
if (entryCount && chainCount) {
|
814
|
-
mean = (double)entryCount / chainCount;
|
815
|
-
variance = chainCount * sqsum - entryCount * entryCount;
|
816
|
-
if (variance < 0 || chainCount == 1)
|
817
|
-
variance = 0;
|
818
|
-
else
|
819
|
-
variance /= chainCount * (chainCount - 1);
|
820
|
-
sigma = sqrt(variance);
|
821
|
-
} else {
|
822
|
-
mean = sigma = 0;
|
823
|
-
}
|
824
|
-
|
825
|
-
fprintf(fp, "Double hashing statistics:\n");
|
826
|
-
fprintf(fp, " table size (in entries): %u\n", tableSize);
|
827
|
-
fprintf(fp, " number of entries: %u\n", table->entryCount);
|
828
|
-
fprintf(fp, " number of removed entries: %u\n", table->removedCount);
|
829
|
-
fprintf(fp, " number of searches: %u\n", table->stats.searches);
|
830
|
-
fprintf(fp, " number of hits: %u\n", table->stats.hits);
|
831
|
-
fprintf(fp, " number of misses: %u\n", table->stats.misses);
|
832
|
-
fprintf(fp, " mean steps per search: %g\n", table->stats.searches ?
|
833
|
-
(double)table->stats.steps
|
834
|
-
/ table->stats.searches :
|
835
|
-
0.);
|
836
|
-
fprintf(fp, " mean hash chain length: %g\n", mean);
|
837
|
-
fprintf(fp, " standard deviation: %g\n", sigma);
|
838
|
-
fprintf(fp, " maximum hash chain length: %u\n", maxChainLen);
|
839
|
-
fprintf(fp, " number of lookups: %u\n", table->stats.lookups);
|
840
|
-
fprintf(fp, " adds that made a new entry: %u\n", table->stats.addMisses);
|
841
|
-
fprintf(fp, "adds that recycled removeds: %u\n", table->stats.addOverRemoved);
|
842
|
-
fprintf(fp, " adds that found an entry: %u\n", table->stats.addHits);
|
843
|
-
fprintf(fp, " add failures: %u\n", table->stats.addFailures);
|
844
|
-
fprintf(fp, " useful removes: %u\n", table->stats.removeHits);
|
845
|
-
fprintf(fp, " useless removes: %u\n", table->stats.removeMisses);
|
846
|
-
fprintf(fp, "removes that freed an entry: %u\n", table->stats.removeFrees);
|
847
|
-
fprintf(fp, " removes while enumerating: %u\n", table->stats.removeEnums);
|
848
|
-
fprintf(fp, " number of grows: %u\n", table->stats.grows);
|
849
|
-
fprintf(fp, " number of shrinks: %u\n", table->stats.shrinks);
|
850
|
-
fprintf(fp, " number of compresses: %u\n", table->stats.compresses);
|
851
|
-
fprintf(fp, "number of enumerate shrinks: %u\n", table->stats.enumShrinks);
|
852
|
-
|
853
|
-
if (dump && maxChainLen && hash2) {
|
854
|
-
fputs("Maximum hash chain:\n", fp);
|
855
|
-
hash1 = maxChainHash1;
|
856
|
-
hash2 = maxChainHash2;
|
857
|
-
entry = ADDRESS_ENTRY(table, hash1);
|
858
|
-
i = 0;
|
859
|
-
do {
|
860
|
-
if (dump(table, entry, i++, fp) != JS_DHASH_NEXT)
|
861
|
-
break;
|
862
|
-
hash1 -= hash2;
|
863
|
-
hash1 &= sizeMask;
|
864
|
-
entry = ADDRESS_ENTRY(table, hash1);
|
865
|
-
} while (JS_DHASH_ENTRY_IS_BUSY(entry));
|
866
|
-
}
|
867
|
-
}
|
868
|
-
#endif /* JS_DHASHMETER */
|