johnson 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +14 -0
- data/CHANGELOG.rdoc +11 -0
- data/Manifest.txt +370 -0
- data/README.rdoc +60 -0
- data/Rakefile +42 -0
- data/bin/johnson +108 -0
- data/docs/MINGW32.mk +124 -0
- data/docs/cross-compile.txt +38 -0
- data/ext/spidermonkey/context.c +115 -0
- data/ext/spidermonkey/context.h +19 -0
- data/ext/spidermonkey/conversions.c +320 -0
- data/ext/spidermonkey/conversions.h +18 -0
- data/ext/spidermonkey/debugger.c +226 -0
- data/ext/spidermonkey/debugger.h +9 -0
- data/ext/spidermonkey/extconf.rb +30 -0
- data/ext/spidermonkey/extensions.c +37 -0
- data/ext/spidermonkey/extensions.h +12 -0
- data/ext/spidermonkey/global.c +40 -0
- data/ext/spidermonkey/global.h +11 -0
- data/ext/spidermonkey/idhash.c +16 -0
- data/ext/spidermonkey/idhash.h +8 -0
- data/ext/spidermonkey/immutable_node.c +1153 -0
- data/ext/spidermonkey/immutable_node.c.erb +523 -0
- data/ext/spidermonkey/immutable_node.h +22 -0
- data/ext/spidermonkey/jroot.h +187 -0
- data/ext/spidermonkey/js_land_proxy.c +610 -0
- data/ext/spidermonkey/js_land_proxy.h +20 -0
- data/ext/spidermonkey/ruby_land_proxy.c +543 -0
- data/ext/spidermonkey/ruby_land_proxy.h +17 -0
- data/ext/spidermonkey/runtime.c +330 -0
- data/ext/spidermonkey/runtime.h +25 -0
- data/ext/spidermonkey/spidermonkey.c +20 -0
- data/ext/spidermonkey/spidermonkey.h +29 -0
- data/johnson.gemspec +44 -0
- data/js/johnson/cli.js +30 -0
- data/js/johnson/prelude.js +80 -0
- data/lib/johnson.rb +55 -0
- data/lib/johnson/cli.rb +7 -0
- data/lib/johnson/cli/options.rb +67 -0
- data/lib/johnson/error.rb +4 -0
- data/lib/johnson/nodes.rb +7 -0
- data/lib/johnson/nodes/binary_node.rb +65 -0
- data/lib/johnson/nodes/for.rb +14 -0
- data/lib/johnson/nodes/for_in.rb +12 -0
- data/lib/johnson/nodes/function.rb +13 -0
- data/lib/johnson/nodes/list.rb +28 -0
- data/lib/johnson/nodes/node.rb +68 -0
- data/lib/johnson/nodes/ternary_node.rb +20 -0
- data/lib/johnson/parser.rb +21 -0
- data/lib/johnson/parser/syntax_error.rb +13 -0
- data/lib/johnson/runtime.rb +63 -0
- data/lib/johnson/spidermonkey/context.rb +10 -0
- data/lib/johnson/spidermonkey/debugger.rb +67 -0
- data/lib/johnson/spidermonkey/immutable_node.rb +282 -0
- data/lib/johnson/spidermonkey/js_land_proxy.rb +62 -0
- data/lib/johnson/spidermonkey/mutable_tree_visitor.rb +242 -0
- data/lib/johnson/spidermonkey/ruby_land_proxy.rb +54 -0
- data/lib/johnson/spidermonkey/runtime.rb +103 -0
- data/lib/johnson/version.rb +3 -0
- data/lib/johnson/visitable.rb +16 -0
- data/lib/johnson/visitors.rb +5 -0
- data/lib/johnson/visitors/dot_visitor.rb +169 -0
- data/lib/johnson/visitors/ecma_visitor.rb +323 -0
- data/lib/johnson/visitors/enumerating_visitor.rb +15 -0
- data/lib/johnson/visitors/sexp_visitor.rb +174 -0
- data/lib/johnson/visitors/visitor.rb +91 -0
- data/lib/rails/init.rb +37 -0
- data/lib/tasks/gem.rake +9 -0
- data/lib/tasks/parsing.rake +37 -0
- data/lib/tasks/testing.rake +36 -0
- data/lib/tasks/vendor.rake +20 -0
- data/test/helper.rb +55 -0
- data/test/johnson/browser_test.rb +43 -0
- data/test/johnson/conversions/array_test.rb +32 -0
- data/test/johnson/conversions/boolean_test.rb +17 -0
- data/test/johnson/conversions/callable_test.rb +34 -0
- data/test/johnson/conversions/file_test.rb +15 -0
- data/test/johnson/conversions/nil_test.rb +20 -0
- data/test/johnson/conversions/number_test.rb +34 -0
- data/test/johnson/conversions/regexp_test.rb +24 -0
- data/test/johnson/conversions/string_test.rb +26 -0
- data/test/johnson/conversions/struct_test.rb +15 -0
- data/test/johnson/conversions/symbol_test.rb +19 -0
- data/test/johnson/conversions/thread_test.rb +24 -0
- data/test/johnson/error_test.rb +9 -0
- data/test/johnson/extensions_test.rb +56 -0
- data/test/johnson/nodes/array_literal_test.rb +57 -0
- data/test/johnson/nodes/array_node_test.rb +26 -0
- data/test/johnson/nodes/binary_node_test.rb +61 -0
- data/test/johnson/nodes/bracket_access_test.rb +16 -0
- data/test/johnson/nodes/delete_test.rb +11 -0
- data/test/johnson/nodes/do_while_test.rb +12 -0
- data/test/johnson/nodes/dot_accessor_test.rb +15 -0
- data/test/johnson/nodes/export_test.rb +9 -0
- data/test/johnson/nodes/for_test.rb +54 -0
- data/test/johnson/nodes/function_test.rb +71 -0
- data/test/johnson/nodes/if_test.rb +41 -0
- data/test/johnson/nodes/import_test.rb +13 -0
- data/test/johnson/nodes/label_test.rb +19 -0
- data/test/johnson/nodes/let_test.rb +31 -0
- data/test/johnson/nodes/object_literal_test.rb +110 -0
- data/test/johnson/nodes/return_test.rb +16 -0
- data/test/johnson/nodes/semi_test.rb +8 -0
- data/test/johnson/nodes/switch_test.rb +55 -0
- data/test/johnson/nodes/ternary_test.rb +25 -0
- data/test/johnson/nodes/throw_test.rb +9 -0
- data/test/johnson/nodes/try_node_test.rb +59 -0
- data/test/johnson/nodes/typeof_test.rb +11 -0
- data/test/johnson/nodes/unary_node_test.rb +23 -0
- data/test/johnson/nodes/void_test.rb +11 -0
- data/test/johnson/nodes/while_test.rb +26 -0
- data/test/johnson/nodes/with_test.rb +10 -0
- data/test/johnson/prelude_test.rb +56 -0
- data/test/johnson/runtime_test.rb +64 -0
- data/test/johnson/spidermonkey/context_test.rb +21 -0
- data/test/johnson/spidermonkey/immutable_node_test.rb +34 -0
- data/test/johnson/spidermonkey/js_land_proxy_test.rb +236 -0
- data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +240 -0
- data/test/johnson/spidermonkey/runtime_test.rb +17 -0
- data/test/johnson/version_test.rb +13 -0
- data/test/johnson/visitors/dot_visitor_test.rb +39 -0
- data/test/johnson/visitors/enumerating_visitor_test.rb +12 -0
- data/test/johnson_test.rb +16 -0
- data/test/parser_test.rb +276 -0
- data/vendor/spidermonkey/.cvsignore +9 -0
- data/vendor/spidermonkey/Makefile.in +449 -0
- data/vendor/spidermonkey/Makefile.ref +365 -0
- data/vendor/spidermonkey/README.html +820 -0
- data/vendor/spidermonkey/SpiderMonkey.rsp +12 -0
- data/vendor/spidermonkey/Y.js +19 -0
- data/vendor/spidermonkey/build.mk +43 -0
- data/vendor/spidermonkey/config.mk +192 -0
- data/vendor/spidermonkey/config/AIX4.1.mk +65 -0
- data/vendor/spidermonkey/config/AIX4.2.mk +64 -0
- data/vendor/spidermonkey/config/AIX4.3.mk +65 -0
- data/vendor/spidermonkey/config/Darwin.mk +83 -0
- data/vendor/spidermonkey/config/Darwin1.3.mk +81 -0
- data/vendor/spidermonkey/config/Darwin1.4.mk +41 -0
- data/vendor/spidermonkey/config/Darwin5.2.mk +81 -0
- data/vendor/spidermonkey/config/Darwin5.3.mk +81 -0
- data/vendor/spidermonkey/config/HP-UXB.10.10.mk +77 -0
- data/vendor/spidermonkey/config/HP-UXB.10.20.mk +77 -0
- data/vendor/spidermonkey/config/HP-UXB.11.00.mk +80 -0
- data/vendor/spidermonkey/config/IRIX.mk +87 -0
- data/vendor/spidermonkey/config/IRIX5.3.mk +44 -0
- data/vendor/spidermonkey/config/IRIX6.1.mk +44 -0
- data/vendor/spidermonkey/config/IRIX6.2.mk +44 -0
- data/vendor/spidermonkey/config/IRIX6.3.mk +44 -0
- data/vendor/spidermonkey/config/IRIX6.5.mk +44 -0
- data/vendor/spidermonkey/config/Linux_All.mk +103 -0
- data/vendor/spidermonkey/config/Mac_OS10.0.mk +82 -0
- data/vendor/spidermonkey/config/OSF1V4.0.mk +72 -0
- data/vendor/spidermonkey/config/OSF1V5.0.mk +69 -0
- data/vendor/spidermonkey/config/SunOS4.1.4.mk +101 -0
- data/vendor/spidermonkey/config/SunOS5.10.mk +50 -0
- data/vendor/spidermonkey/config/SunOS5.3.mk +91 -0
- data/vendor/spidermonkey/config/SunOS5.4.mk +92 -0
- data/vendor/spidermonkey/config/SunOS5.5.1.mk +44 -0
- data/vendor/spidermonkey/config/SunOS5.5.mk +87 -0
- data/vendor/spidermonkey/config/SunOS5.6.mk +89 -0
- data/vendor/spidermonkey/config/SunOS5.7.mk +44 -0
- data/vendor/spidermonkey/config/SunOS5.8.mk +44 -0
- data/vendor/spidermonkey/config/SunOS5.9.mk +44 -0
- data/vendor/spidermonkey/config/WINNT4.0.mk +117 -0
- data/vendor/spidermonkey/config/WINNT5.0.mk +117 -0
- data/vendor/spidermonkey/config/WINNT5.1.mk +117 -0
- data/vendor/spidermonkey/config/WINNT5.2.mk +117 -0
- data/vendor/spidermonkey/config/WINNT6.0.mk +117 -0
- data/vendor/spidermonkey/config/dgux.mk +64 -0
- data/vendor/spidermonkey/editline/Makefile.ref +144 -0
- data/vendor/spidermonkey/editline/README +83 -0
- data/vendor/spidermonkey/editline/editline.3 +175 -0
- data/vendor/spidermonkey/editline/editline.c +1369 -0
- data/vendor/spidermonkey/editline/editline.h +135 -0
- data/vendor/spidermonkey/editline/sysunix.c +182 -0
- data/vendor/spidermonkey/editline/unix.h +82 -0
- data/vendor/spidermonkey/fdlibm/.cvsignore +7 -0
- data/vendor/spidermonkey/fdlibm/Makefile.in +127 -0
- data/vendor/spidermonkey/fdlibm/Makefile.ref +192 -0
- data/vendor/spidermonkey/fdlibm/e_acos.c +147 -0
- data/vendor/spidermonkey/fdlibm/e_acosh.c +105 -0
- data/vendor/spidermonkey/fdlibm/e_asin.c +156 -0
- data/vendor/spidermonkey/fdlibm/e_atan2.c +165 -0
- data/vendor/spidermonkey/fdlibm/e_atanh.c +110 -0
- data/vendor/spidermonkey/fdlibm/e_cosh.c +133 -0
- data/vendor/spidermonkey/fdlibm/e_exp.c +202 -0
- data/vendor/spidermonkey/fdlibm/e_fmod.c +184 -0
- data/vendor/spidermonkey/fdlibm/e_gamma.c +71 -0
- data/vendor/spidermonkey/fdlibm/e_gamma_r.c +70 -0
- data/vendor/spidermonkey/fdlibm/e_hypot.c +173 -0
- data/vendor/spidermonkey/fdlibm/e_j0.c +524 -0
- data/vendor/spidermonkey/fdlibm/e_j1.c +523 -0
- data/vendor/spidermonkey/fdlibm/e_jn.c +315 -0
- data/vendor/spidermonkey/fdlibm/e_lgamma.c +71 -0
- data/vendor/spidermonkey/fdlibm/e_lgamma_r.c +347 -0
- data/vendor/spidermonkey/fdlibm/e_log.c +184 -0
- data/vendor/spidermonkey/fdlibm/e_log10.c +134 -0
- data/vendor/spidermonkey/fdlibm/e_pow.c +386 -0
- data/vendor/spidermonkey/fdlibm/e_rem_pio2.c +222 -0
- data/vendor/spidermonkey/fdlibm/e_remainder.c +120 -0
- data/vendor/spidermonkey/fdlibm/e_scalb.c +89 -0
- data/vendor/spidermonkey/fdlibm/e_sinh.c +122 -0
- data/vendor/spidermonkey/fdlibm/e_sqrt.c +497 -0
- data/vendor/spidermonkey/fdlibm/fdlibm.h +273 -0
- data/vendor/spidermonkey/fdlibm/fdlibm.mak +1453 -0
- data/vendor/spidermonkey/fdlibm/fdlibm.mdp +0 -0
- data/vendor/spidermonkey/fdlibm/k_cos.c +135 -0
- data/vendor/spidermonkey/fdlibm/k_rem_pio2.c +354 -0
- data/vendor/spidermonkey/fdlibm/k_sin.c +114 -0
- data/vendor/spidermonkey/fdlibm/k_standard.c +785 -0
- data/vendor/spidermonkey/fdlibm/k_tan.c +170 -0
- data/vendor/spidermonkey/fdlibm/s_asinh.c +101 -0
- data/vendor/spidermonkey/fdlibm/s_atan.c +175 -0
- data/vendor/spidermonkey/fdlibm/s_cbrt.c +133 -0
- data/vendor/spidermonkey/fdlibm/s_ceil.c +120 -0
- data/vendor/spidermonkey/fdlibm/s_copysign.c +72 -0
- data/vendor/spidermonkey/fdlibm/s_cos.c +118 -0
- data/vendor/spidermonkey/fdlibm/s_erf.c +356 -0
- data/vendor/spidermonkey/fdlibm/s_expm1.c +267 -0
- data/vendor/spidermonkey/fdlibm/s_fabs.c +70 -0
- data/vendor/spidermonkey/fdlibm/s_finite.c +71 -0
- data/vendor/spidermonkey/fdlibm/s_floor.c +121 -0
- data/vendor/spidermonkey/fdlibm/s_frexp.c +99 -0
- data/vendor/spidermonkey/fdlibm/s_ilogb.c +85 -0
- data/vendor/spidermonkey/fdlibm/s_isnan.c +74 -0
- data/vendor/spidermonkey/fdlibm/s_ldexp.c +66 -0
- data/vendor/spidermonkey/fdlibm/s_lib_version.c +73 -0
- data/vendor/spidermonkey/fdlibm/s_log1p.c +211 -0
- data/vendor/spidermonkey/fdlibm/s_logb.c +79 -0
- data/vendor/spidermonkey/fdlibm/s_matherr.c +64 -0
- data/vendor/spidermonkey/fdlibm/s_modf.c +132 -0
- data/vendor/spidermonkey/fdlibm/s_nextafter.c +124 -0
- data/vendor/spidermonkey/fdlibm/s_rint.c +131 -0
- data/vendor/spidermonkey/fdlibm/s_scalbn.c +107 -0
- data/vendor/spidermonkey/fdlibm/s_signgam.c +40 -0
- data/vendor/spidermonkey/fdlibm/s_significand.c +68 -0
- data/vendor/spidermonkey/fdlibm/s_sin.c +118 -0
- data/vendor/spidermonkey/fdlibm/s_tan.c +112 -0
- data/vendor/spidermonkey/fdlibm/s_tanh.c +122 -0
- data/vendor/spidermonkey/fdlibm/w_acos.c +78 -0
- data/vendor/spidermonkey/fdlibm/w_acosh.c +78 -0
- data/vendor/spidermonkey/fdlibm/w_asin.c +80 -0
- data/vendor/spidermonkey/fdlibm/w_atan2.c +79 -0
- data/vendor/spidermonkey/fdlibm/w_atanh.c +81 -0
- data/vendor/spidermonkey/fdlibm/w_cosh.c +77 -0
- data/vendor/spidermonkey/fdlibm/w_exp.c +88 -0
- data/vendor/spidermonkey/fdlibm/w_fmod.c +78 -0
- data/vendor/spidermonkey/fdlibm/w_gamma.c +85 -0
- data/vendor/spidermonkey/fdlibm/w_gamma_r.c +81 -0
- data/vendor/spidermonkey/fdlibm/w_hypot.c +78 -0
- data/vendor/spidermonkey/fdlibm/w_j0.c +105 -0
- data/vendor/spidermonkey/fdlibm/w_j1.c +106 -0
- data/vendor/spidermonkey/fdlibm/w_jn.c +128 -0
- data/vendor/spidermonkey/fdlibm/w_lgamma.c +85 -0
- data/vendor/spidermonkey/fdlibm/w_lgamma_r.c +81 -0
- data/vendor/spidermonkey/fdlibm/w_log.c +78 -0
- data/vendor/spidermonkey/fdlibm/w_log10.c +81 -0
- data/vendor/spidermonkey/fdlibm/w_pow.c +99 -0
- data/vendor/spidermonkey/fdlibm/w_remainder.c +77 -0
- data/vendor/spidermonkey/fdlibm/w_scalb.c +95 -0
- data/vendor/spidermonkey/fdlibm/w_sinh.c +77 -0
- data/vendor/spidermonkey/fdlibm/w_sqrt.c +77 -0
- data/vendor/spidermonkey/javascript-trace.d +73 -0
- data/vendor/spidermonkey/js.c +3951 -0
- data/vendor/spidermonkey/js.mdp +0 -0
- data/vendor/spidermonkey/js.msg +308 -0
- data/vendor/spidermonkey/js3240.rc +79 -0
- data/vendor/spidermonkey/jsOS240.def +654 -0
- data/vendor/spidermonkey/jsapi.c +5836 -0
- data/vendor/spidermonkey/jsapi.h +2624 -0
- data/vendor/spidermonkey/jsarena.c +450 -0
- data/vendor/spidermonkey/jsarena.h +318 -0
- data/vendor/spidermonkey/jsarray.c +2996 -0
- data/vendor/spidermonkey/jsarray.h +127 -0
- data/vendor/spidermonkey/jsatom.c +1045 -0
- data/vendor/spidermonkey/jsatom.h +442 -0
- data/vendor/spidermonkey/jsbit.h +253 -0
- data/vendor/spidermonkey/jsbool.c +176 -0
- data/vendor/spidermonkey/jsbool.h +73 -0
- data/vendor/spidermonkey/jsclist.h +139 -0
- data/vendor/spidermonkey/jscntxt.c +1348 -0
- data/vendor/spidermonkey/jscntxt.h +1120 -0
- data/vendor/spidermonkey/jscompat.h +57 -0
- data/vendor/spidermonkey/jsconfig.h +248 -0
- data/vendor/spidermonkey/jsconfig.mk +181 -0
- data/vendor/spidermonkey/jscpucfg.c +396 -0
- data/vendor/spidermonkey/jscpucfg.h +212 -0
- data/vendor/spidermonkey/jsdate.c +2390 -0
- data/vendor/spidermonkey/jsdate.h +124 -0
- data/vendor/spidermonkey/jsdbgapi.c +1802 -0
- data/vendor/spidermonkey/jsdbgapi.h +464 -0
- data/vendor/spidermonkey/jsdhash.c +868 -0
- data/vendor/spidermonkey/jsdhash.h +592 -0
- data/vendor/spidermonkey/jsdtoa.c +3167 -0
- data/vendor/spidermonkey/jsdtoa.h +130 -0
- data/vendor/spidermonkey/jsdtracef.c +317 -0
- data/vendor/spidermonkey/jsdtracef.h +77 -0
- data/vendor/spidermonkey/jsemit.c +6909 -0
- data/vendor/spidermonkey/jsemit.h +741 -0
- data/vendor/spidermonkey/jsexn.c +1371 -0
- data/vendor/spidermonkey/jsexn.h +96 -0
- data/vendor/spidermonkey/jsfile.c +2736 -0
- data/vendor/spidermonkey/jsfile.h +56 -0
- data/vendor/spidermonkey/jsfile.msg +90 -0
- data/vendor/spidermonkey/jsfun.c +2634 -0
- data/vendor/spidermonkey/jsfun.h +254 -0
- data/vendor/spidermonkey/jsgc.c +3562 -0
- data/vendor/spidermonkey/jsgc.h +403 -0
- data/vendor/spidermonkey/jshash.c +476 -0
- data/vendor/spidermonkey/jshash.h +151 -0
- data/vendor/spidermonkey/jsify.pl +485 -0
- data/vendor/spidermonkey/jsinterp.c +7007 -0
- data/vendor/spidermonkey/jsinterp.h +525 -0
- data/vendor/spidermonkey/jsinvoke.c +43 -0
- data/vendor/spidermonkey/jsiter.c +1067 -0
- data/vendor/spidermonkey/jsiter.h +122 -0
- data/vendor/spidermonkey/jskeyword.tbl +124 -0
- data/vendor/spidermonkey/jskwgen.c +460 -0
- data/vendor/spidermonkey/jslibmath.h +266 -0
- data/vendor/spidermonkey/jslock.c +1309 -0
- data/vendor/spidermonkey/jslock.h +313 -0
- data/vendor/spidermonkey/jslocko.asm +60 -0
- data/vendor/spidermonkey/jslog2.c +94 -0
- data/vendor/spidermonkey/jslong.c +264 -0
- data/vendor/spidermonkey/jslong.h +412 -0
- data/vendor/spidermonkey/jsmath.c +567 -0
- data/vendor/spidermonkey/jsmath.h +57 -0
- data/vendor/spidermonkey/jsnum.c +1239 -0
- data/vendor/spidermonkey/jsnum.h +283 -0
- data/vendor/spidermonkey/jsobj.c +5282 -0
- data/vendor/spidermonkey/jsobj.h +709 -0
- data/vendor/spidermonkey/jsopcode.c +5245 -0
- data/vendor/spidermonkey/jsopcode.h +394 -0
- data/vendor/spidermonkey/jsopcode.tbl +523 -0
- data/vendor/spidermonkey/jsotypes.h +202 -0
- data/vendor/spidermonkey/jsparse.c +6704 -0
- data/vendor/spidermonkey/jsparse.h +511 -0
- data/vendor/spidermonkey/jsprf.c +1262 -0
- data/vendor/spidermonkey/jsprf.h +150 -0
- data/vendor/spidermonkey/jsproto.tbl +128 -0
- data/vendor/spidermonkey/jsprvtd.h +267 -0
- data/vendor/spidermonkey/jspubtd.h +744 -0
- data/vendor/spidermonkey/jsregexp.c +4364 -0
- data/vendor/spidermonkey/jsregexp.h +183 -0
- data/vendor/spidermonkey/jsreops.tbl +145 -0
- data/vendor/spidermonkey/jsscan.c +2012 -0
- data/vendor/spidermonkey/jsscan.h +387 -0
- data/vendor/spidermonkey/jsscope.c +1957 -0
- data/vendor/spidermonkey/jsscope.h +418 -0
- data/vendor/spidermonkey/jsscript.c +1832 -0
- data/vendor/spidermonkey/jsscript.h +287 -0
- data/vendor/spidermonkey/jsshell.msg +50 -0
- data/vendor/spidermonkey/jsstddef.h +83 -0
- data/vendor/spidermonkey/jsstr.c +5005 -0
- data/vendor/spidermonkey/jsstr.h +641 -0
- data/vendor/spidermonkey/jstypes.h +475 -0
- data/vendor/spidermonkey/jsutil.c +345 -0
- data/vendor/spidermonkey/jsutil.h +157 -0
- data/vendor/spidermonkey/jsxdrapi.c +800 -0
- data/vendor/spidermonkey/jsxdrapi.h +218 -0
- data/vendor/spidermonkey/jsxml.c +8476 -0
- data/vendor/spidermonkey/jsxml.h +349 -0
- data/vendor/spidermonkey/lock_SunOS.s +119 -0
- data/vendor/spidermonkey/perfect.js +39 -0
- data/vendor/spidermonkey/plify_jsdhash.sed +36 -0
- data/vendor/spidermonkey/prmjtime.c +846 -0
- data/vendor/spidermonkey/prmjtime.h +103 -0
- data/vendor/spidermonkey/resource.h +15 -0
- data/vendor/spidermonkey/rules.mk +197 -0
- data/vendor/spidermonkey/win32.order +384 -0
- metadata +513 -0
@@ -0,0 +1,868 @@
|
|
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 */
|