distil 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +28 -0
- data/VERSION +1 -0
- data/bin/distil +45 -0
- data/distil.gemspec +586 -0
- data/lib/bootstrap-template.js +56 -0
- data/lib/configurable.rb +125 -0
- data/lib/file-set.rb +42 -0
- data/lib/file-types/css-file.rb +75 -0
- data/lib/file-types/html-file.rb +11 -0
- data/lib/file-types/javascript-file.rb +98 -0
- data/lib/file-types/json-file.rb +14 -0
- data/lib/file-types/nib-file.rb +9 -0
- data/lib/jsdoc.conf +18 -0
- data/lib/jsl.conf +121 -0
- data/lib/project.rb +96 -0
- data/lib/source-file.rb +181 -0
- data/lib/target.rb +96 -0
- data/lib/task.rb +239 -0
- data/lib/tasks/copy-task.rb +21 -0
- data/lib/tasks/css-task.rb +18 -0
- data/lib/tasks/javascript-task.rb +125 -0
- data/lib/tasks/multiple-output-task.rb +134 -0
- data/lib/tasks/nib-task.rb +83 -0
- data/lib/tasks/output-task.rb +73 -0
- data/lib/tasks/single-output-task.rb +83 -0
- data/lib/tasks/test-task.rb +280 -0
- data/lib/test/HtmlTestReporter.js +127 -0
- data/lib/test/Test.js +248 -0
- data/lib/test/TestReporter.js +79 -0
- data/lib/test/TestRunner.js +132 -0
- data/lib/test/browser.rb +97 -0
- data/lib/test/scriptwrapper.html +10 -0
- data/lib/test/unittest.html +127 -0
- data/vendor/Makefile +35 -0
- data/vendor/extconf.rb +3 -0
- data/vendor/jsdoc-extras/plugins/distil-plugin.js +142 -0
- data/vendor/jsdoc-extras/plugins/interface-plugin.js +36 -0
- data/vendor/jsdoc-extras/templates/coherent/allclasses.tmpl +17 -0
- data/vendor/jsdoc-extras/templates/coherent/allfiles.tmpl +53 -0
- data/vendor/jsdoc-extras/templates/coherent/class.tmpl +803 -0
- data/vendor/jsdoc-extras/templates/coherent/index.tmpl +37 -0
- data/vendor/jsdoc-extras/templates/coherent/publish.js +242 -0
- data/vendor/jsdoc-extras/templates/coherent/showdown.js +421 -0
- data/vendor/jsdoc-extras/templates/coherent/static/code-footer.html +3 -0
- data/vendor/jsdoc-extras/templates/coherent/static/code-header.html +7 -0
- data/vendor/jsdoc-extras/templates/coherent/static/default.css +297 -0
- data/vendor/jsdoc-extras/templates/coherent/static/header.html +2 -0
- data/vendor/jsdoc-extras/templates/coherent/static/index.html +19 -0
- data/vendor/jsdoc-extras/templates/coherent/symbol.tmpl +35 -0
- data/vendor/jsdoc-toolkit/README.txt +183 -0
- data/vendor/jsdoc-toolkit/app/frame/Chain.js +102 -0
- data/vendor/jsdoc-toolkit/app/frame/Dumper.js +144 -0
- data/vendor/jsdoc-toolkit/app/frame/Hash.js +84 -0
- data/vendor/jsdoc-toolkit/app/frame/Link.js +171 -0
- data/vendor/jsdoc-toolkit/app/frame/Namespace.js +10 -0
- data/vendor/jsdoc-toolkit/app/frame/Opt.js +134 -0
- data/vendor/jsdoc-toolkit/app/frame/Reflection.js +26 -0
- data/vendor/jsdoc-toolkit/app/frame/String.js +93 -0
- data/vendor/jsdoc-toolkit/app/frame/Testrun.js +129 -0
- data/vendor/jsdoc-toolkit/app/frame.js +33 -0
- data/vendor/jsdoc-toolkit/app/handlers/FOODOC.js +26 -0
- data/vendor/jsdoc-toolkit/app/handlers/XMLDOC/DomReader.js +159 -0
- data/vendor/jsdoc-toolkit/app/handlers/XMLDOC/XMLDoc.js +16 -0
- data/vendor/jsdoc-toolkit/app/handlers/XMLDOC/XMLParse.js +292 -0
- data/vendor/jsdoc-toolkit/app/handlers/XMLDOC.js +26 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/DocComment.js +204 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/DocTag.js +300 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/JsDoc.js +126 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/JsPlate.js +109 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/Lang.js +144 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/Parser.js +144 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/PluginManager.js +33 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/Symbol.js +644 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/SymbolSet.js +241 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/TextStream.js +41 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/Token.js +18 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/TokenReader.js +332 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/TokenStream.js +133 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/Util.js +32 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC/Walker.js +499 -0
- data/vendor/jsdoc-toolkit/app/lib/JSDOC.js +106 -0
- data/vendor/jsdoc-toolkit/app/main.js +129 -0
- data/vendor/jsdoc-toolkit/app/plugins/commentSrcJson.js +20 -0
- data/vendor/jsdoc-toolkit/app/plugins/frameworkPrototype.js +16 -0
- data/vendor/jsdoc-toolkit/app/plugins/functionCall.js +10 -0
- data/vendor/jsdoc-toolkit/app/plugins/publishSrcHilite.js +54 -0
- data/vendor/jsdoc-toolkit/app/plugins/symbolLink.js +10 -0
- data/vendor/jsdoc-toolkit/app/plugins/tagParamConfig.js +31 -0
- data/vendor/jsdoc-toolkit/app/plugins/tagSynonyms.js +43 -0
- data/vendor/jsdoc-toolkit/app/run.js +348 -0
- data/vendor/jsdoc-toolkit/app/t/TestDoc.js +144 -0
- data/vendor/jsdoc-toolkit/app/t/runner.js +13 -0
- data/vendor/jsdoc-toolkit/app/test/addon.js +24 -0
- data/vendor/jsdoc-toolkit/app/test/anon_inner.js +14 -0
- data/vendor/jsdoc-toolkit/app/test/augments.js +31 -0
- data/vendor/jsdoc-toolkit/app/test/augments2.js +26 -0
- data/vendor/jsdoc-toolkit/app/test/borrows.js +46 -0
- data/vendor/jsdoc-toolkit/app/test/borrows2.js +23 -0
- data/vendor/jsdoc-toolkit/app/test/config.js +22 -0
- data/vendor/jsdoc-toolkit/app/test/constructs.js +18 -0
- data/vendor/jsdoc-toolkit/app/test/encoding.js +10 -0
- data/vendor/jsdoc-toolkit/app/test/encoding_other.js +12 -0
- data/vendor/jsdoc-toolkit/app/test/event.js +54 -0
- data/vendor/jsdoc-toolkit/app/test/exports.js +14 -0
- data/vendor/jsdoc-toolkit/app/test/functions_anon.js +39 -0
- data/vendor/jsdoc-toolkit/app/test/functions_nested.js +33 -0
- data/vendor/jsdoc-toolkit/app/test/global.js +13 -0
- data/vendor/jsdoc-toolkit/app/test/globals.js +25 -0
- data/vendor/jsdoc-toolkit/app/test/ignore.js +10 -0
- data/vendor/jsdoc-toolkit/app/test/inner.js +16 -0
- data/vendor/jsdoc-toolkit/app/test/jsdoc_test.js +477 -0
- data/vendor/jsdoc-toolkit/app/test/lend.js +33 -0
- data/vendor/jsdoc-toolkit/app/test/memberof.js +19 -0
- data/vendor/jsdoc-toolkit/app/test/memberof2.js +38 -0
- data/vendor/jsdoc-toolkit/app/test/memberof3.js +33 -0
- data/vendor/jsdoc-toolkit/app/test/memberof_constructor.js +17 -0
- data/vendor/jsdoc-toolkit/app/test/module.js +17 -0
- data/vendor/jsdoc-toolkit/app/test/name.js +19 -0
- data/vendor/jsdoc-toolkit/app/test/namespace_nested.js +23 -0
- data/vendor/jsdoc-toolkit/app/test/nocode.js +13 -0
- data/vendor/jsdoc-toolkit/app/test/oblit_anon.js +20 -0
- data/vendor/jsdoc-toolkit/app/test/overview.js +20 -0
- data/vendor/jsdoc-toolkit/app/test/param_inline.js +37 -0
- data/vendor/jsdoc-toolkit/app/test/params_optional.js +8 -0
- data/vendor/jsdoc-toolkit/app/test/prototype.js +17 -0
- data/vendor/jsdoc-toolkit/app/test/prototype_nested.js +9 -0
- data/vendor/jsdoc-toolkit/app/test/prototype_oblit.js +13 -0
- data/vendor/jsdoc-toolkit/app/test/prototype_oblit_constructor.js +24 -0
- data/vendor/jsdoc-toolkit/app/test/public.js +10 -0
- data/vendor/jsdoc-toolkit/app/test/scripts/code.js +5 -0
- data/vendor/jsdoc-toolkit/app/test/scripts/notcode.txt +5 -0
- data/vendor/jsdoc-toolkit/app/test/shared.js +42 -0
- data/vendor/jsdoc-toolkit/app/test/shared2.js +2 -0
- data/vendor/jsdoc-toolkit/app/test/shortcuts.js +22 -0
- data/vendor/jsdoc-toolkit/app/test/static_this.js +13 -0
- data/vendor/jsdoc-toolkit/app/test/synonyms.js +31 -0
- data/vendor/jsdoc-toolkit/app/test/tosource.js +23 -0
- data/vendor/jsdoc-toolkit/app/test/variable_redefine.js +14 -0
- data/vendor/jsdoc-toolkit/app/test.js +342 -0
- data/vendor/jsdoc-toolkit/changes.txt +116 -0
- data/vendor/jsdoc-toolkit/conf/sample.conf +31 -0
- data/vendor/jsdoc-toolkit/java/build.xml +36 -0
- data/vendor/jsdoc-toolkit/java/build_1.4.xml +36 -0
- data/vendor/jsdoc-toolkit/java/classes/js.jar +0 -0
- data/vendor/jsdoc-toolkit/java/src/JsDebugRun.java +21 -0
- data/vendor/jsdoc-toolkit/java/src/JsRun.java +21 -0
- data/vendor/jsdoc-toolkit/jsdebug.jar +0 -0
- data/vendor/jsdoc-toolkit/jsrun.jar +0 -0
- data/vendor/jsdoc-toolkit/jsrun.sh +53 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/allclasses.tmpl +17 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/allfiles.tmpl +56 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/class.tmpl +649 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/index.tmpl +39 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/publish.js +201 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/static/code-footer.html +3 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/static/code-header.html +14 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/static/default.css +162 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/static/header.html +2 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/static/index.html +19 -0
- data/vendor/jsdoc-toolkit/templates/jsdoc/symbol.tmpl +35 -0
- data/vendor/jsl-0.3.0/src/JavaScriptLintAPI.cpp +333 -0
- data/vendor/jsl-0.3.0/src/JavaScriptLintAPI.h +86 -0
- data/vendor/jsl-0.3.0/src/Makefile.in +375 -0
- data/vendor/jsl-0.3.0/src/Makefile.ref +372 -0
- data/vendor/jsl-0.3.0/src/README.html +826 -0
- data/vendor/jsl-0.3.0/src/SpiderMonkey.rsp +12 -0
- data/vendor/jsl-0.3.0/src/_jsl_online.php +223 -0
- data/vendor/jsl-0.3.0/src/config/AIX4.1.mk +65 -0
- data/vendor/jsl-0.3.0/src/config/AIX4.2.mk +64 -0
- data/vendor/jsl-0.3.0/src/config/AIX4.3.mk +65 -0
- data/vendor/jsl-0.3.0/src/config/Darwin.mk +81 -0
- data/vendor/jsl-0.3.0/src/config/Darwin1.3.mk +81 -0
- data/vendor/jsl-0.3.0/src/config/Darwin1.4.mk +41 -0
- data/vendor/jsl-0.3.0/src/config/Darwin5.2.mk +81 -0
- data/vendor/jsl-0.3.0/src/config/Darwin5.3.mk +81 -0
- data/vendor/jsl-0.3.0/src/config/HP-UXB.10.10.mk +77 -0
- data/vendor/jsl-0.3.0/src/config/HP-UXB.10.20.mk +77 -0
- data/vendor/jsl-0.3.0/src/config/HP-UXB.11.00.mk +80 -0
- data/vendor/jsl-0.3.0/src/config/IRIX.mk +87 -0
- data/vendor/jsl-0.3.0/src/config/IRIX5.3.mk +44 -0
- data/vendor/jsl-0.3.0/src/config/IRIX6.1.mk +44 -0
- data/vendor/jsl-0.3.0/src/config/IRIX6.2.mk +44 -0
- data/vendor/jsl-0.3.0/src/config/IRIX6.3.mk +44 -0
- data/vendor/jsl-0.3.0/src/config/IRIX6.5.mk +44 -0
- data/vendor/jsl-0.3.0/src/config/Linux_All.mk +103 -0
- data/vendor/jsl-0.3.0/src/config/Mac_OS10.0.mk +82 -0
- data/vendor/jsl-0.3.0/src/config/OSF1V4.0.mk +72 -0
- data/vendor/jsl-0.3.0/src/config/OSF1V5.0.mk +69 -0
- data/vendor/jsl-0.3.0/src/config/SunOS4.1.4.mk +101 -0
- data/vendor/jsl-0.3.0/src/config/SunOS5.3.mk +91 -0
- data/vendor/jsl-0.3.0/src/config/SunOS5.4.mk +92 -0
- data/vendor/jsl-0.3.0/src/config/SunOS5.5.1.mk +44 -0
- data/vendor/jsl-0.3.0/src/config/SunOS5.5.mk +87 -0
- data/vendor/jsl-0.3.0/src/config/SunOS5.6.mk +89 -0
- data/vendor/jsl-0.3.0/src/config/SunOS5.7.mk +44 -0
- data/vendor/jsl-0.3.0/src/config/SunOS5.8.mk +44 -0
- data/vendor/jsl-0.3.0/src/config/SunOS5.9.mk +44 -0
- data/vendor/jsl-0.3.0/src/config/WINNT4.0.mk +112 -0
- data/vendor/jsl-0.3.0/src/config/WINNT5.0.mk +112 -0
- data/vendor/jsl-0.3.0/src/config/WINNT5.1.mk +112 -0
- data/vendor/jsl-0.3.0/src/config/WINNT5.2.mk +112 -0
- data/vendor/jsl-0.3.0/src/config/dgux.mk +64 -0
- data/vendor/jsl-0.3.0/src/config.mk +166 -0
- data/vendor/jsl-0.3.0/src/editline/Makefile.ref +144 -0
- data/vendor/jsl-0.3.0/src/editline/README +83 -0
- data/vendor/jsl-0.3.0/src/editline/editline.3 +175 -0
- data/vendor/jsl-0.3.0/src/editline/editline.c +1369 -0
- data/vendor/jsl-0.3.0/src/editline/editline.h +135 -0
- data/vendor/jsl-0.3.0/src/editline/sysunix.c +182 -0
- data/vendor/jsl-0.3.0/src/editline/unix.h +82 -0
- data/vendor/jsl-0.3.0/src/fdlibm/Makefile.in +127 -0
- data/vendor/jsl-0.3.0/src/fdlibm/Makefile.ref +192 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_acos.c +147 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_acosh.c +105 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_asin.c +156 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_atan2.c +165 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_atanh.c +110 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_cosh.c +133 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_exp.c +202 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_fmod.c +184 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_gamma.c +71 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_gamma_r.c +70 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_hypot.c +173 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_j0.c +524 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_j1.c +523 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_jn.c +315 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_lgamma.c +71 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_lgamma_r.c +347 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_log.c +184 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_log10.c +134 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_pow.c +386 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_rem_pio2.c +221 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_remainder.c +120 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_scalb.c +89 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_sinh.c +122 -0
- data/vendor/jsl-0.3.0/src/fdlibm/e_sqrt.c +497 -0
- data/vendor/jsl-0.3.0/src/fdlibm/fdlibm.dsp +160 -0
- data/vendor/jsl-0.3.0/src/fdlibm/fdlibm.h +273 -0
- data/vendor/jsl-0.3.0/src/fdlibm/fdlibm.mak +1453 -0
- data/vendor/jsl-0.3.0/src/fdlibm/fdlibm.mdp +0 -0
- data/vendor/jsl-0.3.0/src/fdlibm/k_cos.c +134 -0
- data/vendor/jsl-0.3.0/src/fdlibm/k_rem_pio2.c +354 -0
- data/vendor/jsl-0.3.0/src/fdlibm/k_sin.c +114 -0
- data/vendor/jsl-0.3.0/src/fdlibm/k_standard.c +785 -0
- data/vendor/jsl-0.3.0/src/fdlibm/k_tan.c +170 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_asinh.c +101 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_atan.c +175 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_cbrt.c +133 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_ceil.c +120 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_copysign.c +72 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_cos.c +118 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_erf.c +356 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_expm1.c +267 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_fabs.c +70 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_finite.c +71 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_floor.c +121 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_frexp.c +99 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_ilogb.c +85 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_isnan.c +74 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_ldexp.c +66 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_lib_version.c +73 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_log1p.c +211 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_logb.c +79 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_matherr.c +64 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_modf.c +132 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_nextafter.c +124 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_rint.c +131 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_scalbn.c +107 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_signgam.c +40 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_significand.c +68 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_sin.c +118 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_tan.c +112 -0
- data/vendor/jsl-0.3.0/src/fdlibm/s_tanh.c +122 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_acos.c +78 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_acosh.c +78 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_asin.c +80 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_atan2.c +79 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_atanh.c +81 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_cosh.c +77 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_exp.c +88 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_fmod.c +78 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_gamma.c +85 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_gamma_r.c +81 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_hypot.c +78 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_j0.c +105 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_j1.c +106 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_jn.c +128 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_lgamma.c +85 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_lgamma_r.c +81 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_log.c +78 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_log10.c +81 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_pow.c +99 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_remainder.c +77 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_scalb.c +95 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_sinh.c +77 -0
- data/vendor/jsl-0.3.0/src/fdlibm/w_sqrt.c +77 -0
- data/vendor/jsl-0.3.0/src/js.c +2447 -0
- data/vendor/jsl-0.3.0/src/js.dsp +420 -0
- data/vendor/jsl-0.3.0/src/js.mak +4025 -0
- data/vendor/jsl-0.3.0/src/js.mdp +0 -0
- data/vendor/jsl-0.3.0/src/js.msg +291 -0
- data/vendor/jsl-0.3.0/src/js.pkg +2 -0
- data/vendor/jsl-0.3.0/src/js3240.rc +79 -0
- data/vendor/jsl-0.3.0/src/jsOS240.def +654 -0
- data/vendor/jsl-0.3.0/src/jsapi.c +4405 -0
- data/vendor/jsl-0.3.0/src/jsapi.h +1856 -0
- data/vendor/jsl-0.3.0/src/jsarena.c +567 -0
- data/vendor/jsl-0.3.0/src/jsarena.h +302 -0
- data/vendor/jsl-0.3.0/src/jsarray.c +1428 -0
- data/vendor/jsl-0.3.0/src/jsarray.h +77 -0
- data/vendor/jsl-0.3.0/src/jsatom.c +927 -0
- data/vendor/jsl-0.3.0/src/jsatom.h +426 -0
- data/vendor/jsl-0.3.0/src/jsbit.h +113 -0
- data/vendor/jsl-0.3.0/src/jsbool.c +220 -0
- data/vendor/jsl-0.3.0/src/jsbool.h +62 -0
- data/vendor/jsl-0.3.0/src/jsclist.h +139 -0
- data/vendor/jsl-0.3.0/src/jscntxt.c +1036 -0
- data/vendor/jsl-0.3.0/src/jscntxt.h +608 -0
- data/vendor/jsl-0.3.0/src/jscompat.h +57 -0
- data/vendor/jsl-0.3.0/src/jsconfig.h +489 -0
- data/vendor/jsl-0.3.0/src/jsconfig.mk +181 -0
- data/vendor/jsl-0.3.0/src/jscpucfg.c +377 -0
- data/vendor/jsl-0.3.0/src/jscpucfg.h +204 -0
- data/vendor/jsl-0.3.0/src/jsdate.c +2238 -0
- data/vendor/jsl-0.3.0/src/jsdate.h +118 -0
- data/vendor/jsl-0.3.0/src/jsdbgapi.c +1260 -0
- data/vendor/jsl-0.3.0/src/jsdbgapi.h +345 -0
- data/vendor/jsl-0.3.0/src/jsdhash.c +763 -0
- data/vendor/jsl-0.3.0/src/jsdhash.h +579 -0
- data/vendor/jsl-0.3.0/src/jsdtoa.c +3135 -0
- data/vendor/jsl-0.3.0/src/jsdtoa.h +130 -0
- data/vendor/jsl-0.3.0/src/jsemit.c +4851 -0
- data/vendor/jsl-0.3.0/src/jsemit.h +576 -0
- data/vendor/jsl-0.3.0/src/jsexn.c +1084 -0
- data/vendor/jsl-0.3.0/src/jsexn.h +102 -0
- data/vendor/jsl-0.3.0/src/jsfile.c +2610 -0
- data/vendor/jsl-0.3.0/src/jsfile.h +50 -0
- data/vendor/jsl-0.3.0/src/jsfile.msg +89 -0
- data/vendor/jsl-0.3.0/src/jsfun.c +2015 -0
- data/vendor/jsl-0.3.0/src/jsfun.h +158 -0
- data/vendor/jsl-0.3.0/src/jsgc.c +1441 -0
- data/vendor/jsl-0.3.0/src/jsgc.h +230 -0
- data/vendor/jsl-0.3.0/src/jshash.c +471 -0
- data/vendor/jsl-0.3.0/src/jshash.h +152 -0
- data/vendor/jsl-0.3.0/src/jsify.pl +485 -0
- data/vendor/jsl-0.3.0/src/jsinterp.c +4797 -0
- data/vendor/jsl-0.3.0/src/jsinterp.h +302 -0
- data/vendor/jsl-0.3.0/src/jsl-test.js +28 -0
- data/vendor/jsl-0.3.0/src/jsl.c +2371 -0
- data/vendor/jsl-0.3.0/src/jsl.conf +127 -0
- data/vendor/jsl-0.3.0/src/jsl.conf.old +124 -0
- data/vendor/jsl-0.3.0/src/jsl.dsp +242 -0
- data/vendor/jsl-0.3.0/src/jsl.dsw +59 -0
- data/vendor/jsl-0.3.0/src/jslibmath.h +290 -0
- data/vendor/jsl-0.3.0/src/jslock.c +1261 -0
- data/vendor/jsl-0.3.0/src/jslock.h +289 -0
- data/vendor/jsl-0.3.0/src/jslocko.asm +59 -0
- data/vendor/jsl-0.3.0/src/jslog2.c +83 -0
- data/vendor/jsl-0.3.0/src/jslong.c +281 -0
- data/vendor/jsl-0.3.0/src/jslong.h +437 -0
- data/vendor/jsl-0.3.0/src/jsmath.c +477 -0
- data/vendor/jsl-0.3.0/src/jsmath.h +55 -0
- data/vendor/jsl-0.3.0/src/jsnum.c +1148 -0
- data/vendor/jsl-0.3.0/src/jsnum.h +257 -0
- data/vendor/jsl-0.3.0/src/jsobj.c +4066 -0
- data/vendor/jsl-0.3.0/src/jsobj.h +475 -0
- data/vendor/jsl-0.3.0/src/jsopcode.c +2730 -0
- data/vendor/jsl-0.3.0/src/jsopcode.h +275 -0
- data/vendor/jsl-0.3.0/src/jsopcode.tbl +344 -0
- data/vendor/jsl-0.3.0/src/jsosdep.h +127 -0
- data/vendor/jsl-0.3.0/src/jsotypes.h +211 -0
- data/vendor/jsl-0.3.0/src/jsparse.c +4438 -0
- data/vendor/jsl-0.3.0/src/jsparse.h +345 -0
- data/vendor/jsl-0.3.0/src/jsprf.c +1212 -0
- data/vendor/jsl-0.3.0/src/jsprf.h +148 -0
- data/vendor/jsl-0.3.0/src/jsprvtd.h +174 -0
- data/vendor/jsl-0.3.0/src/jspubtd.h +586 -0
- data/vendor/jsl-0.3.0/src/jsregexp.c +3831 -0
- data/vendor/jsl-0.3.0/src/jsregexp.h +180 -0
- data/vendor/jsl-0.3.0/src/jsscan.c +1814 -0
- data/vendor/jsl-0.3.0/src/jsscan.h +267 -0
- data/vendor/jsl-0.3.0/src/jsscope.c +1639 -0
- data/vendor/jsl-0.3.0/src/jsscope.h +389 -0
- data/vendor/jsl-0.3.0/src/jsscript.c +1284 -0
- data/vendor/jsl-0.3.0/src/jsscript.h +179 -0
- data/vendor/jsl-0.3.0/src/jsshell.msg +50 -0
- data/vendor/jsl-0.3.0/src/jsstddef.h +83 -0
- data/vendor/jsl-0.3.0/src/jsstr.c +4502 -0
- data/vendor/jsl-0.3.0/src/jsstr.h +448 -0
- data/vendor/jsl-0.3.0/src/jstypes.h +391 -0
- data/vendor/jsl-0.3.0/src/jsutil.c +157 -0
- data/vendor/jsl-0.3.0/src/jsutil.h +75 -0
- data/vendor/jsl-0.3.0/src/jsxdrapi.c +686 -0
- data/vendor/jsl-0.3.0/src/jsxdrapi.h +193 -0
- data/vendor/jsl-0.3.0/src/liveconnect/LiveConnect.dsp +157 -0
- data/vendor/jsl-0.3.0/src/liveconnect/LiveConnectShell.dsp +120 -0
- data/vendor/jsl-0.3.0/src/liveconnect/LiveConnectShell.dsw +44 -0
- data/vendor/jsl-0.3.0/src/liveconnect/Makefile.in +106 -0
- data/vendor/jsl-0.3.0/src/liveconnect/Makefile.ref +169 -0
- data/vendor/jsl-0.3.0/src/liveconnect/README.html +719 -0
- data/vendor/jsl-0.3.0/src/liveconnect/_jni/netscape_javascript_JSException.h +14 -0
- data/vendor/jsl-0.3.0/src/liveconnect/_jni/netscape_javascript_JSObject.h +155 -0
- data/vendor/jsl-0.3.0/src/liveconnect/classes/Makefile.in +89 -0
- data/vendor/jsl-0.3.0/src/liveconnect/classes/Makefile.ref +57 -0
- data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/Makefile.ref +47 -0
- data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/JSException.java +140 -0
- data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/JSObject.java +183 -0
- data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/JSProxy.java +58 -0
- data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/JSRunnable.java +70 -0
- data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/JSUtil.java +59 -0
- data/vendor/jsl-0.3.0/src/liveconnect/classes/netscape/javascript/Makefile.ref +53 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/AIX4.1.mk +45 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/AIX4.2.mk +45 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/AIX4.3.mk +50 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/HP-UXB.10.10.mk +43 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/HP-UXB.10.20.mk +43 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/HP-UXB.11.00.mk +43 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/IRIX6.2.mk +43 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/IRIX6.3.mk +43 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/IRIX6.5.mk +43 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/Linux_All.mk +73 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/OSF1V4.0.mk +65 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/OSF1V5.0.mk +62 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/SunOS5.5.1.mk +55 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/SunOS5.6.mk +39 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/SunOS5.7.mk +39 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/SunOS5.8.mk +39 -0
- data/vendor/jsl-0.3.0/src/liveconnect/config/WINNT4.0.mk +53 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj.c +884 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj.msg +98 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_JSObject.c +1379 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_JavaArray.c +481 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_JavaClass.c +749 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_JavaMember.c +186 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_JavaObject.c +1099 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_JavaPackage.c +548 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_array.c +207 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_class.c +765 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_convert.c +954 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_field.c +421 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_hash.c +504 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_hash.h +161 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_method.c +1823 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_nodl.c +1 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_private.h +689 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_simpleapi.c +219 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsj_utils.c +513 -0
- data/vendor/jsl-0.3.0/src/liveconnect/jsjava.h +313 -0
- data/vendor/jsl-0.3.0/src/liveconnect/liveconnect.pkg +3 -0
- data/vendor/jsl-0.3.0/src/liveconnect/netscape_javascript_JSObject.h +155 -0
- data/vendor/jsl-0.3.0/src/liveconnect/nsCLiveconnect.cpp +785 -0
- data/vendor/jsl-0.3.0/src/liveconnect/nsCLiveconnect.h +197 -0
- data/vendor/jsl-0.3.0/src/liveconnect/nsCLiveconnectFactory.cpp +163 -0
- data/vendor/jsl-0.3.0/src/liveconnect/nsCLiveconnectFactory.h +76 -0
- data/vendor/jsl-0.3.0/src/liveconnect/nsILiveconnect.h +195 -0
- data/vendor/jsl-0.3.0/src/liveconnect/nsISecureLiveconnect.h +84 -0
- data/vendor/jsl-0.3.0/src/liveconnect/nsISecurityContext.h +135 -0
- data/vendor/jsl-0.3.0/src/liveconnect/win32.order +6 -0
- data/vendor/jsl-0.3.0/src/lock_SunOS.s +114 -0
- data/vendor/jsl-0.3.0/src/perfect.js +39 -0
- data/vendor/jsl-0.3.0/src/perlconnect/JS.def +6 -0
- data/vendor/jsl-0.3.0/src/perlconnect/JS.dsp +107 -0
- data/vendor/jsl-0.3.0/src/perlconnect/JS.pm +318 -0
- data/vendor/jsl-0.3.0/src/perlconnect/JS.xs +1050 -0
- data/vendor/jsl-0.3.0/src/perlconnect/Makefile.PL +67 -0
- data/vendor/jsl-0.3.0/src/perlconnect/Makefile.ref +152 -0
- data/vendor/jsl-0.3.0/src/perlconnect/PerlConnect.dsp +103 -0
- data/vendor/jsl-0.3.0/src/perlconnect/PerlConnect.dsw +59 -0
- data/vendor/jsl-0.3.0/src/perlconnect/PerlConnect.pm +126 -0
- data/vendor/jsl-0.3.0/src/perlconnect/PerlConnectShell.dsp +89 -0
- data/vendor/jsl-0.3.0/src/perlconnect/README.html +345 -0
- data/vendor/jsl-0.3.0/src/perlconnect/bg.jpg +0 -0
- data/vendor/jsl-0.3.0/src/perlconnect/jsperl.c +1100 -0
- data/vendor/jsl-0.3.0/src/perlconnect/jsperl.h +52 -0
- data/vendor/jsl-0.3.0/src/perlconnect/jsperlbuild.pl +81 -0
- data/vendor/jsl-0.3.0/src/perlconnect/jsperlpvt.h +57 -0
- data/vendor/jsl-0.3.0/src/perlconnect/test.js +73 -0
- data/vendor/jsl-0.3.0/src/perlconnect/test.pl +244 -0
- data/vendor/jsl-0.3.0/src/perlconnect/typemap +121 -0
- data/vendor/jsl-0.3.0/src/plify_jsdhash.sed +31 -0
- data/vendor/jsl-0.3.0/src/prmjtime.c +646 -0
- data/vendor/jsl-0.3.0/src/prmjtime.h +95 -0
- data/vendor/jsl-0.3.0/src/resource.h +15 -0
- data/vendor/jsl-0.3.0/src/rules.mk +193 -0
- data/vendor/jsl-0.3.0/src/win32.order +391 -0
- data/vendor/jsl-0.3.0/tests/conf/always_use_option_explicit.js +4 -0
- data/vendor/jsl-0.3.0/tests/conf/define.js +8 -0
- data/vendor/jsl-0.3.0/tests/conf/jscript_function_extensions-1.js +7 -0
- data/vendor/jsl-0.3.0/tests/conf/jscript_function_extensions-2.js +8 -0
- data/vendor/jsl-0.3.0/tests/conf/jscript_function_extensions-3.js +27 -0
- data/vendor/jsl-0.3.0/tests/conf/jscript_function_extensions-4.js +4 -0
- data/vendor/jsl-0.3.0/tests/conf/lambda_assign_requires_semicolon.js +24 -0
- data/vendor/jsl-0.3.0/tests/conf/legacy_control_comments.js +8 -0
- data/vendor/jsl-0.3.0/tests/control_comments/control_comments.js +33 -0
- data/vendor/jsl-0.3.0/tests/control_comments/declare.js +26 -0
- data/vendor/jsl-0.3.0/tests/control_comments/import-overflow.js +9 -0
- data/vendor/jsl-0.3.0/tests/control_comments/import.js +5 -0
- data/vendor/jsl-0.3.0/tests/control_comments/import2.js +2 -0
- data/vendor/jsl-0.3.0/tests/control_comments/invalid_fallthru.js +13 -0
- data/vendor/jsl-0.3.0/tests/control_comments/option_explicit-with.js +12 -0
- data/vendor/jsl-0.3.0/tests/control_comments/option_explicit.js +64 -0
- data/vendor/jsl-0.3.0/tests/errors/unterminated_comment.js +8 -0
- data/vendor/jsl-0.3.0/tests/html/script_tag_in_js_literal.html +14 -0
- data/vendor/jsl-0.3.0/tests/run_tests.pl +71 -0
- data/vendor/jsl-0.3.0/tests/warnings/ambiguous_else_stmt.js +21 -0
- data/vendor/jsl-0.3.0/tests/warnings/ambiguous_nested_stmt.js +66 -0
- data/vendor/jsl-0.3.0/tests/warnings/ambiguous_newline.js +261 -0
- data/vendor/jsl-0.3.0/tests/warnings/anon_no_return_value.js +26 -0
- data/vendor/jsl-0.3.0/tests/warnings/assign_to_function_call.js +16 -0
- data/vendor/jsl-0.3.0/tests/warnings/block_without_braces.js +13 -0
- data/vendor/jsl-0.3.0/tests/warnings/comma_separated_stmts.js +17 -0
- data/vendor/jsl-0.3.0/tests/warnings/comparison_type_conv.js +44 -0
- data/vendor/jsl-0.3.0/tests/warnings/default_not_at_end.js +15 -0
- data/vendor/jsl-0.3.0/tests/warnings/dup_option_explicit.js +5 -0
- data/vendor/jsl-0.3.0/tests/warnings/duplicate_case_in_switch.js +62 -0
- data/vendor/jsl-0.3.0/tests/warnings/duplicate_formal.js +5 -0
- data/vendor/jsl-0.3.0/tests/warnings/empty_statement.js +29 -0
- data/vendor/jsl-0.3.0/tests/warnings/equal_as_assign.js +7 -0
- data/vendor/jsl-0.3.0/tests/warnings/inc_dec_within_stmt-ignore.js +21 -0
- data/vendor/jsl-0.3.0/tests/warnings/inc_dec_within_stmt.js +63 -0
- data/vendor/jsl-0.3.0/tests/warnings/jsl_cc_not_understood.js +5 -0
- data/vendor/jsl-0.3.0/tests/warnings/leading_decimal_point.js +7 -0
- data/vendor/jsl-0.3.0/tests/warnings/legacy_cc_not_understood.js +9 -0
- data/vendor/jsl-0.3.0/tests/warnings/meaningless_block.js +12 -0
- data/vendor/jsl-0.3.0/tests/warnings/misplaced_regex.js +20 -0
- data/vendor/jsl-0.3.0/tests/warnings/missing_break.js +87 -0
- data/vendor/jsl-0.3.0/tests/warnings/missing_break_for_last_case.js +19 -0
- data/vendor/jsl-0.3.0/tests/warnings/missing_default_case.js +51 -0
- data/vendor/jsl-0.3.0/tests/warnings/missing_option_explicit.js +5 -0
- data/vendor/jsl-0.3.0/tests/warnings/missing_semicolon.js +19 -0
- data/vendor/jsl-0.3.0/tests/warnings/multiple_plus_minus.js +10 -0
- data/vendor/jsl-0.3.0/tests/warnings/nested_comment.js +6 -0
- data/vendor/jsl-0.3.0/tests/warnings/no_return_value.js +25 -0
- data/vendor/jsl-0.3.0/tests/warnings/octal_number.js +5 -0
- data/vendor/jsl-0.3.0/tests/warnings/parseint_missing_radix.js +15 -0
- data/vendor/jsl-0.3.0/tests/warnings/partial_option_explicit.js +5 -0
- data/vendor/jsl-0.3.0/tests/warnings/redeclared_var.js +10 -0
- data/vendor/jsl-0.3.0/tests/warnings/spidermonkey/bad_backref.js +5 -0
- data/vendor/jsl-0.3.0/tests/warnings/spidermonkey/deprecated_usage.js +11 -0
- data/vendor/jsl-0.3.0/tests/warnings/spidermonkey/invalid_backref.js +5 -0
- data/vendor/jsl-0.3.0/tests/warnings/spidermonkey/trailing_comma.js +5 -0
- data/vendor/jsl-0.3.0/tests/warnings/trailing_comma_in_array.js +8 -0
- data/vendor/jsl-0.3.0/tests/warnings/trailing_decimal_point.js +7 -0
- data/vendor/jsl-0.3.0/tests/warnings/unreachable_code.js +29 -0
- data/vendor/jsl-0.3.0/tests/warnings/use_of_label.js +19 -0
- data/vendor/jsl-0.3.0/tests/warnings/useless_assign.js +20 -0
- data/vendor/jsl-0.3.0/tests/warnings/useless_comparison.js +55 -0
- data/vendor/jsl-0.3.0/tests/warnings/useless_void.js +6 -0
- data/vendor/jsl-0.3.0/tests/warnings/var_hides_arg.js +4 -0
- data/vendor/jsl-0.3.0/tests/warnings/with_statement.js +7 -0
- data/vendor/yuicompressor-2.4.2.jar +0 -0
- metadata +605 -0
|
@@ -0,0 +1,4797 @@
|
|
|
1
|
+
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
2
|
+
*
|
|
3
|
+
* ***** BEGIN LICENSE BLOCK *****
|
|
4
|
+
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
5
|
+
*
|
|
6
|
+
* The contents of this file are subject to the Mozilla Public License Version
|
|
7
|
+
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
8
|
+
* the License. You may obtain a copy of the License at
|
|
9
|
+
* http://www.mozilla.org/MPL/
|
|
10
|
+
*
|
|
11
|
+
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
12
|
+
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
13
|
+
* for the specific language governing rights and limitations under the
|
|
14
|
+
* License.
|
|
15
|
+
*
|
|
16
|
+
* The Original Code is Mozilla Communicator client code, released
|
|
17
|
+
* March 31, 1998.
|
|
18
|
+
*
|
|
19
|
+
* The Initial Developer of the Original Code is
|
|
20
|
+
* Netscape Communications Corporation.
|
|
21
|
+
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
22
|
+
* the Initial Developer. All Rights Reserved.
|
|
23
|
+
*
|
|
24
|
+
* Contributor(s):
|
|
25
|
+
*
|
|
26
|
+
* Alternatively, the contents of this file may be used under the terms of
|
|
27
|
+
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
28
|
+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
29
|
+
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
30
|
+
* of those above. If you wish to allow use of your version of this file only
|
|
31
|
+
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
32
|
+
* use your version of this file under the terms of the MPL, indicate your
|
|
33
|
+
* decision by deleting the provisions above and replace them with the notice
|
|
34
|
+
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
35
|
+
* the provisions above, a recipient may use your version of this file under
|
|
36
|
+
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
37
|
+
*
|
|
38
|
+
* ***** END LICENSE BLOCK ***** */
|
|
39
|
+
|
|
40
|
+
/* build on macs with low memory */
|
|
41
|
+
#if defined(XP_MAC) && defined(MOZ_MAC_LOWMEM)
|
|
42
|
+
#pragma optimization_level 1
|
|
43
|
+
#endif
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
* JavaScript bytecode interpreter.
|
|
47
|
+
*/
|
|
48
|
+
#include "jsstddef.h"
|
|
49
|
+
#include <stdio.h>
|
|
50
|
+
#include <string.h>
|
|
51
|
+
#include <math.h>
|
|
52
|
+
#include "jstypes.h"
|
|
53
|
+
#include "jsarena.h" /* Added by JSIFY */
|
|
54
|
+
#include "jsutil.h" /* Added by JSIFY */
|
|
55
|
+
#include "jsprf.h"
|
|
56
|
+
#include "jsapi.h"
|
|
57
|
+
#include "jsarray.h"
|
|
58
|
+
#include "jsatom.h"
|
|
59
|
+
#include "jsbool.h"
|
|
60
|
+
#include "jscntxt.h"
|
|
61
|
+
#include "jsconfig.h"
|
|
62
|
+
#include "jsdbgapi.h"
|
|
63
|
+
#include "jsfun.h"
|
|
64
|
+
#include "jsgc.h"
|
|
65
|
+
#include "jsinterp.h"
|
|
66
|
+
#include "jslock.h"
|
|
67
|
+
#include "jsnum.h"
|
|
68
|
+
#include "jsobj.h"
|
|
69
|
+
#include "jsopcode.h"
|
|
70
|
+
#include "jsscope.h"
|
|
71
|
+
#include "jsscript.h"
|
|
72
|
+
#include "jsstr.h"
|
|
73
|
+
|
|
74
|
+
#if JS_HAS_JIT
|
|
75
|
+
#include "jsjit.h"
|
|
76
|
+
#endif
|
|
77
|
+
|
|
78
|
+
#ifdef DEBUG
|
|
79
|
+
#define ASSERT_CACHE_IS_EMPTY(cache) \
|
|
80
|
+
JS_BEGIN_MACRO \
|
|
81
|
+
JSPropertyCacheEntry *end_, *pce_, entry_; \
|
|
82
|
+
JSPropertyCache *cache_ = (cache); \
|
|
83
|
+
JS_ASSERT(cache_->empty); \
|
|
84
|
+
end_ = &cache_->table[PROPERTY_CACHE_SIZE]; \
|
|
85
|
+
for (pce_ = &cache_->table[0]; pce_ < end_; pce_++) { \
|
|
86
|
+
PCE_LOAD(cache_, pce_, entry_); \
|
|
87
|
+
JS_ASSERT(!PCE_OBJECT(entry_)); \
|
|
88
|
+
JS_ASSERT(!PCE_PROPERTY(entry_)); \
|
|
89
|
+
} \
|
|
90
|
+
JS_END_MACRO
|
|
91
|
+
#else
|
|
92
|
+
#define ASSERT_CACHE_IS_EMPTY(cache) ((void)0)
|
|
93
|
+
#endif
|
|
94
|
+
|
|
95
|
+
void
|
|
96
|
+
js_FlushPropertyCache(JSContext *cx)
|
|
97
|
+
{
|
|
98
|
+
JSPropertyCache *cache;
|
|
99
|
+
|
|
100
|
+
cache = &cx->runtime->propertyCache;
|
|
101
|
+
if (cache->empty) {
|
|
102
|
+
ASSERT_CACHE_IS_EMPTY(cache);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
memset(cache->table, 0, sizeof cache->table);
|
|
106
|
+
cache->empty = JS_TRUE;
|
|
107
|
+
#ifdef JS_PROPERTY_CACHE_METERING
|
|
108
|
+
cache->flushes++;
|
|
109
|
+
#endif
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
void
|
|
113
|
+
js_DisablePropertyCache(JSContext *cx)
|
|
114
|
+
{
|
|
115
|
+
JS_ASSERT(!cx->runtime->propertyCache.disabled);
|
|
116
|
+
cx->runtime->propertyCache.disabled = JS_TRUE;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
void
|
|
120
|
+
js_EnablePropertyCache(JSContext *cx)
|
|
121
|
+
{
|
|
122
|
+
JS_ASSERT(cx->runtime->propertyCache.disabled);
|
|
123
|
+
ASSERT_CACHE_IS_EMPTY(&cx->runtime->propertyCache);
|
|
124
|
+
cx->runtime->propertyCache.disabled = JS_FALSE;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/*
|
|
128
|
+
* Class for for/in loop property iterator objects.
|
|
129
|
+
*/
|
|
130
|
+
#define JSSLOT_ITER_STATE JSSLOT_PRIVATE
|
|
131
|
+
|
|
132
|
+
static void
|
|
133
|
+
prop_iterator_finalize(JSContext *cx, JSObject *obj)
|
|
134
|
+
{
|
|
135
|
+
jsval iter_state;
|
|
136
|
+
jsval iteratee;
|
|
137
|
+
|
|
138
|
+
/* Protect against stillborn iterators. */
|
|
139
|
+
iter_state = obj->slots[JSSLOT_ITER_STATE];
|
|
140
|
+
iteratee = obj->slots[JSSLOT_PARENT];
|
|
141
|
+
if (!JSVAL_IS_NULL(iter_state) && !JSVAL_IS_PRIMITIVE(iteratee)) {
|
|
142
|
+
OBJ_ENUMERATE(cx, JSVAL_TO_OBJECT(iteratee), JSENUMERATE_DESTROY,
|
|
143
|
+
&iter_state, NULL);
|
|
144
|
+
}
|
|
145
|
+
js_RemoveRoot(cx->runtime, &obj->slots[JSSLOT_PARENT]);
|
|
146
|
+
|
|
147
|
+
/* XXX force the GC to restart so we can collect iteratee, if possible,
|
|
148
|
+
during the current collector activation */
|
|
149
|
+
cx->runtime->gcLevel++;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static JSClass prop_iterator_class = {
|
|
153
|
+
"PropertyIterator",
|
|
154
|
+
0,
|
|
155
|
+
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
|
156
|
+
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, prop_iterator_finalize,
|
|
157
|
+
JSCLASS_NO_OPTIONAL_MEMBERS
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/*
|
|
161
|
+
* Stack macros and functions. These all use a local variable, jsval *sp, to
|
|
162
|
+
* point to the next free stack slot. SAVE_SP must be called before any call
|
|
163
|
+
* to a function that may invoke the interpreter. RESTORE_SP must be called
|
|
164
|
+
* only after return from js_Invoke, because only js_Invoke changes fp->sp.
|
|
165
|
+
*/
|
|
166
|
+
#define PUSH(v) (*sp++ = (v))
|
|
167
|
+
#define POP() (*--sp)
|
|
168
|
+
#ifdef DEBUG
|
|
169
|
+
#define SAVE_SP(fp) \
|
|
170
|
+
(JS_ASSERT((fp)->script || !(fp)->spbase || (sp) == (fp)->spbase), \
|
|
171
|
+
(fp)->sp = sp)
|
|
172
|
+
#else
|
|
173
|
+
#define SAVE_SP(fp) ((fp)->sp = sp)
|
|
174
|
+
#endif
|
|
175
|
+
#define RESTORE_SP(fp) (sp = (fp)->sp)
|
|
176
|
+
|
|
177
|
+
/*
|
|
178
|
+
* Push the generating bytecode's pc onto the parallel pc stack that runs
|
|
179
|
+
* depth slots below the operands.
|
|
180
|
+
*
|
|
181
|
+
* NB: PUSH_OPND uses sp, depth, and pc from its lexical environment. See
|
|
182
|
+
* js_Interpret for these local variables' declarations and uses.
|
|
183
|
+
*/
|
|
184
|
+
#define PUSH_OPND(v) (sp[-depth] = (jsval)pc, PUSH(v))
|
|
185
|
+
#define STORE_OPND(n,v) (sp[(n)-depth] = (jsval)pc, sp[n] = (v))
|
|
186
|
+
#define POP_OPND() POP()
|
|
187
|
+
#define FETCH_OPND(n) (sp[n])
|
|
188
|
+
|
|
189
|
+
/*
|
|
190
|
+
* Push the jsdouble d using sp, depth, and pc from the lexical environment.
|
|
191
|
+
* Try to convert d to a jsint that fits in a jsval, otherwise GC-alloc space
|
|
192
|
+
* for it and push a reference.
|
|
193
|
+
*/
|
|
194
|
+
#define STORE_NUMBER(cx, n, d) \
|
|
195
|
+
JS_BEGIN_MACRO \
|
|
196
|
+
jsint i_; \
|
|
197
|
+
jsval v_; \
|
|
198
|
+
\
|
|
199
|
+
if (JSDOUBLE_IS_INT(d, i_) && INT_FITS_IN_JSVAL(i_)) { \
|
|
200
|
+
v_ = INT_TO_JSVAL(i_); \
|
|
201
|
+
} else { \
|
|
202
|
+
ok = js_NewDoubleValue(cx, d, &v_); \
|
|
203
|
+
if (!ok) \
|
|
204
|
+
goto out; \
|
|
205
|
+
} \
|
|
206
|
+
STORE_OPND(n, v_); \
|
|
207
|
+
JS_END_MACRO
|
|
208
|
+
|
|
209
|
+
#define FETCH_NUMBER(cx, n, d) \
|
|
210
|
+
JS_BEGIN_MACRO \
|
|
211
|
+
jsval v_; \
|
|
212
|
+
\
|
|
213
|
+
v_ = FETCH_OPND(n); \
|
|
214
|
+
VALUE_TO_NUMBER(cx, v_, d); \
|
|
215
|
+
JS_END_MACRO
|
|
216
|
+
|
|
217
|
+
#define FETCH_INT(cx, n, i) \
|
|
218
|
+
JS_BEGIN_MACRO \
|
|
219
|
+
jsval v_ = FETCH_OPND(n); \
|
|
220
|
+
if (JSVAL_IS_INT(v_)) { \
|
|
221
|
+
i = JSVAL_TO_INT(v_); \
|
|
222
|
+
} else { \
|
|
223
|
+
SAVE_SP(fp); \
|
|
224
|
+
ok = js_ValueToECMAInt32(cx, v_, &i); \
|
|
225
|
+
if (!ok) \
|
|
226
|
+
goto out; \
|
|
227
|
+
} \
|
|
228
|
+
JS_END_MACRO
|
|
229
|
+
|
|
230
|
+
#define FETCH_UINT(cx, n, ui) \
|
|
231
|
+
JS_BEGIN_MACRO \
|
|
232
|
+
jsval v_ = FETCH_OPND(n); \
|
|
233
|
+
jsint i_; \
|
|
234
|
+
if (JSVAL_IS_INT(v_) && (i_ = JSVAL_TO_INT(v_)) >= 0) { \
|
|
235
|
+
ui = (uint32) i_; \
|
|
236
|
+
} else { \
|
|
237
|
+
SAVE_SP(fp); \
|
|
238
|
+
ok = js_ValueToECMAUint32(cx, v_, &ui); \
|
|
239
|
+
if (!ok) \
|
|
240
|
+
goto out; \
|
|
241
|
+
} \
|
|
242
|
+
JS_END_MACRO
|
|
243
|
+
|
|
244
|
+
/*
|
|
245
|
+
* Optimized conversion macros that test for the desired type in v before
|
|
246
|
+
* homing sp and calling a conversion function.
|
|
247
|
+
*/
|
|
248
|
+
#define VALUE_TO_NUMBER(cx, v, d) \
|
|
249
|
+
JS_BEGIN_MACRO \
|
|
250
|
+
if (JSVAL_IS_INT(v)) { \
|
|
251
|
+
d = (jsdouble)JSVAL_TO_INT(v); \
|
|
252
|
+
} else if (JSVAL_IS_DOUBLE(v)) { \
|
|
253
|
+
d = *JSVAL_TO_DOUBLE(v); \
|
|
254
|
+
} else { \
|
|
255
|
+
SAVE_SP(fp); \
|
|
256
|
+
ok = js_ValueToNumber(cx, v, &d); \
|
|
257
|
+
if (!ok) \
|
|
258
|
+
goto out; \
|
|
259
|
+
} \
|
|
260
|
+
JS_END_MACRO
|
|
261
|
+
|
|
262
|
+
#define POP_BOOLEAN(cx, v, b) \
|
|
263
|
+
JS_BEGIN_MACRO \
|
|
264
|
+
v = FETCH_OPND(-1); \
|
|
265
|
+
if (v == JSVAL_NULL) { \
|
|
266
|
+
b = JS_FALSE; \
|
|
267
|
+
} else if (JSVAL_IS_BOOLEAN(v)) { \
|
|
268
|
+
b = JSVAL_TO_BOOLEAN(v); \
|
|
269
|
+
} else { \
|
|
270
|
+
SAVE_SP(fp); \
|
|
271
|
+
ok = js_ValueToBoolean(cx, v, &b); \
|
|
272
|
+
if (!ok) \
|
|
273
|
+
goto out; \
|
|
274
|
+
} \
|
|
275
|
+
sp--; \
|
|
276
|
+
JS_END_MACRO
|
|
277
|
+
|
|
278
|
+
#define VALUE_TO_OBJECT(cx, v, obj) \
|
|
279
|
+
JS_BEGIN_MACRO \
|
|
280
|
+
if (JSVAL_IS_OBJECT(v) && v != JSVAL_NULL) { \
|
|
281
|
+
obj = JSVAL_TO_OBJECT(v); \
|
|
282
|
+
} else { \
|
|
283
|
+
SAVE_SP(fp); \
|
|
284
|
+
obj = js_ValueToNonNullObject(cx, v); \
|
|
285
|
+
if (!obj) { \
|
|
286
|
+
ok = JS_FALSE; \
|
|
287
|
+
goto out; \
|
|
288
|
+
} \
|
|
289
|
+
} \
|
|
290
|
+
JS_END_MACRO
|
|
291
|
+
|
|
292
|
+
#if JS_BUG_VOID_TOSTRING
|
|
293
|
+
#define CHECK_VOID_TOSTRING(cx, v) \
|
|
294
|
+
if (JSVAL_IS_VOID(v)) { \
|
|
295
|
+
JSString *str_; \
|
|
296
|
+
str_ = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_VOID]); \
|
|
297
|
+
v = STRING_TO_JSVAL(str_); \
|
|
298
|
+
}
|
|
299
|
+
#else
|
|
300
|
+
#define CHECK_VOID_TOSTRING(cx, v) ((void)0)
|
|
301
|
+
#endif
|
|
302
|
+
|
|
303
|
+
#if JS_BUG_EAGER_TOSTRING
|
|
304
|
+
#define CHECK_EAGER_TOSTRING(hint) (hint = JSTYPE_STRING)
|
|
305
|
+
#else
|
|
306
|
+
#define CHECK_EAGER_TOSTRING(hint) ((void)0)
|
|
307
|
+
#endif
|
|
308
|
+
|
|
309
|
+
#define VALUE_TO_PRIMITIVE(cx, v, hint, vp) \
|
|
310
|
+
JS_BEGIN_MACRO \
|
|
311
|
+
if (JSVAL_IS_PRIMITIVE(v)) { \
|
|
312
|
+
CHECK_VOID_TOSTRING(cx, v); \
|
|
313
|
+
*vp = v; \
|
|
314
|
+
} else { \
|
|
315
|
+
SAVE_SP(fp); \
|
|
316
|
+
CHECK_EAGER_TOSTRING(hint); \
|
|
317
|
+
ok = OBJ_DEFAULT_VALUE(cx, JSVAL_TO_OBJECT(v), hint, vp); \
|
|
318
|
+
if (!ok) \
|
|
319
|
+
goto out; \
|
|
320
|
+
} \
|
|
321
|
+
JS_END_MACRO
|
|
322
|
+
|
|
323
|
+
JS_FRIEND_API(jsval *)
|
|
324
|
+
js_AllocRawStack(JSContext *cx, uintN nslots, void **markp)
|
|
325
|
+
{
|
|
326
|
+
jsval *sp;
|
|
327
|
+
|
|
328
|
+
if (markp)
|
|
329
|
+
*markp = JS_ARENA_MARK(&cx->stackPool);
|
|
330
|
+
JS_ARENA_ALLOCATE_CAST(sp, jsval *, &cx->stackPool, nslots * sizeof(jsval));
|
|
331
|
+
if (!sp) {
|
|
332
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_STACK_OVERFLOW,
|
|
333
|
+
(cx->fp && cx->fp->fun)
|
|
334
|
+
? JS_GetFunctionName(cx->fp->fun)
|
|
335
|
+
: "script");
|
|
336
|
+
}
|
|
337
|
+
return sp;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
JS_FRIEND_API(void)
|
|
341
|
+
js_FreeRawStack(JSContext *cx, void *mark)
|
|
342
|
+
{
|
|
343
|
+
JS_ARENA_RELEASE(&cx->stackPool, mark);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
JS_FRIEND_API(jsval *)
|
|
347
|
+
js_AllocStack(JSContext *cx, uintN nslots, void **markp)
|
|
348
|
+
{
|
|
349
|
+
jsval *sp, *vp, *end;
|
|
350
|
+
JSArena *a;
|
|
351
|
+
JSStackHeader *sh;
|
|
352
|
+
JSStackFrame *fp;
|
|
353
|
+
|
|
354
|
+
/* Callers don't check for zero nslots: we do to avoid empty segments. */
|
|
355
|
+
if (nslots == 0) {
|
|
356
|
+
*markp = NULL;
|
|
357
|
+
return JS_ARENA_MARK(&cx->stackPool);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/* Allocate 2 extra slots for the stack segment header we'll likely need. */
|
|
361
|
+
sp = js_AllocRawStack(cx, 2 + nslots, markp);
|
|
362
|
+
if (!sp)
|
|
363
|
+
return NULL;
|
|
364
|
+
|
|
365
|
+
/* Try to avoid another header if we can piggyback on the last segment. */
|
|
366
|
+
a = cx->stackPool.current;
|
|
367
|
+
sh = cx->stackHeaders;
|
|
368
|
+
if (sh && JS_STACK_SEGMENT(sh) + sh->nslots == sp) {
|
|
369
|
+
/* Extend the last stack segment, give back the 2 header slots. */
|
|
370
|
+
sh->nslots += nslots;
|
|
371
|
+
a->avail -= 2 * sizeof(jsval);
|
|
372
|
+
} else {
|
|
373
|
+
/*
|
|
374
|
+
* Need a new stack segment, so we must initialize unused slots in the
|
|
375
|
+
* current frame. See js_GC, just before marking the "operand" jsvals,
|
|
376
|
+
* where we scan from fp->spbase to fp->sp or through fp->script->depth
|
|
377
|
+
* (whichever covers fewer slots).
|
|
378
|
+
*/
|
|
379
|
+
fp = cx->fp;
|
|
380
|
+
if (fp && fp->script && fp->spbase) {
|
|
381
|
+
#ifdef DEBUG
|
|
382
|
+
jsuword depthdiff = fp->script->depth * sizeof(jsval);
|
|
383
|
+
JS_ASSERT(JS_UPTRDIFF(fp->sp, fp->spbase) <= depthdiff);
|
|
384
|
+
JS_ASSERT(JS_UPTRDIFF(*markp, fp->spbase) >= depthdiff);
|
|
385
|
+
#endif
|
|
386
|
+
end = fp->spbase + fp->script->depth;
|
|
387
|
+
for (vp = fp->sp; vp < end; vp++)
|
|
388
|
+
*vp = JSVAL_VOID;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/* Allocate and push a stack segment header from the 2 extra slots. */
|
|
392
|
+
sh = (JSStackHeader *)sp;
|
|
393
|
+
sh->nslots = nslots;
|
|
394
|
+
sh->down = cx->stackHeaders;
|
|
395
|
+
cx->stackHeaders = sh;
|
|
396
|
+
sp += 2;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
return sp;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
JS_FRIEND_API(void)
|
|
403
|
+
js_FreeStack(JSContext *cx, void *mark)
|
|
404
|
+
{
|
|
405
|
+
JSStackHeader *sh;
|
|
406
|
+
jsuword slotdiff;
|
|
407
|
+
|
|
408
|
+
/* Check for zero nslots allocation special case. */
|
|
409
|
+
if (!mark)
|
|
410
|
+
return;
|
|
411
|
+
|
|
412
|
+
/* We can assert because js_FreeStack always balances js_AllocStack. */
|
|
413
|
+
sh = cx->stackHeaders;
|
|
414
|
+
JS_ASSERT(sh);
|
|
415
|
+
|
|
416
|
+
/* If mark is in the current segment, reduce sh->nslots, else pop sh. */
|
|
417
|
+
slotdiff = JS_UPTRDIFF(mark, JS_STACK_SEGMENT(sh)) / sizeof(jsval);
|
|
418
|
+
if (slotdiff < (jsuword)sh->nslots)
|
|
419
|
+
sh->nslots = slotdiff;
|
|
420
|
+
else
|
|
421
|
+
cx->stackHeaders = sh->down;
|
|
422
|
+
|
|
423
|
+
/* Release the stackPool space allocated since mark was set. */
|
|
424
|
+
JS_ARENA_RELEASE(&cx->stackPool, mark);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/*
|
|
428
|
+
* To economize on slots space in functions, the compiler records arguments and
|
|
429
|
+
* local variables as shared (JSPROP_SHARED) properties with well-known getters
|
|
430
|
+
* and setters: js_{Get,Set}Argument, js_{Get,Set}LocalVariable. Now, we could
|
|
431
|
+
* record args and vars in lists or hash tables in function-private data, but
|
|
432
|
+
* that means more duplication in code, and more data at runtime in the hash
|
|
433
|
+
* table case due to round-up to powers of two, just to recapitulate the scope
|
|
434
|
+
* machinery in the function object.
|
|
435
|
+
*
|
|
436
|
+
* What's more, for a long time (to the dawn of "Mocha" in 1995), these getters
|
|
437
|
+
* and setters knew how to search active stack frames in a context to find the
|
|
438
|
+
* top activation of the function f, in order to satisfy a get or set of f.a,
|
|
439
|
+
* for argument a, or f.x, for local variable x. You could use f.a instead of
|
|
440
|
+
* just a in function f(a) { return f.a }, for example, to return the actual
|
|
441
|
+
* parameter.
|
|
442
|
+
*
|
|
443
|
+
* ECMA requires that we give up on this ancient extension, because it is not
|
|
444
|
+
* compatible with the standard as used by real-world scripts. While Chapter
|
|
445
|
+
* 16 does allow for additional properties to be defined on native objects by
|
|
446
|
+
* a conforming implementation, these magic getters and setters cause f.a's
|
|
447
|
+
* meaning to vary unexpectedly. Real-world scripts set f.A = 42 to define
|
|
448
|
+
* "class static" (after Java) constants, for example, but if A also names an
|
|
449
|
+
* arg or var in f, the constant is not available while f is active, and any
|
|
450
|
+
* non-constant class-static can't be set while f is active.
|
|
451
|
+
*
|
|
452
|
+
* So, to label arg and var properties in functions without giving them magic
|
|
453
|
+
* abilities to affect active frame stack slots, while keeping the properties
|
|
454
|
+
* shared (slot-less) to save space in the common case (where no assignment
|
|
455
|
+
* sets a function property with the same name as an arg or var), the setters
|
|
456
|
+
* for args and vars must handle two special cases here.
|
|
457
|
+
*
|
|
458
|
+
* XXX functions tend to have few args and vars, so we risk O(n^2) growth here
|
|
459
|
+
* XXX ECMA *really* wants args and vars to be stored in function-private data,
|
|
460
|
+
* not as function object properties.
|
|
461
|
+
*/
|
|
462
|
+
static JSBool
|
|
463
|
+
SetFunctionSlot(JSContext *cx, JSObject *obj, JSPropertyOp setter, jsid id,
|
|
464
|
+
jsval v)
|
|
465
|
+
{
|
|
466
|
+
uintN slot;
|
|
467
|
+
JSObject *origobj;
|
|
468
|
+
JSScope *scope;
|
|
469
|
+
JSScopeProperty *sprop;
|
|
470
|
+
JSString *str;
|
|
471
|
+
JSBool ok;
|
|
472
|
+
|
|
473
|
+
slot = (uintN) JSVAL_TO_INT(id);
|
|
474
|
+
if (OBJ_GET_CLASS(cx, obj) != &js_FunctionClass) {
|
|
475
|
+
/*
|
|
476
|
+
* Given a non-function object obj that has a function object in its
|
|
477
|
+
* prototype chain, where an argument or local variable property named
|
|
478
|
+
* by (setter, slot) is being set, override the shared property in the
|
|
479
|
+
* prototype with an unshared property in obj. This situation arises
|
|
480
|
+
* in real-world JS due to .prototype setting and collisions among a
|
|
481
|
+
* function's "static property" names and arg or var names, believe it
|
|
482
|
+
* or not.
|
|
483
|
+
*/
|
|
484
|
+
origobj = obj;
|
|
485
|
+
do {
|
|
486
|
+
obj = OBJ_GET_PROTO(cx, obj);
|
|
487
|
+
if (!obj)
|
|
488
|
+
return JS_TRUE;
|
|
489
|
+
} while (OBJ_GET_CLASS(cx, obj) != &js_FunctionClass);
|
|
490
|
+
|
|
491
|
+
JS_LOCK_OBJ(cx, obj);
|
|
492
|
+
scope = OBJ_SCOPE(obj);
|
|
493
|
+
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
|
|
494
|
+
if (sprop->setter == setter) {
|
|
495
|
+
JS_ASSERT(!JSVAL_IS_INT(sprop->id) &&
|
|
496
|
+
ATOM_IS_STRING((JSAtom *)sprop->id) &&
|
|
497
|
+
(sprop->flags & SPROP_HAS_SHORTID));
|
|
498
|
+
|
|
499
|
+
if ((uintN) sprop->shortid == slot) {
|
|
500
|
+
str = ATOM_TO_STRING((JSAtom *)sprop->id);
|
|
501
|
+
JS_UNLOCK_SCOPE(cx, scope);
|
|
502
|
+
|
|
503
|
+
return JS_DefineUCProperty(cx, origobj,
|
|
504
|
+
JSSTRING_CHARS(str),
|
|
505
|
+
JSSTRING_LENGTH(str),
|
|
506
|
+
v, NULL, NULL,
|
|
507
|
+
JSPROP_ENUMERATE);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
JS_UNLOCK_SCOPE(cx, scope);
|
|
512
|
+
return JS_TRUE;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/*
|
|
516
|
+
* Argument and local variable properties of function objects are shared
|
|
517
|
+
* by default (JSPROP_SHARED), therefore slot-less. But if for function
|
|
518
|
+
* f(a) {}, f.a = 42 is evaluated, f.a should be 42 after the assignment,
|
|
519
|
+
* whether or not f is active. So js_SetArgument and js_SetLocalVariable
|
|
520
|
+
* must be prepared to change an arg or var from shared to unshared status,
|
|
521
|
+
* allocating a slot in obj to hold v.
|
|
522
|
+
*/
|
|
523
|
+
ok = JS_TRUE;
|
|
524
|
+
JS_LOCK_OBJ(cx, obj);
|
|
525
|
+
scope = OBJ_SCOPE(obj);
|
|
526
|
+
for (sprop = SCOPE_LAST_PROP(scope); sprop; sprop = sprop->parent) {
|
|
527
|
+
if (sprop->setter == setter && (uintN) sprop->shortid == slot) {
|
|
528
|
+
if (sprop->attrs & JSPROP_SHARED) {
|
|
529
|
+
sprop = js_ChangeScopePropertyAttrs(cx, scope, sprop,
|
|
530
|
+
0, ~JSPROP_SHARED,
|
|
531
|
+
sprop->getter, setter);
|
|
532
|
+
if (!sprop) {
|
|
533
|
+
ok = JS_FALSE;
|
|
534
|
+
} else {
|
|
535
|
+
/* See js_SetProperty, near the bottom. */
|
|
536
|
+
GC_POKE(cx, pval);
|
|
537
|
+
LOCKED_OBJ_SET_SLOT(obj, sprop->slot, v);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
break;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
JS_UNLOCK_SCOPE(cx, scope);
|
|
544
|
+
return ok;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
JSBool
|
|
548
|
+
js_GetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
549
|
+
{
|
|
550
|
+
return JS_TRUE;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
JSBool
|
|
554
|
+
js_SetArgument(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
555
|
+
{
|
|
556
|
+
return SetFunctionSlot(cx, obj, js_SetArgument, id, *vp);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
JSBool
|
|
560
|
+
js_GetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
561
|
+
{
|
|
562
|
+
return JS_TRUE;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
JSBool
|
|
566
|
+
js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp)
|
|
567
|
+
{
|
|
568
|
+
return SetFunctionSlot(cx, obj, js_SetLocalVariable, id, *vp);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/*
|
|
572
|
+
* Compute the 'this' parameter and store it in frame as frame.thisp.
|
|
573
|
+
* Activation objects ("Call" objects not created with "new Call()", i.e.,
|
|
574
|
+
* "Call" objects that have private data) may not be referred to by 'this',
|
|
575
|
+
* as dictated by ECMA.
|
|
576
|
+
*
|
|
577
|
+
* N.B.: fp->argv must be set, fp->argv[-1] the nominal 'this' paramter as
|
|
578
|
+
* a jsval, and fp->argv[-2] must be the callee object reference, usually a
|
|
579
|
+
* function object. Also, fp->flags must contain JSFRAME_CONSTRUCTING if we
|
|
580
|
+
* are preparing for a constructor call.
|
|
581
|
+
*/
|
|
582
|
+
static JSBool
|
|
583
|
+
ComputeThis(JSContext *cx, JSObject *thisp, JSStackFrame *fp)
|
|
584
|
+
{
|
|
585
|
+
JSObject *parent;
|
|
586
|
+
|
|
587
|
+
if (thisp && OBJ_GET_CLASS(cx, thisp) != &js_CallClass) {
|
|
588
|
+
/* Some objects (e.g., With) delegate 'this' to another object. */
|
|
589
|
+
thisp = OBJ_THIS_OBJECT(cx, thisp);
|
|
590
|
+
if (!thisp)
|
|
591
|
+
return JS_FALSE;
|
|
592
|
+
|
|
593
|
+
/* Default return value for a constructor is the new object. */
|
|
594
|
+
if (fp->flags & JSFRAME_CONSTRUCTING)
|
|
595
|
+
fp->rval = OBJECT_TO_JSVAL(thisp);
|
|
596
|
+
} else {
|
|
597
|
+
/*
|
|
598
|
+
* ECMA requires "the global object", but in the presence of multiple
|
|
599
|
+
* top-level objects (windows, frames, or certain layers in the client
|
|
600
|
+
* object model), we prefer fun's parent. An example that causes this
|
|
601
|
+
* code to run:
|
|
602
|
+
*
|
|
603
|
+
* // in window w1
|
|
604
|
+
* function f() { return this }
|
|
605
|
+
* function g() { return f }
|
|
606
|
+
*
|
|
607
|
+
* // in window w2
|
|
608
|
+
* var h = w1.g()
|
|
609
|
+
* alert(h() == w1)
|
|
610
|
+
*
|
|
611
|
+
* The alert should display "true".
|
|
612
|
+
*/
|
|
613
|
+
JS_ASSERT(!(fp->flags & JSFRAME_CONSTRUCTING));
|
|
614
|
+
if (JSVAL_IS_PRIMITIVE(fp->argv[-2]) ||
|
|
615
|
+
!(parent = OBJ_GET_PARENT(cx, JSVAL_TO_OBJECT(fp->argv[-2])))) {
|
|
616
|
+
thisp = cx->globalObject;
|
|
617
|
+
} else {
|
|
618
|
+
/* walk up to find the top-level object */
|
|
619
|
+
thisp = parent;
|
|
620
|
+
while ((parent = OBJ_GET_PARENT(cx, thisp)) != NULL)
|
|
621
|
+
thisp = parent;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
fp->thisp = thisp;
|
|
625
|
+
fp->argv[-1] = OBJECT_TO_JSVAL(thisp);
|
|
626
|
+
return JS_TRUE;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
#ifdef DUMP_CALL_TABLE
|
|
630
|
+
|
|
631
|
+
#include "jsclist.h"
|
|
632
|
+
#include "jshash.h"
|
|
633
|
+
#include "jsdtoa.h"
|
|
634
|
+
|
|
635
|
+
typedef struct CallKey {
|
|
636
|
+
jsval callee; /* callee value */
|
|
637
|
+
const char *filename; /* function filename or null */
|
|
638
|
+
uintN lineno; /* function lineno or 0 */
|
|
639
|
+
} CallKey;
|
|
640
|
+
|
|
641
|
+
/* Compensate for typeof null == "object" brain damage. */
|
|
642
|
+
#define JSTYPE_NULL JSTYPE_LIMIT
|
|
643
|
+
#define TYPEOF(cx,v) (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
|
|
644
|
+
#define TYPENAME(t) (((t) == JSTYPE_NULL) ? js_null_str : js_type_str[t])
|
|
645
|
+
#define NTYPEHIST (JSTYPE_LIMIT + 1)
|
|
646
|
+
|
|
647
|
+
typedef struct CallValue {
|
|
648
|
+
uint32 total; /* total call count */
|
|
649
|
+
uint32 recycled; /* LRU-recycled calls lost */
|
|
650
|
+
uint16 minargc; /* minimum argument count */
|
|
651
|
+
uint16 maxargc; /* maximum argument count */
|
|
652
|
+
struct ArgInfo {
|
|
653
|
+
uint32 typeHist[NTYPEHIST]; /* histogram by type */
|
|
654
|
+
JSCList lruList; /* top 10 values LRU list */
|
|
655
|
+
struct ArgValCount {
|
|
656
|
+
JSCList lruLink; /* LRU list linkage */
|
|
657
|
+
jsval value; /* recently passed value */
|
|
658
|
+
uint32 count; /* number of times passed */
|
|
659
|
+
char strbuf[112]; /* string conversion buffer */
|
|
660
|
+
} topValCounts[10]; /* top 10 value storage */
|
|
661
|
+
} argInfo[8];
|
|
662
|
+
} CallValue;
|
|
663
|
+
|
|
664
|
+
typedef struct CallEntry {
|
|
665
|
+
JSHashEntry entry;
|
|
666
|
+
CallKey key;
|
|
667
|
+
CallValue value;
|
|
668
|
+
char name[32]; /* function name copy */
|
|
669
|
+
} CallEntry;
|
|
670
|
+
|
|
671
|
+
static void *
|
|
672
|
+
AllocCallTable(void *pool, size_t size)
|
|
673
|
+
{
|
|
674
|
+
return malloc(size);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
static void
|
|
678
|
+
FreeCallTable(void *pool, void *item)
|
|
679
|
+
{
|
|
680
|
+
free(item);
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
static JSHashEntry *
|
|
684
|
+
AllocCallEntry(void *pool, const void *key)
|
|
685
|
+
{
|
|
686
|
+
return (JSHashEntry*) calloc(1, sizeof(CallEntry));
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
static void
|
|
690
|
+
FreeCallEntry(void *pool, JSHashEntry *he, uintN flag)
|
|
691
|
+
{
|
|
692
|
+
JS_ASSERT(flag == HT_FREE_ENTRY);
|
|
693
|
+
free(he);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
static JSHashAllocOps callTableAllocOps = {
|
|
697
|
+
AllocCallTable, FreeCallTable,
|
|
698
|
+
AllocCallEntry, FreeCallEntry
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
JS_STATIC_DLL_CALLBACK(JSHashNumber)
|
|
702
|
+
js_hash_call_key(const void *key)
|
|
703
|
+
{
|
|
704
|
+
CallKey *ck = (CallKey *) key;
|
|
705
|
+
JSHashNumber hash = (jsuword)ck->callee >> 3;
|
|
706
|
+
|
|
707
|
+
if (ck->filename) {
|
|
708
|
+
hash = (hash << 4) ^ JS_HashString(ck->filename);
|
|
709
|
+
hash = (hash << 4) ^ ck->lineno;
|
|
710
|
+
}
|
|
711
|
+
return hash;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
JS_STATIC_DLL_CALLBACK(intN)
|
|
715
|
+
js_compare_call_keys(const void *k1, const void *k2)
|
|
716
|
+
{
|
|
717
|
+
CallKey *ck1 = (CallKey *)k1, *ck2 = (CallKey *)k2;
|
|
718
|
+
|
|
719
|
+
return ck1->callee == ck2->callee &&
|
|
720
|
+
((ck1->filename && ck2->filename)
|
|
721
|
+
? strcmp(ck1->filename, ck2->filename) == 0
|
|
722
|
+
: ck1->filename == ck2->filename) &&
|
|
723
|
+
ck1->lineno == ck2->lineno;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
JSHashTable *js_CallTable;
|
|
727
|
+
size_t js_LogCallToSourceLimit;
|
|
728
|
+
|
|
729
|
+
JS_STATIC_DLL_CALLBACK(intN)
|
|
730
|
+
CallTableDumper(JSHashEntry *he, intN k, void *arg)
|
|
731
|
+
{
|
|
732
|
+
CallEntry *ce = (CallEntry *)he;
|
|
733
|
+
FILE *fp = (FILE *)arg;
|
|
734
|
+
uintN argc, i, n;
|
|
735
|
+
struct ArgInfo *ai;
|
|
736
|
+
JSType save, type;
|
|
737
|
+
JSCList *cl;
|
|
738
|
+
struct ArgValCount *avc;
|
|
739
|
+
jsval argval;
|
|
740
|
+
|
|
741
|
+
if (ce->key.filename) {
|
|
742
|
+
/* We're called at the end of the mark phase, so mark our filenames. */
|
|
743
|
+
js_MarkScriptFilename(ce->key.filename);
|
|
744
|
+
fprintf(fp, "%s:%u ", ce->key.filename, ce->key.lineno);
|
|
745
|
+
} else {
|
|
746
|
+
fprintf(fp, "@%p ", (void *) ce->key.callee);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (ce->name[0])
|
|
750
|
+
fprintf(fp, "name %s ", ce->name);
|
|
751
|
+
fprintf(fp, "calls %lu (%lu) argc %u/%u\n",
|
|
752
|
+
(unsigned long) ce->value.total,
|
|
753
|
+
(unsigned long) ce->value.recycled,
|
|
754
|
+
ce->value.minargc, ce->value.maxargc);
|
|
755
|
+
|
|
756
|
+
argc = JS_MIN(ce->value.maxargc, 8);
|
|
757
|
+
for (i = 0; i < argc; i++) {
|
|
758
|
+
ai = &ce->value.argInfo[i];
|
|
759
|
+
|
|
760
|
+
n = 0;
|
|
761
|
+
save = -1;
|
|
762
|
+
for (type = JSTYPE_VOID; type <= JSTYPE_LIMIT; type++) {
|
|
763
|
+
if (ai->typeHist[type]) {
|
|
764
|
+
save = type;
|
|
765
|
+
++n;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
if (n == 1) {
|
|
769
|
+
fprintf(fp, " arg %u type %s: %lu\n",
|
|
770
|
+
i, TYPENAME(save), (unsigned long) ai->typeHist[save]);
|
|
771
|
+
} else {
|
|
772
|
+
fprintf(fp, " arg %u type histogram:\n", i);
|
|
773
|
+
for (type = JSTYPE_VOID; type <= JSTYPE_LIMIT; type++) {
|
|
774
|
+
fprintf(fp, " %9s: %8lu ",
|
|
775
|
+
TYPENAME(type), (unsigned long) ai->typeHist[type]);
|
|
776
|
+
for (n = (uintN) JS_HOWMANY(ai->typeHist[type], 10); n > 0; --n)
|
|
777
|
+
fputc('*', fp);
|
|
778
|
+
fputc('\n', fp);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
fprintf(fp, " arg %u top 10 values:\n", i);
|
|
783
|
+
n = 1;
|
|
784
|
+
for (cl = ai->lruList.prev; cl != &ai->lruList; cl = cl->prev) {
|
|
785
|
+
avc = (struct ArgValCount *)cl;
|
|
786
|
+
if (!avc->count)
|
|
787
|
+
break;
|
|
788
|
+
argval = avc->value;
|
|
789
|
+
fprintf(fp, " %9u: %8lu %.*s (%#lx)\n",
|
|
790
|
+
n, (unsigned long) avc->count,
|
|
791
|
+
sizeof avc->strbuf, avc->strbuf, argval);
|
|
792
|
+
++n;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
return HT_ENUMERATE_NEXT;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
void
|
|
800
|
+
js_DumpCallTable(JSContext *cx)
|
|
801
|
+
{
|
|
802
|
+
char name[24];
|
|
803
|
+
FILE *fp;
|
|
804
|
+
static uintN dumpCount;
|
|
805
|
+
|
|
806
|
+
if (!js_CallTable)
|
|
807
|
+
return;
|
|
808
|
+
|
|
809
|
+
JS_snprintf(name, sizeof name, "/tmp/calltable.dump.%u", dumpCount & 7);
|
|
810
|
+
dumpCount++;
|
|
811
|
+
fp = fopen(name, "w");
|
|
812
|
+
if (!fp)
|
|
813
|
+
return;
|
|
814
|
+
|
|
815
|
+
JS_HashTableEnumerateEntries(js_CallTable, CallTableDumper, fp);
|
|
816
|
+
fclose(fp);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
static void
|
|
820
|
+
LogCall(JSContext *cx, jsval callee, uintN argc, jsval *argv)
|
|
821
|
+
{
|
|
822
|
+
CallKey key;
|
|
823
|
+
const char *name, *cstr;
|
|
824
|
+
JSFunction *fun;
|
|
825
|
+
JSHashNumber keyHash;
|
|
826
|
+
JSHashEntry **hep, *he;
|
|
827
|
+
CallEntry *ce;
|
|
828
|
+
uintN i, j;
|
|
829
|
+
jsval argval;
|
|
830
|
+
JSType type;
|
|
831
|
+
struct ArgInfo *ai;
|
|
832
|
+
struct ArgValCount *avc;
|
|
833
|
+
JSString *str;
|
|
834
|
+
|
|
835
|
+
if (!js_CallTable) {
|
|
836
|
+
js_CallTable = JS_NewHashTable(1024, js_hash_call_key,
|
|
837
|
+
js_compare_call_keys, NULL,
|
|
838
|
+
&callTableAllocOps, NULL);
|
|
839
|
+
if (!js_CallTable)
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
key.callee = callee;
|
|
844
|
+
key.filename = NULL;
|
|
845
|
+
key.lineno = 0;
|
|
846
|
+
name = "";
|
|
847
|
+
if (JSVAL_IS_FUNCTION(cx, callee)) {
|
|
848
|
+
fun = (JSFunction *) JS_GetPrivate(cx, JSVAL_TO_OBJECT(callee));
|
|
849
|
+
if (fun->atom)
|
|
850
|
+
name = js_AtomToPrintableString(cx, fun->atom);
|
|
851
|
+
if (fun->interpreted) {
|
|
852
|
+
key.filename = fun->u.script->filename;
|
|
853
|
+
key.lineno = fun->u.script->lineno;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
keyHash = js_hash_call_key(&key);
|
|
857
|
+
|
|
858
|
+
hep = JS_HashTableRawLookup(js_CallTable, keyHash, &key);
|
|
859
|
+
he = *hep;
|
|
860
|
+
if (he) {
|
|
861
|
+
ce = (CallEntry *) he;
|
|
862
|
+
JS_ASSERT(strncmp(ce->name, name, sizeof ce->name) == 0);
|
|
863
|
+
} else {
|
|
864
|
+
he = JS_HashTableRawAdd(js_CallTable, hep, keyHash, &key, NULL);
|
|
865
|
+
if (!he)
|
|
866
|
+
return;
|
|
867
|
+
ce = (CallEntry *) he;
|
|
868
|
+
ce->entry.key = &ce->key;
|
|
869
|
+
ce->entry.value = &ce->value;
|
|
870
|
+
ce->key = key;
|
|
871
|
+
for (i = 0; i < 8; i++) {
|
|
872
|
+
ai = &ce->value.argInfo[i];
|
|
873
|
+
JS_INIT_CLIST(&ai->lruList);
|
|
874
|
+
for (j = 0; j < 10; j++)
|
|
875
|
+
JS_APPEND_LINK(&ai->topValCounts[j].lruLink, &ai->lruList);
|
|
876
|
+
}
|
|
877
|
+
strncpy(ce->name, name, sizeof ce->name);
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
++ce->value.total;
|
|
881
|
+
if (ce->value.minargc < argc)
|
|
882
|
+
ce->value.minargc = argc;
|
|
883
|
+
if (ce->value.maxargc < argc)
|
|
884
|
+
ce->value.maxargc = argc;
|
|
885
|
+
if (argc > 8)
|
|
886
|
+
argc = 8;
|
|
887
|
+
for (i = 0; i < argc; i++) {
|
|
888
|
+
ai = &ce->value.argInfo[i];
|
|
889
|
+
argval = argv[i];
|
|
890
|
+
type = TYPEOF(cx, argval);
|
|
891
|
+
++ai->typeHist[type];
|
|
892
|
+
|
|
893
|
+
for (j = 0; ; j++) {
|
|
894
|
+
if (j == 10) {
|
|
895
|
+
avc = (struct ArgValCount *) ai->lruList.next;
|
|
896
|
+
ce->value.recycled += avc->count;
|
|
897
|
+
avc->value = argval;
|
|
898
|
+
avc->count = 1;
|
|
899
|
+
break;
|
|
900
|
+
}
|
|
901
|
+
avc = &ai->topValCounts[j];
|
|
902
|
+
if (avc->value == argval) {
|
|
903
|
+
++avc->count;
|
|
904
|
+
break;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
/* Move avc to the back of the LRU list. */
|
|
909
|
+
JS_REMOVE_LINK(&avc->lruLink);
|
|
910
|
+
JS_APPEND_LINK(&avc->lruLink, &ai->lruList);
|
|
911
|
+
|
|
912
|
+
str = NULL;
|
|
913
|
+
cstr = "";
|
|
914
|
+
switch (TYPEOF(cx, argval)) {
|
|
915
|
+
case JSTYPE_VOID:
|
|
916
|
+
cstr = js_type_str[JSTYPE_VOID];
|
|
917
|
+
break;
|
|
918
|
+
case JSTYPE_NULL:
|
|
919
|
+
cstr = js_null_str;
|
|
920
|
+
break;
|
|
921
|
+
case JSTYPE_BOOLEAN:
|
|
922
|
+
cstr = js_boolean_str[JSVAL_TO_BOOLEAN(argval)];
|
|
923
|
+
break;
|
|
924
|
+
case JSTYPE_NUMBER:
|
|
925
|
+
if (JSVAL_IS_INT(argval)) {
|
|
926
|
+
JS_snprintf(avc->strbuf, sizeof avc->strbuf, "%ld",
|
|
927
|
+
JSVAL_TO_INT(argval));
|
|
928
|
+
} else {
|
|
929
|
+
JS_dtostr(avc->strbuf, sizeof avc->strbuf, DTOSTR_STANDARD, 0,
|
|
930
|
+
*JSVAL_TO_DOUBLE(argval));
|
|
931
|
+
}
|
|
932
|
+
continue;
|
|
933
|
+
case JSTYPE_STRING:
|
|
934
|
+
str = js_QuoteString(cx, JSVAL_TO_STRING(argval), (jschar)'"');
|
|
935
|
+
break;
|
|
936
|
+
case JSTYPE_FUNCTION:
|
|
937
|
+
if (JSVAL_IS_FUNCTION(cx, argval)) {
|
|
938
|
+
fun = (JSFunction *)JS_GetPrivate(cx, JSVAL_TO_OBJECT(argval));
|
|
939
|
+
if (fun && fun->atom) {
|
|
940
|
+
str = ATOM_TO_STRING(fun->atom);
|
|
941
|
+
break;
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
/* FALL THROUGH */
|
|
945
|
+
case JSTYPE_OBJECT:
|
|
946
|
+
js_LogCallToSourceLimit = sizeof avc->strbuf;
|
|
947
|
+
cx->options |= JSOPTION_LOGCALL_TOSOURCE;
|
|
948
|
+
str = js_ValueToSource(cx, argval);
|
|
949
|
+
cx->options &= ~JSOPTION_LOGCALL_TOSOURCE;
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
952
|
+
if (str)
|
|
953
|
+
cstr = JS_GetStringBytes(str);
|
|
954
|
+
strncpy(avc->strbuf, cstr, sizeof avc->strbuf);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
#endif /* DUMP_CALL_TABLE */
|
|
959
|
+
|
|
960
|
+
/*
|
|
961
|
+
* Find a function reference and its 'this' object implicit first parameter
|
|
962
|
+
* under argc arguments on cx's stack, and call the function. Push missing
|
|
963
|
+
* required arguments, allocate declared local variables, and pop everything
|
|
964
|
+
* when done. Then push the return value.
|
|
965
|
+
*/
|
|
966
|
+
JS_FRIEND_API(JSBool)
|
|
967
|
+
js_Invoke(JSContext *cx, uintN argc, uintN flags)
|
|
968
|
+
{
|
|
969
|
+
void *mark;
|
|
970
|
+
JSStackFrame *fp, frame;
|
|
971
|
+
jsval *sp, *newsp, *limit;
|
|
972
|
+
jsval *vp, v;
|
|
973
|
+
JSObject *funobj, *parent, *thisp;
|
|
974
|
+
JSBool ok;
|
|
975
|
+
JSClass *clasp;
|
|
976
|
+
JSObjectOps *ops;
|
|
977
|
+
JSNative native;
|
|
978
|
+
JSFunction *fun;
|
|
979
|
+
JSScript *script;
|
|
980
|
+
uintN minargs, nvars;
|
|
981
|
+
intN nslots, nalloc, surplus;
|
|
982
|
+
JSInterpreterHook hook;
|
|
983
|
+
void *hookData;
|
|
984
|
+
|
|
985
|
+
/* Mark the top of stack and load frequently-used registers. */
|
|
986
|
+
mark = JS_ARENA_MARK(&cx->stackPool);
|
|
987
|
+
fp = cx->fp;
|
|
988
|
+
sp = fp->sp;
|
|
989
|
+
|
|
990
|
+
/*
|
|
991
|
+
* Set vp to the callee value's stack slot (it's where rval goes).
|
|
992
|
+
* Once vp is set, control should flow through label out2: to return.
|
|
993
|
+
* Set frame.rval early so native class and object ops can throw and
|
|
994
|
+
* return false, causing a goto out2 with ok set to false. Also set
|
|
995
|
+
* frame.flags to flags so that ComputeThis can test bits in it.
|
|
996
|
+
*/
|
|
997
|
+
vp = sp - (2 + argc);
|
|
998
|
+
v = *vp;
|
|
999
|
+
frame.rval = JSVAL_VOID;
|
|
1000
|
+
frame.flags = flags;
|
|
1001
|
+
thisp = JSVAL_TO_OBJECT(vp[1]);
|
|
1002
|
+
|
|
1003
|
+
/*
|
|
1004
|
+
* A callee must be an object reference, unless its |this| parameter
|
|
1005
|
+
* implements the __noSuchMethod__ method, in which case that method will
|
|
1006
|
+
* be called like so:
|
|
1007
|
+
*
|
|
1008
|
+
* thisp.__noSuchMethod__(id, args)
|
|
1009
|
+
*
|
|
1010
|
+
* where id is the name of the method that this invocation attempted to
|
|
1011
|
+
* call by name, and args is an Array containing this invocation's actual
|
|
1012
|
+
* parameters.
|
|
1013
|
+
*/
|
|
1014
|
+
if (JSVAL_IS_PRIMITIVE(v)) {
|
|
1015
|
+
#if JS_HAS_NO_SUCH_METHOD
|
|
1016
|
+
jsbytecode *pc;
|
|
1017
|
+
jsatomid atomIndex;
|
|
1018
|
+
JSAtom *atom;
|
|
1019
|
+
JSObject *argsobj;
|
|
1020
|
+
JSArena *a;
|
|
1021
|
+
|
|
1022
|
+
if (!fp->script || (flags & JSINVOKE_INTERNAL))
|
|
1023
|
+
goto bad;
|
|
1024
|
+
|
|
1025
|
+
/*
|
|
1026
|
+
* We must ComputeThis here to censor Call objects; performance hit,
|
|
1027
|
+
* but at least it's idempotent.
|
|
1028
|
+
*
|
|
1029
|
+
* Normally, we call ComputeThis after all frame members have been
|
|
1030
|
+
* set, and in particular, after any revision of the callee value at
|
|
1031
|
+
* *vp due to clasp->convert (see below). This matters because
|
|
1032
|
+
* ComputeThis may access *vp via fp->argv[-2], to follow the parent
|
|
1033
|
+
* chain to a global object to use as the |this| parameter.
|
|
1034
|
+
*
|
|
1035
|
+
* Obviously, here in the JSVAL_IS_PRIMITIVE(v) case, there can't be
|
|
1036
|
+
* any such defaulting of |this| to callee (v, *vp) ancestor.
|
|
1037
|
+
*/
|
|
1038
|
+
frame.argv = vp + 2;
|
|
1039
|
+
ok = ComputeThis(cx, thisp, &frame);
|
|
1040
|
+
if (!ok)
|
|
1041
|
+
goto out2;
|
|
1042
|
+
thisp = frame.thisp;
|
|
1043
|
+
|
|
1044
|
+
ok = OBJ_GET_PROPERTY(cx, thisp,
|
|
1045
|
+
(jsid)cx->runtime->atomState.noSuchMethodAtom,
|
|
1046
|
+
&v);
|
|
1047
|
+
if (!ok)
|
|
1048
|
+
goto out2;
|
|
1049
|
+
if (JSVAL_IS_PRIMITIVE(v))
|
|
1050
|
+
goto bad;
|
|
1051
|
+
|
|
1052
|
+
pc = (jsbytecode *) vp[-(intN)fp->script->depth];
|
|
1053
|
+
switch ((JSOp) *pc) {
|
|
1054
|
+
case JSOP_NAME:
|
|
1055
|
+
case JSOP_GETPROP:
|
|
1056
|
+
atomIndex = GET_ATOM_INDEX(pc);
|
|
1057
|
+
atom = js_GetAtom(cx, &fp->script->atomMap, atomIndex);
|
|
1058
|
+
argsobj = js_NewArrayObject(cx, argc, vp + 2);
|
|
1059
|
+
if (!argsobj) {
|
|
1060
|
+
ok = JS_FALSE;
|
|
1061
|
+
goto out2;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
sp = vp + 4;
|
|
1065
|
+
if (argc < 2) {
|
|
1066
|
+
a = cx->stackPool.current;
|
|
1067
|
+
if ((jsuword)sp > a->limit) {
|
|
1068
|
+
/*
|
|
1069
|
+
* Arguments must be contiguous, and must include argv[-1]
|
|
1070
|
+
* and argv[-2], so allocate more stack, advance sp, and
|
|
1071
|
+
* set newsp[1] to thisp (vp[1]). The other argv elements
|
|
1072
|
+
* will be set below, using negative indexing from sp.
|
|
1073
|
+
*/
|
|
1074
|
+
newsp = js_AllocRawStack(cx, 4, NULL);
|
|
1075
|
+
if (!newsp) {
|
|
1076
|
+
ok = JS_FALSE;
|
|
1077
|
+
goto out2;
|
|
1078
|
+
}
|
|
1079
|
+
newsp[1] = OBJECT_TO_JSVAL(thisp);
|
|
1080
|
+
sp = newsp + 4;
|
|
1081
|
+
} else if ((jsuword)sp > a->avail) {
|
|
1082
|
+
/*
|
|
1083
|
+
* Inline, optimized version of JS_ARENA_ALLOCATE to claim
|
|
1084
|
+
* the small number of words not already allocated as part
|
|
1085
|
+
* of the caller's operand stack.
|
|
1086
|
+
*/
|
|
1087
|
+
JS_ArenaCountAllocation(&cx->stackPool,
|
|
1088
|
+
(jsuword)sp - a->avail);
|
|
1089
|
+
a->avail = (jsuword)sp;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
sp[-4] = v;
|
|
1094
|
+
JS_ASSERT(sp[-3] == OBJECT_TO_JSVAL(thisp));
|
|
1095
|
+
sp[-2] = ATOM_KEY(atom);
|
|
1096
|
+
sp[-1] = OBJECT_TO_JSVAL(argsobj);
|
|
1097
|
+
fp->sp = sp;
|
|
1098
|
+
argc = 2;
|
|
1099
|
+
break;
|
|
1100
|
+
|
|
1101
|
+
default:
|
|
1102
|
+
goto bad;
|
|
1103
|
+
}
|
|
1104
|
+
#else
|
|
1105
|
+
goto bad;
|
|
1106
|
+
#endif
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
funobj = JSVAL_TO_OBJECT(v);
|
|
1110
|
+
parent = OBJ_GET_PARENT(cx, funobj);
|
|
1111
|
+
clasp = OBJ_GET_CLASS(cx, funobj);
|
|
1112
|
+
if (clasp != &js_FunctionClass) {
|
|
1113
|
+
/* Function is inlined, all other classes use object ops. */
|
|
1114
|
+
ops = funobj->map->ops;
|
|
1115
|
+
|
|
1116
|
+
/*
|
|
1117
|
+
* XXX this makes no sense -- why convert to function if clasp->call?
|
|
1118
|
+
* XXX better to call that hook without converting
|
|
1119
|
+
* XXX the only thing that needs fixing is liveconnect
|
|
1120
|
+
*
|
|
1121
|
+
* Try converting to function, for closure and API compatibility.
|
|
1122
|
+
* We attempt the conversion under all circumstances for 1.2, but
|
|
1123
|
+
* only if there is a call op defined otherwise.
|
|
1124
|
+
*/
|
|
1125
|
+
if (cx->version == JSVERSION_1_2 ||
|
|
1126
|
+
((ops == &js_ObjectOps) ? clasp->call : ops->call)) {
|
|
1127
|
+
ok = clasp->convert(cx, funobj, JSTYPE_FUNCTION, &v);
|
|
1128
|
+
if (!ok)
|
|
1129
|
+
goto out2;
|
|
1130
|
+
|
|
1131
|
+
if (JSVAL_IS_FUNCTION(cx, v)) {
|
|
1132
|
+
/* Make vp refer to funobj to keep it available as argv[-2]. */
|
|
1133
|
+
*vp = v;
|
|
1134
|
+
funobj = JSVAL_TO_OBJECT(v);
|
|
1135
|
+
parent = OBJ_GET_PARENT(cx, funobj);
|
|
1136
|
+
goto have_fun;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
fun = NULL;
|
|
1140
|
+
script = NULL;
|
|
1141
|
+
minargs = nvars = 0;
|
|
1142
|
+
|
|
1143
|
+
/* Try a call or construct native object op. */
|
|
1144
|
+
native = (flags & JSINVOKE_CONSTRUCT) ? ops->construct : ops->call;
|
|
1145
|
+
if (!native)
|
|
1146
|
+
goto bad;
|
|
1147
|
+
} else {
|
|
1148
|
+
have_fun:
|
|
1149
|
+
/* Get private data and set derived locals from it. */
|
|
1150
|
+
fun = (JSFunction *) JS_GetPrivate(cx, funobj);
|
|
1151
|
+
if (fun->interpreted) {
|
|
1152
|
+
native = NULL;
|
|
1153
|
+
script = fun->u.script;
|
|
1154
|
+
} else {
|
|
1155
|
+
native = fun->u.native;
|
|
1156
|
+
script = NULL;
|
|
1157
|
+
}
|
|
1158
|
+
minargs = fun->nargs + fun->extra;
|
|
1159
|
+
nvars = fun->nvars;
|
|
1160
|
+
|
|
1161
|
+
/* Handle bound method special case. */
|
|
1162
|
+
if (fun->flags & JSFUN_BOUND_METHOD)
|
|
1163
|
+
thisp = parent;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
/* Initialize the rest of frame, except for sp (set by SAVE_SP later). */
|
|
1167
|
+
frame.varobj = NULL;
|
|
1168
|
+
frame.callobj = frame.argsobj = NULL;
|
|
1169
|
+
frame.script = script;
|
|
1170
|
+
frame.fun = fun;
|
|
1171
|
+
frame.argc = argc;
|
|
1172
|
+
frame.argv = sp - argc;
|
|
1173
|
+
frame.nvars = nvars;
|
|
1174
|
+
frame.vars = sp;
|
|
1175
|
+
frame.down = fp;
|
|
1176
|
+
frame.annotation = NULL;
|
|
1177
|
+
frame.scopeChain = NULL; /* set below for real, after cx->fp is set */
|
|
1178
|
+
frame.pc = NULL;
|
|
1179
|
+
frame.spbase = NULL;
|
|
1180
|
+
frame.sharpDepth = 0;
|
|
1181
|
+
frame.sharpArray = NULL;
|
|
1182
|
+
frame.dormantNext = NULL;
|
|
1183
|
+
|
|
1184
|
+
/* Compute the 'this' parameter and store it in frame as frame.thisp. */
|
|
1185
|
+
ok = ComputeThis(cx, thisp, &frame);
|
|
1186
|
+
if (!ok)
|
|
1187
|
+
goto out2;
|
|
1188
|
+
|
|
1189
|
+
/* From here on, control must flow through label out: to return. */
|
|
1190
|
+
cx->fp = &frame;
|
|
1191
|
+
|
|
1192
|
+
/* Init these now in case we goto out before first hook call. */
|
|
1193
|
+
hook = cx->runtime->callHook;
|
|
1194
|
+
hookData = NULL;
|
|
1195
|
+
|
|
1196
|
+
/* Check for missing arguments expected by the function. */
|
|
1197
|
+
nslots = (intN)((argc < minargs) ? minargs - argc : 0);
|
|
1198
|
+
if (nslots) {
|
|
1199
|
+
/* All arguments must be contiguous, so we may have to copy actuals. */
|
|
1200
|
+
nalloc = nslots;
|
|
1201
|
+
limit = (jsval *) cx->stackPool.current->limit;
|
|
1202
|
+
if (sp + nslots > limit) {
|
|
1203
|
+
/* Hit end of arena: we have to copy argv[-2..(argc+nslots-1)]. */
|
|
1204
|
+
nalloc += 2 + argc;
|
|
1205
|
+
} else {
|
|
1206
|
+
/* Take advantage of surplus slots in the caller's frame depth. */
|
|
1207
|
+
surplus = (jsval *)mark - sp;
|
|
1208
|
+
JS_ASSERT(surplus >= 0);
|
|
1209
|
+
nalloc -= surplus;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/* Check whether we have enough space in the caller's frame. */
|
|
1213
|
+
if (nalloc > 0) {
|
|
1214
|
+
/* Need space for actuals plus missing formals minus surplus. */
|
|
1215
|
+
newsp = js_AllocRawStack(cx, (uintN)nalloc, NULL);
|
|
1216
|
+
if (!newsp) {
|
|
1217
|
+
ok = JS_FALSE;
|
|
1218
|
+
goto out;
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
/* If we couldn't allocate contiguous args, copy actuals now. */
|
|
1222
|
+
if (newsp != mark) {
|
|
1223
|
+
JS_ASSERT(sp + nslots > limit);
|
|
1224
|
+
JS_ASSERT(2 + argc + nslots == (uintN)nalloc);
|
|
1225
|
+
*newsp++ = vp[0];
|
|
1226
|
+
*newsp++ = vp[1];
|
|
1227
|
+
if (argc)
|
|
1228
|
+
memcpy(newsp, frame.argv, argc * sizeof(jsval));
|
|
1229
|
+
frame.argv = newsp;
|
|
1230
|
+
sp = frame.vars = newsp + argc;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
/* Advance frame.vars to make room for the missing args. */
|
|
1235
|
+
frame.vars += nslots;
|
|
1236
|
+
|
|
1237
|
+
/* Push void to initialize missing args. */
|
|
1238
|
+
while (--nslots >= 0)
|
|
1239
|
+
PUSH(JSVAL_VOID);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
/* Now allocate stack space for local variables. */
|
|
1243
|
+
nslots = (intN)frame.nvars;
|
|
1244
|
+
if (nslots) {
|
|
1245
|
+
surplus = (intN)((jsval *)cx->stackPool.current->avail - frame.vars);
|
|
1246
|
+
if (surplus < nslots) {
|
|
1247
|
+
newsp = js_AllocRawStack(cx, (uintN)nslots, NULL);
|
|
1248
|
+
if (!newsp) {
|
|
1249
|
+
ok = JS_FALSE;
|
|
1250
|
+
goto out;
|
|
1251
|
+
}
|
|
1252
|
+
if (newsp != sp) {
|
|
1253
|
+
/* NB: Discontinuity between argv and vars. */
|
|
1254
|
+
sp = frame.vars = newsp;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
/* Push void to initialize local variables. */
|
|
1259
|
+
while (--nslots >= 0)
|
|
1260
|
+
PUSH(JSVAL_VOID);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
/* Store the current sp in frame before calling fun. */
|
|
1264
|
+
SAVE_SP(&frame);
|
|
1265
|
+
|
|
1266
|
+
/* call the hook if present */
|
|
1267
|
+
if (hook && (native || script))
|
|
1268
|
+
hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->callHookData);
|
|
1269
|
+
|
|
1270
|
+
/* Call the function, either a native method or an interpreted script. */
|
|
1271
|
+
if (native) {
|
|
1272
|
+
#if JS_HAS_LVALUE_RETURN
|
|
1273
|
+
/* Set by JS_SetCallReturnValue2, used to return reference types. */
|
|
1274
|
+
cx->rval2set = JS_FALSE;
|
|
1275
|
+
#endif
|
|
1276
|
+
|
|
1277
|
+
/* If native, use caller varobj and scopeChain for eval. */
|
|
1278
|
+
frame.varobj = fp->varobj;
|
|
1279
|
+
frame.scopeChain = fp->scopeChain;
|
|
1280
|
+
ok = native(cx, frame.thisp, argc, frame.argv, &frame.rval);
|
|
1281
|
+
JS_RUNTIME_METER(cx->runtime, nativeCalls);
|
|
1282
|
+
} else if (script) {
|
|
1283
|
+
#ifdef DUMP_CALL_TABLE
|
|
1284
|
+
LogCall(cx, *vp, argc, frame.argv);
|
|
1285
|
+
#endif
|
|
1286
|
+
/* Use parent scope so js_GetCallObject can find the right "Call". */
|
|
1287
|
+
frame.scopeChain = parent;
|
|
1288
|
+
if (fun->flags & JSFUN_HEAVYWEIGHT) {
|
|
1289
|
+
#if JS_HAS_CALL_OBJECT
|
|
1290
|
+
/* Scope with a call object parented by the callee's parent. */
|
|
1291
|
+
if (!js_GetCallObject(cx, &frame, parent)) {
|
|
1292
|
+
ok = JS_FALSE;
|
|
1293
|
+
goto out;
|
|
1294
|
+
}
|
|
1295
|
+
#else
|
|
1296
|
+
/* Bad old code used the function as a proxy for all calls to it. */
|
|
1297
|
+
frame.scopeChain = funobj;
|
|
1298
|
+
#endif
|
|
1299
|
+
}
|
|
1300
|
+
ok = js_Interpret(cx, &v);
|
|
1301
|
+
} else {
|
|
1302
|
+
/* fun might be onerror trying to report a syntax error in itself. */
|
|
1303
|
+
frame.scopeChain = NULL;
|
|
1304
|
+
ok = JS_TRUE;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
out:
|
|
1308
|
+
if (hookData) {
|
|
1309
|
+
hook = cx->runtime->callHook;
|
|
1310
|
+
if (hook)
|
|
1311
|
+
hook(cx, &frame, JS_FALSE, &ok, hookData);
|
|
1312
|
+
}
|
|
1313
|
+
#if JS_HAS_CALL_OBJECT
|
|
1314
|
+
/* If frame has a call object, sync values and clear back-pointer. */
|
|
1315
|
+
if (frame.callobj)
|
|
1316
|
+
ok &= js_PutCallObject(cx, &frame);
|
|
1317
|
+
#endif
|
|
1318
|
+
#if JS_HAS_ARGS_OBJECT
|
|
1319
|
+
/* If frame has an arguments object, sync values and clear back-pointer. */
|
|
1320
|
+
if (frame.argsobj)
|
|
1321
|
+
ok &= js_PutArgsObject(cx, &frame);
|
|
1322
|
+
#endif
|
|
1323
|
+
|
|
1324
|
+
/* Restore cx->fp now that we're done releasing frame objects. */
|
|
1325
|
+
cx->fp = fp;
|
|
1326
|
+
|
|
1327
|
+
out2:
|
|
1328
|
+
/* Pop everything we may have allocated off the stack. */
|
|
1329
|
+
JS_ARENA_RELEASE(&cx->stackPool, mark);
|
|
1330
|
+
|
|
1331
|
+
/* Store the return value and restore sp just above it. */
|
|
1332
|
+
*vp = frame.rval;
|
|
1333
|
+
fp->sp = vp + 1;
|
|
1334
|
+
|
|
1335
|
+
/*
|
|
1336
|
+
* Store the location of the JSOP_CALL or JSOP_EVAL that generated the
|
|
1337
|
+
* return value, but only if this is an external (compiled from script
|
|
1338
|
+
* source) call that has stack budget for the generating pc.
|
|
1339
|
+
*/
|
|
1340
|
+
if (fp->script && !(flags & JSINVOKE_INTERNAL))
|
|
1341
|
+
vp[-(intN)fp->script->depth] = (jsval)fp->pc;
|
|
1342
|
+
return ok;
|
|
1343
|
+
|
|
1344
|
+
bad:
|
|
1345
|
+
js_ReportIsNotFunction(cx, vp, flags & JSINVOKE_CONSTRUCT);
|
|
1346
|
+
ok = JS_FALSE;
|
|
1347
|
+
goto out2;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
JSBool
|
|
1351
|
+
js_InternalInvoke(JSContext *cx, JSObject *obj, jsval fval, uintN flags,
|
|
1352
|
+
uintN argc, jsval *argv, jsval *rval)
|
|
1353
|
+
{
|
|
1354
|
+
JSStackFrame *fp, *oldfp, frame;
|
|
1355
|
+
jsval *oldsp, *sp;
|
|
1356
|
+
void *mark;
|
|
1357
|
+
uintN i;
|
|
1358
|
+
JSBool ok;
|
|
1359
|
+
|
|
1360
|
+
fp = oldfp = cx->fp;
|
|
1361
|
+
if (!fp) {
|
|
1362
|
+
memset(&frame, 0, sizeof frame);
|
|
1363
|
+
cx->fp = fp = &frame;
|
|
1364
|
+
}
|
|
1365
|
+
oldsp = fp->sp;
|
|
1366
|
+
sp = js_AllocStack(cx, 2 + argc, &mark);
|
|
1367
|
+
if (!sp) {
|
|
1368
|
+
ok = JS_FALSE;
|
|
1369
|
+
goto out;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
PUSH(fval);
|
|
1373
|
+
PUSH(OBJECT_TO_JSVAL(obj));
|
|
1374
|
+
for (i = 0; i < argc; i++)
|
|
1375
|
+
PUSH(argv[i]);
|
|
1376
|
+
fp->sp = sp;
|
|
1377
|
+
ok = js_Invoke(cx, argc, flags | JSINVOKE_INTERNAL);
|
|
1378
|
+
if (ok) {
|
|
1379
|
+
RESTORE_SP(fp);
|
|
1380
|
+
*rval = POP_OPND();
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
js_FreeStack(cx, mark);
|
|
1384
|
+
out:
|
|
1385
|
+
fp->sp = oldsp;
|
|
1386
|
+
if (oldfp != fp)
|
|
1387
|
+
cx->fp = oldfp;
|
|
1388
|
+
|
|
1389
|
+
return ok;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
JSBool
|
|
1393
|
+
js_InternalGetOrSet(JSContext *cx, JSObject *obj, jsid id, jsval fval,
|
|
1394
|
+
JSAccessMode mode, uintN argc, jsval *argv, jsval *rval)
|
|
1395
|
+
{
|
|
1396
|
+
/*
|
|
1397
|
+
* Check general (not object-ops/class-specific) access from the running
|
|
1398
|
+
* script to obj.id only if id has a scripted getter or setter that we're
|
|
1399
|
+
* about to invoke. If we don't check this case, nothing else will -- no
|
|
1400
|
+
* other native code has the chance to check.
|
|
1401
|
+
*
|
|
1402
|
+
* Contrast this non-native (scripted) case with native getter and setter
|
|
1403
|
+
* accesses, where the native itself must do an access check, if security
|
|
1404
|
+
* policies requires it. We make a checkAccess or checkObjectAccess call
|
|
1405
|
+
* back to the embedding program only in those cases where we're not going
|
|
1406
|
+
* to call an embedding-defined native function, getter, setter, or class
|
|
1407
|
+
* hook anyway. Where we do call such a native, there's no need for the
|
|
1408
|
+
* engine to impose a separate access check callback on all embeddings --
|
|
1409
|
+
* many embeddings have no security policy at all.
|
|
1410
|
+
*/
|
|
1411
|
+
JS_ASSERT(mode == JSACC_READ || mode == JSACC_WRITE);
|
|
1412
|
+
if (cx->runtime->checkObjectAccess &&
|
|
1413
|
+
JSVAL_IS_FUNCTION(cx, fval) &&
|
|
1414
|
+
((JSFunction *)JS_GetPrivate(cx, JSVAL_TO_OBJECT(fval)))->interpreted &&
|
|
1415
|
+
!cx->runtime->checkObjectAccess(cx, obj, ID_TO_VALUE(id), mode,
|
|
1416
|
+
&fval)) {
|
|
1417
|
+
return JS_FALSE;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
return js_InternalCall(cx, obj, fval, argc, argv, rval);
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
JSBool
|
|
1424
|
+
js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
|
1425
|
+
JSStackFrame *down, uintN flags, jsval *result)
|
|
1426
|
+
{
|
|
1427
|
+
JSInterpreterHook hook;
|
|
1428
|
+
void *hookData, *mark;
|
|
1429
|
+
JSStackFrame *oldfp, frame;
|
|
1430
|
+
JSObject *obj, *tmp;
|
|
1431
|
+
JSBool ok;
|
|
1432
|
+
|
|
1433
|
+
hook = cx->runtime->executeHook;
|
|
1434
|
+
hookData = mark = NULL;
|
|
1435
|
+
oldfp = cx->fp;
|
|
1436
|
+
frame.callobj = frame.argsobj = NULL;
|
|
1437
|
+
frame.script = script;
|
|
1438
|
+
if (down) {
|
|
1439
|
+
/* Propagate arg/var state for eval and the debugger API. */
|
|
1440
|
+
frame.varobj = down->varobj;
|
|
1441
|
+
frame.fun = down->fun;
|
|
1442
|
+
frame.thisp = down->thisp;
|
|
1443
|
+
frame.argc = down->argc;
|
|
1444
|
+
frame.argv = down->argv;
|
|
1445
|
+
frame.nvars = down->nvars;
|
|
1446
|
+
frame.vars = down->vars;
|
|
1447
|
+
frame.annotation = down->annotation;
|
|
1448
|
+
frame.sharpArray = down->sharpArray;
|
|
1449
|
+
} else {
|
|
1450
|
+
obj = chain;
|
|
1451
|
+
if (cx->options & JSOPTION_VAROBJFIX) {
|
|
1452
|
+
while ((tmp = OBJ_GET_PARENT(cx, obj)) != NULL)
|
|
1453
|
+
obj = tmp;
|
|
1454
|
+
}
|
|
1455
|
+
frame.varobj = obj;
|
|
1456
|
+
frame.fun = NULL;
|
|
1457
|
+
frame.thisp = chain;
|
|
1458
|
+
frame.argc = 0;
|
|
1459
|
+
frame.argv = NULL;
|
|
1460
|
+
frame.nvars = script->numGlobalVars;
|
|
1461
|
+
if (frame.nvars) {
|
|
1462
|
+
frame.vars = js_AllocRawStack(cx, frame.nvars, &mark);
|
|
1463
|
+
if (!frame.vars)
|
|
1464
|
+
return JS_FALSE;
|
|
1465
|
+
memset(frame.vars, 0, frame.nvars * sizeof(jsval));
|
|
1466
|
+
} else {
|
|
1467
|
+
frame.vars = NULL;
|
|
1468
|
+
}
|
|
1469
|
+
frame.annotation = NULL;
|
|
1470
|
+
frame.sharpArray = NULL;
|
|
1471
|
+
}
|
|
1472
|
+
frame.rval = JSVAL_VOID;
|
|
1473
|
+
frame.down = down;
|
|
1474
|
+
frame.scopeChain = chain;
|
|
1475
|
+
frame.pc = NULL;
|
|
1476
|
+
frame.sp = oldfp ? oldfp->sp : NULL;
|
|
1477
|
+
frame.spbase = NULL;
|
|
1478
|
+
frame.sharpDepth = 0;
|
|
1479
|
+
frame.flags = flags;
|
|
1480
|
+
frame.dormantNext = NULL;
|
|
1481
|
+
|
|
1482
|
+
/*
|
|
1483
|
+
* Here we wrap the call to js_Interpret with code to (conditionally)
|
|
1484
|
+
* save and restore the old stack frame chain into a chain of 'dormant'
|
|
1485
|
+
* frame chains. Since we are replacing cx->fp, we were running into
|
|
1486
|
+
* the problem that if GC was called under this frame, some of the GC
|
|
1487
|
+
* things associated with the old frame chain (available here only in
|
|
1488
|
+
* the C variable 'oldfp') were not rooted and were being collected.
|
|
1489
|
+
*
|
|
1490
|
+
* So, now we preserve the links to these 'dormant' frame chains in cx
|
|
1491
|
+
* before calling js_Interpret and cleanup afterwards. The GC walks
|
|
1492
|
+
* these dormant chains and marks objects in the same way that it marks
|
|
1493
|
+
* objects in the primary cx->fp chain.
|
|
1494
|
+
*/
|
|
1495
|
+
if (oldfp && oldfp != down) {
|
|
1496
|
+
JS_ASSERT(!oldfp->dormantNext);
|
|
1497
|
+
oldfp->dormantNext = cx->dormantFrameChain;
|
|
1498
|
+
cx->dormantFrameChain = oldfp;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
cx->fp = &frame;
|
|
1502
|
+
if (hook)
|
|
1503
|
+
hookData = hook(cx, &frame, JS_TRUE, 0, cx->runtime->executeHookData);
|
|
1504
|
+
|
|
1505
|
+
/*
|
|
1506
|
+
* Use frame.rval, not result, so the last result stays rooted across any
|
|
1507
|
+
* GC activations nested within this js_Interpret.
|
|
1508
|
+
*/
|
|
1509
|
+
ok = js_Interpret(cx, &frame.rval);
|
|
1510
|
+
*result = frame.rval;
|
|
1511
|
+
|
|
1512
|
+
if (hookData) {
|
|
1513
|
+
hook = cx->runtime->executeHook;
|
|
1514
|
+
if (hook)
|
|
1515
|
+
hook(cx, &frame, JS_FALSE, &ok, hookData);
|
|
1516
|
+
}
|
|
1517
|
+
if (mark)
|
|
1518
|
+
js_FreeRawStack(cx, mark);
|
|
1519
|
+
cx->fp = oldfp;
|
|
1520
|
+
|
|
1521
|
+
if (oldfp && oldfp != down) {
|
|
1522
|
+
JS_ASSERT(cx->dormantFrameChain == oldfp);
|
|
1523
|
+
cx->dormantFrameChain = oldfp->dormantNext;
|
|
1524
|
+
oldfp->dormantNext = NULL;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
return ok;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
#if JS_HAS_EXPORT_IMPORT
|
|
1531
|
+
/*
|
|
1532
|
+
* If id is JSVAL_VOID, import all exported properties from obj.
|
|
1533
|
+
*/
|
|
1534
|
+
static JSBool
|
|
1535
|
+
ImportProperty(JSContext *cx, JSObject *obj, jsid id)
|
|
1536
|
+
{
|
|
1537
|
+
JSBool ok;
|
|
1538
|
+
JSIdArray *ida;
|
|
1539
|
+
JSProperty *prop;
|
|
1540
|
+
JSObject *obj2, *target, *funobj, *closure;
|
|
1541
|
+
JSString *str;
|
|
1542
|
+
uintN attrs;
|
|
1543
|
+
jsint i;
|
|
1544
|
+
jsval value;
|
|
1545
|
+
|
|
1546
|
+
if (JSVAL_IS_VOID(id)) {
|
|
1547
|
+
ida = JS_Enumerate(cx, obj);
|
|
1548
|
+
if (!ida)
|
|
1549
|
+
return JS_FALSE;
|
|
1550
|
+
ok = JS_TRUE;
|
|
1551
|
+
if (ida->length == 0)
|
|
1552
|
+
goto out;
|
|
1553
|
+
} else {
|
|
1554
|
+
ida = NULL;
|
|
1555
|
+
if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
|
|
1556
|
+
return JS_FALSE;
|
|
1557
|
+
if (!prop) {
|
|
1558
|
+
str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK,
|
|
1559
|
+
ID_TO_VALUE(id), NULL);
|
|
1560
|
+
if (str)
|
|
1561
|
+
js_ReportIsNotDefined(cx, JS_GetStringBytes(str));
|
|
1562
|
+
return JS_FALSE;
|
|
1563
|
+
}
|
|
1564
|
+
ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
|
|
1565
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
1566
|
+
if (!ok)
|
|
1567
|
+
return JS_FALSE;
|
|
1568
|
+
if (!(attrs & JSPROP_EXPORTED)) {
|
|
1569
|
+
str = js_DecompileValueGenerator(cx, JSDVG_IGNORE_STACK,
|
|
1570
|
+
ID_TO_VALUE(id), NULL);
|
|
1571
|
+
if (str) {
|
|
1572
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
1573
|
+
JSMSG_NOT_EXPORTED,
|
|
1574
|
+
JS_GetStringBytes(str));
|
|
1575
|
+
}
|
|
1576
|
+
return JS_FALSE;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
target = cx->fp->varobj;
|
|
1581
|
+
i = 0;
|
|
1582
|
+
do {
|
|
1583
|
+
if (ida) {
|
|
1584
|
+
id = ida->vector[i];
|
|
1585
|
+
ok = OBJ_GET_ATTRIBUTES(cx, obj, id, NULL, &attrs);
|
|
1586
|
+
if (!ok)
|
|
1587
|
+
goto out;
|
|
1588
|
+
if (!(attrs & JSPROP_EXPORTED))
|
|
1589
|
+
continue;
|
|
1590
|
+
}
|
|
1591
|
+
ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_IMPORT, &value, &attrs);
|
|
1592
|
+
if (!ok)
|
|
1593
|
+
goto out;
|
|
1594
|
+
if (JSVAL_IS_FUNCTION(cx, value)) {
|
|
1595
|
+
funobj = JSVAL_TO_OBJECT(value);
|
|
1596
|
+
closure = js_CloneFunctionObject(cx, funobj, obj);
|
|
1597
|
+
if (!closure) {
|
|
1598
|
+
ok = JS_FALSE;
|
|
1599
|
+
goto out;
|
|
1600
|
+
}
|
|
1601
|
+
value = OBJECT_TO_JSVAL(closure);
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
/*
|
|
1605
|
+
* Handle the case of importing a property that refers to a local
|
|
1606
|
+
* variable or formal parameter of a function activation. These
|
|
1607
|
+
* properties are accessed by opcodes using stack slot numbers
|
|
1608
|
+
* generated by the compiler rather than runtime name-lookup. These
|
|
1609
|
+
* local references, therefore, bypass the normal scope chain lookup.
|
|
1610
|
+
* So, instead of defining a new property in the activation object,
|
|
1611
|
+
* modify the existing value in the stack slot.
|
|
1612
|
+
*/
|
|
1613
|
+
if (OBJ_GET_CLASS(cx, target) == &js_CallClass) {
|
|
1614
|
+
ok = OBJ_LOOKUP_PROPERTY(cx, target, id, &obj2, &prop);
|
|
1615
|
+
if (!ok)
|
|
1616
|
+
goto out;
|
|
1617
|
+
} else {
|
|
1618
|
+
prop = NULL;
|
|
1619
|
+
}
|
|
1620
|
+
if (prop && target == obj2) {
|
|
1621
|
+
ok = OBJ_SET_PROPERTY(cx, target, id, &value);
|
|
1622
|
+
} else {
|
|
1623
|
+
ok = OBJ_DEFINE_PROPERTY(cx, target, id, value, NULL, NULL,
|
|
1624
|
+
attrs & ~JSPROP_EXPORTED,
|
|
1625
|
+
NULL);
|
|
1626
|
+
}
|
|
1627
|
+
if (prop)
|
|
1628
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
1629
|
+
if (!ok)
|
|
1630
|
+
goto out;
|
|
1631
|
+
} while (ida && ++i < ida->length);
|
|
1632
|
+
|
|
1633
|
+
out:
|
|
1634
|
+
if (ida)
|
|
1635
|
+
JS_DestroyIdArray(cx, ida);
|
|
1636
|
+
return ok;
|
|
1637
|
+
}
|
|
1638
|
+
#endif /* JS_HAS_EXPORT_IMPORT */
|
|
1639
|
+
|
|
1640
|
+
JSBool
|
|
1641
|
+
js_CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs,
|
|
1642
|
+
JSObject **objp, JSProperty **propp)
|
|
1643
|
+
{
|
|
1644
|
+
JSObject *obj2;
|
|
1645
|
+
JSProperty *prop;
|
|
1646
|
+
uintN oldAttrs, report;
|
|
1647
|
+
JSBool isFunction;
|
|
1648
|
+
jsval value;
|
|
1649
|
+
const char *type, *name;
|
|
1650
|
+
|
|
1651
|
+
if (!OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop))
|
|
1652
|
+
return JS_FALSE;
|
|
1653
|
+
if (propp) {
|
|
1654
|
+
*objp = obj2;
|
|
1655
|
+
*propp = prop;
|
|
1656
|
+
}
|
|
1657
|
+
if (!prop)
|
|
1658
|
+
return JS_TRUE;
|
|
1659
|
+
|
|
1660
|
+
/* From here, return true, or goto bad on failure to drop prop. */
|
|
1661
|
+
if (!OBJ_GET_ATTRIBUTES(cx, obj2, id, prop, &oldAttrs))
|
|
1662
|
+
goto bad;
|
|
1663
|
+
|
|
1664
|
+
/* If either property is readonly, we have an error. */
|
|
1665
|
+
report = ((oldAttrs | attrs) & JSPROP_READONLY)
|
|
1666
|
+
? JSREPORT_ERROR
|
|
1667
|
+
: JSREPORT_WARNING | JSREPORT_STRICT;
|
|
1668
|
+
|
|
1669
|
+
if (report != JSREPORT_ERROR) {
|
|
1670
|
+
/*
|
|
1671
|
+
* Allow redeclaration of variables and functions, but insist that the
|
|
1672
|
+
* new value is not a getter if the old value was, ditto for setters --
|
|
1673
|
+
* unless prop is impermanent (in which case anyone could delete it and
|
|
1674
|
+
* redefine it, willy-nilly).
|
|
1675
|
+
*/
|
|
1676
|
+
if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
|
|
1677
|
+
return JS_TRUE;
|
|
1678
|
+
if ((~(oldAttrs ^ attrs) & (JSPROP_GETTER | JSPROP_SETTER)) == 0)
|
|
1679
|
+
return JS_TRUE;
|
|
1680
|
+
if (!(oldAttrs & JSPROP_PERMANENT))
|
|
1681
|
+
return JS_TRUE;
|
|
1682
|
+
report = JSREPORT_ERROR;
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
isFunction = (oldAttrs & (JSPROP_GETTER | JSPROP_SETTER)) != 0;
|
|
1686
|
+
if (!isFunction) {
|
|
1687
|
+
if (!OBJ_GET_PROPERTY(cx, obj, id, &value))
|
|
1688
|
+
goto bad;
|
|
1689
|
+
isFunction = JSVAL_IS_FUNCTION(cx, value);
|
|
1690
|
+
}
|
|
1691
|
+
type = (oldAttrs & attrs & JSPROP_GETTER)
|
|
1692
|
+
? js_getter_str
|
|
1693
|
+
: (oldAttrs & attrs & JSPROP_SETTER)
|
|
1694
|
+
? js_setter_str
|
|
1695
|
+
: (oldAttrs & JSPROP_READONLY)
|
|
1696
|
+
? js_const_str
|
|
1697
|
+
: isFunction
|
|
1698
|
+
? js_function_str
|
|
1699
|
+
: js_var_str;
|
|
1700
|
+
name = js_AtomToPrintableString(cx, (JSAtom *)id);
|
|
1701
|
+
if (!name)
|
|
1702
|
+
goto bad;
|
|
1703
|
+
return JS_ReportErrorFlagsAndNumber(cx, report,
|
|
1704
|
+
js_GetErrorMessage, NULL,
|
|
1705
|
+
JSMSG_REDECLARED_VAR,
|
|
1706
|
+
type, name);
|
|
1707
|
+
|
|
1708
|
+
bad:
|
|
1709
|
+
if (propp) {
|
|
1710
|
+
*objp = NULL;
|
|
1711
|
+
*propp = NULL;
|
|
1712
|
+
}
|
|
1713
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
1714
|
+
return JS_FALSE;
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
#ifndef MAX_INTERP_LEVEL
|
|
1718
|
+
#if defined(XP_OS2)
|
|
1719
|
+
#define MAX_INTERP_LEVEL 250
|
|
1720
|
+
#else
|
|
1721
|
+
#define MAX_INTERP_LEVEL 1000
|
|
1722
|
+
#endif
|
|
1723
|
+
#endif
|
|
1724
|
+
|
|
1725
|
+
#define MAX_INLINE_CALL_COUNT 1000
|
|
1726
|
+
|
|
1727
|
+
JSBool
|
|
1728
|
+
js_Interpret(JSContext *cx, jsval *result)
|
|
1729
|
+
{
|
|
1730
|
+
JSRuntime *rt;
|
|
1731
|
+
JSStackFrame *fp;
|
|
1732
|
+
JSScript *script;
|
|
1733
|
+
uintN inlineCallCount;
|
|
1734
|
+
JSObject *obj, *obj2, *proto, *parent;
|
|
1735
|
+
JSVersion currentVersion, originalVersion;
|
|
1736
|
+
JSBranchCallback onbranch;
|
|
1737
|
+
JSBool ok, cond;
|
|
1738
|
+
JSTrapHandler interruptHandler;
|
|
1739
|
+
jsint depth, len;
|
|
1740
|
+
jsval *sp, *newsp;
|
|
1741
|
+
void *mark;
|
|
1742
|
+
jsbytecode *pc, *pc2, *endpc;
|
|
1743
|
+
JSOp op, op2;
|
|
1744
|
+
const JSCodeSpec *cs;
|
|
1745
|
+
JSAtom *atom;
|
|
1746
|
+
uintN argc, slot, attrs;
|
|
1747
|
+
jsval *vp, lval, rval, ltmp, rtmp;
|
|
1748
|
+
jsid id;
|
|
1749
|
+
JSObject *withobj, *origobj, *propobj;
|
|
1750
|
+
jsval iter_state;
|
|
1751
|
+
JSProperty *prop;
|
|
1752
|
+
JSScopeProperty *sprop;
|
|
1753
|
+
JSString *str, *str2;
|
|
1754
|
+
jsint i, j;
|
|
1755
|
+
jsdouble d, d2;
|
|
1756
|
+
JSClass *clasp, *funclasp;
|
|
1757
|
+
JSFunction *fun;
|
|
1758
|
+
JSType type;
|
|
1759
|
+
#ifdef DEBUG
|
|
1760
|
+
FILE *tracefp;
|
|
1761
|
+
#endif
|
|
1762
|
+
#if JS_HAS_EXPORT_IMPORT
|
|
1763
|
+
JSIdArray *ida;
|
|
1764
|
+
#endif
|
|
1765
|
+
#if JS_HAS_SWITCH_STATEMENT
|
|
1766
|
+
jsint low, high, off, npairs;
|
|
1767
|
+
JSBool match;
|
|
1768
|
+
#endif
|
|
1769
|
+
#if JS_HAS_GETTER_SETTER
|
|
1770
|
+
JSPropertyOp getter, setter;
|
|
1771
|
+
#endif
|
|
1772
|
+
int stackDummy;
|
|
1773
|
+
|
|
1774
|
+
*result = JSVAL_VOID;
|
|
1775
|
+
rt = cx->runtime;
|
|
1776
|
+
|
|
1777
|
+
/* Set registerized frame pointer and derived script pointer. */
|
|
1778
|
+
fp = cx->fp;
|
|
1779
|
+
script = fp->script;
|
|
1780
|
+
|
|
1781
|
+
/* Count of JS function calls that nest in this C js_Interpret frame. */
|
|
1782
|
+
inlineCallCount = 0;
|
|
1783
|
+
|
|
1784
|
+
/*
|
|
1785
|
+
* Optimized Get and SetVersion for proper script language versioning.
|
|
1786
|
+
*
|
|
1787
|
+
* If any native method or JSClass/JSObjectOps hook calls JS_SetVersion
|
|
1788
|
+
* and changes cx->version, the effect will "stick" and we will stop
|
|
1789
|
+
* maintaining currentVersion. This is relied upon by testsuites, for
|
|
1790
|
+
* the most part -- web browsers select version before compiling and not
|
|
1791
|
+
* at run-time.
|
|
1792
|
+
*/
|
|
1793
|
+
currentVersion = script->version;
|
|
1794
|
+
originalVersion = cx->version;
|
|
1795
|
+
if (currentVersion != originalVersion)
|
|
1796
|
+
JS_SetVersion(cx, currentVersion);
|
|
1797
|
+
|
|
1798
|
+
/*
|
|
1799
|
+
* Prepare to call a user-supplied branch handler, and abort the script
|
|
1800
|
+
* if it returns false. We reload onbranch after calling out to native
|
|
1801
|
+
* functions (but not to getters, setters, or other native hooks).
|
|
1802
|
+
*/
|
|
1803
|
+
#define LOAD_BRANCH_CALLBACK(cx) (onbranch = (cx)->branchCallback)
|
|
1804
|
+
|
|
1805
|
+
LOAD_BRANCH_CALLBACK(cx);
|
|
1806
|
+
ok = JS_TRUE;
|
|
1807
|
+
#define CHECK_BRANCH(len) \
|
|
1808
|
+
JS_BEGIN_MACRO \
|
|
1809
|
+
if (len <= 0 && onbranch) { \
|
|
1810
|
+
SAVE_SP(fp); \
|
|
1811
|
+
if (!(ok = (*onbranch)(cx, script))) \
|
|
1812
|
+
goto out; \
|
|
1813
|
+
} \
|
|
1814
|
+
JS_END_MACRO
|
|
1815
|
+
|
|
1816
|
+
/*
|
|
1817
|
+
* Load the debugger's interrupt hook here and after calling out to native
|
|
1818
|
+
* functions (but not to getters, setters, or other native hooks), so we do
|
|
1819
|
+
* not have to reload it each time through the interpreter loop -- we hope
|
|
1820
|
+
* the compiler can keep it in a register.
|
|
1821
|
+
* XXX if it spills, we still lose
|
|
1822
|
+
*/
|
|
1823
|
+
#define LOAD_INTERRUPT_HANDLER(rt) (interruptHandler = (rt)->interruptHandler)
|
|
1824
|
+
|
|
1825
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
1826
|
+
|
|
1827
|
+
pc = script->code;
|
|
1828
|
+
endpc = pc + script->length;
|
|
1829
|
+
depth = (jsint) script->depth;
|
|
1830
|
+
len = -1;
|
|
1831
|
+
|
|
1832
|
+
/* Check for too much js_Interpret nesting, or too deep a C stack. */
|
|
1833
|
+
if (++cx->interpLevel == MAX_INTERP_LEVEL ||
|
|
1834
|
+
!JS_CHECK_STACK_SIZE(cx, stackDummy)) {
|
|
1835
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_OVER_RECURSED);
|
|
1836
|
+
ok = JS_FALSE;
|
|
1837
|
+
goto out;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
/*
|
|
1841
|
+
* Allocate operand and pc stack slots for the script's worst-case depth.
|
|
1842
|
+
*/
|
|
1843
|
+
newsp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark);
|
|
1844
|
+
if (!newsp) {
|
|
1845
|
+
ok = JS_FALSE;
|
|
1846
|
+
goto out;
|
|
1847
|
+
}
|
|
1848
|
+
sp = newsp + depth;
|
|
1849
|
+
fp->spbase = sp;
|
|
1850
|
+
SAVE_SP(fp);
|
|
1851
|
+
|
|
1852
|
+
while (pc < endpc) {
|
|
1853
|
+
fp->pc = pc;
|
|
1854
|
+
op = (JSOp) *pc;
|
|
1855
|
+
do_op:
|
|
1856
|
+
cs = &js_CodeSpec[op];
|
|
1857
|
+
len = cs->length;
|
|
1858
|
+
|
|
1859
|
+
#ifdef DEBUG
|
|
1860
|
+
tracefp = (FILE *) cx->tracefp;
|
|
1861
|
+
if (tracefp) {
|
|
1862
|
+
intN nuses, n;
|
|
1863
|
+
|
|
1864
|
+
fprintf(tracefp, "%4u: ", js_PCToLineNumber(cx, script, pc));
|
|
1865
|
+
js_Disassemble1(cx, script, pc,
|
|
1866
|
+
PTRDIFF(pc, script->code, jsbytecode), JS_FALSE,
|
|
1867
|
+
tracefp);
|
|
1868
|
+
nuses = cs->nuses;
|
|
1869
|
+
if (nuses) {
|
|
1870
|
+
SAVE_SP(fp);
|
|
1871
|
+
for (n = -nuses; n < 0; n++) {
|
|
1872
|
+
str = js_DecompileValueGenerator(cx, n, sp[n], NULL);
|
|
1873
|
+
if (str != NULL) {
|
|
1874
|
+
fprintf(tracefp, "%s %s",
|
|
1875
|
+
(n == -nuses) ? " inputs:" : ",",
|
|
1876
|
+
JS_GetStringBytes(str));
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
fprintf(tracefp, " @ %d\n", sp - fp->spbase);
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
#endif
|
|
1883
|
+
|
|
1884
|
+
if (interruptHandler) {
|
|
1885
|
+
SAVE_SP(fp);
|
|
1886
|
+
switch (interruptHandler(cx, script, pc, &rval,
|
|
1887
|
+
rt->interruptHandlerData)) {
|
|
1888
|
+
case JSTRAP_ERROR:
|
|
1889
|
+
ok = JS_FALSE;
|
|
1890
|
+
goto out;
|
|
1891
|
+
case JSTRAP_CONTINUE:
|
|
1892
|
+
break;
|
|
1893
|
+
case JSTRAP_RETURN:
|
|
1894
|
+
fp->rval = rval;
|
|
1895
|
+
goto out;
|
|
1896
|
+
#if JS_HAS_EXCEPTIONS
|
|
1897
|
+
case JSTRAP_THROW:
|
|
1898
|
+
cx->throwing = JS_TRUE;
|
|
1899
|
+
cx->exception = rval;
|
|
1900
|
+
ok = JS_FALSE;
|
|
1901
|
+
goto out;
|
|
1902
|
+
#endif /* JS_HAS_EXCEPTIONS */
|
|
1903
|
+
default:;
|
|
1904
|
+
}
|
|
1905
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
switch (op) {
|
|
1909
|
+
case JSOP_NOP:
|
|
1910
|
+
break;
|
|
1911
|
+
|
|
1912
|
+
case JSOP_GROUP:
|
|
1913
|
+
obj = NULL;
|
|
1914
|
+
break;
|
|
1915
|
+
|
|
1916
|
+
case JSOP_PUSH:
|
|
1917
|
+
PUSH_OPND(JSVAL_VOID);
|
|
1918
|
+
break;
|
|
1919
|
+
|
|
1920
|
+
case JSOP_POP:
|
|
1921
|
+
sp--;
|
|
1922
|
+
break;
|
|
1923
|
+
|
|
1924
|
+
case JSOP_POP2:
|
|
1925
|
+
sp -= 2;
|
|
1926
|
+
break;
|
|
1927
|
+
|
|
1928
|
+
case JSOP_SWAP:
|
|
1929
|
+
/*
|
|
1930
|
+
* N.B. JSOP_SWAP doesn't swap the corresponding generating pcs
|
|
1931
|
+
* for the operands it swaps.
|
|
1932
|
+
*/
|
|
1933
|
+
ltmp = sp[-1];
|
|
1934
|
+
sp[-1] = sp[-2];
|
|
1935
|
+
sp[-2] = ltmp;
|
|
1936
|
+
break;
|
|
1937
|
+
|
|
1938
|
+
case JSOP_POPV:
|
|
1939
|
+
*result = POP_OPND();
|
|
1940
|
+
break;
|
|
1941
|
+
|
|
1942
|
+
case JSOP_ENTERWITH:
|
|
1943
|
+
rval = FETCH_OPND(-1);
|
|
1944
|
+
VALUE_TO_OBJECT(cx, rval, obj);
|
|
1945
|
+
withobj = js_NewObject(cx, &js_WithClass, obj, fp->scopeChain);
|
|
1946
|
+
if (!withobj)
|
|
1947
|
+
goto out;
|
|
1948
|
+
fp->scopeChain = withobj;
|
|
1949
|
+
STORE_OPND(-1, OBJECT_TO_JSVAL(withobj));
|
|
1950
|
+
break;
|
|
1951
|
+
|
|
1952
|
+
case JSOP_LEAVEWITH:
|
|
1953
|
+
rval = POP_OPND();
|
|
1954
|
+
JS_ASSERT(JSVAL_IS_OBJECT(rval));
|
|
1955
|
+
withobj = JSVAL_TO_OBJECT(rval);
|
|
1956
|
+
JS_ASSERT(OBJ_GET_CLASS(cx, withobj) == &js_WithClass);
|
|
1957
|
+
|
|
1958
|
+
rval = OBJ_GET_SLOT(cx, withobj, JSSLOT_PARENT);
|
|
1959
|
+
JS_ASSERT(JSVAL_IS_OBJECT(rval));
|
|
1960
|
+
fp->scopeChain = JSVAL_TO_OBJECT(rval);
|
|
1961
|
+
break;
|
|
1962
|
+
|
|
1963
|
+
case JSOP_SETRVAL:
|
|
1964
|
+
fp->rval = POP_OPND();
|
|
1965
|
+
break;
|
|
1966
|
+
|
|
1967
|
+
case JSOP_RETURN:
|
|
1968
|
+
CHECK_BRANCH(-1);
|
|
1969
|
+
fp->rval = POP_OPND();
|
|
1970
|
+
/* FALL THROUGH */
|
|
1971
|
+
|
|
1972
|
+
case JSOP_RETRVAL: /* fp->rval already set */
|
|
1973
|
+
if (inlineCallCount)
|
|
1974
|
+
inline_return:
|
|
1975
|
+
{
|
|
1976
|
+
JSInlineFrame *ifp = (JSInlineFrame *) fp;
|
|
1977
|
+
void *hookData = ifp->hookData;
|
|
1978
|
+
|
|
1979
|
+
if (hookData) {
|
|
1980
|
+
JSInterpreterHook hook = cx->runtime->callHook;
|
|
1981
|
+
if (hook) {
|
|
1982
|
+
hook(cx, fp, JS_FALSE, &ok, hookData);
|
|
1983
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
#if JS_HAS_ARGS_OBJECT
|
|
1987
|
+
if (fp->argsobj)
|
|
1988
|
+
ok &= js_PutArgsObject(cx, fp);
|
|
1989
|
+
#endif
|
|
1990
|
+
|
|
1991
|
+
/* Restore context version only if callee hasn't set version. */
|
|
1992
|
+
if (cx->version == currentVersion) {
|
|
1993
|
+
currentVersion = ifp->callerVersion;
|
|
1994
|
+
if (currentVersion != cx->version)
|
|
1995
|
+
JS_SetVersion(cx, currentVersion);
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
/* Store the return value in the caller's operand frame. */
|
|
1999
|
+
vp = fp->argv - 2;
|
|
2000
|
+
*vp = fp->rval;
|
|
2001
|
+
|
|
2002
|
+
/* Restore cx->fp and release the inline frame's space. */
|
|
2003
|
+
cx->fp = fp = fp->down;
|
|
2004
|
+
JS_ARENA_RELEASE(&cx->stackPool, ifp->mark);
|
|
2005
|
+
|
|
2006
|
+
/* Restore sp to point just above the return value. */
|
|
2007
|
+
fp->sp = vp + 1;
|
|
2008
|
+
RESTORE_SP(fp);
|
|
2009
|
+
|
|
2010
|
+
/* Restore the calling script's interpreter registers. */
|
|
2011
|
+
script = fp->script;
|
|
2012
|
+
depth = (jsint) script->depth;
|
|
2013
|
+
pc = fp->pc;
|
|
2014
|
+
endpc = script->code + script->length;
|
|
2015
|
+
|
|
2016
|
+
/* Store the generating pc for the return value. */
|
|
2017
|
+
vp[-depth] = (jsval)pc;
|
|
2018
|
+
|
|
2019
|
+
/* Set remaining variables for 'goto advance_pc'. */
|
|
2020
|
+
op = (JSOp) *pc;
|
|
2021
|
+
cs = &js_CodeSpec[op];
|
|
2022
|
+
len = cs->length;
|
|
2023
|
+
|
|
2024
|
+
/* Resume execution in the calling frame. */
|
|
2025
|
+
inlineCallCount--;
|
|
2026
|
+
if (ok)
|
|
2027
|
+
goto advance_pc;
|
|
2028
|
+
}
|
|
2029
|
+
goto out;
|
|
2030
|
+
|
|
2031
|
+
#if JS_HAS_SWITCH_STATEMENT
|
|
2032
|
+
case JSOP_DEFAULT:
|
|
2033
|
+
(void) POP();
|
|
2034
|
+
/* FALL THROUGH */
|
|
2035
|
+
#endif
|
|
2036
|
+
case JSOP_GOTO:
|
|
2037
|
+
len = GET_JUMP_OFFSET(pc);
|
|
2038
|
+
CHECK_BRANCH(len);
|
|
2039
|
+
break;
|
|
2040
|
+
|
|
2041
|
+
case JSOP_IFEQ:
|
|
2042
|
+
POP_BOOLEAN(cx, rval, cond);
|
|
2043
|
+
if (cond == JS_FALSE) {
|
|
2044
|
+
len = GET_JUMP_OFFSET(pc);
|
|
2045
|
+
CHECK_BRANCH(len);
|
|
2046
|
+
}
|
|
2047
|
+
break;
|
|
2048
|
+
|
|
2049
|
+
case JSOP_IFNE:
|
|
2050
|
+
POP_BOOLEAN(cx, rval, cond);
|
|
2051
|
+
if (cond != JS_FALSE) {
|
|
2052
|
+
len = GET_JUMP_OFFSET(pc);
|
|
2053
|
+
CHECK_BRANCH(len);
|
|
2054
|
+
}
|
|
2055
|
+
break;
|
|
2056
|
+
|
|
2057
|
+
case JSOP_OR:
|
|
2058
|
+
POP_BOOLEAN(cx, rval, cond);
|
|
2059
|
+
if (cond == JS_TRUE) {
|
|
2060
|
+
len = GET_JUMP_OFFSET(pc);
|
|
2061
|
+
PUSH_OPND(rval);
|
|
2062
|
+
}
|
|
2063
|
+
break;
|
|
2064
|
+
|
|
2065
|
+
case JSOP_AND:
|
|
2066
|
+
POP_BOOLEAN(cx, rval, cond);
|
|
2067
|
+
if (cond == JS_FALSE) {
|
|
2068
|
+
len = GET_JUMP_OFFSET(pc);
|
|
2069
|
+
PUSH_OPND(rval);
|
|
2070
|
+
}
|
|
2071
|
+
break;
|
|
2072
|
+
|
|
2073
|
+
|
|
2074
|
+
#if JS_HAS_SWITCH_STATEMENT
|
|
2075
|
+
case JSOP_DEFAULTX:
|
|
2076
|
+
(void) POP();
|
|
2077
|
+
/* FALL THROUGH */
|
|
2078
|
+
#endif
|
|
2079
|
+
case JSOP_GOTOX:
|
|
2080
|
+
len = GET_JUMPX_OFFSET(pc);
|
|
2081
|
+
CHECK_BRANCH(len);
|
|
2082
|
+
break;
|
|
2083
|
+
|
|
2084
|
+
case JSOP_IFEQX:
|
|
2085
|
+
POP_BOOLEAN(cx, rval, cond);
|
|
2086
|
+
if (cond == JS_FALSE) {
|
|
2087
|
+
len = GET_JUMPX_OFFSET(pc);
|
|
2088
|
+
CHECK_BRANCH(len);
|
|
2089
|
+
}
|
|
2090
|
+
break;
|
|
2091
|
+
|
|
2092
|
+
case JSOP_IFNEX:
|
|
2093
|
+
POP_BOOLEAN(cx, rval, cond);
|
|
2094
|
+
if (cond != JS_FALSE) {
|
|
2095
|
+
len = GET_JUMPX_OFFSET(pc);
|
|
2096
|
+
CHECK_BRANCH(len);
|
|
2097
|
+
}
|
|
2098
|
+
break;
|
|
2099
|
+
|
|
2100
|
+
case JSOP_ORX:
|
|
2101
|
+
POP_BOOLEAN(cx, rval, cond);
|
|
2102
|
+
if (cond == JS_TRUE) {
|
|
2103
|
+
len = GET_JUMPX_OFFSET(pc);
|
|
2104
|
+
PUSH_OPND(rval);
|
|
2105
|
+
}
|
|
2106
|
+
break;
|
|
2107
|
+
|
|
2108
|
+
case JSOP_ANDX:
|
|
2109
|
+
POP_BOOLEAN(cx, rval, cond);
|
|
2110
|
+
if (cond == JS_FALSE) {
|
|
2111
|
+
len = GET_JUMPX_OFFSET(pc);
|
|
2112
|
+
PUSH_OPND(rval);
|
|
2113
|
+
}
|
|
2114
|
+
break;
|
|
2115
|
+
|
|
2116
|
+
case JSOP_TOOBJECT:
|
|
2117
|
+
SAVE_SP(fp);
|
|
2118
|
+
ok = js_ValueToObject(cx, FETCH_OPND(-1), &obj);
|
|
2119
|
+
if (!ok)
|
|
2120
|
+
goto out;
|
|
2121
|
+
STORE_OPND(-1, OBJECT_TO_JSVAL(obj));
|
|
2122
|
+
break;
|
|
2123
|
+
|
|
2124
|
+
#define FETCH_ELEMENT_ID(n, id) \
|
|
2125
|
+
JS_BEGIN_MACRO \
|
|
2126
|
+
/* If the index is not a jsint, atomize it. */ \
|
|
2127
|
+
id = (jsid) FETCH_OPND(n); \
|
|
2128
|
+
if (JSVAL_IS_INT(id)) { \
|
|
2129
|
+
atom = NULL; \
|
|
2130
|
+
} else { \
|
|
2131
|
+
SAVE_SP(fp); \
|
|
2132
|
+
atom = js_ValueToStringAtom(cx, (jsval)id); \
|
|
2133
|
+
if (!atom) { \
|
|
2134
|
+
ok = JS_FALSE; \
|
|
2135
|
+
goto out; \
|
|
2136
|
+
} \
|
|
2137
|
+
id = (jsid)atom; \
|
|
2138
|
+
} \
|
|
2139
|
+
JS_END_MACRO
|
|
2140
|
+
|
|
2141
|
+
#define POP_ELEMENT_ID(id) \
|
|
2142
|
+
JS_BEGIN_MACRO \
|
|
2143
|
+
FETCH_ELEMENT_ID(-1, id); \
|
|
2144
|
+
sp--; \
|
|
2145
|
+
JS_END_MACRO
|
|
2146
|
+
|
|
2147
|
+
#if JS_HAS_IN_OPERATOR
|
|
2148
|
+
case JSOP_IN:
|
|
2149
|
+
rval = FETCH_OPND(-1);
|
|
2150
|
+
if (JSVAL_IS_PRIMITIVE(rval)) {
|
|
2151
|
+
str = js_DecompileValueGenerator(cx, -1, rval, NULL);
|
|
2152
|
+
if (str) {
|
|
2153
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
2154
|
+
JSMSG_IN_NOT_OBJECT,
|
|
2155
|
+
JS_GetStringBytes(str));
|
|
2156
|
+
}
|
|
2157
|
+
ok = JS_FALSE;
|
|
2158
|
+
goto out;
|
|
2159
|
+
}
|
|
2160
|
+
sp--;
|
|
2161
|
+
obj = JSVAL_TO_OBJECT(rval);
|
|
2162
|
+
FETCH_ELEMENT_ID(-1, id);
|
|
2163
|
+
ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
|
|
2164
|
+
if (!ok)
|
|
2165
|
+
goto out;
|
|
2166
|
+
STORE_OPND(-1, BOOLEAN_TO_JSVAL(prop != NULL));
|
|
2167
|
+
if (prop)
|
|
2168
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
2169
|
+
break;
|
|
2170
|
+
#endif /* JS_HAS_IN_OPERATOR */
|
|
2171
|
+
|
|
2172
|
+
case JSOP_FORPROP:
|
|
2173
|
+
/*
|
|
2174
|
+
* Handle JSOP_FORPROP first, so the cost of the goto do_forinloop
|
|
2175
|
+
* is not paid for the more common cases.
|
|
2176
|
+
*/
|
|
2177
|
+
lval = FETCH_OPND(-1);
|
|
2178
|
+
atom = GET_ATOM(cx, script, pc);
|
|
2179
|
+
id = (jsid)atom;
|
|
2180
|
+
i = -2;
|
|
2181
|
+
goto do_forinloop;
|
|
2182
|
+
|
|
2183
|
+
case JSOP_FORNAME:
|
|
2184
|
+
atom = GET_ATOM(cx, script, pc);
|
|
2185
|
+
id = (jsid)atom;
|
|
2186
|
+
|
|
2187
|
+
/*
|
|
2188
|
+
* ECMA 12.6.3 says to eval the LHS after looking for properties
|
|
2189
|
+
* to enumerate, and bail without LHS eval if there are no props.
|
|
2190
|
+
* We do Find here to share the most code at label do_forinloop.
|
|
2191
|
+
* If looking for enumerable properties could have side effects,
|
|
2192
|
+
* then we'd have to move this into the common code and condition
|
|
2193
|
+
* it on op == JSOP_FORNAME.
|
|
2194
|
+
*/
|
|
2195
|
+
SAVE_SP(fp);
|
|
2196
|
+
ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
|
|
2197
|
+
if (!ok)
|
|
2198
|
+
goto out;
|
|
2199
|
+
if (prop)
|
|
2200
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
2201
|
+
lval = OBJECT_TO_JSVAL(obj);
|
|
2202
|
+
/* FALL THROUGH */
|
|
2203
|
+
|
|
2204
|
+
case JSOP_FORARG:
|
|
2205
|
+
case JSOP_FORVAR:
|
|
2206
|
+
/*
|
|
2207
|
+
* JSOP_FORARG and JSOP_FORVAR don't require any lval computation
|
|
2208
|
+
* here, because they address slots on the stack (in fp->args and
|
|
2209
|
+
* fp->vars, respectively).
|
|
2210
|
+
*/
|
|
2211
|
+
/* FALL THROUGH */
|
|
2212
|
+
|
|
2213
|
+
case JSOP_FORELEM:
|
|
2214
|
+
/*
|
|
2215
|
+
* JSOP_FORELEM simply initializes or updates the iteration state
|
|
2216
|
+
* and leaves the index expression evaluation and assignment to the
|
|
2217
|
+
* enumerator until after the next property has been acquired, via
|
|
2218
|
+
* a JSOP_ENUMELEM bytecode.
|
|
2219
|
+
*/
|
|
2220
|
+
i = -1;
|
|
2221
|
+
|
|
2222
|
+
do_forinloop:
|
|
2223
|
+
/*
|
|
2224
|
+
* ECMA-compatible for/in evals the object just once, before loop.
|
|
2225
|
+
* Bad old bytecodes (since removed) did it on every iteration.
|
|
2226
|
+
*/
|
|
2227
|
+
obj = JSVAL_TO_OBJECT(sp[i]);
|
|
2228
|
+
|
|
2229
|
+
/* If the thing to the right of 'in' has no properties, break. */
|
|
2230
|
+
if (!obj) {
|
|
2231
|
+
rval = JSVAL_FALSE;
|
|
2232
|
+
goto end_forinloop;
|
|
2233
|
+
}
|
|
2234
|
+
|
|
2235
|
+
/*
|
|
2236
|
+
* Save the thing to the right of 'in' as origobj. Later on, we
|
|
2237
|
+
* use this variable to suppress enumeration of shadowed prototype
|
|
2238
|
+
* properties.
|
|
2239
|
+
*/
|
|
2240
|
+
origobj = obj;
|
|
2241
|
+
|
|
2242
|
+
/*
|
|
2243
|
+
* Reach under the top of stack to find our property iterator, a
|
|
2244
|
+
* JSObject that contains the iteration state. (An object is used
|
|
2245
|
+
* rather than a native struct so that the iteration state is
|
|
2246
|
+
* cleaned up via GC if the for-in loop terminates abruptly.)
|
|
2247
|
+
*/
|
|
2248
|
+
vp = &sp[i - 1];
|
|
2249
|
+
rval = *vp;
|
|
2250
|
+
|
|
2251
|
+
/* Is this the first iteration ? */
|
|
2252
|
+
if (JSVAL_IS_VOID(rval)) {
|
|
2253
|
+
/* Yes, create a new JSObject to hold the iterator state */
|
|
2254
|
+
propobj = js_NewObject(cx, &prop_iterator_class, NULL, obj);
|
|
2255
|
+
if (!propobj) {
|
|
2256
|
+
ok = JS_FALSE;
|
|
2257
|
+
goto out;
|
|
2258
|
+
}
|
|
2259
|
+
propobj->slots[JSSLOT_ITER_STATE] = JSVAL_NULL;
|
|
2260
|
+
|
|
2261
|
+
/*
|
|
2262
|
+
* Root the parent slot so we can get it even in our finalizer
|
|
2263
|
+
* (otherwise, it would live as long as we do, but it might be
|
|
2264
|
+
* finalized first).
|
|
2265
|
+
*/
|
|
2266
|
+
ok = js_AddRoot(cx, &propobj->slots[JSSLOT_PARENT],
|
|
2267
|
+
"propobj->parent");
|
|
2268
|
+
if (!ok)
|
|
2269
|
+
goto out;
|
|
2270
|
+
|
|
2271
|
+
/*
|
|
2272
|
+
* Rewrite the iterator so we know to do the next case.
|
|
2273
|
+
* Do this before calling the enumerator, which could
|
|
2274
|
+
* displace cx->newborn and cause GC.
|
|
2275
|
+
*/
|
|
2276
|
+
*vp = OBJECT_TO_JSVAL(propobj);
|
|
2277
|
+
|
|
2278
|
+
ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, 0);
|
|
2279
|
+
|
|
2280
|
+
/*
|
|
2281
|
+
* Stash private iteration state into property iterator object.
|
|
2282
|
+
* We do this before checking 'ok' to ensure that propobj is
|
|
2283
|
+
* in a valid state even if OBJ_ENUMERATE returned JS_FALSE.
|
|
2284
|
+
* NB: This code knows that the first slots are pre-allocated.
|
|
2285
|
+
*/
|
|
2286
|
+
#if JS_INITIAL_NSLOTS < 5
|
|
2287
|
+
#error JS_INITIAL_NSLOTS must be greater than or equal to 5.
|
|
2288
|
+
#endif
|
|
2289
|
+
propobj->slots[JSSLOT_ITER_STATE] = iter_state;
|
|
2290
|
+
if (!ok)
|
|
2291
|
+
goto out;
|
|
2292
|
+
} else {
|
|
2293
|
+
/* This is not the first iteration. Recover iterator state. */
|
|
2294
|
+
propobj = JSVAL_TO_OBJECT(rval);
|
|
2295
|
+
JS_ASSERT(OBJ_GET_CLASS(cx, propobj) == &prop_iterator_class);
|
|
2296
|
+
obj = JSVAL_TO_OBJECT(propobj->slots[JSSLOT_PARENT]);
|
|
2297
|
+
iter_state = propobj->slots[JSSLOT_ITER_STATE];
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
enum_next_property:
|
|
2301
|
+
/* Get the next jsid to be enumerated and store it in rval. */
|
|
2302
|
+
OBJ_ENUMERATE(cx, obj, JSENUMERATE_NEXT, &iter_state, &rval);
|
|
2303
|
+
propobj->slots[JSSLOT_ITER_STATE] = iter_state;
|
|
2304
|
+
|
|
2305
|
+
/* No more jsids to iterate in obj? */
|
|
2306
|
+
if (iter_state == JSVAL_NULL) {
|
|
2307
|
+
/* Enumerate the properties on obj's prototype chain. */
|
|
2308
|
+
obj = OBJ_GET_PROTO(cx, obj);
|
|
2309
|
+
if (!obj) {
|
|
2310
|
+
/* End of property list -- terminate loop. */
|
|
2311
|
+
rval = JSVAL_FALSE;
|
|
2312
|
+
goto end_forinloop;
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
ok = OBJ_ENUMERATE(cx, obj, JSENUMERATE_INIT, &iter_state, 0);
|
|
2316
|
+
|
|
2317
|
+
/*
|
|
2318
|
+
* Stash private iteration state into property iterator object.
|
|
2319
|
+
* We do this before checking 'ok' to ensure that propobj is
|
|
2320
|
+
* in a valid state even if OBJ_ENUMERATE returned JS_FALSE.
|
|
2321
|
+
* NB: This code knows that the first slots are pre-allocated.
|
|
2322
|
+
*/
|
|
2323
|
+
propobj->slots[JSSLOT_ITER_STATE] = iter_state;
|
|
2324
|
+
if (!ok)
|
|
2325
|
+
goto out;
|
|
2326
|
+
|
|
2327
|
+
/*
|
|
2328
|
+
* Update the iterator JSObject's parent link to refer to the
|
|
2329
|
+
* current object. This is used in the iterator JSObject's
|
|
2330
|
+
* finalizer.
|
|
2331
|
+
*/
|
|
2332
|
+
propobj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(obj);
|
|
2333
|
+
goto enum_next_property;
|
|
2334
|
+
}
|
|
2335
|
+
|
|
2336
|
+
/* Skip properties not owned by obj, and leave next id in rval. */
|
|
2337
|
+
ok = OBJ_LOOKUP_PROPERTY(cx, origobj, rval, &obj2, &prop);
|
|
2338
|
+
if (!ok)
|
|
2339
|
+
goto out;
|
|
2340
|
+
if (prop) {
|
|
2341
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
2342
|
+
|
|
2343
|
+
/* Yes, don't enumerate again. Go to the next property. */
|
|
2344
|
+
if (obj2 != obj)
|
|
2345
|
+
goto enum_next_property;
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
/* Make sure rval is a string for uniformity and compatibility. */
|
|
2349
|
+
if (!JSVAL_IS_INT(rval)) {
|
|
2350
|
+
rval = ATOM_KEY((JSAtom *)rval);
|
|
2351
|
+
} else if (cx->version != JSVERSION_1_2) {
|
|
2352
|
+
str = js_NumberToString(cx, (jsdouble) JSVAL_TO_INT(rval));
|
|
2353
|
+
if (!str) {
|
|
2354
|
+
ok = JS_FALSE;
|
|
2355
|
+
goto out;
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
rval = STRING_TO_JSVAL(str);
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
switch (op) {
|
|
2362
|
+
case JSOP_FORARG:
|
|
2363
|
+
slot = GET_ARGNO(pc);
|
|
2364
|
+
JS_ASSERT(slot < fp->fun->nargs);
|
|
2365
|
+
fp->argv[slot] = rval;
|
|
2366
|
+
break;
|
|
2367
|
+
|
|
2368
|
+
case JSOP_FORVAR:
|
|
2369
|
+
slot = GET_VARNO(pc);
|
|
2370
|
+
JS_ASSERT(slot < fp->fun->nvars);
|
|
2371
|
+
fp->vars[slot] = rval;
|
|
2372
|
+
break;
|
|
2373
|
+
|
|
2374
|
+
case JSOP_FORELEM:
|
|
2375
|
+
/* FORELEM is not a SET operation, it's more like BINDNAME. */
|
|
2376
|
+
PUSH_OPND(rval);
|
|
2377
|
+
break;
|
|
2378
|
+
|
|
2379
|
+
default:
|
|
2380
|
+
/* Convert lval to a non-null object containing id. */
|
|
2381
|
+
VALUE_TO_OBJECT(cx, lval, obj);
|
|
2382
|
+
|
|
2383
|
+
/* Set the variable obj[id] to refer to rval. */
|
|
2384
|
+
fp->flags |= JSFRAME_ASSIGNING;
|
|
2385
|
+
ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
|
|
2386
|
+
fp->flags &= ~JSFRAME_ASSIGNING;
|
|
2387
|
+
if (!ok)
|
|
2388
|
+
goto out;
|
|
2389
|
+
break;
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
/* Push true to keep looping through properties. */
|
|
2393
|
+
rval = JSVAL_TRUE;
|
|
2394
|
+
|
|
2395
|
+
end_forinloop:
|
|
2396
|
+
sp += i + 1;
|
|
2397
|
+
PUSH_OPND(rval);
|
|
2398
|
+
break;
|
|
2399
|
+
|
|
2400
|
+
case JSOP_DUP:
|
|
2401
|
+
JS_ASSERT(sp > fp->spbase);
|
|
2402
|
+
rval = sp[-1];
|
|
2403
|
+
PUSH_OPND(rval);
|
|
2404
|
+
break;
|
|
2405
|
+
|
|
2406
|
+
case JSOP_DUP2:
|
|
2407
|
+
JS_ASSERT(sp - 1 > fp->spbase);
|
|
2408
|
+
lval = FETCH_OPND(-2);
|
|
2409
|
+
rval = FETCH_OPND(-1);
|
|
2410
|
+
PUSH_OPND(lval);
|
|
2411
|
+
PUSH_OPND(rval);
|
|
2412
|
+
break;
|
|
2413
|
+
|
|
2414
|
+
#define PROPERTY_OP(n, call) \
|
|
2415
|
+
JS_BEGIN_MACRO \
|
|
2416
|
+
/* Pop the left part and resolve it to a non-null object. */ \
|
|
2417
|
+
lval = FETCH_OPND(n); \
|
|
2418
|
+
VALUE_TO_OBJECT(cx, lval, obj); \
|
|
2419
|
+
\
|
|
2420
|
+
/* Get or set the property, set ok false if error, true if success. */\
|
|
2421
|
+
SAVE_SP(fp); \
|
|
2422
|
+
call; \
|
|
2423
|
+
if (!ok) \
|
|
2424
|
+
goto out; \
|
|
2425
|
+
JS_END_MACRO
|
|
2426
|
+
|
|
2427
|
+
#define ELEMENT_OP(n, call) \
|
|
2428
|
+
JS_BEGIN_MACRO \
|
|
2429
|
+
FETCH_ELEMENT_ID(n, id); \
|
|
2430
|
+
PROPERTY_OP(n-1, call); \
|
|
2431
|
+
JS_END_MACRO
|
|
2432
|
+
|
|
2433
|
+
/*
|
|
2434
|
+
* Direct callers, i.e. those who do not wrap CACHED_GET and CACHED_SET calls
|
|
2435
|
+
* in PROPERTY_OP or ELEMENT_OP macro calls must SAVE_SP(fp); beforehand, just
|
|
2436
|
+
* in case a getter or setter function is invoked.
|
|
2437
|
+
*/
|
|
2438
|
+
#define CACHED_GET(call) \
|
|
2439
|
+
JS_BEGIN_MACRO \
|
|
2440
|
+
if (!OBJ_IS_NATIVE(obj)) { \
|
|
2441
|
+
ok = call; \
|
|
2442
|
+
} else { \
|
|
2443
|
+
JS_LOCK_OBJ(cx, obj); \
|
|
2444
|
+
PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop); \
|
|
2445
|
+
if (sprop) { \
|
|
2446
|
+
JSScope *scope_ = OBJ_SCOPE(obj); \
|
|
2447
|
+
slot = (uintN)sprop->slot; \
|
|
2448
|
+
rval = (slot != SPROP_INVALID_SLOT) \
|
|
2449
|
+
? LOCKED_OBJ_GET_SLOT(obj, slot) \
|
|
2450
|
+
: JSVAL_VOID; \
|
|
2451
|
+
JS_UNLOCK_SCOPE(cx, scope_); \
|
|
2452
|
+
ok = SPROP_GET(cx, sprop, obj, obj, &rval); \
|
|
2453
|
+
JS_LOCK_SCOPE(cx, scope_); \
|
|
2454
|
+
if (ok && SPROP_HAS_VALID_SLOT(sprop, scope_)) \
|
|
2455
|
+
LOCKED_OBJ_SET_SLOT(obj, slot, rval); \
|
|
2456
|
+
JS_UNLOCK_SCOPE(cx, scope_); \
|
|
2457
|
+
} else { \
|
|
2458
|
+
JS_UNLOCK_OBJ(cx, obj); \
|
|
2459
|
+
ok = call; \
|
|
2460
|
+
/* No fill here: js_GetProperty fills the cache. */ \
|
|
2461
|
+
} \
|
|
2462
|
+
} \
|
|
2463
|
+
JS_END_MACRO
|
|
2464
|
+
|
|
2465
|
+
#define CACHED_SET(call) \
|
|
2466
|
+
JS_BEGIN_MACRO \
|
|
2467
|
+
if (!OBJ_IS_NATIVE(obj)) { \
|
|
2468
|
+
ok = call; \
|
|
2469
|
+
} else { \
|
|
2470
|
+
JSScope *scope_; \
|
|
2471
|
+
JS_LOCK_OBJ(cx, obj); \
|
|
2472
|
+
PROPERTY_CACHE_TEST(&rt->propertyCache, obj, id, sprop); \
|
|
2473
|
+
if (sprop && \
|
|
2474
|
+
!(sprop->attrs & JSPROP_READONLY) && \
|
|
2475
|
+
(scope_ = OBJ_SCOPE(obj), !SCOPE_IS_SEALED(scope_))) { \
|
|
2476
|
+
JS_UNLOCK_SCOPE(cx, scope_); \
|
|
2477
|
+
ok = SPROP_SET(cx, sprop, obj, obj, &rval); \
|
|
2478
|
+
JS_LOCK_SCOPE(cx, scope_); \
|
|
2479
|
+
if (ok && SPROP_HAS_VALID_SLOT(sprop, scope_)) { \
|
|
2480
|
+
LOCKED_OBJ_SET_SLOT(obj, sprop->slot, rval); \
|
|
2481
|
+
GC_POKE(cx, JSVAL_NULL); /* XXX second arg ignored */ \
|
|
2482
|
+
} \
|
|
2483
|
+
JS_UNLOCK_SCOPE(cx, scope_); \
|
|
2484
|
+
} else { \
|
|
2485
|
+
JS_UNLOCK_OBJ(cx, obj); \
|
|
2486
|
+
ok = call; \
|
|
2487
|
+
/* No fill here: js_SetProperty writes through the cache. */ \
|
|
2488
|
+
} \
|
|
2489
|
+
} \
|
|
2490
|
+
JS_END_MACRO
|
|
2491
|
+
|
|
2492
|
+
case JSOP_SETCONST:
|
|
2493
|
+
obj = fp->varobj;
|
|
2494
|
+
atom = GET_ATOM(cx, script, pc);
|
|
2495
|
+
rval = FETCH_OPND(-1);
|
|
2496
|
+
ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, rval, NULL, NULL,
|
|
2497
|
+
JSPROP_ENUMERATE | JSPROP_PERMANENT |
|
|
2498
|
+
JSPROP_READONLY,
|
|
2499
|
+
NULL);
|
|
2500
|
+
if (!ok)
|
|
2501
|
+
goto out;
|
|
2502
|
+
STORE_OPND(-1, rval);
|
|
2503
|
+
break;
|
|
2504
|
+
|
|
2505
|
+
case JSOP_BINDNAME:
|
|
2506
|
+
atom = GET_ATOM(cx, script, pc);
|
|
2507
|
+
SAVE_SP(fp);
|
|
2508
|
+
obj = js_FindIdentifierBase(cx, (jsid)atom);
|
|
2509
|
+
if (!obj) {
|
|
2510
|
+
ok = JS_FALSE;
|
|
2511
|
+
goto out;
|
|
2512
|
+
}
|
|
2513
|
+
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
|
2514
|
+
break;
|
|
2515
|
+
|
|
2516
|
+
case JSOP_SETNAME:
|
|
2517
|
+
atom = GET_ATOM(cx, script, pc);
|
|
2518
|
+
id = (jsid)atom;
|
|
2519
|
+
rval = FETCH_OPND(-1);
|
|
2520
|
+
lval = FETCH_OPND(-2);
|
|
2521
|
+
JS_ASSERT(!JSVAL_IS_PRIMITIVE(lval));
|
|
2522
|
+
obj = JSVAL_TO_OBJECT(lval);
|
|
2523
|
+
SAVE_SP(fp);
|
|
2524
|
+
CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
|
|
2525
|
+
if (!ok)
|
|
2526
|
+
goto out;
|
|
2527
|
+
sp--;
|
|
2528
|
+
STORE_OPND(-1, rval);
|
|
2529
|
+
break;
|
|
2530
|
+
|
|
2531
|
+
#define INTEGER_OP(OP, EXTRA_CODE) \
|
|
2532
|
+
JS_BEGIN_MACRO \
|
|
2533
|
+
FETCH_INT(cx, -1, j); \
|
|
2534
|
+
FETCH_INT(cx, -2, i); \
|
|
2535
|
+
if (!ok) \
|
|
2536
|
+
goto out; \
|
|
2537
|
+
EXTRA_CODE \
|
|
2538
|
+
d = i OP j; \
|
|
2539
|
+
sp--; \
|
|
2540
|
+
STORE_NUMBER(cx, -1, d); \
|
|
2541
|
+
JS_END_MACRO
|
|
2542
|
+
|
|
2543
|
+
#define BITWISE_OP(OP) INTEGER_OP(OP, (void) 0;)
|
|
2544
|
+
#define SIGNED_SHIFT_OP(OP) INTEGER_OP(OP, j &= 31;)
|
|
2545
|
+
|
|
2546
|
+
case JSOP_BITOR:
|
|
2547
|
+
BITWISE_OP(|);
|
|
2548
|
+
break;
|
|
2549
|
+
|
|
2550
|
+
case JSOP_BITXOR:
|
|
2551
|
+
BITWISE_OP(^);
|
|
2552
|
+
break;
|
|
2553
|
+
|
|
2554
|
+
case JSOP_BITAND:
|
|
2555
|
+
BITWISE_OP(&);
|
|
2556
|
+
break;
|
|
2557
|
+
|
|
2558
|
+
#if defined(XP_WIN)
|
|
2559
|
+
#define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN) \
|
|
2560
|
+
((JSDOUBLE_IS_NaN(LVAL) || JSDOUBLE_IS_NaN(RVAL)) \
|
|
2561
|
+
? (IFNAN) \
|
|
2562
|
+
: (LVAL) OP (RVAL))
|
|
2563
|
+
#else
|
|
2564
|
+
#define COMPARE_DOUBLES(LVAL, OP, RVAL, IFNAN) ((LVAL) OP (RVAL))
|
|
2565
|
+
#endif
|
|
2566
|
+
|
|
2567
|
+
#define RELATIONAL_OP(OP) \
|
|
2568
|
+
JS_BEGIN_MACRO \
|
|
2569
|
+
rval = FETCH_OPND(-1); \
|
|
2570
|
+
lval = FETCH_OPND(-2); \
|
|
2571
|
+
/* Optimize for two int-tagged operands (typical loop control). */ \
|
|
2572
|
+
if ((lval & rval) & JSVAL_INT) { \
|
|
2573
|
+
ltmp = lval ^ JSVAL_VOID; \
|
|
2574
|
+
rtmp = rval ^ JSVAL_VOID; \
|
|
2575
|
+
if (ltmp && rtmp) { \
|
|
2576
|
+
cond = JSVAL_TO_INT(lval) OP JSVAL_TO_INT(rval); \
|
|
2577
|
+
} else { \
|
|
2578
|
+
d = ltmp ? JSVAL_TO_INT(lval) : *rt->jsNaN; \
|
|
2579
|
+
d2 = rtmp ? JSVAL_TO_INT(rval) : *rt->jsNaN; \
|
|
2580
|
+
cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE); \
|
|
2581
|
+
} \
|
|
2582
|
+
} else { \
|
|
2583
|
+
VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_NUMBER, &lval); \
|
|
2584
|
+
VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_NUMBER, &rval); \
|
|
2585
|
+
if (JSVAL_IS_STRING(lval) && JSVAL_IS_STRING(rval)) { \
|
|
2586
|
+
str = JSVAL_TO_STRING(lval); \
|
|
2587
|
+
str2 = JSVAL_TO_STRING(rval); \
|
|
2588
|
+
cond = js_CompareStrings(str, str2) OP 0; \
|
|
2589
|
+
} else { \
|
|
2590
|
+
VALUE_TO_NUMBER(cx, lval, d); \
|
|
2591
|
+
VALUE_TO_NUMBER(cx, rval, d2); \
|
|
2592
|
+
cond = COMPARE_DOUBLES(d, OP, d2, JS_FALSE); \
|
|
2593
|
+
} \
|
|
2594
|
+
} \
|
|
2595
|
+
sp--; \
|
|
2596
|
+
STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
|
|
2597
|
+
JS_END_MACRO
|
|
2598
|
+
|
|
2599
|
+
#define EQUALITY_OP(OP, IFNAN) \
|
|
2600
|
+
JS_BEGIN_MACRO \
|
|
2601
|
+
rval = FETCH_OPND(-1); \
|
|
2602
|
+
lval = FETCH_OPND(-2); \
|
|
2603
|
+
ltmp = JSVAL_TAG(lval); \
|
|
2604
|
+
rtmp = JSVAL_TAG(rval); \
|
|
2605
|
+
if (ltmp == rtmp) { \
|
|
2606
|
+
if (ltmp == JSVAL_STRING) { \
|
|
2607
|
+
str = JSVAL_TO_STRING(lval); \
|
|
2608
|
+
str2 = JSVAL_TO_STRING(rval); \
|
|
2609
|
+
cond = js_CompareStrings(str, str2) OP 0; \
|
|
2610
|
+
} else if (ltmp == JSVAL_DOUBLE) { \
|
|
2611
|
+
d = *JSVAL_TO_DOUBLE(lval); \
|
|
2612
|
+
d2 = *JSVAL_TO_DOUBLE(rval); \
|
|
2613
|
+
cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
|
|
2614
|
+
} else { \
|
|
2615
|
+
/* Handle all undefined (=>NaN) and int combinations. */ \
|
|
2616
|
+
cond = lval OP rval; \
|
|
2617
|
+
} \
|
|
2618
|
+
} else { \
|
|
2619
|
+
if (JSVAL_IS_NULL(lval) || JSVAL_IS_VOID(lval)) { \
|
|
2620
|
+
cond = (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) OP 1; \
|
|
2621
|
+
} else if (JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval)) { \
|
|
2622
|
+
cond = 1 OP 0; \
|
|
2623
|
+
} else { \
|
|
2624
|
+
if (ltmp == JSVAL_OBJECT) { \
|
|
2625
|
+
VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, &lval); \
|
|
2626
|
+
ltmp = JSVAL_TAG(lval); \
|
|
2627
|
+
} else if (rtmp == JSVAL_OBJECT) { \
|
|
2628
|
+
VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &rval); \
|
|
2629
|
+
rtmp = JSVAL_TAG(rval); \
|
|
2630
|
+
} \
|
|
2631
|
+
if (ltmp == JSVAL_STRING && rtmp == JSVAL_STRING) { \
|
|
2632
|
+
str = JSVAL_TO_STRING(lval); \
|
|
2633
|
+
str2 = JSVAL_TO_STRING(rval); \
|
|
2634
|
+
cond = js_CompareStrings(str, str2) OP 0; \
|
|
2635
|
+
} else { \
|
|
2636
|
+
VALUE_TO_NUMBER(cx, lval, d); \
|
|
2637
|
+
VALUE_TO_NUMBER(cx, rval, d2); \
|
|
2638
|
+
cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
|
|
2639
|
+
} \
|
|
2640
|
+
} \
|
|
2641
|
+
} \
|
|
2642
|
+
sp--; \
|
|
2643
|
+
STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
|
|
2644
|
+
JS_END_MACRO
|
|
2645
|
+
|
|
2646
|
+
case JSOP_EQ:
|
|
2647
|
+
EQUALITY_OP(==, JS_FALSE);
|
|
2648
|
+
break;
|
|
2649
|
+
|
|
2650
|
+
case JSOP_NE:
|
|
2651
|
+
EQUALITY_OP(!=, JS_TRUE);
|
|
2652
|
+
break;
|
|
2653
|
+
|
|
2654
|
+
#if !JS_BUG_FALLIBLE_EQOPS
|
|
2655
|
+
#define NEW_EQUALITY_OP(OP, IFNAN) \
|
|
2656
|
+
JS_BEGIN_MACRO \
|
|
2657
|
+
rval = FETCH_OPND(-1); \
|
|
2658
|
+
lval = FETCH_OPND(-2); \
|
|
2659
|
+
ltmp = JSVAL_TAG(lval); \
|
|
2660
|
+
rtmp = JSVAL_TAG(rval); \
|
|
2661
|
+
if (ltmp == rtmp) { \
|
|
2662
|
+
if (ltmp == JSVAL_STRING) { \
|
|
2663
|
+
str = JSVAL_TO_STRING(lval); \
|
|
2664
|
+
str2 = JSVAL_TO_STRING(rval); \
|
|
2665
|
+
cond = js_CompareStrings(str, str2) OP 0; \
|
|
2666
|
+
} else if (ltmp == JSVAL_DOUBLE) { \
|
|
2667
|
+
d = *JSVAL_TO_DOUBLE(lval); \
|
|
2668
|
+
d2 = *JSVAL_TO_DOUBLE(rval); \
|
|
2669
|
+
cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
|
|
2670
|
+
} else { \
|
|
2671
|
+
cond = lval OP rval; \
|
|
2672
|
+
} \
|
|
2673
|
+
} else { \
|
|
2674
|
+
if (ltmp == JSVAL_DOUBLE && JSVAL_IS_INT(rval)) { \
|
|
2675
|
+
d = *JSVAL_TO_DOUBLE(lval); \
|
|
2676
|
+
d2 = JSVAL_TO_INT(rval); \
|
|
2677
|
+
cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
|
|
2678
|
+
} else if (JSVAL_IS_INT(lval) && rtmp == JSVAL_DOUBLE) { \
|
|
2679
|
+
d = JSVAL_TO_INT(lval); \
|
|
2680
|
+
d2 = *JSVAL_TO_DOUBLE(rval); \
|
|
2681
|
+
cond = COMPARE_DOUBLES(d, OP, d2, IFNAN); \
|
|
2682
|
+
} else { \
|
|
2683
|
+
cond = lval OP rval; \
|
|
2684
|
+
} \
|
|
2685
|
+
} \
|
|
2686
|
+
sp--; \
|
|
2687
|
+
STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond)); \
|
|
2688
|
+
JS_END_MACRO
|
|
2689
|
+
|
|
2690
|
+
case JSOP_NEW_EQ:
|
|
2691
|
+
NEW_EQUALITY_OP(==, JS_FALSE);
|
|
2692
|
+
break;
|
|
2693
|
+
|
|
2694
|
+
case JSOP_NEW_NE:
|
|
2695
|
+
NEW_EQUALITY_OP(!=, JS_TRUE);
|
|
2696
|
+
break;
|
|
2697
|
+
|
|
2698
|
+
#if JS_HAS_SWITCH_STATEMENT
|
|
2699
|
+
case JSOP_CASE:
|
|
2700
|
+
NEW_EQUALITY_OP(==, JS_FALSE);
|
|
2701
|
+
(void) POP();
|
|
2702
|
+
if (cond) {
|
|
2703
|
+
len = GET_JUMP_OFFSET(pc);
|
|
2704
|
+
CHECK_BRANCH(len);
|
|
2705
|
+
} else {
|
|
2706
|
+
PUSH(lval);
|
|
2707
|
+
}
|
|
2708
|
+
break;
|
|
2709
|
+
|
|
2710
|
+
case JSOP_CASEX:
|
|
2711
|
+
NEW_EQUALITY_OP(==, JS_FALSE);
|
|
2712
|
+
(void) POP();
|
|
2713
|
+
if (cond) {
|
|
2714
|
+
len = GET_JUMPX_OFFSET(pc);
|
|
2715
|
+
CHECK_BRANCH(len);
|
|
2716
|
+
} else {
|
|
2717
|
+
PUSH(lval);
|
|
2718
|
+
}
|
|
2719
|
+
break;
|
|
2720
|
+
#endif
|
|
2721
|
+
|
|
2722
|
+
#endif /* !JS_BUG_FALLIBLE_EQOPS */
|
|
2723
|
+
|
|
2724
|
+
case JSOP_LT:
|
|
2725
|
+
RELATIONAL_OP(<);
|
|
2726
|
+
break;
|
|
2727
|
+
|
|
2728
|
+
case JSOP_LE:
|
|
2729
|
+
RELATIONAL_OP(<=);
|
|
2730
|
+
break;
|
|
2731
|
+
|
|
2732
|
+
case JSOP_GT:
|
|
2733
|
+
RELATIONAL_OP(>);
|
|
2734
|
+
break;
|
|
2735
|
+
|
|
2736
|
+
case JSOP_GE:
|
|
2737
|
+
RELATIONAL_OP(>=);
|
|
2738
|
+
break;
|
|
2739
|
+
|
|
2740
|
+
#undef EQUALITY_OP
|
|
2741
|
+
#undef RELATIONAL_OP
|
|
2742
|
+
|
|
2743
|
+
case JSOP_LSH:
|
|
2744
|
+
SIGNED_SHIFT_OP(<<);
|
|
2745
|
+
break;
|
|
2746
|
+
|
|
2747
|
+
case JSOP_RSH:
|
|
2748
|
+
SIGNED_SHIFT_OP(>>);
|
|
2749
|
+
break;
|
|
2750
|
+
|
|
2751
|
+
case JSOP_URSH:
|
|
2752
|
+
{
|
|
2753
|
+
uint32 u;
|
|
2754
|
+
|
|
2755
|
+
FETCH_INT(cx, -1, j);
|
|
2756
|
+
FETCH_UINT(cx, -2, u);
|
|
2757
|
+
j &= 31;
|
|
2758
|
+
d = u >> j;
|
|
2759
|
+
sp--;
|
|
2760
|
+
STORE_NUMBER(cx, -1, d);
|
|
2761
|
+
break;
|
|
2762
|
+
}
|
|
2763
|
+
|
|
2764
|
+
#undef INTEGER_OP
|
|
2765
|
+
#undef BITWISE_OP
|
|
2766
|
+
#undef SIGNED_SHIFT_OP
|
|
2767
|
+
|
|
2768
|
+
case JSOP_ADD:
|
|
2769
|
+
rval = FETCH_OPND(-1);
|
|
2770
|
+
lval = FETCH_OPND(-2);
|
|
2771
|
+
VALUE_TO_PRIMITIVE(cx, lval, JSTYPE_VOID, <mp);
|
|
2772
|
+
VALUE_TO_PRIMITIVE(cx, rval, JSTYPE_VOID, &rtmp);
|
|
2773
|
+
if ((cond = JSVAL_IS_STRING(ltmp)) || JSVAL_IS_STRING(rtmp)) {
|
|
2774
|
+
SAVE_SP(fp);
|
|
2775
|
+
if (cond) {
|
|
2776
|
+
str = JSVAL_TO_STRING(ltmp);
|
|
2777
|
+
ok = (str2 = js_ValueToString(cx, rtmp)) != NULL;
|
|
2778
|
+
} else {
|
|
2779
|
+
str2 = JSVAL_TO_STRING(rtmp);
|
|
2780
|
+
ok = (str = js_ValueToString(cx, ltmp)) != NULL;
|
|
2781
|
+
}
|
|
2782
|
+
if (!ok)
|
|
2783
|
+
goto out;
|
|
2784
|
+
str = js_ConcatStrings(cx, str, str2);
|
|
2785
|
+
if (!str) {
|
|
2786
|
+
ok = JS_FALSE;
|
|
2787
|
+
goto out;
|
|
2788
|
+
}
|
|
2789
|
+
sp--;
|
|
2790
|
+
STORE_OPND(-1, STRING_TO_JSVAL(str));
|
|
2791
|
+
} else {
|
|
2792
|
+
VALUE_TO_NUMBER(cx, lval, d);
|
|
2793
|
+
VALUE_TO_NUMBER(cx, rval, d2);
|
|
2794
|
+
d += d2;
|
|
2795
|
+
sp--;
|
|
2796
|
+
STORE_NUMBER(cx, -1, d);
|
|
2797
|
+
}
|
|
2798
|
+
break;
|
|
2799
|
+
|
|
2800
|
+
#define BINARY_OP(OP) \
|
|
2801
|
+
JS_BEGIN_MACRO \
|
|
2802
|
+
FETCH_NUMBER(cx, -1, d2); \
|
|
2803
|
+
FETCH_NUMBER(cx, -2, d); \
|
|
2804
|
+
d = d OP d2; \
|
|
2805
|
+
sp--; \
|
|
2806
|
+
STORE_NUMBER(cx, -1, d); \
|
|
2807
|
+
JS_END_MACRO
|
|
2808
|
+
|
|
2809
|
+
case JSOP_SUB:
|
|
2810
|
+
BINARY_OP(-);
|
|
2811
|
+
break;
|
|
2812
|
+
|
|
2813
|
+
case JSOP_MUL:
|
|
2814
|
+
BINARY_OP(*);
|
|
2815
|
+
break;
|
|
2816
|
+
|
|
2817
|
+
case JSOP_DIV:
|
|
2818
|
+
FETCH_NUMBER(cx, -1, d2);
|
|
2819
|
+
FETCH_NUMBER(cx, -2, d);
|
|
2820
|
+
sp--;
|
|
2821
|
+
if (d2 == 0) {
|
|
2822
|
+
#if defined(XP_WIN)
|
|
2823
|
+
/* XXX MSVC miscompiles such that (NaN == 0) */
|
|
2824
|
+
if (JSDOUBLE_IS_NaN(d2))
|
|
2825
|
+
rval = DOUBLE_TO_JSVAL(rt->jsNaN);
|
|
2826
|
+
else
|
|
2827
|
+
#endif
|
|
2828
|
+
if (d == 0 || JSDOUBLE_IS_NaN(d))
|
|
2829
|
+
rval = DOUBLE_TO_JSVAL(rt->jsNaN);
|
|
2830
|
+
else if ((JSDOUBLE_HI32(d) ^ JSDOUBLE_HI32(d2)) >> 31)
|
|
2831
|
+
rval = DOUBLE_TO_JSVAL(rt->jsNegativeInfinity);
|
|
2832
|
+
else
|
|
2833
|
+
rval = DOUBLE_TO_JSVAL(rt->jsPositiveInfinity);
|
|
2834
|
+
STORE_OPND(-1, rval);
|
|
2835
|
+
} else {
|
|
2836
|
+
d /= d2;
|
|
2837
|
+
STORE_NUMBER(cx, -1, d);
|
|
2838
|
+
}
|
|
2839
|
+
break;
|
|
2840
|
+
|
|
2841
|
+
case JSOP_MOD:
|
|
2842
|
+
FETCH_NUMBER(cx, -1, d2);
|
|
2843
|
+
FETCH_NUMBER(cx, -2, d);
|
|
2844
|
+
sp--;
|
|
2845
|
+
if (d2 == 0) {
|
|
2846
|
+
STORE_OPND(-1, DOUBLE_TO_JSVAL(rt->jsNaN));
|
|
2847
|
+
} else {
|
|
2848
|
+
#if defined(XP_WIN)
|
|
2849
|
+
/* Workaround MS fmod bug where 42 % (1/0) => NaN, not 42. */
|
|
2850
|
+
if (!(JSDOUBLE_IS_FINITE(d) && JSDOUBLE_IS_INFINITE(d2)))
|
|
2851
|
+
#endif
|
|
2852
|
+
d = fmod(d, d2);
|
|
2853
|
+
STORE_NUMBER(cx, -1, d);
|
|
2854
|
+
}
|
|
2855
|
+
break;
|
|
2856
|
+
|
|
2857
|
+
case JSOP_NOT:
|
|
2858
|
+
POP_BOOLEAN(cx, rval, cond);
|
|
2859
|
+
PUSH_OPND(BOOLEAN_TO_JSVAL(!cond));
|
|
2860
|
+
break;
|
|
2861
|
+
|
|
2862
|
+
case JSOP_BITNOT:
|
|
2863
|
+
FETCH_INT(cx, -1, i);
|
|
2864
|
+
d = (jsdouble) ~i;
|
|
2865
|
+
STORE_NUMBER(cx, -1, d);
|
|
2866
|
+
break;
|
|
2867
|
+
|
|
2868
|
+
case JSOP_NEG:
|
|
2869
|
+
FETCH_NUMBER(cx, -1, d);
|
|
2870
|
+
#ifdef HPUX
|
|
2871
|
+
/*
|
|
2872
|
+
* Negation of a zero doesn't produce a negative
|
|
2873
|
+
* zero on HPUX. Perform the operation by bit
|
|
2874
|
+
* twiddling.
|
|
2875
|
+
*/
|
|
2876
|
+
JSDOUBLE_HI32(d) ^= JSDOUBLE_HI32_SIGNBIT;
|
|
2877
|
+
#else
|
|
2878
|
+
d = -d;
|
|
2879
|
+
#endif
|
|
2880
|
+
STORE_NUMBER(cx, -1, d);
|
|
2881
|
+
break;
|
|
2882
|
+
|
|
2883
|
+
case JSOP_POS:
|
|
2884
|
+
FETCH_NUMBER(cx, -1, d);
|
|
2885
|
+
STORE_NUMBER(cx, -1, d);
|
|
2886
|
+
break;
|
|
2887
|
+
|
|
2888
|
+
case JSOP_NEW:
|
|
2889
|
+
/* Get immediate argc and find the constructor function. */
|
|
2890
|
+
argc = GET_ARGC(pc);
|
|
2891
|
+
|
|
2892
|
+
#if JS_HAS_INITIALIZERS
|
|
2893
|
+
do_new:
|
|
2894
|
+
#endif
|
|
2895
|
+
vp = sp - (2 + argc);
|
|
2896
|
+
JS_ASSERT(vp >= fp->spbase);
|
|
2897
|
+
|
|
2898
|
+
fun = NULL;
|
|
2899
|
+
obj2 = NULL;
|
|
2900
|
+
lval = *vp;
|
|
2901
|
+
if (!JSVAL_IS_OBJECT(lval) ||
|
|
2902
|
+
(obj2 = JSVAL_TO_OBJECT(lval)) == NULL ||
|
|
2903
|
+
/* XXX clean up to avoid special cases above ObjectOps layer */
|
|
2904
|
+
OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass ||
|
|
2905
|
+
!obj2->map->ops->construct)
|
|
2906
|
+
{
|
|
2907
|
+
SAVE_SP(fp);
|
|
2908
|
+
fun = js_ValueToFunction(cx, vp, JSV2F_CONSTRUCT);
|
|
2909
|
+
if (!fun) {
|
|
2910
|
+
ok = JS_FALSE;
|
|
2911
|
+
goto out;
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2914
|
+
|
|
2915
|
+
clasp = &js_ObjectClass;
|
|
2916
|
+
if (!obj2) {
|
|
2917
|
+
proto = parent = NULL;
|
|
2918
|
+
fun = NULL;
|
|
2919
|
+
} else {
|
|
2920
|
+
/* Get the constructor prototype object for this function. */
|
|
2921
|
+
ok = OBJ_GET_PROPERTY(cx, obj2,
|
|
2922
|
+
(jsid)rt->atomState.classPrototypeAtom,
|
|
2923
|
+
&rval);
|
|
2924
|
+
if (!ok)
|
|
2925
|
+
goto out;
|
|
2926
|
+
proto = JSVAL_IS_OBJECT(rval) ? JSVAL_TO_OBJECT(rval) : NULL;
|
|
2927
|
+
parent = OBJ_GET_PARENT(cx, obj2);
|
|
2928
|
+
|
|
2929
|
+
if (OBJ_GET_CLASS(cx, obj2) == &js_FunctionClass) {
|
|
2930
|
+
funclasp = ((JSFunction *)JS_GetPrivate(cx, obj2))->clasp;
|
|
2931
|
+
if (funclasp)
|
|
2932
|
+
clasp = funclasp;
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
obj = js_NewObject(cx, clasp, proto, parent);
|
|
2936
|
+
if (!obj) {
|
|
2937
|
+
ok = JS_FALSE;
|
|
2938
|
+
goto out;
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
/* Now we have an object with a constructor method; call it. */
|
|
2942
|
+
vp[1] = OBJECT_TO_JSVAL(obj);
|
|
2943
|
+
SAVE_SP(fp);
|
|
2944
|
+
ok = js_Invoke(cx, argc, JSINVOKE_CONSTRUCT);
|
|
2945
|
+
RESTORE_SP(fp);
|
|
2946
|
+
LOAD_BRANCH_CALLBACK(cx);
|
|
2947
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
2948
|
+
if (!ok) {
|
|
2949
|
+
cx->newborn[GCX_OBJECT] = NULL;
|
|
2950
|
+
goto out;
|
|
2951
|
+
}
|
|
2952
|
+
|
|
2953
|
+
/* Check the return value and update obj from it. */
|
|
2954
|
+
rval = *vp;
|
|
2955
|
+
if (JSVAL_IS_PRIMITIVE(rval)) {
|
|
2956
|
+
if (fun || !JSVERSION_IS_ECMA(cx->version)) {
|
|
2957
|
+
*vp = OBJECT_TO_JSVAL(obj);
|
|
2958
|
+
break;
|
|
2959
|
+
}
|
|
2960
|
+
/* native [[Construct]] returning primitive is error */
|
|
2961
|
+
str = js_ValueToString(cx, rval);
|
|
2962
|
+
if (str) {
|
|
2963
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
2964
|
+
JSMSG_BAD_NEW_RESULT,
|
|
2965
|
+
JS_GetStringBytes(str));
|
|
2966
|
+
}
|
|
2967
|
+
ok = JS_FALSE;
|
|
2968
|
+
goto out;
|
|
2969
|
+
}
|
|
2970
|
+
obj = JSVAL_TO_OBJECT(rval);
|
|
2971
|
+
JS_RUNTIME_METER(rt, constructs);
|
|
2972
|
+
break;
|
|
2973
|
+
|
|
2974
|
+
case JSOP_DELNAME:
|
|
2975
|
+
atom = GET_ATOM(cx, script, pc);
|
|
2976
|
+
id = (jsid)atom;
|
|
2977
|
+
|
|
2978
|
+
SAVE_SP(fp);
|
|
2979
|
+
ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
|
|
2980
|
+
if (!ok)
|
|
2981
|
+
goto out;
|
|
2982
|
+
|
|
2983
|
+
/* ECMA says to return true if name is undefined or inherited. */
|
|
2984
|
+
rval = JSVAL_TRUE;
|
|
2985
|
+
if (prop) {
|
|
2986
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
2987
|
+
ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval);
|
|
2988
|
+
if (!ok)
|
|
2989
|
+
goto out;
|
|
2990
|
+
}
|
|
2991
|
+
PUSH_OPND(rval);
|
|
2992
|
+
break;
|
|
2993
|
+
|
|
2994
|
+
case JSOP_DELPROP:
|
|
2995
|
+
atom = GET_ATOM(cx, script, pc);
|
|
2996
|
+
id = (jsid)atom;
|
|
2997
|
+
PROPERTY_OP(-1, ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
|
|
2998
|
+
STORE_OPND(-1, rval);
|
|
2999
|
+
break;
|
|
3000
|
+
|
|
3001
|
+
case JSOP_DELELEM:
|
|
3002
|
+
ELEMENT_OP(-1, ok = OBJ_DELETE_PROPERTY(cx, obj, id, &rval));
|
|
3003
|
+
sp--;
|
|
3004
|
+
STORE_OPND(-1, rval);
|
|
3005
|
+
break;
|
|
3006
|
+
|
|
3007
|
+
case JSOP_TYPEOF:
|
|
3008
|
+
rval = POP_OPND();
|
|
3009
|
+
type = JS_TypeOfValue(cx, rval);
|
|
3010
|
+
atom = rt->atomState.typeAtoms[type];
|
|
3011
|
+
str = ATOM_TO_STRING(atom);
|
|
3012
|
+
PUSH_OPND(STRING_TO_JSVAL(str));
|
|
3013
|
+
break;
|
|
3014
|
+
|
|
3015
|
+
case JSOP_VOID:
|
|
3016
|
+
(void) POP_OPND();
|
|
3017
|
+
PUSH_OPND(JSVAL_VOID);
|
|
3018
|
+
break;
|
|
3019
|
+
|
|
3020
|
+
case JSOP_INCNAME:
|
|
3021
|
+
case JSOP_DECNAME:
|
|
3022
|
+
case JSOP_NAMEINC:
|
|
3023
|
+
case JSOP_NAMEDEC:
|
|
3024
|
+
atom = GET_ATOM(cx, script, pc);
|
|
3025
|
+
id = (jsid)atom;
|
|
3026
|
+
|
|
3027
|
+
SAVE_SP(fp);
|
|
3028
|
+
ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
|
|
3029
|
+
if (!ok)
|
|
3030
|
+
goto out;
|
|
3031
|
+
if (!prop)
|
|
3032
|
+
goto atom_not_defined;
|
|
3033
|
+
|
|
3034
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
3035
|
+
lval = OBJECT_TO_JSVAL(obj);
|
|
3036
|
+
goto do_incop;
|
|
3037
|
+
|
|
3038
|
+
case JSOP_INCPROP:
|
|
3039
|
+
case JSOP_DECPROP:
|
|
3040
|
+
case JSOP_PROPINC:
|
|
3041
|
+
case JSOP_PROPDEC:
|
|
3042
|
+
atom = GET_ATOM(cx, script, pc);
|
|
3043
|
+
id = (jsid)atom;
|
|
3044
|
+
lval = POP_OPND();
|
|
3045
|
+
goto do_incop;
|
|
3046
|
+
|
|
3047
|
+
case JSOP_INCELEM:
|
|
3048
|
+
case JSOP_DECELEM:
|
|
3049
|
+
case JSOP_ELEMINC:
|
|
3050
|
+
case JSOP_ELEMDEC:
|
|
3051
|
+
POP_ELEMENT_ID(id);
|
|
3052
|
+
lval = POP_OPND();
|
|
3053
|
+
|
|
3054
|
+
do_incop:
|
|
3055
|
+
VALUE_TO_OBJECT(cx, lval, obj);
|
|
3056
|
+
|
|
3057
|
+
/* The operand must contain a number. */
|
|
3058
|
+
SAVE_SP(fp);
|
|
3059
|
+
CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval));
|
|
3060
|
+
if (!ok)
|
|
3061
|
+
goto out;
|
|
3062
|
+
|
|
3063
|
+
/* The expression result goes in rtmp, the updated value in rval. */
|
|
3064
|
+
if (JSVAL_IS_INT(rval) &&
|
|
3065
|
+
rval != INT_TO_JSVAL(JSVAL_INT_MIN) &&
|
|
3066
|
+
rval != INT_TO_JSVAL(JSVAL_INT_MAX)) {
|
|
3067
|
+
if (cs->format & JOF_POST) {
|
|
3068
|
+
rtmp = rval;
|
|
3069
|
+
(cs->format & JOF_INC) ? (rval += 2) : (rval -= 2);
|
|
3070
|
+
} else {
|
|
3071
|
+
(cs->format & JOF_INC) ? (rval += 2) : (rval -= 2);
|
|
3072
|
+
rtmp = rval;
|
|
3073
|
+
}
|
|
3074
|
+
} else {
|
|
3075
|
+
|
|
3076
|
+
/*
|
|
3077
|
+
* Initially, rval contains the value to increment or decrement, which is not
|
|
3078
|
+
* yet converted. As above, the expression result goes in rtmp, the updated
|
|
3079
|
+
* value goes in rval.
|
|
3080
|
+
*/
|
|
3081
|
+
#define NONINT_INCREMENT_OP_MIDDLE() \
|
|
3082
|
+
JS_BEGIN_MACRO \
|
|
3083
|
+
VALUE_TO_NUMBER(cx, rval, d); \
|
|
3084
|
+
if (cs->format & JOF_POST) { \
|
|
3085
|
+
rtmp = rval; \
|
|
3086
|
+
if (!JSVAL_IS_NUMBER(rtmp)) { \
|
|
3087
|
+
ok = js_NewNumberValue(cx, d, &rtmp); \
|
|
3088
|
+
if (!ok) \
|
|
3089
|
+
goto out; \
|
|
3090
|
+
} \
|
|
3091
|
+
(cs->format & JOF_INC) ? d++ : d--; \
|
|
3092
|
+
ok = js_NewNumberValue(cx, d, &rval); \
|
|
3093
|
+
} else { \
|
|
3094
|
+
(cs->format & JOF_INC) ? ++d : --d; \
|
|
3095
|
+
ok = js_NewNumberValue(cx, d, &rval); \
|
|
3096
|
+
rtmp = rval; \
|
|
3097
|
+
} \
|
|
3098
|
+
if (!ok) \
|
|
3099
|
+
goto out; \
|
|
3100
|
+
JS_END_MACRO
|
|
3101
|
+
|
|
3102
|
+
NONINT_INCREMENT_OP_MIDDLE();
|
|
3103
|
+
}
|
|
3104
|
+
|
|
3105
|
+
CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
|
|
3106
|
+
if (!ok)
|
|
3107
|
+
goto out;
|
|
3108
|
+
PUSH_OPND(rtmp);
|
|
3109
|
+
break;
|
|
3110
|
+
|
|
3111
|
+
/*
|
|
3112
|
+
* NB: This macro can't use JS_BEGIN_MACRO/JS_END_MACRO around its body because
|
|
3113
|
+
* it must break from the switch case that calls it, not from the do...while(0)
|
|
3114
|
+
* loop created by the JS_BEGIN/END_MACRO brackets.
|
|
3115
|
+
*/
|
|
3116
|
+
#define FAST_INCREMENT_OP(SLOT,COUNT,BASE,PRE,OP,MINMAX) \
|
|
3117
|
+
slot = SLOT; \
|
|
3118
|
+
JS_ASSERT(slot < fp->fun->COUNT); \
|
|
3119
|
+
vp = fp->BASE + slot; \
|
|
3120
|
+
rval = *vp; \
|
|
3121
|
+
if (JSVAL_IS_INT(rval) && \
|
|
3122
|
+
rval != INT_TO_JSVAL(JSVAL_INT_##MINMAX)) { \
|
|
3123
|
+
PRE = rval; \
|
|
3124
|
+
rval OP 2; \
|
|
3125
|
+
*vp = rval; \
|
|
3126
|
+
PUSH_OPND(PRE); \
|
|
3127
|
+
break; \
|
|
3128
|
+
} \
|
|
3129
|
+
goto do_nonint_fast_incop;
|
|
3130
|
+
|
|
3131
|
+
case JSOP_INCARG:
|
|
3132
|
+
FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rval, +=, MAX);
|
|
3133
|
+
case JSOP_DECARG:
|
|
3134
|
+
FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rval, -=, MIN);
|
|
3135
|
+
case JSOP_ARGINC:
|
|
3136
|
+
FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rtmp, +=, MAX);
|
|
3137
|
+
case JSOP_ARGDEC:
|
|
3138
|
+
FAST_INCREMENT_OP(GET_ARGNO(pc), nargs, argv, rtmp, -=, MIN);
|
|
3139
|
+
|
|
3140
|
+
case JSOP_INCVAR:
|
|
3141
|
+
FAST_INCREMENT_OP(GET_VARNO(pc), nvars, vars, rval, +=, MAX);
|
|
3142
|
+
case JSOP_DECVAR:
|
|
3143
|
+
FAST_INCREMENT_OP(GET_VARNO(pc), nvars, vars, rval, -=, MIN);
|
|
3144
|
+
case JSOP_VARINC:
|
|
3145
|
+
FAST_INCREMENT_OP(GET_VARNO(pc), nvars, vars, rtmp, +=, MAX);
|
|
3146
|
+
case JSOP_VARDEC:
|
|
3147
|
+
FAST_INCREMENT_OP(GET_VARNO(pc), nvars, vars, rtmp, -=, MIN);
|
|
3148
|
+
|
|
3149
|
+
#undef FAST_INCREMENT_OP
|
|
3150
|
+
|
|
3151
|
+
do_nonint_fast_incop:
|
|
3152
|
+
NONINT_INCREMENT_OP_MIDDLE();
|
|
3153
|
+
*vp = rval;
|
|
3154
|
+
PUSH_OPND(rtmp);
|
|
3155
|
+
break;
|
|
3156
|
+
|
|
3157
|
+
#define FAST_GLOBAL_INCREMENT_OP(SLOWOP,PRE,OP,MINMAX) \
|
|
3158
|
+
slot = GET_VARNO(pc); \
|
|
3159
|
+
JS_ASSERT(slot < fp->nvars); \
|
|
3160
|
+
lval = fp->vars[slot]; \
|
|
3161
|
+
if (JSVAL_IS_NULL(lval)) { \
|
|
3162
|
+
op = SLOWOP; \
|
|
3163
|
+
goto do_op; \
|
|
3164
|
+
} \
|
|
3165
|
+
slot = JSVAL_TO_INT(lval); \
|
|
3166
|
+
obj = fp->varobj; \
|
|
3167
|
+
rval = OBJ_GET_SLOT(cx, obj, slot); \
|
|
3168
|
+
if (JSVAL_IS_INT(rval) && \
|
|
3169
|
+
rval != INT_TO_JSVAL(JSVAL_INT_##MINMAX)) { \
|
|
3170
|
+
PRE = rval; \
|
|
3171
|
+
rval OP 2; \
|
|
3172
|
+
OBJ_SET_SLOT(cx, obj, slot, rval); \
|
|
3173
|
+
PUSH_OPND(PRE); \
|
|
3174
|
+
break; \
|
|
3175
|
+
} \
|
|
3176
|
+
goto do_nonint_fast_global_incop;
|
|
3177
|
+
|
|
3178
|
+
case JSOP_INCGVAR:
|
|
3179
|
+
FAST_GLOBAL_INCREMENT_OP(JSOP_INCNAME, rval, +=, MAX);
|
|
3180
|
+
case JSOP_DECGVAR:
|
|
3181
|
+
FAST_GLOBAL_INCREMENT_OP(JSOP_DECNAME, rval, -=, MIN);
|
|
3182
|
+
case JSOP_GVARINC:
|
|
3183
|
+
FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEINC, rtmp, +=, MAX);
|
|
3184
|
+
case JSOP_GVARDEC:
|
|
3185
|
+
FAST_GLOBAL_INCREMENT_OP(JSOP_NAMEDEC, rtmp, -=, MIN);
|
|
3186
|
+
|
|
3187
|
+
#undef FAST_GLOBAL_INCREMENT_OP
|
|
3188
|
+
|
|
3189
|
+
do_nonint_fast_global_incop:
|
|
3190
|
+
NONINT_INCREMENT_OP_MIDDLE();
|
|
3191
|
+
OBJ_SET_SLOT(cx, obj, slot, rval);
|
|
3192
|
+
PUSH_OPND(rtmp);
|
|
3193
|
+
break;
|
|
3194
|
+
|
|
3195
|
+
case JSOP_GETPROP:
|
|
3196
|
+
/* Get an immediate atom naming the property. */
|
|
3197
|
+
atom = GET_ATOM(cx, script, pc);
|
|
3198
|
+
id = (jsid)atom;
|
|
3199
|
+
PROPERTY_OP(-1, CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval)));
|
|
3200
|
+
STORE_OPND(-1, rval);
|
|
3201
|
+
break;
|
|
3202
|
+
|
|
3203
|
+
case JSOP_SETPROP:
|
|
3204
|
+
/* Pop the right-hand side into rval for OBJ_SET_PROPERTY. */
|
|
3205
|
+
rval = FETCH_OPND(-1);
|
|
3206
|
+
|
|
3207
|
+
/* Get an immediate atom naming the property. */
|
|
3208
|
+
atom = GET_ATOM(cx, script, pc);
|
|
3209
|
+
id = (jsid)atom;
|
|
3210
|
+
PROPERTY_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)));
|
|
3211
|
+
sp--;
|
|
3212
|
+
STORE_OPND(-1, rval);
|
|
3213
|
+
break;
|
|
3214
|
+
|
|
3215
|
+
case JSOP_GETELEM:
|
|
3216
|
+
ELEMENT_OP(-1, CACHED_GET(OBJ_GET_PROPERTY(cx, obj, id, &rval)));
|
|
3217
|
+
sp--;
|
|
3218
|
+
STORE_OPND(-1, rval);
|
|
3219
|
+
break;
|
|
3220
|
+
|
|
3221
|
+
case JSOP_SETELEM:
|
|
3222
|
+
rval = FETCH_OPND(-1);
|
|
3223
|
+
ELEMENT_OP(-2, CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)));
|
|
3224
|
+
sp -= 2;
|
|
3225
|
+
STORE_OPND(-1, rval);
|
|
3226
|
+
break;
|
|
3227
|
+
|
|
3228
|
+
case JSOP_ENUMELEM:
|
|
3229
|
+
/* Funky: the value to set is under the [obj, id] pair. */
|
|
3230
|
+
FETCH_ELEMENT_ID(-1, id);
|
|
3231
|
+
lval = FETCH_OPND(-2);
|
|
3232
|
+
VALUE_TO_OBJECT(cx, lval, obj);
|
|
3233
|
+
rval = FETCH_OPND(-3);
|
|
3234
|
+
SAVE_SP(fp);
|
|
3235
|
+
ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
|
|
3236
|
+
if (!ok)
|
|
3237
|
+
goto out;
|
|
3238
|
+
sp -= 3;
|
|
3239
|
+
break;
|
|
3240
|
+
|
|
3241
|
+
/*
|
|
3242
|
+
* LAZY_ARGS_THISP allows the JSOP_ARGSUB bytecode to defer creation of the
|
|
3243
|
+
* arguments object until it is truly needed. JSOP_ARGSUB optimizes away
|
|
3244
|
+
* arguments objects when the only uses of the 'arguments' parameter are to
|
|
3245
|
+
* fetch individual actual parameters. But if such a use were then invoked,
|
|
3246
|
+
* e.g., arguments[i](), the 'this' parameter would and must bind to the
|
|
3247
|
+
* caller's arguments object. So JSOP_ARGSUB sets obj to LAZY_ARGS_THISP.
|
|
3248
|
+
*/
|
|
3249
|
+
#define LAZY_ARGS_THISP ((JSObject *) 1)
|
|
3250
|
+
|
|
3251
|
+
case JSOP_PUSHOBJ:
|
|
3252
|
+
if (obj == LAZY_ARGS_THISP && !(obj = js_GetArgsObject(cx, fp))) {
|
|
3253
|
+
ok = JS_FALSE;
|
|
3254
|
+
goto out;
|
|
3255
|
+
}
|
|
3256
|
+
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
|
3257
|
+
break;
|
|
3258
|
+
|
|
3259
|
+
case JSOP_CALL:
|
|
3260
|
+
case JSOP_EVAL:
|
|
3261
|
+
argc = GET_ARGC(pc);
|
|
3262
|
+
vp = sp - (argc + 2);
|
|
3263
|
+
lval = *vp;
|
|
3264
|
+
SAVE_SP(fp);
|
|
3265
|
+
|
|
3266
|
+
if (JSVAL_IS_FUNCTION(cx, lval) &&
|
|
3267
|
+
(obj = JSVAL_TO_OBJECT(lval),
|
|
3268
|
+
fun = (JSFunction *) JS_GetPrivate(cx, obj),
|
|
3269
|
+
fun->interpreted &&
|
|
3270
|
+
!(fun->flags & (JSFUN_HEAVYWEIGHT | JSFUN_BOUND_METHOD)) &&
|
|
3271
|
+
argc >= (uintN)(fun->nargs + fun->extra)))
|
|
3272
|
+
/* inline_call: */
|
|
3273
|
+
{
|
|
3274
|
+
uintN nframeslots, nvars;
|
|
3275
|
+
void *newmark;
|
|
3276
|
+
JSInlineFrame *newifp;
|
|
3277
|
+
JSInterpreterHook hook;
|
|
3278
|
+
|
|
3279
|
+
/* Restrict recursion of lightweight functions. */
|
|
3280
|
+
if (inlineCallCount == MAX_INLINE_CALL_COUNT) {
|
|
3281
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
3282
|
+
JSMSG_OVER_RECURSED);
|
|
3283
|
+
ok = JS_FALSE;
|
|
3284
|
+
goto out;
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
#if JS_HAS_JIT
|
|
3288
|
+
/* ZZZbe should do this only if interpreted often enough. */
|
|
3289
|
+
ok = jsjit_Compile(cx, fun);
|
|
3290
|
+
if (!ok)
|
|
3291
|
+
goto out;
|
|
3292
|
+
#endif
|
|
3293
|
+
|
|
3294
|
+
/* Compute the number of stack slots needed for fun. */
|
|
3295
|
+
nframeslots = (sizeof(JSInlineFrame) + sizeof(jsval) - 1)
|
|
3296
|
+
/ sizeof(jsval);
|
|
3297
|
+
nvars = fun->nvars;
|
|
3298
|
+
script = fun->u.script;
|
|
3299
|
+
depth = (jsint) script->depth;
|
|
3300
|
+
|
|
3301
|
+
/* Allocate the frame and space for vars and operands. */
|
|
3302
|
+
newsp = js_AllocRawStack(cx, nframeslots + nvars + 2 * depth,
|
|
3303
|
+
&newmark);
|
|
3304
|
+
if (!newsp) {
|
|
3305
|
+
ok = JS_FALSE;
|
|
3306
|
+
goto bad_inline_call;
|
|
3307
|
+
}
|
|
3308
|
+
newifp = (JSInlineFrame *) newsp;
|
|
3309
|
+
newsp += nframeslots;
|
|
3310
|
+
|
|
3311
|
+
/* Initialize the stack frame. */
|
|
3312
|
+
memset(newifp, 0, sizeof(JSInlineFrame));
|
|
3313
|
+
newifp->frame.script = script;
|
|
3314
|
+
newifp->frame.fun = fun;
|
|
3315
|
+
newifp->frame.argc = argc;
|
|
3316
|
+
newifp->frame.argv = vp + 2;
|
|
3317
|
+
newifp->frame.rval = JSVAL_VOID;
|
|
3318
|
+
newifp->frame.nvars = nvars;
|
|
3319
|
+
newifp->frame.vars = newsp;
|
|
3320
|
+
newifp->frame.down = fp;
|
|
3321
|
+
newifp->frame.scopeChain = OBJ_GET_PARENT(cx, obj);
|
|
3322
|
+
newifp->mark = newmark;
|
|
3323
|
+
|
|
3324
|
+
/* Compute the 'this' parameter now that argv is set. */
|
|
3325
|
+
ok = ComputeThis(cx, JSVAL_TO_OBJECT(vp[1]), &newifp->frame);
|
|
3326
|
+
if (!ok) {
|
|
3327
|
+
js_FreeRawStack(cx, newmark);
|
|
3328
|
+
goto bad_inline_call;
|
|
3329
|
+
}
|
|
3330
|
+
#ifdef DUMP_CALL_TABLE
|
|
3331
|
+
LogCall(cx, *vp, argc, vp + 2);
|
|
3332
|
+
#endif
|
|
3333
|
+
|
|
3334
|
+
/* Push void to initialize local variables. */
|
|
3335
|
+
sp = newsp;
|
|
3336
|
+
while (nvars--)
|
|
3337
|
+
PUSH(JSVAL_VOID);
|
|
3338
|
+
sp += depth;
|
|
3339
|
+
newifp->frame.spbase = sp;
|
|
3340
|
+
SAVE_SP(&newifp->frame);
|
|
3341
|
+
|
|
3342
|
+
/* Call the debugger hook if present. */
|
|
3343
|
+
hook = cx->runtime->callHook;
|
|
3344
|
+
if (hook) {
|
|
3345
|
+
newifp->hookData = hook(cx, &newifp->frame, JS_TRUE, 0,
|
|
3346
|
+
cx->runtime->callHookData);
|
|
3347
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3350
|
+
/* Switch to new version if currentVersion wasn't overridden. */
|
|
3351
|
+
newifp->callerVersion = cx->version;
|
|
3352
|
+
if (cx->version == currentVersion) {
|
|
3353
|
+
currentVersion = script->version;
|
|
3354
|
+
if (currentVersion != cx->version)
|
|
3355
|
+
JS_SetVersion(cx, currentVersion);
|
|
3356
|
+
}
|
|
3357
|
+
|
|
3358
|
+
/* Push the frame and set interpreter registers. */
|
|
3359
|
+
cx->fp = fp = &newifp->frame;
|
|
3360
|
+
pc = script->code;
|
|
3361
|
+
endpc = pc + script->length;
|
|
3362
|
+
inlineCallCount++;
|
|
3363
|
+
JS_RUNTIME_METER(rt, inlineCalls);
|
|
3364
|
+
continue;
|
|
3365
|
+
|
|
3366
|
+
bad_inline_call:
|
|
3367
|
+
script = fp->script;
|
|
3368
|
+
depth = (jsint) script->depth;
|
|
3369
|
+
goto out;
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3372
|
+
ok = js_Invoke(cx, argc, 0);
|
|
3373
|
+
RESTORE_SP(fp);
|
|
3374
|
+
LOAD_BRANCH_CALLBACK(cx);
|
|
3375
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
3376
|
+
if (!ok)
|
|
3377
|
+
goto out;
|
|
3378
|
+
JS_RUNTIME_METER(rt, nonInlineCalls);
|
|
3379
|
+
#if JS_HAS_LVALUE_RETURN
|
|
3380
|
+
if (cx->rval2set) {
|
|
3381
|
+
/*
|
|
3382
|
+
* Sneaky: use the stack depth we didn't claim in our budget,
|
|
3383
|
+
* but that we know is there on account of [fun, this] already
|
|
3384
|
+
* having been pushed, at a minimum (if no args). Those two
|
|
3385
|
+
* slots have been popped and [rval] has been pushed, which
|
|
3386
|
+
* leaves one more slot for rval2 before we might overflow.
|
|
3387
|
+
*
|
|
3388
|
+
* NB: rval2 must be the property identifier, and rval the
|
|
3389
|
+
* object from which to get the property. The pair form an
|
|
3390
|
+
* ECMA "reference type", which can be used on the right- or
|
|
3391
|
+
* left-hand side of assignment ops. Only native methods can
|
|
3392
|
+
* return reference types. See JSOP_SETCALL just below for
|
|
3393
|
+
* the left-hand-side case.
|
|
3394
|
+
*/
|
|
3395
|
+
PUSH_OPND(cx->rval2);
|
|
3396
|
+
cx->rval2set = JS_FALSE;
|
|
3397
|
+
ELEMENT_OP(-1, ok = OBJ_GET_PROPERTY(cx, obj, id, &rval));
|
|
3398
|
+
sp--;
|
|
3399
|
+
STORE_OPND(-1, rval);
|
|
3400
|
+
}
|
|
3401
|
+
#endif
|
|
3402
|
+
obj = NULL;
|
|
3403
|
+
break;
|
|
3404
|
+
|
|
3405
|
+
#if JS_HAS_LVALUE_RETURN
|
|
3406
|
+
case JSOP_SETCALL:
|
|
3407
|
+
argc = GET_ARGC(pc);
|
|
3408
|
+
SAVE_SP(fp);
|
|
3409
|
+
ok = js_Invoke(cx, argc, 0);
|
|
3410
|
+
RESTORE_SP(fp);
|
|
3411
|
+
LOAD_BRANCH_CALLBACK(cx);
|
|
3412
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
3413
|
+
if (!ok)
|
|
3414
|
+
goto out;
|
|
3415
|
+
if (!cx->rval2set) {
|
|
3416
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
3417
|
+
JSMSG_BAD_LEFTSIDE_OF_ASS);
|
|
3418
|
+
ok = JS_FALSE;
|
|
3419
|
+
goto out;
|
|
3420
|
+
}
|
|
3421
|
+
PUSH_OPND(cx->rval2);
|
|
3422
|
+
cx->rval2set = JS_FALSE;
|
|
3423
|
+
obj = NULL;
|
|
3424
|
+
break;
|
|
3425
|
+
#endif
|
|
3426
|
+
|
|
3427
|
+
case JSOP_NAME:
|
|
3428
|
+
atom = GET_ATOM(cx, script, pc);
|
|
3429
|
+
id = (jsid)atom;
|
|
3430
|
+
|
|
3431
|
+
SAVE_SP(fp);
|
|
3432
|
+
ok = js_FindProperty(cx, id, &obj, &obj2, &prop);
|
|
3433
|
+
if (!ok)
|
|
3434
|
+
goto out;
|
|
3435
|
+
if (!prop) {
|
|
3436
|
+
/* Kludge to allow (typeof foo == "undefined") tests. */
|
|
3437
|
+
for (pc2 = pc + len; pc2 < endpc; pc2++) {
|
|
3438
|
+
op2 = (JSOp)*pc2;
|
|
3439
|
+
if (op2 == JSOP_TYPEOF) {
|
|
3440
|
+
PUSH_OPND(JSVAL_VOID);
|
|
3441
|
+
goto advance_pc;
|
|
3442
|
+
}
|
|
3443
|
+
if (op2 != JSOP_GROUP)
|
|
3444
|
+
break;
|
|
3445
|
+
}
|
|
3446
|
+
goto atom_not_defined;
|
|
3447
|
+
}
|
|
3448
|
+
|
|
3449
|
+
/* Take the slow path if prop was not found in a native object. */
|
|
3450
|
+
if (!OBJ_IS_NATIVE(obj) || !OBJ_IS_NATIVE(obj2)) {
|
|
3451
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
3452
|
+
ok = OBJ_GET_PROPERTY(cx, obj, id, &rval);
|
|
3453
|
+
if (!ok)
|
|
3454
|
+
goto out;
|
|
3455
|
+
PUSH_OPND(rval);
|
|
3456
|
+
break;
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3459
|
+
/* Get and push the obj[id] property's value. */
|
|
3460
|
+
sprop = (JSScopeProperty *)prop;
|
|
3461
|
+
slot = (uintN)sprop->slot;
|
|
3462
|
+
rval = (slot != SPROP_INVALID_SLOT)
|
|
3463
|
+
? LOCKED_OBJ_GET_SLOT(obj2, slot)
|
|
3464
|
+
: JSVAL_VOID;
|
|
3465
|
+
JS_UNLOCK_OBJ(cx, obj2);
|
|
3466
|
+
ok = SPROP_GET(cx, sprop, obj, obj2, &rval);
|
|
3467
|
+
JS_LOCK_OBJ(cx, obj2);
|
|
3468
|
+
if (!ok) {
|
|
3469
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
3470
|
+
goto out;
|
|
3471
|
+
}
|
|
3472
|
+
if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2)))
|
|
3473
|
+
LOCKED_OBJ_SET_SLOT(obj2, slot, rval);
|
|
3474
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
3475
|
+
PUSH_OPND(rval);
|
|
3476
|
+
break;
|
|
3477
|
+
|
|
3478
|
+
case JSOP_UINT16:
|
|
3479
|
+
i = (jsint) GET_ATOM_INDEX(pc);
|
|
3480
|
+
rval = INT_TO_JSVAL(i);
|
|
3481
|
+
PUSH_OPND(rval);
|
|
3482
|
+
obj = NULL;
|
|
3483
|
+
break;
|
|
3484
|
+
|
|
3485
|
+
case JSOP_NUMBER:
|
|
3486
|
+
case JSOP_STRING:
|
|
3487
|
+
case JSOP_OBJECT:
|
|
3488
|
+
atom = GET_ATOM(cx, script, pc);
|
|
3489
|
+
PUSH_OPND(ATOM_KEY(atom));
|
|
3490
|
+
obj = NULL;
|
|
3491
|
+
break;
|
|
3492
|
+
|
|
3493
|
+
case JSOP_REGEXP:
|
|
3494
|
+
{
|
|
3495
|
+
JSRegExp *re;
|
|
3496
|
+
JSObject *funobj;
|
|
3497
|
+
|
|
3498
|
+
/*
|
|
3499
|
+
* Push a regexp object for the atom mapped by the bytecode at pc,
|
|
3500
|
+
* cloning the literal's regexp object if necessary, to simulate in
|
|
3501
|
+
* the pre-compile/execute-later case what ECMA specifies for the
|
|
3502
|
+
* compile-and-go case: that scanning each regexp literal creates
|
|
3503
|
+
* a single corresponding RegExp object.
|
|
3504
|
+
*
|
|
3505
|
+
* To support pre-compilation transparently, we must handle the
|
|
3506
|
+
* case where a regexp object literal is used in a different global
|
|
3507
|
+
* at execution time from the global with which it was scanned at
|
|
3508
|
+
* compile time. We do this by re-wrapping the JSRegExp private
|
|
3509
|
+
* data struct with a cloned object having the right prototype and
|
|
3510
|
+
* parent, and having its own lastIndex property value storage.
|
|
3511
|
+
*
|
|
3512
|
+
* Unlike JSOP_DEFFUN and other prolog bytecodes that may clone
|
|
3513
|
+
* literal objects, we don't want to pay a script prolog execution
|
|
3514
|
+
* price for all regexp literals in a script (many may not be used
|
|
3515
|
+
* by a particular execution of that script, depending on control
|
|
3516
|
+
* flow), so we initialize lazily here.
|
|
3517
|
+
*
|
|
3518
|
+
* XXX This code is specific to regular expression objects. If we
|
|
3519
|
+
* need a similar op for other kinds of object literals, we should
|
|
3520
|
+
* push cloning down under JSObjectOps and reuse code here.
|
|
3521
|
+
*/
|
|
3522
|
+
atom = GET_ATOM(cx, script, pc);
|
|
3523
|
+
JS_ASSERT(ATOM_IS_OBJECT(atom));
|
|
3524
|
+
obj = ATOM_TO_OBJECT(atom);
|
|
3525
|
+
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
|
|
3526
|
+
|
|
3527
|
+
re = (JSRegExp *) JS_GetPrivate(cx, obj);
|
|
3528
|
+
slot = re->cloneIndex;
|
|
3529
|
+
if (fp->fun) {
|
|
3530
|
+
/*
|
|
3531
|
+
* We're in function code, not global or eval code (in eval
|
|
3532
|
+
* code, JSOP_REGEXP is never emitted). The code generator
|
|
3533
|
+
* recorded in fp->fun->nregexps the number of re->cloneIndex
|
|
3534
|
+
* slots that it reserved in the cloned funobj.
|
|
3535
|
+
*/
|
|
3536
|
+
funobj = JSVAL_TO_OBJECT(fp->argv[-2]);
|
|
3537
|
+
slot += JSCLASS_RESERVED_SLOTS(&js_FunctionClass);
|
|
3538
|
+
if (!JS_GetReservedSlot(cx, funobj, slot, &rval))
|
|
3539
|
+
return JS_FALSE;
|
|
3540
|
+
if (JSVAL_IS_VOID(rval))
|
|
3541
|
+
rval = JSVAL_NULL;
|
|
3542
|
+
} else {
|
|
3543
|
+
/*
|
|
3544
|
+
* We're in global code. The code generator already arranged
|
|
3545
|
+
* via script->numGlobalVars to reserve a global variable slot
|
|
3546
|
+
* at cloneIndex. All global variable slots are initialized
|
|
3547
|
+
* to null, not void, for faster testing in JSOP_*GVAR cases.
|
|
3548
|
+
*/
|
|
3549
|
+
rval = fp->vars[slot];
|
|
3550
|
+
#ifdef __GNUC__
|
|
3551
|
+
funobj = NULL; /* suppress bogus gcc warnings */
|
|
3552
|
+
#endif
|
|
3553
|
+
}
|
|
3554
|
+
|
|
3555
|
+
if (JSVAL_IS_NULL(rval)) {
|
|
3556
|
+
/* Compute the current global object in obj2. */
|
|
3557
|
+
obj2 = fp->scopeChain;
|
|
3558
|
+
while ((parent = OBJ_GET_PARENT(cx, obj2)) != NULL)
|
|
3559
|
+
obj2 = parent;
|
|
3560
|
+
|
|
3561
|
+
/*
|
|
3562
|
+
* If obj's parent is not obj2, we must clone obj so that it
|
|
3563
|
+
* has the right parent, and therefore, the right prototype.
|
|
3564
|
+
*
|
|
3565
|
+
* Yes, this means we assume that the correct RegExp.prototype
|
|
3566
|
+
* to which regexp instances (including literals) delegate can
|
|
3567
|
+
* be distinguished solely by the instance's parent, which was
|
|
3568
|
+
* set to the parent of the RegExp constructor function object
|
|
3569
|
+
* when the instance was created. In other words,
|
|
3570
|
+
*
|
|
3571
|
+
* (/x/.__parent__ == RegExp.__parent__) implies
|
|
3572
|
+
* (/x/.__proto__ == RegExp.prototype)
|
|
3573
|
+
*
|
|
3574
|
+
* (unless you assign a different object to RegExp.prototype
|
|
3575
|
+
* at runtime, in which case, ECMA doesn't specify operation,
|
|
3576
|
+
* and you get what you deserve).
|
|
3577
|
+
*
|
|
3578
|
+
* This same coupling between instance parent and constructor
|
|
3579
|
+
* parent turns up everywhere (see jsobj.c's FindConstructor,
|
|
3580
|
+
* js_ConstructObject, and js_NewObject). It's fundamental to
|
|
3581
|
+
* the design of the language when you consider multiple global
|
|
3582
|
+
* objects and separate compilation and execution, even though
|
|
3583
|
+
* it is not specified fully in ECMA.
|
|
3584
|
+
*/
|
|
3585
|
+
if (OBJ_GET_PARENT(cx, obj) != obj2) {
|
|
3586
|
+
obj = js_CloneRegExpObject(cx, obj, obj2);
|
|
3587
|
+
if (!obj) {
|
|
3588
|
+
ok = JS_FALSE;
|
|
3589
|
+
goto out;
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
rval = OBJECT_TO_JSVAL(obj);
|
|
3593
|
+
|
|
3594
|
+
/* Store the regexp object value in its cloneIndex slot. */
|
|
3595
|
+
if (fp->fun) {
|
|
3596
|
+
if (!JS_SetReservedSlot(cx, funobj, slot, rval))
|
|
3597
|
+
return JS_FALSE;
|
|
3598
|
+
} else {
|
|
3599
|
+
fp->vars[slot] = rval;
|
|
3600
|
+
}
|
|
3601
|
+
}
|
|
3602
|
+
|
|
3603
|
+
PUSH_OPND(rval);
|
|
3604
|
+
obj = NULL;
|
|
3605
|
+
break;
|
|
3606
|
+
}
|
|
3607
|
+
|
|
3608
|
+
case JSOP_ZERO:
|
|
3609
|
+
PUSH_OPND(JSVAL_ZERO);
|
|
3610
|
+
obj = NULL;
|
|
3611
|
+
break;
|
|
3612
|
+
|
|
3613
|
+
case JSOP_ONE:
|
|
3614
|
+
PUSH_OPND(JSVAL_ONE);
|
|
3615
|
+
obj = NULL;
|
|
3616
|
+
break;
|
|
3617
|
+
|
|
3618
|
+
case JSOP_NULL:
|
|
3619
|
+
PUSH_OPND(JSVAL_NULL);
|
|
3620
|
+
obj = NULL;
|
|
3621
|
+
break;
|
|
3622
|
+
|
|
3623
|
+
case JSOP_THIS:
|
|
3624
|
+
PUSH_OPND(OBJECT_TO_JSVAL(fp->thisp));
|
|
3625
|
+
obj = NULL;
|
|
3626
|
+
break;
|
|
3627
|
+
|
|
3628
|
+
case JSOP_FALSE:
|
|
3629
|
+
PUSH_OPND(JSVAL_FALSE);
|
|
3630
|
+
obj = NULL;
|
|
3631
|
+
break;
|
|
3632
|
+
|
|
3633
|
+
case JSOP_TRUE:
|
|
3634
|
+
PUSH_OPND(JSVAL_TRUE);
|
|
3635
|
+
obj = NULL;
|
|
3636
|
+
break;
|
|
3637
|
+
|
|
3638
|
+
#if JS_HAS_SWITCH_STATEMENT
|
|
3639
|
+
case JSOP_TABLESWITCH:
|
|
3640
|
+
pc2 = pc;
|
|
3641
|
+
len = GET_JUMP_OFFSET(pc2);
|
|
3642
|
+
|
|
3643
|
+
/*
|
|
3644
|
+
* ECMAv2 forbids conversion of discriminant, so we will skip to
|
|
3645
|
+
* the default case if the discriminant isn't already an int jsval.
|
|
3646
|
+
* (This opcode is emitted only for dense jsint-domain switches.)
|
|
3647
|
+
*/
|
|
3648
|
+
if (cx->version == JSVERSION_DEFAULT ||
|
|
3649
|
+
cx->version >= JSVERSION_1_4) {
|
|
3650
|
+
rval = POP_OPND();
|
|
3651
|
+
if (!JSVAL_IS_INT(rval))
|
|
3652
|
+
break;
|
|
3653
|
+
i = JSVAL_TO_INT(rval);
|
|
3654
|
+
} else {
|
|
3655
|
+
FETCH_INT(cx, -1, i);
|
|
3656
|
+
sp--;
|
|
3657
|
+
}
|
|
3658
|
+
|
|
3659
|
+
pc2 += JUMP_OFFSET_LEN;
|
|
3660
|
+
low = GET_JUMP_OFFSET(pc2);
|
|
3661
|
+
pc2 += JUMP_OFFSET_LEN;
|
|
3662
|
+
high = GET_JUMP_OFFSET(pc2);
|
|
3663
|
+
|
|
3664
|
+
i -= low;
|
|
3665
|
+
if ((jsuint)i < (jsuint)(high - low + 1)) {
|
|
3666
|
+
pc2 += JUMP_OFFSET_LEN + JUMP_OFFSET_LEN * i;
|
|
3667
|
+
off = (jsint) GET_JUMP_OFFSET(pc2);
|
|
3668
|
+
if (off)
|
|
3669
|
+
len = off;
|
|
3670
|
+
}
|
|
3671
|
+
break;
|
|
3672
|
+
|
|
3673
|
+
case JSOP_LOOKUPSWITCH:
|
|
3674
|
+
lval = POP_OPND();
|
|
3675
|
+
pc2 = pc;
|
|
3676
|
+
len = GET_JUMP_OFFSET(pc2);
|
|
3677
|
+
|
|
3678
|
+
if (!JSVAL_IS_NUMBER(lval) &&
|
|
3679
|
+
!JSVAL_IS_STRING(lval) &&
|
|
3680
|
+
!JSVAL_IS_BOOLEAN(lval)) {
|
|
3681
|
+
goto advance_pc;
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
pc2 += JUMP_OFFSET_LEN;
|
|
3685
|
+
npairs = (jsint) GET_ATOM_INDEX(pc2);
|
|
3686
|
+
pc2 += ATOM_INDEX_LEN;
|
|
3687
|
+
|
|
3688
|
+
#define SEARCH_PAIRS(MATCH_CODE) \
|
|
3689
|
+
while (npairs) { \
|
|
3690
|
+
atom = GET_ATOM(cx, script, pc2); \
|
|
3691
|
+
rval = ATOM_KEY(atom); \
|
|
3692
|
+
MATCH_CODE \
|
|
3693
|
+
if (match) { \
|
|
3694
|
+
pc2 += ATOM_INDEX_LEN; \
|
|
3695
|
+
len = GET_JUMP_OFFSET(pc2); \
|
|
3696
|
+
goto advance_pc; \
|
|
3697
|
+
} \
|
|
3698
|
+
pc2 += ATOM_INDEX_LEN + JUMP_OFFSET_LEN; \
|
|
3699
|
+
npairs--; \
|
|
3700
|
+
}
|
|
3701
|
+
if (JSVAL_IS_STRING(lval)) {
|
|
3702
|
+
str = JSVAL_TO_STRING(lval);
|
|
3703
|
+
SEARCH_PAIRS(
|
|
3704
|
+
match = (JSVAL_IS_STRING(rval) &&
|
|
3705
|
+
((str2 = JSVAL_TO_STRING(rval)) == str ||
|
|
3706
|
+
!js_CompareStrings(str2, str)));
|
|
3707
|
+
)
|
|
3708
|
+
} else if (JSVAL_IS_DOUBLE(lval)) {
|
|
3709
|
+
d = *JSVAL_TO_DOUBLE(lval);
|
|
3710
|
+
SEARCH_PAIRS(
|
|
3711
|
+
match = (JSVAL_IS_DOUBLE(rval) &&
|
|
3712
|
+
*JSVAL_TO_DOUBLE(rval) == d);
|
|
3713
|
+
)
|
|
3714
|
+
} else {
|
|
3715
|
+
SEARCH_PAIRS(
|
|
3716
|
+
match = (lval == rval);
|
|
3717
|
+
)
|
|
3718
|
+
}
|
|
3719
|
+
#undef SEARCH_PAIRS
|
|
3720
|
+
break;
|
|
3721
|
+
|
|
3722
|
+
case JSOP_TABLESWITCHX:
|
|
3723
|
+
pc2 = pc;
|
|
3724
|
+
len = GET_JUMPX_OFFSET(pc2);
|
|
3725
|
+
|
|
3726
|
+
/*
|
|
3727
|
+
* ECMAv2 forbids conversion of discriminant, so we will skip to
|
|
3728
|
+
* the default case if the discriminant isn't already an int jsval.
|
|
3729
|
+
* (This opcode is emitted only for dense jsint-domain switches.)
|
|
3730
|
+
*/
|
|
3731
|
+
if (cx->version == JSVERSION_DEFAULT ||
|
|
3732
|
+
cx->version >= JSVERSION_1_4) {
|
|
3733
|
+
rval = POP_OPND();
|
|
3734
|
+
if (!JSVAL_IS_INT(rval))
|
|
3735
|
+
break;
|
|
3736
|
+
i = JSVAL_TO_INT(rval);
|
|
3737
|
+
} else {
|
|
3738
|
+
FETCH_INT(cx, -1, i);
|
|
3739
|
+
sp--;
|
|
3740
|
+
}
|
|
3741
|
+
|
|
3742
|
+
pc2 += JUMPX_OFFSET_LEN;
|
|
3743
|
+
low = GET_JUMP_OFFSET(pc2);
|
|
3744
|
+
pc2 += JUMP_OFFSET_LEN;
|
|
3745
|
+
high = GET_JUMP_OFFSET(pc2);
|
|
3746
|
+
|
|
3747
|
+
i -= low;
|
|
3748
|
+
if ((jsuint)i < (jsuint)(high - low + 1)) {
|
|
3749
|
+
pc2 += JUMP_OFFSET_LEN + JUMPX_OFFSET_LEN * i;
|
|
3750
|
+
off = (jsint) GET_JUMPX_OFFSET(pc2);
|
|
3751
|
+
if (off)
|
|
3752
|
+
len = off;
|
|
3753
|
+
}
|
|
3754
|
+
break;
|
|
3755
|
+
|
|
3756
|
+
case JSOP_LOOKUPSWITCHX:
|
|
3757
|
+
lval = POP_OPND();
|
|
3758
|
+
pc2 = pc;
|
|
3759
|
+
len = GET_JUMPX_OFFSET(pc2);
|
|
3760
|
+
|
|
3761
|
+
if (!JSVAL_IS_NUMBER(lval) &&
|
|
3762
|
+
!JSVAL_IS_STRING(lval) &&
|
|
3763
|
+
!JSVAL_IS_BOOLEAN(lval)) {
|
|
3764
|
+
goto advance_pc;
|
|
3765
|
+
}
|
|
3766
|
+
|
|
3767
|
+
pc2 += JUMPX_OFFSET_LEN;
|
|
3768
|
+
npairs = (jsint) GET_ATOM_INDEX(pc2);
|
|
3769
|
+
pc2 += ATOM_INDEX_LEN;
|
|
3770
|
+
|
|
3771
|
+
#define SEARCH_EXTENDED_PAIRS(MATCH_CODE) \
|
|
3772
|
+
while (npairs) { \
|
|
3773
|
+
atom = GET_ATOM(cx, script, pc2); \
|
|
3774
|
+
rval = ATOM_KEY(atom); \
|
|
3775
|
+
MATCH_CODE \
|
|
3776
|
+
if (match) { \
|
|
3777
|
+
pc2 += ATOM_INDEX_LEN; \
|
|
3778
|
+
len = GET_JUMPX_OFFSET(pc2); \
|
|
3779
|
+
goto advance_pc; \
|
|
3780
|
+
} \
|
|
3781
|
+
pc2 += ATOM_INDEX_LEN + JUMPX_OFFSET_LEN; \
|
|
3782
|
+
npairs--; \
|
|
3783
|
+
}
|
|
3784
|
+
if (JSVAL_IS_STRING(lval)) {
|
|
3785
|
+
str = JSVAL_TO_STRING(lval);
|
|
3786
|
+
SEARCH_EXTENDED_PAIRS(
|
|
3787
|
+
match = (JSVAL_IS_STRING(rval) &&
|
|
3788
|
+
((str2 = JSVAL_TO_STRING(rval)) == str ||
|
|
3789
|
+
!js_CompareStrings(str2, str)));
|
|
3790
|
+
)
|
|
3791
|
+
} else if (JSVAL_IS_DOUBLE(lval)) {
|
|
3792
|
+
d = *JSVAL_TO_DOUBLE(lval);
|
|
3793
|
+
SEARCH_EXTENDED_PAIRS(
|
|
3794
|
+
match = (JSVAL_IS_DOUBLE(rval) &&
|
|
3795
|
+
*JSVAL_TO_DOUBLE(rval) == d);
|
|
3796
|
+
)
|
|
3797
|
+
} else {
|
|
3798
|
+
SEARCH_EXTENDED_PAIRS(
|
|
3799
|
+
match = (lval == rval);
|
|
3800
|
+
)
|
|
3801
|
+
}
|
|
3802
|
+
#undef SEARCH_EXTENDED_PAIRS
|
|
3803
|
+
break;
|
|
3804
|
+
|
|
3805
|
+
case JSOP_CONDSWITCH:
|
|
3806
|
+
break;
|
|
3807
|
+
|
|
3808
|
+
#endif /* JS_HAS_SWITCH_STATEMENT */
|
|
3809
|
+
|
|
3810
|
+
#if JS_HAS_EXPORT_IMPORT
|
|
3811
|
+
case JSOP_EXPORTALL:
|
|
3812
|
+
obj = fp->varobj;
|
|
3813
|
+
ida = JS_Enumerate(cx, obj);
|
|
3814
|
+
if (!ida) {
|
|
3815
|
+
ok = JS_FALSE;
|
|
3816
|
+
} else {
|
|
3817
|
+
for (i = 0, j = ida->length; i < j; i++) {
|
|
3818
|
+
id = ida->vector[i];
|
|
3819
|
+
ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
|
|
3820
|
+
if (!ok)
|
|
3821
|
+
break;
|
|
3822
|
+
if (!prop)
|
|
3823
|
+
continue;
|
|
3824
|
+
ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
|
|
3825
|
+
if (ok) {
|
|
3826
|
+
attrs |= JSPROP_EXPORTED;
|
|
3827
|
+
ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, &attrs);
|
|
3828
|
+
}
|
|
3829
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
3830
|
+
if (!ok)
|
|
3831
|
+
break;
|
|
3832
|
+
}
|
|
3833
|
+
JS_DestroyIdArray(cx, ida);
|
|
3834
|
+
}
|
|
3835
|
+
break;
|
|
3836
|
+
|
|
3837
|
+
case JSOP_EXPORTNAME:
|
|
3838
|
+
atom = GET_ATOM(cx, script, pc);
|
|
3839
|
+
id = (jsid)atom;
|
|
3840
|
+
obj = fp->varobj;
|
|
3841
|
+
ok = OBJ_LOOKUP_PROPERTY(cx, obj, id, &obj2, &prop);
|
|
3842
|
+
if (!ok)
|
|
3843
|
+
goto out;
|
|
3844
|
+
if (!prop) {
|
|
3845
|
+
ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL,
|
|
3846
|
+
JSPROP_EXPORTED, NULL);
|
|
3847
|
+
} else {
|
|
3848
|
+
ok = OBJ_GET_ATTRIBUTES(cx, obj, id, prop, &attrs);
|
|
3849
|
+
if (ok) {
|
|
3850
|
+
attrs |= JSPROP_EXPORTED;
|
|
3851
|
+
ok = OBJ_SET_ATTRIBUTES(cx, obj, id, prop, &attrs);
|
|
3852
|
+
}
|
|
3853
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
3854
|
+
}
|
|
3855
|
+
if (!ok)
|
|
3856
|
+
goto out;
|
|
3857
|
+
break;
|
|
3858
|
+
|
|
3859
|
+
case JSOP_IMPORTALL:
|
|
3860
|
+
id = (jsid)JSVAL_VOID;
|
|
3861
|
+
PROPERTY_OP(-1, ok = ImportProperty(cx, obj, id));
|
|
3862
|
+
sp--;
|
|
3863
|
+
break;
|
|
3864
|
+
|
|
3865
|
+
case JSOP_IMPORTPROP:
|
|
3866
|
+
/* Get an immediate atom naming the property. */
|
|
3867
|
+
atom = GET_ATOM(cx, script, pc);
|
|
3868
|
+
id = (jsid)atom;
|
|
3869
|
+
PROPERTY_OP(-1, ok = ImportProperty(cx, obj, id));
|
|
3870
|
+
sp--;
|
|
3871
|
+
break;
|
|
3872
|
+
|
|
3873
|
+
case JSOP_IMPORTELEM:
|
|
3874
|
+
ELEMENT_OP(-1, ok = ImportProperty(cx, obj, id));
|
|
3875
|
+
sp -= 2;
|
|
3876
|
+
break;
|
|
3877
|
+
#endif /* JS_HAS_EXPORT_IMPORT */
|
|
3878
|
+
|
|
3879
|
+
case JSOP_TRAP:
|
|
3880
|
+
switch (JS_HandleTrap(cx, script, pc, &rval)) {
|
|
3881
|
+
case JSTRAP_ERROR:
|
|
3882
|
+
ok = JS_FALSE;
|
|
3883
|
+
goto out;
|
|
3884
|
+
case JSTRAP_CONTINUE:
|
|
3885
|
+
JS_ASSERT(JSVAL_IS_INT(rval));
|
|
3886
|
+
op = (JSOp) JSVAL_TO_INT(rval);
|
|
3887
|
+
JS_ASSERT((uintN)op < (uintN)JSOP_LIMIT);
|
|
3888
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
3889
|
+
goto do_op;
|
|
3890
|
+
case JSTRAP_RETURN:
|
|
3891
|
+
fp->rval = rval;
|
|
3892
|
+
goto out;
|
|
3893
|
+
#if JS_HAS_EXCEPTIONS
|
|
3894
|
+
case JSTRAP_THROW:
|
|
3895
|
+
cx->throwing = JS_TRUE;
|
|
3896
|
+
cx->exception = rval;
|
|
3897
|
+
ok = JS_FALSE;
|
|
3898
|
+
goto out;
|
|
3899
|
+
#endif /* JS_HAS_EXCEPTIONS */
|
|
3900
|
+
default:;
|
|
3901
|
+
}
|
|
3902
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
3903
|
+
break;
|
|
3904
|
+
|
|
3905
|
+
case JSOP_ARGUMENTS:
|
|
3906
|
+
SAVE_SP(fp);
|
|
3907
|
+
ok = js_GetArgsValue(cx, fp, &rval);
|
|
3908
|
+
if (!ok)
|
|
3909
|
+
goto out;
|
|
3910
|
+
PUSH_OPND(rval);
|
|
3911
|
+
break;
|
|
3912
|
+
|
|
3913
|
+
case JSOP_ARGSUB:
|
|
3914
|
+
id = (jsid) INT_TO_JSVAL(GET_ARGNO(pc));
|
|
3915
|
+
SAVE_SP(fp);
|
|
3916
|
+
ok = js_GetArgsProperty(cx, fp, id, &obj, &rval);
|
|
3917
|
+
if (!ok)
|
|
3918
|
+
goto out;
|
|
3919
|
+
if (!obj) {
|
|
3920
|
+
/*
|
|
3921
|
+
* If arguments was not overridden by eval('arguments = ...'),
|
|
3922
|
+
* set obj to the magic cookie respected by JSOP_PUSHOBJ, just
|
|
3923
|
+
* in case this bytecode is part of an 'arguments[i](j, k)' or
|
|
3924
|
+
* similar such invocation sequence, where the function that
|
|
3925
|
+
* is invoked expects its 'this' parameter to be the caller's
|
|
3926
|
+
* arguments object.
|
|
3927
|
+
*/
|
|
3928
|
+
obj = LAZY_ARGS_THISP;
|
|
3929
|
+
}
|
|
3930
|
+
PUSH_OPND(rval);
|
|
3931
|
+
break;
|
|
3932
|
+
|
|
3933
|
+
#undef LAZY_ARGS_THISP
|
|
3934
|
+
|
|
3935
|
+
case JSOP_ARGCNT:
|
|
3936
|
+
id = (jsid) rt->atomState.lengthAtom;
|
|
3937
|
+
SAVE_SP(fp);
|
|
3938
|
+
ok = js_GetArgsProperty(cx, fp, id, &obj, &rval);
|
|
3939
|
+
if (!ok)
|
|
3940
|
+
goto out;
|
|
3941
|
+
PUSH_OPND(rval);
|
|
3942
|
+
break;
|
|
3943
|
+
|
|
3944
|
+
case JSOP_GETARG:
|
|
3945
|
+
slot = GET_ARGNO(pc);
|
|
3946
|
+
JS_ASSERT(slot < fp->fun->nargs);
|
|
3947
|
+
PUSH_OPND(fp->argv[slot]);
|
|
3948
|
+
obj = NULL;
|
|
3949
|
+
break;
|
|
3950
|
+
|
|
3951
|
+
case JSOP_SETARG:
|
|
3952
|
+
slot = GET_ARGNO(pc);
|
|
3953
|
+
JS_ASSERT(slot < fp->fun->nargs);
|
|
3954
|
+
vp = &fp->argv[slot];
|
|
3955
|
+
GC_POKE(cx, *vp);
|
|
3956
|
+
*vp = FETCH_OPND(-1);
|
|
3957
|
+
obj = NULL;
|
|
3958
|
+
break;
|
|
3959
|
+
|
|
3960
|
+
case JSOP_GETVAR:
|
|
3961
|
+
slot = GET_VARNO(pc);
|
|
3962
|
+
JS_ASSERT(slot < fp->fun->nvars);
|
|
3963
|
+
PUSH_OPND(fp->vars[slot]);
|
|
3964
|
+
obj = NULL;
|
|
3965
|
+
break;
|
|
3966
|
+
|
|
3967
|
+
case JSOP_SETVAR:
|
|
3968
|
+
slot = GET_VARNO(pc);
|
|
3969
|
+
JS_ASSERT(slot < fp->fun->nvars);
|
|
3970
|
+
vp = &fp->vars[slot];
|
|
3971
|
+
GC_POKE(cx, *vp);
|
|
3972
|
+
*vp = FETCH_OPND(-1);
|
|
3973
|
+
obj = NULL;
|
|
3974
|
+
break;
|
|
3975
|
+
|
|
3976
|
+
case JSOP_GETGVAR:
|
|
3977
|
+
slot = GET_VARNO(pc);
|
|
3978
|
+
JS_ASSERT(slot < fp->nvars);
|
|
3979
|
+
lval = fp->vars[slot];
|
|
3980
|
+
if (JSVAL_IS_NULL(lval)) {
|
|
3981
|
+
op = JSOP_NAME;
|
|
3982
|
+
goto do_op;
|
|
3983
|
+
}
|
|
3984
|
+
slot = JSVAL_TO_INT(lval);
|
|
3985
|
+
obj = fp->varobj;
|
|
3986
|
+
rval = OBJ_GET_SLOT(cx, obj, slot);
|
|
3987
|
+
PUSH_OPND(rval);
|
|
3988
|
+
break;
|
|
3989
|
+
|
|
3990
|
+
case JSOP_SETGVAR:
|
|
3991
|
+
slot = GET_VARNO(pc);
|
|
3992
|
+
JS_ASSERT(slot < fp->nvars);
|
|
3993
|
+
rval = FETCH_OPND(-1);
|
|
3994
|
+
lval = fp->vars[slot];
|
|
3995
|
+
obj = fp->varobj;
|
|
3996
|
+
if (JSVAL_IS_NULL(lval)) {
|
|
3997
|
+
/*
|
|
3998
|
+
* Inline-clone and specialize JSOP_SETNAME code here because
|
|
3999
|
+
* JSOP_SETGVAR has arity 1: [rval], not arity 2: [obj, rval]
|
|
4000
|
+
* as JSOP_SETNAME does, where [obj] is due to JSOP_BINDNAME.
|
|
4001
|
+
*/
|
|
4002
|
+
atom = GET_ATOM(cx, script, pc);
|
|
4003
|
+
id = (jsid)atom;
|
|
4004
|
+
SAVE_SP(fp);
|
|
4005
|
+
CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval));
|
|
4006
|
+
if (!ok)
|
|
4007
|
+
goto out;
|
|
4008
|
+
STORE_OPND(-1, rval);
|
|
4009
|
+
} else {
|
|
4010
|
+
slot = JSVAL_TO_INT(lval);
|
|
4011
|
+
GC_POKE(cx, obj->slots[slot]);
|
|
4012
|
+
OBJ_SET_SLOT(cx, obj, slot, rval);
|
|
4013
|
+
}
|
|
4014
|
+
break;
|
|
4015
|
+
|
|
4016
|
+
case JSOP_DEFCONST:
|
|
4017
|
+
case JSOP_DEFVAR:
|
|
4018
|
+
{
|
|
4019
|
+
jsatomid atomIndex;
|
|
4020
|
+
|
|
4021
|
+
atomIndex = GET_ATOM_INDEX(pc);
|
|
4022
|
+
atom = js_GetAtom(cx, &script->atomMap, atomIndex);
|
|
4023
|
+
obj = fp->varobj;
|
|
4024
|
+
attrs = JSPROP_ENUMERATE;
|
|
4025
|
+
if (!(fp->flags & JSFRAME_EVAL))
|
|
4026
|
+
attrs |= JSPROP_PERMANENT;
|
|
4027
|
+
if (op == JSOP_DEFCONST)
|
|
4028
|
+
attrs |= JSPROP_READONLY;
|
|
4029
|
+
|
|
4030
|
+
/* Lookup id in order to check for redeclaration problems. */
|
|
4031
|
+
id = (jsid)atom;
|
|
4032
|
+
ok = js_CheckRedeclaration(cx, obj, id, attrs, &obj2, &prop);
|
|
4033
|
+
if (!ok)
|
|
4034
|
+
goto out;
|
|
4035
|
+
|
|
4036
|
+
/* Bind a variable only if it's not yet defined. */
|
|
4037
|
+
if (!prop) {
|
|
4038
|
+
ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL,
|
|
4039
|
+
attrs, &prop);
|
|
4040
|
+
if (!ok)
|
|
4041
|
+
goto out;
|
|
4042
|
+
JS_ASSERT(prop);
|
|
4043
|
+
obj2 = obj;
|
|
4044
|
+
}
|
|
4045
|
+
|
|
4046
|
+
/*
|
|
4047
|
+
* Try to optimize a property we either just created, or found
|
|
4048
|
+
* directly in the global object, that is permanent, has a slot,
|
|
4049
|
+
* and has stub getter and setter, into a "fast global" accessed
|
|
4050
|
+
* by the JSOP_*GVAR opcodes.
|
|
4051
|
+
*/
|
|
4052
|
+
if (script->numGlobalVars &&
|
|
4053
|
+
(attrs & JSPROP_PERMANENT) &&
|
|
4054
|
+
obj2 == obj &&
|
|
4055
|
+
OBJ_IS_NATIVE(obj)) {
|
|
4056
|
+
sprop = (JSScopeProperty *) prop;
|
|
4057
|
+
if (SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj)) &&
|
|
4058
|
+
SPROP_HAS_STUB_GETTER(sprop) &&
|
|
4059
|
+
SPROP_HAS_STUB_SETTER(sprop)) {
|
|
4060
|
+
/*
|
|
4061
|
+
* Fast globals use fp->vars to map the global name's
|
|
4062
|
+
* atomIndex to the permanent fp->varobj slot number,
|
|
4063
|
+
* tagged as a jsval. The atomIndex for the global's
|
|
4064
|
+
* name literal is identical to its fp->vars index.
|
|
4065
|
+
*/
|
|
4066
|
+
fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
|
|
4067
|
+
}
|
|
4068
|
+
}
|
|
4069
|
+
|
|
4070
|
+
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
|
4071
|
+
break;
|
|
4072
|
+
}
|
|
4073
|
+
|
|
4074
|
+
case JSOP_DEFFUN:
|
|
4075
|
+
{
|
|
4076
|
+
jsatomid atomIndex;
|
|
4077
|
+
uintN flags;
|
|
4078
|
+
|
|
4079
|
+
atomIndex = GET_ATOM_INDEX(pc);
|
|
4080
|
+
atom = js_GetAtom(cx, &script->atomMap, atomIndex);
|
|
4081
|
+
obj = ATOM_TO_OBJECT(atom);
|
|
4082
|
+
fun = (JSFunction *) JS_GetPrivate(cx, obj);
|
|
4083
|
+
id = (jsid) fun->atom;
|
|
4084
|
+
|
|
4085
|
+
/*
|
|
4086
|
+
* We must be at top-level (either outermost block that forms a
|
|
4087
|
+
* function's body, or a global) scope, not inside an expression
|
|
4088
|
+
* (JSOP_{ANON,NAMED}FUNOBJ) or compound statement (JSOP_CLOSURE)
|
|
4089
|
+
* in the same compilation unit (ECMA Program).
|
|
4090
|
+
*
|
|
4091
|
+
* However, we could be in a Program being eval'd from inside a
|
|
4092
|
+
* with statement, so we need to distinguish variables object from
|
|
4093
|
+
* scope chain head. Hence the two assignments to parent below.
|
|
4094
|
+
* First we make sure the function object we're defining has the
|
|
4095
|
+
* right scope chain. Then we define its name in fp->varobj.
|
|
4096
|
+
*
|
|
4097
|
+
* If static link is not current scope, clone fun's object to link
|
|
4098
|
+
* to the current scope via parent. This clause exists to enable
|
|
4099
|
+
* sharing of compiled functions among multiple equivalent scopes,
|
|
4100
|
+
* splitting the cost of compilation evenly among the scopes and
|
|
4101
|
+
* amortizing it over a number of executions. Examples include XUL
|
|
4102
|
+
* scripts and event handlers shared among Mozilla chrome windows,
|
|
4103
|
+
* and server-side JS user-defined functions shared among requests.
|
|
4104
|
+
*
|
|
4105
|
+
* NB: The Script object exposes compile and exec in the language,
|
|
4106
|
+
* such that this clause introduces an incompatible change from old
|
|
4107
|
+
* JS versions that supported Script. Such a JS version supported
|
|
4108
|
+
* executing a script that defined and called functions scoped by
|
|
4109
|
+
* the compile-time static link, not by the exec-time scope chain.
|
|
4110
|
+
*
|
|
4111
|
+
* We sacrifice compatibility, breaking such scripts, in order to
|
|
4112
|
+
* promote compile-cost sharing and amortizing, and because Script
|
|
4113
|
+
* is not and will not be standardized.
|
|
4114
|
+
*/
|
|
4115
|
+
parent = fp->scopeChain;
|
|
4116
|
+
if (OBJ_GET_PARENT(cx, obj) != parent) {
|
|
4117
|
+
obj = js_CloneFunctionObject(cx, obj, parent);
|
|
4118
|
+
if (!obj) {
|
|
4119
|
+
ok = JS_FALSE;
|
|
4120
|
+
goto out;
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4124
|
+
/*
|
|
4125
|
+
* ECMA requires functions defined when entering Global code to be
|
|
4126
|
+
* permanent, and functions defined when entering Eval code to be
|
|
4127
|
+
* impermanent.
|
|
4128
|
+
*/
|
|
4129
|
+
attrs = JSPROP_ENUMERATE;
|
|
4130
|
+
if (!(fp->flags & JSFRAME_EVAL))
|
|
4131
|
+
attrs |= JSPROP_PERMANENT;
|
|
4132
|
+
|
|
4133
|
+
/*
|
|
4134
|
+
* Load function flags that are also property attributes. Getters
|
|
4135
|
+
* and setters do not need a slot, their value is stored elsewhere
|
|
4136
|
+
* in the property itself, not in obj->slots.
|
|
4137
|
+
*/
|
|
4138
|
+
flags = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
|
|
4139
|
+
if (flags)
|
|
4140
|
+
attrs |= flags | JSPROP_SHARED;
|
|
4141
|
+
|
|
4142
|
+
/*
|
|
4143
|
+
* Check for a const property of the same name -- or any kind
|
|
4144
|
+
* of property if executing with the strict option. We check
|
|
4145
|
+
* here at runtime as well as at compile-time, to handle eval
|
|
4146
|
+
* as well as multiple HTML script tags.
|
|
4147
|
+
*/
|
|
4148
|
+
parent = fp->varobj;
|
|
4149
|
+
ok = js_CheckRedeclaration(cx, parent, id, attrs, NULL, NULL);
|
|
4150
|
+
if (!ok)
|
|
4151
|
+
goto out;
|
|
4152
|
+
|
|
4153
|
+
ok = OBJ_DEFINE_PROPERTY(cx, parent, id,
|
|
4154
|
+
flags ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
|
|
4155
|
+
(flags & JSFUN_GETTER)
|
|
4156
|
+
? (JSPropertyOp) obj
|
|
4157
|
+
: NULL,
|
|
4158
|
+
(flags & JSFUN_SETTER)
|
|
4159
|
+
? (JSPropertyOp) obj
|
|
4160
|
+
: NULL,
|
|
4161
|
+
attrs,
|
|
4162
|
+
&prop);
|
|
4163
|
+
if (!ok)
|
|
4164
|
+
goto out;
|
|
4165
|
+
if (attrs == (JSPROP_ENUMERATE | JSPROP_PERMANENT) &&
|
|
4166
|
+
script->numGlobalVars) {
|
|
4167
|
+
/*
|
|
4168
|
+
* As with JSOP_DEFVAR and JSOP_DEFCONST (above), fast globals
|
|
4169
|
+
* use fp->vars to map the global function name's atomIndex to
|
|
4170
|
+
* its permanent fp->varobj slot number, tagged as a jsval.
|
|
4171
|
+
*/
|
|
4172
|
+
sprop = (JSScopeProperty *) prop;
|
|
4173
|
+
fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
|
|
4174
|
+
}
|
|
4175
|
+
OBJ_DROP_PROPERTY(cx, parent, prop);
|
|
4176
|
+
break;
|
|
4177
|
+
}
|
|
4178
|
+
|
|
4179
|
+
#if JS_HAS_LEXICAL_CLOSURE
|
|
4180
|
+
case JSOP_DEFLOCALFUN:
|
|
4181
|
+
/*
|
|
4182
|
+
* Define a local function (i.e., one nested at the top level of
|
|
4183
|
+
* another function), parented by the current scope chain, and
|
|
4184
|
+
* stored in a local variable slot that the compiler allocated.
|
|
4185
|
+
* This is an optimization over JSOP_DEFFUN that avoids requiring
|
|
4186
|
+
* a call object for the outer function's activation.
|
|
4187
|
+
*/
|
|
4188
|
+
pc2 = pc;
|
|
4189
|
+
slot = GET_VARNO(pc2);
|
|
4190
|
+
pc2 += VARNO_LEN;
|
|
4191
|
+
atom = GET_ATOM(cx, script, pc2);
|
|
4192
|
+
obj = ATOM_TO_OBJECT(atom);
|
|
4193
|
+
fun = (JSFunction *) JS_GetPrivate(cx, obj);
|
|
4194
|
+
|
|
4195
|
+
parent = fp->scopeChain;
|
|
4196
|
+
if (OBJ_GET_PARENT(cx, obj) != parent) {
|
|
4197
|
+
obj = js_CloneFunctionObject(cx, obj, parent);
|
|
4198
|
+
if (!obj) {
|
|
4199
|
+
ok = JS_FALSE;
|
|
4200
|
+
goto out;
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
fp->vars[slot] = OBJECT_TO_JSVAL(obj);
|
|
4204
|
+
break;
|
|
4205
|
+
|
|
4206
|
+
case JSOP_ANONFUNOBJ:
|
|
4207
|
+
/* Push the specified function object literal. */
|
|
4208
|
+
atom = GET_ATOM(cx, script, pc);
|
|
4209
|
+
obj = ATOM_TO_OBJECT(atom);
|
|
4210
|
+
|
|
4211
|
+
/* If re-parenting, push a clone of the function object. */
|
|
4212
|
+
parent = fp->scopeChain;
|
|
4213
|
+
if (OBJ_GET_PARENT(cx, obj) != parent) {
|
|
4214
|
+
obj = js_CloneFunctionObject(cx, obj, parent);
|
|
4215
|
+
if (!obj) {
|
|
4216
|
+
ok = JS_FALSE;
|
|
4217
|
+
goto out;
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
|
4221
|
+
break;
|
|
4222
|
+
|
|
4223
|
+
case JSOP_NAMEDFUNOBJ:
|
|
4224
|
+
/* ECMA ed. 3 FunctionExpression: function Identifier [etc.]. */
|
|
4225
|
+
atom = GET_ATOM(cx, script, pc);
|
|
4226
|
+
rval = ATOM_KEY(atom);
|
|
4227
|
+
JS_ASSERT(JSVAL_IS_FUNCTION(cx, rval));
|
|
4228
|
+
|
|
4229
|
+
/*
|
|
4230
|
+
* 1. Create a new object as if by the expression new Object().
|
|
4231
|
+
* 2. Add Result(1) to the front of the scope chain.
|
|
4232
|
+
*
|
|
4233
|
+
* Step 2 is achieved by making the new object's parent be the
|
|
4234
|
+
* current scope chain, and then making the new object the parent
|
|
4235
|
+
* of the Function object clone.
|
|
4236
|
+
*/
|
|
4237
|
+
SAVE_SP(fp);
|
|
4238
|
+
parent = js_ConstructObject(cx, &js_ObjectClass, NULL,
|
|
4239
|
+
fp->scopeChain, 0, NULL);
|
|
4240
|
+
if (!parent) {
|
|
4241
|
+
ok = JS_FALSE;
|
|
4242
|
+
goto out;
|
|
4243
|
+
}
|
|
4244
|
+
|
|
4245
|
+
/*
|
|
4246
|
+
* 3. Create a new Function object as specified in section 13.2
|
|
4247
|
+
* with [parameters and body specified by the function expression
|
|
4248
|
+
* that was parsed by the compiler into a Function object, and
|
|
4249
|
+
* saved in the script's atom map].
|
|
4250
|
+
*/
|
|
4251
|
+
obj = js_CloneFunctionObject(cx, JSVAL_TO_OBJECT(rval), parent);
|
|
4252
|
+
if (!obj) {
|
|
4253
|
+
ok = JS_FALSE;
|
|
4254
|
+
goto out;
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4257
|
+
/*
|
|
4258
|
+
* 4. Create a property in the object Result(1). The property's
|
|
4259
|
+
* name is [fun->atom, the identifier parsed by the compiler],
|
|
4260
|
+
* value is Result(3), and attributes are { DontDelete, ReadOnly }.
|
|
4261
|
+
*/
|
|
4262
|
+
fun = (JSFunction *) JS_GetPrivate(cx, obj);
|
|
4263
|
+
attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
|
|
4264
|
+
if (attrs)
|
|
4265
|
+
attrs |= JSPROP_SHARED;
|
|
4266
|
+
ok = OBJ_DEFINE_PROPERTY(cx, parent, (jsid)fun->atom,
|
|
4267
|
+
attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
|
|
4268
|
+
(attrs & JSFUN_GETTER)
|
|
4269
|
+
? (JSPropertyOp) obj
|
|
4270
|
+
: NULL,
|
|
4271
|
+
(attrs & JSFUN_SETTER)
|
|
4272
|
+
? (JSPropertyOp) obj
|
|
4273
|
+
: NULL,
|
|
4274
|
+
attrs |
|
|
4275
|
+
JSPROP_ENUMERATE | JSPROP_PERMANENT |
|
|
4276
|
+
JSPROP_READONLY,
|
|
4277
|
+
NULL);
|
|
4278
|
+
if (!ok) {
|
|
4279
|
+
cx->newborn[GCX_OBJECT] = NULL;
|
|
4280
|
+
goto out;
|
|
4281
|
+
}
|
|
4282
|
+
|
|
4283
|
+
/*
|
|
4284
|
+
* 5. Remove Result(1) from the front of the scope chain [no-op].
|
|
4285
|
+
* 6. Return Result(3).
|
|
4286
|
+
*/
|
|
4287
|
+
PUSH_OPND(OBJECT_TO_JSVAL(obj));
|
|
4288
|
+
break;
|
|
4289
|
+
|
|
4290
|
+
case JSOP_CLOSURE:
|
|
4291
|
+
{
|
|
4292
|
+
jsatomid atomIndex;
|
|
4293
|
+
|
|
4294
|
+
/*
|
|
4295
|
+
* ECMA ed. 3 extension: a named function expression in a compound
|
|
4296
|
+
* statement (not at the top statement level of global code, or at
|
|
4297
|
+
* the top level of a function body).
|
|
4298
|
+
*
|
|
4299
|
+
* Get immediate operand atom, which is a function object literal.
|
|
4300
|
+
* From it, get the function to close.
|
|
4301
|
+
*/
|
|
4302
|
+
atomIndex = GET_ATOM_INDEX(pc);
|
|
4303
|
+
atom = js_GetAtom(cx, &script->atomMap, atomIndex);
|
|
4304
|
+
JS_ASSERT(JSVAL_IS_FUNCTION(cx, ATOM_KEY(atom)));
|
|
4305
|
+
obj = ATOM_TO_OBJECT(atom);
|
|
4306
|
+
|
|
4307
|
+
/*
|
|
4308
|
+
* Clone the function object with the current scope chain as the
|
|
4309
|
+
* clone's parent. The original function object is the prototype
|
|
4310
|
+
* of the clone. Do this only if re-parenting; the compiler may
|
|
4311
|
+
* have seen the right parent already and created a sufficiently
|
|
4312
|
+
* well-scoped function object.
|
|
4313
|
+
*/
|
|
4314
|
+
parent = fp->scopeChain;
|
|
4315
|
+
if (OBJ_GET_PARENT(cx, obj) != parent) {
|
|
4316
|
+
obj = js_CloneFunctionObject(cx, obj, parent);
|
|
4317
|
+
if (!obj) {
|
|
4318
|
+
ok = JS_FALSE;
|
|
4319
|
+
goto out;
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
/*
|
|
4324
|
+
* Make a property in fp->varobj with id fun->atom and value obj,
|
|
4325
|
+
* unless fun is a getter or setter (in which case, obj is cast to
|
|
4326
|
+
* a JSPropertyOp and passed accordingly).
|
|
4327
|
+
*/
|
|
4328
|
+
fun = (JSFunction *) JS_GetPrivate(cx, obj);
|
|
4329
|
+
attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER);
|
|
4330
|
+
if (attrs)
|
|
4331
|
+
attrs |= JSPROP_SHARED;
|
|
4332
|
+
parent = fp->varobj;
|
|
4333
|
+
ok = OBJ_DEFINE_PROPERTY(cx, parent, (jsid)fun->atom,
|
|
4334
|
+
attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj),
|
|
4335
|
+
(attrs & JSFUN_GETTER)
|
|
4336
|
+
? (JSPropertyOp) obj
|
|
4337
|
+
: NULL,
|
|
4338
|
+
(attrs & JSFUN_SETTER)
|
|
4339
|
+
? (JSPropertyOp) obj
|
|
4340
|
+
: NULL,
|
|
4341
|
+
attrs | JSPROP_ENUMERATE
|
|
4342
|
+
| JSPROP_PERMANENT,
|
|
4343
|
+
&prop);
|
|
4344
|
+
if (!ok) {
|
|
4345
|
+
cx->newborn[GCX_OBJECT] = NULL;
|
|
4346
|
+
goto out;
|
|
4347
|
+
}
|
|
4348
|
+
if (attrs == 0 && script->numGlobalVars) {
|
|
4349
|
+
/*
|
|
4350
|
+
* As with JSOP_DEFVAR and JSOP_DEFCONST (above), fast globals
|
|
4351
|
+
* use fp->vars to map the global function name's atomIndex to
|
|
4352
|
+
* its permanent fp->varobj slot number, tagged as a jsval.
|
|
4353
|
+
*/
|
|
4354
|
+
sprop = (JSScopeProperty *) prop;
|
|
4355
|
+
fp->vars[atomIndex] = INT_TO_JSVAL(sprop->slot);
|
|
4356
|
+
}
|
|
4357
|
+
OBJ_DROP_PROPERTY(cx, parent, prop);
|
|
4358
|
+
break;
|
|
4359
|
+
}
|
|
4360
|
+
#endif /* JS_HAS_LEXICAL_CLOSURE */
|
|
4361
|
+
|
|
4362
|
+
#if JS_HAS_GETTER_SETTER
|
|
4363
|
+
case JSOP_GETTER:
|
|
4364
|
+
case JSOP_SETTER:
|
|
4365
|
+
JS_ASSERT(len == 1);
|
|
4366
|
+
op2 = (JSOp) *++pc;
|
|
4367
|
+
cs = &js_CodeSpec[op2];
|
|
4368
|
+
len = cs->length;
|
|
4369
|
+
switch (op2) {
|
|
4370
|
+
case JSOP_SETNAME:
|
|
4371
|
+
case JSOP_SETPROP:
|
|
4372
|
+
atom = GET_ATOM(cx, script, pc);
|
|
4373
|
+
id = (jsid)atom;
|
|
4374
|
+
i = -1;
|
|
4375
|
+
rval = FETCH_OPND(i);
|
|
4376
|
+
goto gs_pop_lval;
|
|
4377
|
+
|
|
4378
|
+
case JSOP_SETELEM:
|
|
4379
|
+
rval = FETCH_OPND(-1);
|
|
4380
|
+
i = -2;
|
|
4381
|
+
FETCH_ELEMENT_ID(i, id);
|
|
4382
|
+
gs_pop_lval:
|
|
4383
|
+
lval = FETCH_OPND(i-1);
|
|
4384
|
+
VALUE_TO_OBJECT(cx, lval, obj);
|
|
4385
|
+
break;
|
|
4386
|
+
|
|
4387
|
+
#if JS_HAS_INITIALIZERS
|
|
4388
|
+
case JSOP_INITPROP:
|
|
4389
|
+
JS_ASSERT(sp - fp->spbase >= 2);
|
|
4390
|
+
i = -1;
|
|
4391
|
+
rval = FETCH_OPND(i);
|
|
4392
|
+
atom = GET_ATOM(cx, script, pc);
|
|
4393
|
+
id = (jsid)atom;
|
|
4394
|
+
goto gs_get_lval;
|
|
4395
|
+
|
|
4396
|
+
case JSOP_INITELEM:
|
|
4397
|
+
JS_ASSERT(sp - fp->spbase >= 3);
|
|
4398
|
+
rval = FETCH_OPND(-1);
|
|
4399
|
+
i = -2;
|
|
4400
|
+
FETCH_ELEMENT_ID(i, id);
|
|
4401
|
+
gs_get_lval:
|
|
4402
|
+
lval = FETCH_OPND(i-1);
|
|
4403
|
+
JS_ASSERT(JSVAL_IS_OBJECT(lval));
|
|
4404
|
+
obj = JSVAL_TO_OBJECT(lval);
|
|
4405
|
+
break;
|
|
4406
|
+
#endif /* JS_HAS_INITIALIZERS */
|
|
4407
|
+
|
|
4408
|
+
default:
|
|
4409
|
+
JS_ASSERT(0);
|
|
4410
|
+
}
|
|
4411
|
+
|
|
4412
|
+
if (JS_TypeOfValue(cx, rval) != JSTYPE_FUNCTION) {
|
|
4413
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
4414
|
+
JSMSG_BAD_GETTER_OR_SETTER,
|
|
4415
|
+
(op == JSOP_GETTER)
|
|
4416
|
+
? js_getter_str
|
|
4417
|
+
: js_setter_str);
|
|
4418
|
+
ok = JS_FALSE;
|
|
4419
|
+
goto out;
|
|
4420
|
+
}
|
|
4421
|
+
|
|
4422
|
+
/*
|
|
4423
|
+
* Getters and setters are just like watchpoints from an access
|
|
4424
|
+
* control point of view.
|
|
4425
|
+
*/
|
|
4426
|
+
ok = OBJ_CHECK_ACCESS(cx, obj, id, JSACC_WATCH, &rtmp, &attrs);
|
|
4427
|
+
if (!ok)
|
|
4428
|
+
goto out;
|
|
4429
|
+
|
|
4430
|
+
if (op == JSOP_GETTER) {
|
|
4431
|
+
getter = (JSPropertyOp) JSVAL_TO_OBJECT(rval);
|
|
4432
|
+
setter = NULL;
|
|
4433
|
+
attrs = JSPROP_GETTER;
|
|
4434
|
+
} else {
|
|
4435
|
+
getter = NULL;
|
|
4436
|
+
setter = (JSPropertyOp) JSVAL_TO_OBJECT(rval);
|
|
4437
|
+
attrs = JSPROP_SETTER;
|
|
4438
|
+
}
|
|
4439
|
+
attrs |= JSPROP_ENUMERATE | JSPROP_SHARED;
|
|
4440
|
+
|
|
4441
|
+
/* Check for a readonly or permanent property of the same name. */
|
|
4442
|
+
ok = js_CheckRedeclaration(cx, obj, id, attrs, NULL, NULL);
|
|
4443
|
+
if (!ok)
|
|
4444
|
+
goto out;
|
|
4445
|
+
|
|
4446
|
+
ok = OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, getter, setter,
|
|
4447
|
+
attrs, NULL);
|
|
4448
|
+
if (!ok)
|
|
4449
|
+
goto out;
|
|
4450
|
+
|
|
4451
|
+
sp += i;
|
|
4452
|
+
if (cs->ndefs)
|
|
4453
|
+
STORE_OPND(-1, rval);
|
|
4454
|
+
break;
|
|
4455
|
+
#endif /* JS_HAS_GETTER_SETTER */
|
|
4456
|
+
|
|
4457
|
+
#if JS_HAS_INITIALIZERS
|
|
4458
|
+
case JSOP_NEWINIT:
|
|
4459
|
+
argc = 0;
|
|
4460
|
+
fp->sharpDepth++;
|
|
4461
|
+
goto do_new;
|
|
4462
|
+
|
|
4463
|
+
case JSOP_ENDINIT:
|
|
4464
|
+
if (--fp->sharpDepth == 0)
|
|
4465
|
+
fp->sharpArray = NULL;
|
|
4466
|
+
|
|
4467
|
+
/* Re-set the newborn root to the top of this object tree. */
|
|
4468
|
+
JS_ASSERT(sp - fp->spbase >= 1);
|
|
4469
|
+
lval = FETCH_OPND(-1);
|
|
4470
|
+
JS_ASSERT(JSVAL_IS_OBJECT(lval));
|
|
4471
|
+
cx->newborn[GCX_OBJECT] = JSVAL_TO_GCTHING(lval);
|
|
4472
|
+
break;
|
|
4473
|
+
|
|
4474
|
+
case JSOP_INITPROP:
|
|
4475
|
+
/* Pop the property's value into rval. */
|
|
4476
|
+
JS_ASSERT(sp - fp->spbase >= 2);
|
|
4477
|
+
rval = FETCH_OPND(-1);
|
|
4478
|
+
|
|
4479
|
+
/* Get the immediate property name into id. */
|
|
4480
|
+
atom = GET_ATOM(cx, script, pc);
|
|
4481
|
+
id = (jsid)atom;
|
|
4482
|
+
i = -1;
|
|
4483
|
+
goto do_init;
|
|
4484
|
+
|
|
4485
|
+
case JSOP_INITELEM:
|
|
4486
|
+
/* Pop the element's value into rval. */
|
|
4487
|
+
JS_ASSERT(sp - fp->spbase >= 3);
|
|
4488
|
+
rval = FETCH_OPND(-1);
|
|
4489
|
+
|
|
4490
|
+
/* Pop and conditionally atomize the element id. */
|
|
4491
|
+
FETCH_ELEMENT_ID(-2, id);
|
|
4492
|
+
i = -2;
|
|
4493
|
+
|
|
4494
|
+
do_init:
|
|
4495
|
+
/* Find the object being initialized at top of stack. */
|
|
4496
|
+
lval = FETCH_OPND(i-1);
|
|
4497
|
+
JS_ASSERT(JSVAL_IS_OBJECT(lval));
|
|
4498
|
+
obj = JSVAL_TO_OBJECT(lval);
|
|
4499
|
+
|
|
4500
|
+
/* Set the property named by obj[id] to rval. */
|
|
4501
|
+
ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
|
|
4502
|
+
if (!ok)
|
|
4503
|
+
goto out;
|
|
4504
|
+
sp += i;
|
|
4505
|
+
break;
|
|
4506
|
+
|
|
4507
|
+
#if JS_HAS_SHARP_VARS
|
|
4508
|
+
case JSOP_DEFSHARP:
|
|
4509
|
+
obj = fp->sharpArray;
|
|
4510
|
+
if (!obj) {
|
|
4511
|
+
obj = js_NewArrayObject(cx, 0, NULL);
|
|
4512
|
+
if (!obj) {
|
|
4513
|
+
ok = JS_FALSE;
|
|
4514
|
+
goto out;
|
|
4515
|
+
}
|
|
4516
|
+
fp->sharpArray = obj;
|
|
4517
|
+
}
|
|
4518
|
+
i = (jsint) GET_ATOM_INDEX(pc);
|
|
4519
|
+
id = (jsid) INT_TO_JSVAL(i);
|
|
4520
|
+
rval = FETCH_OPND(-1);
|
|
4521
|
+
if (JSVAL_IS_PRIMITIVE(rval)) {
|
|
4522
|
+
char numBuf[12];
|
|
4523
|
+
JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
|
|
4524
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
4525
|
+
JSMSG_BAD_SHARP_DEF, numBuf);
|
|
4526
|
+
ok = JS_FALSE;
|
|
4527
|
+
goto out;
|
|
4528
|
+
}
|
|
4529
|
+
ok = OBJ_SET_PROPERTY(cx, obj, id, &rval);
|
|
4530
|
+
if (!ok)
|
|
4531
|
+
goto out;
|
|
4532
|
+
break;
|
|
4533
|
+
|
|
4534
|
+
case JSOP_USESHARP:
|
|
4535
|
+
i = (jsint) GET_ATOM_INDEX(pc);
|
|
4536
|
+
id = (jsid) INT_TO_JSVAL(i);
|
|
4537
|
+
obj = fp->sharpArray;
|
|
4538
|
+
if (!obj) {
|
|
4539
|
+
rval = JSVAL_VOID;
|
|
4540
|
+
} else {
|
|
4541
|
+
ok = OBJ_GET_PROPERTY(cx, obj, id, &rval);
|
|
4542
|
+
if (!ok)
|
|
4543
|
+
goto out;
|
|
4544
|
+
}
|
|
4545
|
+
if (!JSVAL_IS_OBJECT(rval)) {
|
|
4546
|
+
char numBuf[12];
|
|
4547
|
+
JS_snprintf(numBuf, sizeof numBuf, "%u", (unsigned) i);
|
|
4548
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
4549
|
+
JSMSG_BAD_SHARP_USE, numBuf);
|
|
4550
|
+
ok = JS_FALSE;
|
|
4551
|
+
goto out;
|
|
4552
|
+
}
|
|
4553
|
+
PUSH_OPND(rval);
|
|
4554
|
+
break;
|
|
4555
|
+
#endif /* JS_HAS_SHARP_VARS */
|
|
4556
|
+
#endif /* JS_HAS_INITIALIZERS */
|
|
4557
|
+
|
|
4558
|
+
#if JS_HAS_EXCEPTIONS
|
|
4559
|
+
/* No-ops for ease of decompilation and jit'ing. */
|
|
4560
|
+
case JSOP_TRY:
|
|
4561
|
+
case JSOP_FINALLY:
|
|
4562
|
+
break;
|
|
4563
|
+
|
|
4564
|
+
/* Reset the stack to the given depth. */
|
|
4565
|
+
case JSOP_SETSP:
|
|
4566
|
+
i = (jsint) GET_ATOM_INDEX(pc);
|
|
4567
|
+
JS_ASSERT(i >= 0);
|
|
4568
|
+
sp = fp->spbase + i;
|
|
4569
|
+
break;
|
|
4570
|
+
|
|
4571
|
+
case JSOP_GOSUB:
|
|
4572
|
+
i = PTRDIFF(pc, script->main, jsbytecode) + len;
|
|
4573
|
+
len = GET_JUMP_OFFSET(pc);
|
|
4574
|
+
PUSH(INT_TO_JSVAL(i));
|
|
4575
|
+
break;
|
|
4576
|
+
|
|
4577
|
+
case JSOP_GOSUBX:
|
|
4578
|
+
i = PTRDIFF(pc, script->main, jsbytecode) + len;
|
|
4579
|
+
len = GET_JUMPX_OFFSET(pc);
|
|
4580
|
+
PUSH(INT_TO_JSVAL(i));
|
|
4581
|
+
break;
|
|
4582
|
+
|
|
4583
|
+
case JSOP_RETSUB:
|
|
4584
|
+
rval = POP();
|
|
4585
|
+
JS_ASSERT(JSVAL_IS_INT(rval));
|
|
4586
|
+
i = JSVAL_TO_INT(rval);
|
|
4587
|
+
pc = script->main + i;
|
|
4588
|
+
len = 0;
|
|
4589
|
+
break;
|
|
4590
|
+
|
|
4591
|
+
case JSOP_EXCEPTION:
|
|
4592
|
+
PUSH(cx->exception);
|
|
4593
|
+
break;
|
|
4594
|
+
|
|
4595
|
+
case JSOP_THROW:
|
|
4596
|
+
cx->throwing = JS_TRUE;
|
|
4597
|
+
cx->exception = POP_OPND();
|
|
4598
|
+
ok = JS_FALSE;
|
|
4599
|
+
/* let the code at out try to catch the exception. */
|
|
4600
|
+
goto out;
|
|
4601
|
+
|
|
4602
|
+
case JSOP_INITCATCHVAR:
|
|
4603
|
+
/* Pop the property's value into rval. */
|
|
4604
|
+
JS_ASSERT(sp - fp->spbase >= 2);
|
|
4605
|
+
rval = POP_OPND();
|
|
4606
|
+
|
|
4607
|
+
/* Get the immediate catch variable name into id. */
|
|
4608
|
+
atom = GET_ATOM(cx, script, pc);
|
|
4609
|
+
id = (jsid)atom;
|
|
4610
|
+
|
|
4611
|
+
/* Find the object being initialized at top of stack. */
|
|
4612
|
+
lval = FETCH_OPND(-1);
|
|
4613
|
+
JS_ASSERT(JSVAL_IS_OBJECT(lval));
|
|
4614
|
+
obj = JSVAL_TO_OBJECT(lval);
|
|
4615
|
+
|
|
4616
|
+
/* Define obj[id] to contain rval and to be permanent. */
|
|
4617
|
+
ok = OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL,
|
|
4618
|
+
JSPROP_PERMANENT, NULL);
|
|
4619
|
+
if (!ok)
|
|
4620
|
+
goto out;
|
|
4621
|
+
break;
|
|
4622
|
+
#endif /* JS_HAS_EXCEPTIONS */
|
|
4623
|
+
|
|
4624
|
+
#if JS_HAS_INSTANCEOF
|
|
4625
|
+
case JSOP_INSTANCEOF:
|
|
4626
|
+
rval = FETCH_OPND(-1);
|
|
4627
|
+
if (JSVAL_IS_PRIMITIVE(rval)) {
|
|
4628
|
+
SAVE_SP(fp);
|
|
4629
|
+
str = js_DecompileValueGenerator(cx, -1, rval, NULL);
|
|
4630
|
+
if (str) {
|
|
4631
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
4632
|
+
JSMSG_BAD_INSTANCEOF_RHS,
|
|
4633
|
+
JS_GetStringBytes(str));
|
|
4634
|
+
}
|
|
4635
|
+
ok = JS_FALSE;
|
|
4636
|
+
goto out;
|
|
4637
|
+
}
|
|
4638
|
+
obj = JSVAL_TO_OBJECT(rval);
|
|
4639
|
+
lval = FETCH_OPND(-2);
|
|
4640
|
+
cond = JS_FALSE;
|
|
4641
|
+
if (obj->map->ops->hasInstance) {
|
|
4642
|
+
SAVE_SP(fp);
|
|
4643
|
+
ok = obj->map->ops->hasInstance(cx, obj, lval, &cond);
|
|
4644
|
+
if (!ok)
|
|
4645
|
+
goto out;
|
|
4646
|
+
}
|
|
4647
|
+
sp--;
|
|
4648
|
+
STORE_OPND(-1, BOOLEAN_TO_JSVAL(cond));
|
|
4649
|
+
break;
|
|
4650
|
+
#endif /* JS_HAS_INSTANCEOF */
|
|
4651
|
+
|
|
4652
|
+
#if JS_HAS_DEBUGGER_KEYWORD
|
|
4653
|
+
case JSOP_DEBUGGER:
|
|
4654
|
+
{
|
|
4655
|
+
JSTrapHandler handler = rt->debuggerHandler;
|
|
4656
|
+
if (handler) {
|
|
4657
|
+
SAVE_SP(fp);
|
|
4658
|
+
switch (handler(cx, script, pc, &rval,
|
|
4659
|
+
rt->debuggerHandlerData)) {
|
|
4660
|
+
case JSTRAP_ERROR:
|
|
4661
|
+
ok = JS_FALSE;
|
|
4662
|
+
goto out;
|
|
4663
|
+
case JSTRAP_CONTINUE:
|
|
4664
|
+
break;
|
|
4665
|
+
case JSTRAP_RETURN:
|
|
4666
|
+
fp->rval = rval;
|
|
4667
|
+
goto out;
|
|
4668
|
+
#if JS_HAS_EXCEPTIONS
|
|
4669
|
+
case JSTRAP_THROW:
|
|
4670
|
+
cx->throwing = JS_TRUE;
|
|
4671
|
+
cx->exception = rval;
|
|
4672
|
+
ok = JS_FALSE;
|
|
4673
|
+
goto out;
|
|
4674
|
+
#endif /* JS_HAS_EXCEPTIONS */
|
|
4675
|
+
default:;
|
|
4676
|
+
}
|
|
4677
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
4678
|
+
}
|
|
4679
|
+
break;
|
|
4680
|
+
}
|
|
4681
|
+
#endif /* JS_HAS_DEBUGGER_KEYWORD */
|
|
4682
|
+
|
|
4683
|
+
default: {
|
|
4684
|
+
char numBuf[12];
|
|
4685
|
+
JS_snprintf(numBuf, sizeof numBuf, "%d", op);
|
|
4686
|
+
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
|
|
4687
|
+
JSMSG_BAD_BYTECODE, numBuf);
|
|
4688
|
+
ok = JS_FALSE;
|
|
4689
|
+
goto out;
|
|
4690
|
+
}
|
|
4691
|
+
}
|
|
4692
|
+
|
|
4693
|
+
advance_pc:
|
|
4694
|
+
pc += len;
|
|
4695
|
+
|
|
4696
|
+
#ifdef DEBUG
|
|
4697
|
+
if (tracefp) {
|
|
4698
|
+
intN ndefs, n;
|
|
4699
|
+
jsval *siter;
|
|
4700
|
+
|
|
4701
|
+
ndefs = cs->ndefs;
|
|
4702
|
+
if (ndefs) {
|
|
4703
|
+
SAVE_SP(fp);
|
|
4704
|
+
for (n = -ndefs; n < 0; n++) {
|
|
4705
|
+
str = js_DecompileValueGenerator(cx, n, sp[n], NULL);
|
|
4706
|
+
if (str) {
|
|
4707
|
+
fprintf(tracefp, "%s %s",
|
|
4708
|
+
(n == -ndefs) ? " output:" : ",",
|
|
4709
|
+
JS_GetStringBytes(str));
|
|
4710
|
+
}
|
|
4711
|
+
}
|
|
4712
|
+
fprintf(tracefp, " @ %d\n", sp - fp->spbase);
|
|
4713
|
+
}
|
|
4714
|
+
fprintf(tracefp, " stack: ");
|
|
4715
|
+
for (siter = fp->spbase; siter < sp; siter++) {
|
|
4716
|
+
str = js_ValueToSource(cx, *siter);
|
|
4717
|
+
fprintf(tracefp, "%s ",
|
|
4718
|
+
str ? JS_GetStringBytes(str) : "<null>");
|
|
4719
|
+
}
|
|
4720
|
+
fputc('\n', tracefp);
|
|
4721
|
+
}
|
|
4722
|
+
#endif
|
|
4723
|
+
}
|
|
4724
|
+
out:
|
|
4725
|
+
|
|
4726
|
+
#if JS_HAS_EXCEPTIONS
|
|
4727
|
+
/*
|
|
4728
|
+
* Has an exception been raised?
|
|
4729
|
+
*/
|
|
4730
|
+
if (!ok && cx->throwing) {
|
|
4731
|
+
/*
|
|
4732
|
+
* Call debugger throw hook if set (XXX thread safety?).
|
|
4733
|
+
*/
|
|
4734
|
+
JSTrapHandler handler = rt->throwHook;
|
|
4735
|
+
if (handler) {
|
|
4736
|
+
SAVE_SP(fp);
|
|
4737
|
+
switch (handler(cx, script, pc, &rval, rt->throwHookData)) {
|
|
4738
|
+
case JSTRAP_ERROR:
|
|
4739
|
+
cx->throwing = JS_FALSE;
|
|
4740
|
+
goto no_catch;
|
|
4741
|
+
case JSTRAP_RETURN:
|
|
4742
|
+
ok = JS_TRUE;
|
|
4743
|
+
cx->throwing = JS_FALSE;
|
|
4744
|
+
fp->rval = rval;
|
|
4745
|
+
goto no_catch;
|
|
4746
|
+
case JSTRAP_THROW:
|
|
4747
|
+
cx->exception = rval;
|
|
4748
|
+
case JSTRAP_CONTINUE:
|
|
4749
|
+
default:;
|
|
4750
|
+
}
|
|
4751
|
+
LOAD_INTERRUPT_HANDLER(rt);
|
|
4752
|
+
}
|
|
4753
|
+
|
|
4754
|
+
/*
|
|
4755
|
+
* Look for a try block within this frame that can catch the exception.
|
|
4756
|
+
*/
|
|
4757
|
+
SCRIPT_FIND_CATCH_START(script, pc, pc);
|
|
4758
|
+
if (pc) {
|
|
4759
|
+
len = 0;
|
|
4760
|
+
cx->throwing = JS_FALSE; /* caught */
|
|
4761
|
+
ok = JS_TRUE;
|
|
4762
|
+
goto advance_pc;
|
|
4763
|
+
}
|
|
4764
|
+
}
|
|
4765
|
+
no_catch:
|
|
4766
|
+
#endif
|
|
4767
|
+
|
|
4768
|
+
/*
|
|
4769
|
+
* Check whether control fell off the end of a lightweight function, or an
|
|
4770
|
+
* exception thrown under such a function was not caught by it. If so, go
|
|
4771
|
+
* to the inline code under JSOP_RETURN.
|
|
4772
|
+
*/
|
|
4773
|
+
if (inlineCallCount)
|
|
4774
|
+
goto inline_return;
|
|
4775
|
+
|
|
4776
|
+
/*
|
|
4777
|
+
* Reset sp before freeing stack slots, because our caller may GC soon.
|
|
4778
|
+
* Clear spbase to indicate that we've popped the 2 * depth operand slots.
|
|
4779
|
+
* Restore the previous frame's execution state.
|
|
4780
|
+
*/
|
|
4781
|
+
fp->sp = fp->spbase;
|
|
4782
|
+
fp->spbase = NULL;
|
|
4783
|
+
js_FreeRawStack(cx, mark);
|
|
4784
|
+
if (cx->version == currentVersion && currentVersion != originalVersion)
|
|
4785
|
+
JS_SetVersion(cx, originalVersion);
|
|
4786
|
+
cx->interpLevel--;
|
|
4787
|
+
return ok;
|
|
4788
|
+
|
|
4789
|
+
atom_not_defined:
|
|
4790
|
+
{
|
|
4791
|
+
const char *printable = js_AtomToPrintableString(cx, atom);
|
|
4792
|
+
if (printable)
|
|
4793
|
+
js_ReportIsNotDefined(cx, printable);
|
|
4794
|
+
ok = JS_FALSE;
|
|
4795
|
+
goto out;
|
|
4796
|
+
}
|
|
4797
|
+
}
|