pax_global_header00006660000000000000000000000064117676000750014523gustar00rootroot0000000000000052 comment=82ffb8f3e09e77e3b1f5782c35b621e7ca742b58 rhino-1.7R4/000077500000000000000000000000001176760007500127175ustar00rootroot00000000000000rhino-1.7R4/.cvsignore000066400000000000000000000000541176760007500147160ustar00rootroot00000000000000build lib build.local.properties downloaded rhino-1.7R4/LICENSE.txt000066400000000000000000000406141176760007500145470ustar00rootroot00000000000000The majority of Rhino is licensed under the MPL 2.0: Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. rhino-1.7R4/README.html000066400000000000000000000007471176760007500145520ustar00rootroot00000000000000

Rhino: JavaScript in Java

Rhino is an implementation of JavaScript in Java. Documentation can be found here. rhino-1.7R4/apiClasses.properties000066400000000000000000000034001176760007500171210ustar00rootroot00000000000000# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. apiClasses=\ src/org/mozilla/javascript/Callable.java,\ src/org/mozilla/javascript/ClassCache.java,\ src/org/mozilla/javascript/ClassShutter.java,\ src/org/mozilla/javascript/CompilerEnvirons.java,\ src/org/mozilla/javascript/ContinuationPending.java,\ src/org/mozilla/javascript/Context.java,\ src/org/mozilla/javascript/ContextAction.java,\ src/org/mozilla/javascript/ContextFactory.java,\ src/org/mozilla/javascript/GeneratedClassLoader.java,\ src/org/mozilla/javascript/EcmaError.java,\ src/org/mozilla/javascript/ErrorReporter.java,\ src/org/mozilla/javascript/EvaluatorException.java,\ src/org/mozilla/javascript/Function.java,\ src/org/mozilla/javascript/FunctionObject.java,\ src/org/mozilla/javascript/GeneratedClassLoader.java,\ src/org/mozilla/javascript/ImporterTopLevel.java,\ src/org/mozilla/javascript/JavaScriptException.java,\ src/org/mozilla/javascript/RefCallable.java,\ src/org/mozilla/javascript/RhinoException.java,\ src/org/mozilla/javascript/Script.java,\ src/org/mozilla/javascript/Scriptable.java,\ src/org/mozilla/javascript/ScriptableObject.java,\ src/org/mozilla/javascript/SecurityController.java,\ src/org/mozilla/javascript/WrapFactory.java,\ src/org/mozilla/javascript/WrappedException.java,\ src/org/mozilla/javascript/Wrapper.java,\ src/org/mozilla/javascript/Synchronizer.java,\ src/org/mozilla/javascript/optimizer/ClassCompiler.java,\ src/org/mozilla/javascript/debug/DebuggableScript.java,\ src/org/mozilla/javascript/serialize/ScriptableInputStream.java,\ src/org/mozilla/javascript/serialize/ScriptableOutputStream.java rhino-1.7R4/build-date000066400000000000000000000000471176760007500146550ustar00rootroot00000000000000This version was built on @datestamp@. rhino-1.7R4/build.properties000066400000000000000000000015271176760007500161410ustar00rootroot00000000000000# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. name: rhino Name: Rhino version: 1_7R4 # See Context#getImplementationVersion() for format of this! implementation.version: Rhino 1.7 release 4 ${implementation.date} build.dir: build rhino.jar: js.jar small-rhino.jar: smalljs.jar rhino-14.jar: js-14.jar small-rhino-14.jar: smalljs-14.jar dist.name: rhino${version} dist.dir: ${build.dir}/${dist.name} # compilation destionation classes: ${build.dir}/classes # compilation settings debug: on target-jvm: 1.5 source-level: 1.5 # jar generation settings jar-compression: true # optional external packages xmlbeans: . xbean.jar: ${xmlbeans}/lib/xbean.jar jsr173.jar: ${xmlbeans}/lib/jsr173_1.0_api.jar rhino-1.7R4/build.xml000066400000000000000000000314401176760007500145420ustar00rootroot00000000000000 Calling ${xmlimplsrc-build-file} Calling ${xmlimplsrc-build-file} The following targets are available with this build file: clean remove all compiled classes and copied property files compile compile classes and copy all property files into ${classes} directory excluding deprecated code compile-all compile all classes and copy all property files into ${classes} directory including deprecated code deepclean remove all generated files and directories dist create ${dist.file} with full Rhino distribution help print this help jar create ${rhino.jar} in ${dist.dir} smalljar create ${small-rhino.jar} in ${dist.dir} with minimalist set of Rhino classes. See footprint.html from the doc directory for details. javadoc generate Rhino API documentation in ${dist.dir}/javadoc source-zip create ${dist.source-only-zip} with all Rhino source files necessary to recreate ${dist.file} rhino-1.7R4/deprecatedsrc/000077500000000000000000000000001176760007500155275ustar00rootroot00000000000000rhino-1.7R4/deprecatedsrc/build.xml000066400000000000000000000016461176760007500173570ustar00rootroot00000000000000 rhino-1.7R4/deprecatedsrc/org/000077500000000000000000000000001176760007500163165ustar00rootroot00000000000000rhino-1.7R4/deprecatedsrc/org/mozilla/000077500000000000000000000000001176760007500177655ustar00rootroot00000000000000rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/000077500000000000000000000000001176760007500221335ustar00rootroot00000000000000rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/ClassDefinitionException.java000066400000000000000000000012401176760007500277300ustar00rootroot00000000000000 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * @deprecated The exception is no longer thrown by Rhino runtime as * {@link EvaluatorException} is used instead. */ public class ClassDefinitionException extends RuntimeException { static final long serialVersionUID = -5637830967241712746L; public ClassDefinitionException(String detail) { super(detail); } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/NotAFunctionException.java000066400000000000000000000011611176760007500272230ustar00rootroot00000000000000 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * @deprecated The exception is no longer thrown by Rhino runtime as * {@link EvaluatorException} is used instead. */ public class NotAFunctionException extends RuntimeException { static final long serialVersionUID = 6461524852170711724L; public NotAFunctionException() { } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/PropertyException.java000066400000000000000000000011431176760007500265000ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * @deprecated This exception is no longer thrown by Rhino runtime. */ public class PropertyException extends RuntimeException { static final long serialVersionUID = -8221564865490676219L; public PropertyException(String detail) { super(detail); } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/000077500000000000000000000000001176760007500227335ustar00rootroot00000000000000rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/000077500000000000000000000000001176760007500236745ustar00rootroot00000000000000rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/000077500000000000000000000000001176760007500255055ustar00rootroot00000000000000rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/LogicalEquality.java000066400000000000000000000204221176760007500314400ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import org.apache.xmlbeans.XmlCursor; import java.util.*; public class LogicalEquality { public static boolean nodesEqual(XmlCursor xmlOne, XmlCursor xmlTwo) { boolean result = false; if (xmlOne.isStartdoc()) { xmlOne.toFirstContentToken(); } if (xmlTwo.isStartdoc()) { xmlTwo.toFirstContentToken(); } if (xmlOne.currentTokenType() == xmlTwo.currentTokenType()) { if (xmlOne.isEnddoc()) { // Both empty result = true; } else if (xmlOne.isAttr()) { result = attributesEqual(xmlOne, xmlTwo); } else if (xmlOne.isText()) { result = textNodesEqual(xmlOne, xmlTwo); } else if (xmlOne.isComment()) { result = commentsEqual(xmlOne, xmlTwo); } else if (xmlOne.isProcinst()) { result = processingInstructionsEqual(xmlOne, xmlTwo); } else if (xmlOne.isStart()) { // Compare root elements result = elementsEqual(xmlOne, xmlTwo); } } return result; } private static boolean elementsEqual(XmlCursor xmlOne, XmlCursor xmlTwo) { boolean result = true; if (!qnamesEqual(xmlOne.getName(), xmlTwo.getName())) { result = false; } else { // These filter out empty text nodes. nextToken(xmlOne); nextToken(xmlTwo); do { if (xmlOne.currentTokenType() != xmlTwo.currentTokenType()) { // Not same token result = false; break; } else if (xmlOne.isEnd()) { // Done with this element, step over end break; } else if (xmlOne.isEnddoc()) { // Shouldn't get here break; } else if (xmlOne.isAttr()) { // This one will move us to the first non-attr token. result = attributeListsEqual(xmlOne, xmlTwo); } else { if (xmlOne.isText()) { result = textNodesEqual(xmlOne, xmlTwo); } else if (xmlOne.isComment()) { result = commentsEqual(xmlOne, xmlTwo); } else if (xmlOne.isProcinst()) { result = processingInstructionsEqual(xmlOne, xmlTwo); } else if (xmlOne.isStart()) { result = elementsEqual(xmlOne, xmlTwo); } else { //XML.log("Unknown token type" + xmlOne.currentTokenType()); } // These filter out empty text nodes. nextToken(xmlOne); nextToken(xmlTwo); } } while(result); } return result; } /** * * @param xmlOne * @param xmlTwo * @return */ private static boolean attributeListsEqual(XmlCursor xmlOne, XmlCursor xmlTwo) { boolean result = true; TreeMap mapOne = loadAttributeMap(xmlOne); TreeMap mapTwo = loadAttributeMap(xmlTwo); if (mapOne.size() != mapTwo.size()) { result = false; } else { Set keysOne = mapOne.keySet(); Set keysTwo = mapTwo.keySet(); Iterator itOne = keysOne.iterator(); Iterator itTwo = keysTwo.iterator(); while (result && itOne.hasNext()) { String valueOne = (String) itOne.next(); String valueTwo = (String) itTwo.next(); if (!valueOne.equals(valueTwo)) { result = false; } else { javax.xml.namespace.QName qnameOne = (javax.xml.namespace.QName) mapOne.get(valueOne); javax.xml.namespace.QName qnameTwo = (javax.xml.namespace.QName) mapTwo.get(valueTwo); if (!qnamesEqual(qnameOne, qnameTwo)) { result = false; } } } } return result; } /** * * @param xml * @return */ private static TreeMap loadAttributeMap(XmlCursor xml) { TreeMap result = new TreeMap(); while (xml.isAttr()) { result.put(xml.getTextValue(), xml.getName()); nextToken(xml); } return result; } /** * * @param xmlOne * @param xmlTwo * @return */ private static boolean attributesEqual(XmlCursor xmlOne, XmlCursor xmlTwo) { boolean result = false; if (xmlOne.isAttr() && xmlTwo.isAttr()) { if (qnamesEqual(xmlOne.getName(), xmlTwo.getName())) { if (xmlOne.getTextValue().equals(xmlTwo.getTextValue())) { result = true; } } } return result; } /** * * @param xmlOne * @param xmlTwo * @return */ private static boolean textNodesEqual(XmlCursor xmlOne, XmlCursor xmlTwo) { boolean result = false; if (xmlOne.isText() && xmlTwo.isText()) { if (xmlOne.getChars().equals(xmlTwo.getChars())) { result = true; } } return result; } /** * * @param xmlOne * @param xmlTwo * @return */ private static boolean commentsEqual(XmlCursor xmlOne, XmlCursor xmlTwo) { boolean result = false; if (xmlOne.isComment() && xmlTwo.isComment()) { if (xmlOne.getTextValue().equals(xmlTwo.getTextValue())) { result = true; } } return result; } /** * * @param xmlOne * @param xmlTwo * @return */ private static boolean processingInstructionsEqual(XmlCursor xmlOne, XmlCursor xmlTwo) { boolean result = false; if (xmlOne.isProcinst() && xmlTwo.isProcinst()) { if (qnamesEqual(xmlOne.getName(), xmlTwo.getName())) { if (xmlOne.getTextValue().equals(xmlTwo.getTextValue())) { result = true; } } } return result; } /** * * @param qnameOne * @param qnameTwo * @return */ private static boolean qnamesEqual(javax.xml.namespace.QName qnameOne, javax.xml.namespace.QName qnameTwo) { boolean result = false; if (qnameOne.getNamespaceURI().equals(qnameTwo.getNamespaceURI())) { if (qnameOne.getLocalPart().equals(qnameTwo.getLocalPart())) { return true; } } return result; } /** * filter out empty textNodes here * * @param xml */ private static void nextToken(XmlCursor xml) { do { xml.toNextToken(); if (!xml.isText()) { // Not a text node break; } else if (xml.getChars().trim().length() > 0) { // Text node is not empty break; } } while (true); } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/Namespace.java000066400000000000000000000173431176760007500302540ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import org.mozilla.javascript.*; /** * Class Namespace * */ class Namespace extends IdScriptableObject { static final long serialVersionUID = -5765755238131301744L; private static final Object NAMESPACE_TAG = "Namespace"; private XMLLibImpl lib; private String prefix; private String uri; public Namespace(XMLLibImpl lib, String uri) { super(lib.globalScope(), lib.namespacePrototype); if (uri == null) throw new IllegalArgumentException(); this.lib = lib; this.prefix = (uri.length() == 0) ? "" : null; this.uri = uri; } public Namespace(XMLLibImpl lib, String prefix, String uri) { super(lib.globalScope(), lib.namespacePrototype); if (uri == null) throw new IllegalArgumentException(); if (uri.length() == 0) { // prefix should be "" for empty uri if (prefix == null) throw new IllegalArgumentException(); if (prefix.length() != 0) throw new IllegalArgumentException(); } this.lib = lib; this.prefix = prefix; this.uri = uri; } public void exportAsJSClass(boolean sealed) { exportAsJSClass(MAX_PROTOTYPE_ID, lib.globalScope(), sealed); } /** * * @return */ public String uri() { return uri; } /** * * @return */ public String prefix() { return prefix; } /** * * @return */ public String toString () { return uri(); } /** * * @return */ public String toLocaleString () { return toString(); } public boolean equals(Object obj) { if (!(obj instanceof Namespace)) return false; return equals((Namespace)obj); } public int hashCode() { return uri().hashCode(); } protected Object equivalentValues(Object value) { if (!(value instanceof Namespace)) return Scriptable.NOT_FOUND; boolean result = equals((Namespace)value); return result ? Boolean.TRUE : Boolean.FALSE; } private boolean equals(Namespace n) { return uri().equals(n.uri()); } /** * * @return */ public String getClassName () { return "Namespace"; } /** * * @param hint * @return */ public Object getDefaultValue (Class hint) { return uri(); } // #string_id_map# private static final int Id_prefix = 1, Id_uri = 2, MAX_INSTANCE_ID = 2; protected int getMaxInstanceId() { return super.getMaxInstanceId() + MAX_INSTANCE_ID; } protected int findInstanceIdInfo(String s) { int id; // #generated# Last update: 2004-07-20 19:50:50 CEST L0: { id = 0; String X = null; int s_length = s.length(); if (s_length==3) { X="uri";id=Id_uri; } else if (s_length==6) { X="prefix";id=Id_prefix; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# if (id == 0) return super.findInstanceIdInfo(s); int attr; switch (id) { case Id_prefix: case Id_uri: attr = PERMANENT | READONLY; break; default: throw new IllegalStateException(); } return instanceIdInfo(attr, super.getMaxInstanceId() + id); } // #/string_id_map# protected String getInstanceIdName(int id) { switch (id - super.getMaxInstanceId()) { case Id_prefix: return "prefix"; case Id_uri: return "uri"; } return super.getInstanceIdName(id); } protected Object getInstanceIdValue(int id) { switch (id - super.getMaxInstanceId()) { case Id_prefix: if (prefix == null) return Undefined.instance; return prefix; case Id_uri: return uri; } return super.getInstanceIdValue(id); } // #string_id_map# private static final int Id_constructor = 1, Id_toString = 2, Id_toSource = 3, MAX_PROTOTYPE_ID = 3; protected int findPrototypeId(String s) { int id; // #generated# Last update: 2004-08-21 12:07:01 CEST L0: { id = 0; String X = null; int c; int s_length = s.length(); if (s_length==8) { c=s.charAt(3); if (c=='o') { X="toSource";id=Id_toSource; } else if (c=='t') { X="toString";id=Id_toString; } } else if (s_length==11) { X="constructor";id=Id_constructor; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# return id; } // #/string_id_map# protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=2; s="constructor"; break; case Id_toString: arity=0; s="toString"; break; case Id_toSource: arity=0; s="toSource"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(NAMESPACE_TAG, id, s, arity); } public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(NAMESPACE_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_constructor: return jsConstructor(cx, (thisObj == null), args); case Id_toString: return realThis(thisObj, f).toString(); case Id_toSource: return realThis(thisObj, f).js_toSource(); } throw new IllegalArgumentException(String.valueOf(id)); } private Namespace realThis(Scriptable thisObj, IdFunctionObject f) { if(!(thisObj instanceof Namespace)) throw incompatibleCallError(f); return (Namespace)thisObj; } private Object jsConstructor(Context cx, boolean inNewExpr, Object[] args) { if (!inNewExpr && args.length == 1) { return lib.castToNamespace(cx, args[0]); } if (args.length == 0) { return lib.constructNamespace(cx); } else if (args.length == 1) { return lib.constructNamespace(cx, args[0]); } else { return lib.constructNamespace(cx, args[0], args[1]); } } private String js_toSource() { StringBuffer sb = new StringBuffer(); sb.append('('); toSourceImpl(prefix, uri, sb); sb.append(')'); return sb.toString(); } static void toSourceImpl(String prefix, String uri, StringBuffer sb) { sb.append("new Namespace("); if (uri.length() == 0) { if (!"".equals(prefix)) throw new IllegalArgumentException(prefix); } else { sb.append('\''); if (prefix != null) { sb.append(ScriptRuntime.escapeString(prefix, '\'')); sb.append("', '"); } sb.append(ScriptRuntime.escapeString(uri, '\'')); sb.append('\''); } sb.append(')'); } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/NamespaceHelper.java000066400000000000000000000206151176760007500314100ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import java.util.*; import org.apache.xmlbeans.XmlCursor; import org.mozilla.javascript.*; class NamespaceHelper { private XMLLibImpl lib; private final Map prefixToURI = new HashMap(); private final Map uriToPrefix = new HashMap(); // A set of URIs that are used without explicit namespace declaration in scope. private final Set undeclared = new HashSet(); private NamespaceHelper(XMLLibImpl lib) { this.lib = lib; // Insert the default namespace prefixToURI.put("", ""); Set prefixes = new HashSet(); prefixes.add(""); uriToPrefix.put("", prefixes); } /** * Declared a new namespace * * @param prefix * @param uri * @param declarations */ private void declareNamespace(String prefix, String uri, ObjArray declarations) { Set prefixes = (Set)uriToPrefix.get(uri); if(prefixes == null) { prefixes = new HashSet(); uriToPrefix.put(uri, prefixes); } if(!prefixes.contains(prefix)) { String oldURI = (String)prefixToURI.get(prefix); // Add the new mapping prefixes.add(prefix); prefixToURI.put(prefix, uri); if(declarations != null) declarations.add(new Namespace(lib, prefix, uri)); if(oldURI != null) { // Update the existing mapping prefixes = (Set)uriToPrefix.get(oldURI); prefixes.remove(prefix); } } } /** * Updates the internal state of this NamespaceHelper to reflect the * existance of the XML token pointed to by the cursor. */ private void processName(XmlCursor cursor, ObjArray declarations) { javax.xml.namespace.QName qname = cursor.getName(); String uri = qname.getNamespaceURI(); Set prefixes = (Set)uriToPrefix.get(uri); if(prefixes == null || prefixes.size() == 0) { undeclared.add(uri); if(declarations != null) declarations.add(new Namespace(lib, uri)); } } /** * Updates the internal state of this NamespaceHelper with the * namespace information of the element pointed to by the cursor. */ private void update(XmlCursor cursor, ObjArray declarations) { // Process the Namespace declarations cursor.push(); while(cursor.toNextToken().isAnyAttr()) { if(cursor.isNamespace()) { javax.xml.namespace.QName name = cursor.getName(); String prefix = name.getLocalPart(); String uri = name.getNamespaceURI(); declareNamespace(prefix, uri, declarations); } } cursor.pop(); // Process the element processName(cursor, declarations); // Process the attributes cursor.push(); boolean hasNext = cursor.toFirstAttribute(); while(hasNext) { processName(cursor, declarations); hasNext = cursor.toNextAttribute(); } cursor.pop(); } /** * @return Object[] array of Namespace objects in scope at the cursor. */ public static Object[] inScopeNamespaces(XMLLibImpl lib, XmlCursor cursor) { ObjArray namespaces = new ObjArray(); NamespaceHelper helper = new NamespaceHelper(lib); cursor.push(); int depth = 0; while(cursor.hasPrevToken()) { if(cursor.isContainer()) { cursor.push(); depth++; } cursor.toParent(); } for(int i = 0; i < depth; i++) { cursor.pop(); helper.update(cursor, null); } Iterator i = helper.prefixToURI.entrySet().iterator(); while(i.hasNext()) { Map.Entry entry = (Map.Entry)i.next(); Namespace ns = new Namespace(lib, (String)entry.getKey(), (String)entry.getValue()); namespaces.add(ns); } i = helper.undeclared.iterator(); while(i.hasNext()) { Namespace ns = new Namespace(lib, (String)i.next()); namespaces.add(ns); } cursor.pop(); return namespaces.toArray(); } static Namespace getNamespace(XMLLibImpl lib, XmlCursor cursor, Object[] inScopeNamespaces) { String uri; String prefix; if (cursor.isProcinst()) { uri = ""; prefix = ""; } else { javax.xml.namespace.QName qname = cursor.getName(); uri = qname.getNamespaceURI(); prefix = qname.getPrefix(); } if (inScopeNamespaces == null) return new Namespace(lib, prefix, uri); Namespace result = null; for (int i = 0; i != inScopeNamespaces.length; ++i) { Namespace ns = (Namespace)inScopeNamespaces[i]; if(ns == null) continue; String nsURI = ns.uri(); if(nsURI.equals(uri)) { if(prefix.equals(ns.prefix())) { result = ns; break; } if(result == null || (result.prefix() == null && ns.prefix() != null)) result = ns; } } if(result == null) result = new Namespace(lib, prefix, uri); return result; } /** * @return List of Namespace objects that are declared in the container pointed to by the cursor. */ public static Object[] namespaceDeclarations(XMLLibImpl lib, XmlCursor cursor) { ObjArray declarations = new ObjArray(); NamespaceHelper helper = new NamespaceHelper(lib); cursor.push(); int depth = 0; while(cursor.hasPrevToken()) { if(cursor.isContainer()) { cursor.push(); depth++; } cursor.toParent(); } for(int i = 0; i < depth - 1; i++) { cursor.pop(); helper.update(cursor, null); } if(depth > 0) { cursor.pop(); helper.update(cursor, declarations); } cursor.pop(); return declarations.toArray(); } /** * @return Prefix to URI map of all namespaces in scope at the cursor. */ public static Map getAllNamespaces(XMLLibImpl lib, XmlCursor cursor) { NamespaceHelper helper = new NamespaceHelper(lib); cursor.push(); int depth = 0; while(cursor.hasPrevToken()) { if(cursor.isContainer()) { cursor.push(); depth++; } cursor.toParent(); } for(int i = 0; i < depth; i++) { cursor.pop(); helper.update(cursor, null); } cursor.pop(); return helper.prefixToURI; } public static void getNamespaces(XmlCursor cursor, Map prefixToURI) { cursor.push(); while(cursor.toNextToken().isAnyAttr()) { if(cursor.isNamespace()) { javax.xml.namespace.QName name = cursor.getName(); String prefix = name.getLocalPart(); String uri = name.getNamespaceURI(); prefixToURI.put(prefix, uri); } } cursor.pop(); } public static void removeNamespace(XmlCursor cursor, String prefix) { cursor.push(); while(cursor.toNextToken().isAnyAttr()) { if(cursor.isNamespace()) { javax.xml.namespace.QName name = cursor.getName(); if(name.getLocalPart().equals(prefix)) { cursor.removeXml(); break; } } } cursor.pop(); } }rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/QName.java000066400000000000000000000170031176760007500273520ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import org.mozilla.javascript.*; /** * Class QName * */ final class QName extends IdScriptableObject { static final long serialVersionUID = 416745167693026750L; private static final Object QNAME_TAG = "QName"; XMLLibImpl lib; private String prefix; private String localName; private String uri; QName(XMLLibImpl lib, String uri, String localName, String prefix) { super(lib.globalScope(), lib.qnamePrototype); if (localName == null) throw new IllegalArgumentException(); this.lib = lib; this.uri = uri; this.prefix = prefix; this.localName = localName; } void exportAsJSClass(boolean sealed) { exportAsJSClass(MAX_PROTOTYPE_ID, lib.globalScope(), sealed); } /** * * @return */ public String toString() { String result; if (uri == null) { result = "*::".concat(localName); } else if(uri.length() == 0) { result = localName; } else { result = uri + "::" + localName; } return result; } public String localName() { return localName; } String prefix() { return (prefix == null) ? prefix : ""; } String uri() { return uri; } public boolean equals(Object obj) { if(!(obj instanceof QName)) return false; return equals((QName)obj); } public int hashCode() { return localName.hashCode() ^ (uri == null ? 0 : uri.hashCode()); } protected Object equivalentValues(Object value) { if(!(value instanceof QName)) return Scriptable.NOT_FOUND; boolean result = equals((QName)value); return result ? Boolean.TRUE : Boolean.FALSE; } private boolean equals(QName q) { boolean result; if (uri == null) { result = q.uri == null && localName.equals(q.localName); } else { result = uri.equals(q.uri) && localName.equals(q.localName); } return result; } /** * * @return */ public String getClassName () { return "QName"; } /** * * @param hint * @return */ public Object getDefaultValue (Class hint) { return toString(); } // #string_id_map# private static final int Id_localName = 1, Id_uri = 2, MAX_INSTANCE_ID = 2; protected int getMaxInstanceId() { return super.getMaxInstanceId() + MAX_INSTANCE_ID; } protected int findInstanceIdInfo(String s) { int id; // #generated# Last update: 2004-07-18 12:32:51 CEST L0: { id = 0; String X = null; int s_length = s.length(); if (s_length==3) { X="uri";id=Id_uri; } else if (s_length==9) { X="localName";id=Id_localName; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# if (id == 0) return super.findInstanceIdInfo(s); int attr; switch (id) { case Id_localName: case Id_uri: attr = PERMANENT | READONLY; break; default: throw new IllegalStateException(); } return instanceIdInfo(attr, super.getMaxInstanceId() + id); } // #/string_id_map# protected String getInstanceIdName(int id) { switch (id - super.getMaxInstanceId()) { case Id_localName: return "localName"; case Id_uri: return "uri"; } return super.getInstanceIdName(id); } protected Object getInstanceIdValue(int id) { switch (id - super.getMaxInstanceId()) { case Id_localName: return localName; case Id_uri: return uri; } return super.getInstanceIdValue(id); } // #string_id_map# private static final int Id_constructor = 1, Id_toString = 2, Id_toSource = 3, MAX_PROTOTYPE_ID = 3; protected int findPrototypeId(String s) { int id; // #generated# Last update: 2004-08-21 12:45:13 CEST L0: { id = 0; String X = null; int c; int s_length = s.length(); if (s_length==8) { c=s.charAt(3); if (c=='o') { X="toSource";id=Id_toSource; } else if (c=='t') { X="toString";id=Id_toString; } } else if (s_length==11) { X="constructor";id=Id_constructor; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# return id; } // #/string_id_map# protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=2; s="constructor"; break; case Id_toString: arity=0; s="toString"; break; case Id_toSource: arity=0; s="toSource"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(QNAME_TAG, id, s, arity); } public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(QNAME_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_constructor: return jsConstructor(cx, (thisObj == null), args); case Id_toString: return realThis(thisObj, f).toString(); case Id_toSource: return realThis(thisObj, f).js_toSource(); } throw new IllegalArgumentException(String.valueOf(id)); } private QName realThis(Scriptable thisObj, IdFunctionObject f) { if(!(thisObj instanceof QName)) throw incompatibleCallError(f); return (QName)thisObj; } private Object jsConstructor(Context cx, boolean inNewExpr, Object[] args) { if (!inNewExpr && args.length == 1) { return lib.castToQName(cx, args[0]); } if (args.length == 0) { return lib.constructQName(cx, Undefined.instance); } else if (args.length == 1) { return lib.constructQName(cx, args[0]); } else { return lib.constructQName(cx, args[0], args[1]); } } private String js_toSource() { StringBuffer sb = new StringBuffer(); sb.append('('); toSourceImpl(uri, localName, prefix, sb); sb.append(')'); return sb.toString(); } private static void toSourceImpl(String uri, String localName, String prefix, StringBuffer sb) { sb.append("new QName("); if (uri == null && prefix == null) { if (!"*".equals(localName)) { sb.append("null, "); } } else { Namespace.toSourceImpl(prefix, uri, sb); sb.append(", "); } sb.append('\''); sb.append(ScriptRuntime.escapeString(localName, '\'')); sb.append("')"); } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XML.java000066400000000000000000002263531176760007500270230ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import java.io.Serializable; import java.util.*; import org.mozilla.javascript.*; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlCursor.XmlBookmark; import org.apache.xmlbeans.XmlCursor.TokenType; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlOptions; class XML extends XMLObjectImpl { static final long serialVersionUID = -630969919086449092L; final static class XScriptAnnotation extends XmlBookmark implements Serializable { private static final long serialVersionUID = 1L; javax.xml.namespace.QName _name; XML _xScriptXML; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Constructurs // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// XScriptAnnotation (XmlCursor curs) { _name = curs.getName(); } } /** * */ final static class NamespaceDeclarations { private int _prefixIdx; private StringBuffer _namespaceDecls; private String _defaultNSURI; NamespaceDeclarations (XmlCursor curs) { _prefixIdx = 0; _namespaceDecls = new StringBuffer(); skipNonElements(curs); _defaultNSURI = curs.namespaceForPrefix(""); if (isAnyDefaultNamespace()) { addDecl("", _defaultNSURI); } } private void addDecl (String prefix, String ns) { _namespaceDecls.append((prefix.length() > 0 ? "declare namespace " + prefix : "default element namespace") + " = \"" + ns + "\"" + "\n"); } String getNextPrefix (String ns) { String prefix = "NS" + _prefixIdx++; _namespaceDecls.append("declare namespace " + prefix + " = " + "\"" + ns + "\"" + "\n"); return prefix; } boolean isAnyDefaultNamespace () { return _defaultNSURI != null ?_defaultNSURI.length() > 0 : false; } String getDeclarations() { return _namespaceDecls.toString(); } } // Fields //static final XML prototype = new XML(); private XScriptAnnotation _anno; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Constructors // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * * @param anno */ private XML(XMLLibImpl lib, XScriptAnnotation anno) { super(lib, lib.xmlPrototype); _anno = anno; _anno._xScriptXML = this; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Public factories for creating a XScript XML object given an XBean cursor. // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static XML createEmptyXML(XMLLibImpl lib) { XScriptAnnotation anno; XmlObject xo = XmlObject.Factory.newInstance(); XmlCursor curs = xo.newCursor(); try { anno = new XScriptAnnotation(curs); curs.setBookmark(anno); } finally { curs.dispose(); } return new XML(lib, anno); } private static XML createXML (XMLLibImpl lib, XmlCursor curs) { if (curs.currentTokenType().isStartdoc()) { curs.toFirstContentToken(); } XScriptAnnotation anno = findAnnotation(curs); return new XML(lib, anno); } /** * Special constructor for making an attribute * */ private static XML createAttributeXML(XMLLibImpl lib, XmlCursor cursor) { if (!cursor.isAttr()) throw new IllegalArgumentException(); XScriptAnnotation anno = new XScriptAnnotation(cursor); cursor.setBookmark(anno); return new XML(lib, anno); } /** * * @param qname * @param value * @return */ static XML createTextElement(XMLLibImpl lib, javax.xml.namespace.QName qname, String value) { XScriptAnnotation anno; XmlObject xo = XmlObject.Factory.newInstance(); XmlCursor cursor = xo.newCursor(); try { cursor.toNextToken(); cursor.beginElement(qname.getLocalPart(), qname.getNamespaceURI()); //if(namespace.length() > 0) // cursor.insertNamespace("", namespace); cursor.insertChars(value); cursor.toStartDoc(); cursor.toNextToken(); anno = new XScriptAnnotation(cursor); cursor.setBookmark(anno); } finally { cursor.dispose(); } return new XML(lib, anno); } static XML createFromXmlObject(XMLLibImpl lib, XmlObject xo) { XScriptAnnotation anno; XmlCursor curs = xo.newCursor(); if (curs.currentTokenType().isStartdoc()) { curs.toFirstContentToken(); } try { anno = new XScriptAnnotation(curs); curs.setBookmark(anno); } finally { curs.dispose(); } return new XML(lib, anno); } static XML createFromJS(XMLLibImpl lib, Object inputObject) { XmlObject xo; boolean isText = false; String frag; if (inputObject == null || inputObject == Undefined.instance) { frag = ""; } else if (inputObject instanceof XMLObjectImpl) { // todo: faster way for XMLObjects? frag = ((XMLObjectImpl) inputObject).toXMLString(0); } else { if (inputObject instanceof Wrapper) { Object wrapped = ((Wrapper)inputObject).unwrap(); if (wrapped instanceof XmlObject) { return createFromXmlObject(lib, (XmlObject)wrapped); } } frag = ScriptRuntime.toString(inputObject); } if (frag.trim().startsWith("<>")) { throw ScriptRuntime.typeError("Invalid use of XML object anonymous tags <>."); } if (frag.indexOf("<") == -1) { // Must be solo text node, wrap in XML fragment isText = true; frag = "" + frag + ""; } XmlOptions options = new XmlOptions(); if (lib.ignoreComments) { options.put(XmlOptions.LOAD_STRIP_COMMENTS); } if (lib.ignoreProcessingInstructions) { options.put(XmlOptions.LOAD_STRIP_PROCINSTS); } if (lib.ignoreWhitespace) { options.put(XmlOptions.LOAD_STRIP_WHITESPACE); } try { xo = XmlObject.Factory.parse(frag, options); // Apply the default namespace Context cx = Context.getCurrentContext(); String defaultURI = lib.getDefaultNamespaceURI(cx); if(defaultURI.length() > 0) { XmlCursor cursor = xo.newCursor(); boolean isRoot = true; while(!cursor.toNextToken().isEnddoc()) { if(!cursor.isStart()) continue; // Check if this element explicitly sets the // default namespace boolean defaultNSDeclared = false; cursor.push(); while(cursor.toNextToken().isAnyAttr()) { if(cursor.isNamespace()) { if(cursor.getName().getLocalPart().length() == 0) { defaultNSDeclared = true; break; } } } cursor.pop(); if(defaultNSDeclared) { cursor.toEndToken(); continue; } // Check if this element's name is in no namespace javax.xml.namespace.QName qname = cursor.getName(); if(qname.getNamespaceURI().length() == 0) { // Change the namespace qname = new javax.xml.namespace.QName(defaultURI, qname.getLocalPart()); cursor.setName(qname); } if(isRoot) { // Declare the default namespace cursor.push(); cursor.toNextToken(); cursor.insertNamespace("", defaultURI); cursor.pop(); isRoot = false; } } cursor.dispose(); } } catch (XmlException xe) { /* todo need to handle namespace prefix not found in XML look for namespace type in the scope change. String errorMsg = "Use of undefined namespace prefix: "; String msg = xe.getError().getMessage(); if (msg.startsWith(errorMsg)) { String prefix = msg.substring(errorMsg.length()); } */ String errMsg = xe.getMessage(); if (errMsg.equals("error: Unexpected end of file after null")) { // Create an empty document. xo = XmlObject.Factory.newInstance(); } else { throw ScriptRuntime.typeError(xe.getMessage()); } } catch (Throwable e) { // todo: TLL Catch specific exceptions during parse. throw ScriptRuntime.typeError("Not Parsable as XML"); } XmlCursor curs = xo.newCursor(); if (curs.currentTokenType().isStartdoc()) { curs.toFirstContentToken(); } if (isText) { // Move it to point to the text node curs.toFirstContentToken(); } XScriptAnnotation anno; try { anno = new XScriptAnnotation(curs); curs.setBookmark(anno); } finally { curs.dispose(); } return new XML(lib, anno); } static XML getFromAnnotation(XMLLibImpl lib, XScriptAnnotation anno) { if (anno._xScriptXML == null) { anno._xScriptXML = new XML(lib, anno); } return anno._xScriptXML; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Private functions: // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * * @param curs * @return */ private static TokenType skipNonElements (XmlCursor curs) { TokenType tt = curs.currentTokenType(); while (tt.isComment() || tt.isProcinst()) { tt = curs.toNextToken(); } return tt; } /** * * @param curs * @return */ protected static XScriptAnnotation findAnnotation(XmlCursor curs) { XmlBookmark anno = curs.getBookmark(XScriptAnnotation.class); if (anno == null) { anno = new XScriptAnnotation(curs); curs.setBookmark(anno); } return (XScriptAnnotation)anno; } /** * * @return */ private XmlOptions getOptions() { XmlOptions options = new XmlOptions(); if (lib.ignoreComments) { options.put(XmlOptions.LOAD_STRIP_COMMENTS); } if (lib.ignoreProcessingInstructions) { options.put(XmlOptions.LOAD_STRIP_PROCINSTS); } if (lib.ignoreWhitespace) { options.put(XmlOptions.LOAD_STRIP_WHITESPACE); } if (lib.prettyPrinting) { options.put(XmlOptions.SAVE_PRETTY_PRINT, null); options.put(XmlOptions.SAVE_PRETTY_PRINT_INDENT, new Integer(lib.prettyIndent)); } return options; } /** * * @param cursor * @param opts * @return */ private static String dumpNode(XmlCursor cursor, XmlOptions opts) { if (cursor.isText()) return cursor.getChars(); if (cursor.isFinish()) return ""; cursor.push(); boolean wanRawText = cursor.isStartdoc() && !cursor.toFirstChild(); cursor.pop(); return wanRawText ? cursor.getTextValue() : cursor.xmlText( opts ); } /** * * @return */ private XmlCursor newCursor () { XmlCursor curs; if (_anno != null) { curs = _anno.createCursor(); if (curs == null) { // Orphaned case. XmlObject doc = XmlObject.Factory.newInstance(); curs = doc.newCursor(); if (_anno._name != null) { curs.toNextToken(); curs.insertElement(_anno._name); curs.toPrevSibling(); } curs.setBookmark(_anno); } } else { XmlObject doc = XmlObject.Factory.newInstance(); curs = doc.newCursor(); } return curs; } /* * fUseStartDoc used by child(int index) the index is at startDoc is the element at the top-level * otherwise we always want to drill in. */ private boolean moveToChild(XmlCursor curs, long index, boolean fFirstChild, boolean fUseStartDoc) { if (index < 0) throw new IllegalArgumentException(); long idxChild = 0; if (!fUseStartDoc && curs.currentTokenType().isStartdoc()) { // We always move to the children of the top node. // todo: This assumes that we want have multiple top-level nodes. Which we should be able tohave. curs.toFirstContentToken(); } TokenType tt = curs.toFirstContentToken(); if (!tt.isNone() && !tt.isEnd()) { while (true) { if (index == idxChild) { return true; } tt = curs.currentTokenType(); if (tt.isText()) { curs.toNextToken(); } else if (tt.isStart()) { // Need to do this we want to be pointing at the text if that after the end token. curs.toEndToken(); curs.toNextToken(); } else if (tt.isComment() || tt.isProcinst()) { continue; } else { break; } idxChild++; } } else if (fFirstChild && index == 0) { // Drill into where first child would be. // curs.toFirstContentToken(); return true; } return false; } /** * * @return */ XmlCursor.TokenType tokenType() { XmlCursor.TokenType result; XmlCursor curs = newCursor(); if (curs.isStartdoc()) { curs.toFirstContentToken(); } result = curs.currentTokenType(); curs.dispose(); return result; } /** * * @param srcCurs * @param destCurs * @param fDontMoveIfSame * @return */ private boolean moveSrcToDest (XmlCursor srcCurs, XmlCursor destCurs, boolean fDontMoveIfSame) { boolean fMovedSomething = true; TokenType tt; do { if (fDontMoveIfSame && srcCurs.isInSameDocument(destCurs) && (srcCurs.comparePosition(destCurs) == 0)) { // If the source and destination are pointing at the same place then there's nothing to move. fMovedSomething = false; break; } // todo ***TLL*** Use replaceContents (when added) and eliminate children removes (see above todo). if (destCurs.currentTokenType().isStartdoc()) { destCurs.toNextToken(); } // todo ***TLL*** Can Eric support notion of copy instead of me copying then moving??? XmlCursor copyCurs = copy(srcCurs); copyCurs.moveXml(destCurs); copyCurs.dispose(); tt = srcCurs.currentTokenType(); } while (!tt.isStart() && !tt.isEnd() && !tt.isEnddoc()); return fMovedSomething; } /** * * @param cursToCopy * @return */ private XmlCursor copy (XmlCursor cursToCopy) { XmlObject xo = XmlObject.Factory.newInstance(); XmlCursor copyCurs = null; if (cursToCopy.currentTokenType().isText()) { try { // Try just as a textnode, to do that we need to wrap the text in a special fragment tag // that is not visible from the XmlCursor. copyCurs = XmlObject.Factory.parse("" + cursToCopy.getChars() + "").newCursor(); if (!cursToCopy.toNextSibling()) { if (cursToCopy.currentTokenType().isText()) { cursToCopy.toNextToken(); // It's not an element it's text so skip it. } } } catch (Exception ex) { throw ScriptRuntime.typeError(ex.getMessage()); } } else { copyCurs = xo.newCursor(); copyCurs.toFirstContentToken(); if (cursToCopy.currentTokenType() == XmlCursor.TokenType.STARTDOC) { cursToCopy.toNextToken(); } cursToCopy.copyXml(copyCurs); if (!cursToCopy.toNextSibling()) // If element skip element. { if (cursToCopy.currentTokenType().isText()) { cursToCopy.toNextToken(); // It's not an element it's text so skip it. } } } copyCurs.toStartDoc(); copyCurs.toFirstContentToken(); return copyCurs; } private static final int APPEND_CHILD = 1; private static final int PREPEND_CHILD = 2; /** * * @param curs * @param xmlToInsert */ private void insertChild(XmlCursor curs, Object xmlToInsert) { if (xmlToInsert == null || xmlToInsert instanceof Undefined) { // Do nothing } else if (xmlToInsert instanceof XmlCursor) { moveSrcToDest((XmlCursor)xmlToInsert, curs, true); } else if (xmlToInsert instanceof XML) { XML xmlValue = (XML) xmlToInsert; // If it's an attribute, then change to text node if (xmlValue.tokenType() == XmlCursor.TokenType.ATTR) { insertChild(curs, xmlValue.toString()); } else { XmlCursor cursToInsert = ((XML) xmlToInsert).newCursor(); moveSrcToDest(cursToInsert, curs, true); cursToInsert.dispose(); } } else if (xmlToInsert instanceof XMLList) { XMLList list = (XMLList) xmlToInsert; for (int i = 0; i < list.length(); i++) { insertChild(curs, list.item(i)); } } else { // Convert to string and make XML out of it String xmlStr = ScriptRuntime.toString(xmlToInsert); XmlObject xo = XmlObject.Factory.newInstance(); // Create an empty document. XmlCursor sourceCurs = xo.newCursor(); sourceCurs.toNextToken(); // To hold the text. sourceCurs.insertChars(xmlStr); sourceCurs.toPrevToken(); // Call us again with the cursor. moveSrcToDest(sourceCurs, curs, true); } } /** * * @param childToMatch * @param xmlToInsert * @param addToType */ private void insertChild(XML childToMatch, Object xmlToInsert, int addToType) { XmlCursor curs = newCursor(); TokenType tt = curs.currentTokenType(); XmlCursor xmlChildCursor = childToMatch.newCursor(); if (tt.isStartdoc()) { tt = curs.toFirstContentToken(); } if (tt.isContainer()) { tt = curs.toNextToken(); while (!tt.isEnd()) { if (tt.isStart()) { // See if this child is the same as the one thep passed in if (curs.comparePosition(xmlChildCursor) == 0) { // Found it if (addToType == APPEND_CHILD) { // Move the cursor to just past the end of this element curs.toEndToken(); curs.toNextToken(); } insertChild(curs, xmlToInsert); break; } } // Skip over child elements if (tt.isStart()) { tt = curs.toEndToken(); } tt = curs.toNextToken(); } } xmlChildCursor.dispose(); curs.dispose(); } /** * * @param curs */ protected void removeToken (XmlCursor curs) { XmlObject xo = XmlObject.Factory.newInstance(); // Don't delete anything move to another document so it gets orphaned nicely. XmlCursor tmpCurs = xo.newCursor(); tmpCurs.toFirstContentToken(); curs.moveXml(tmpCurs); tmpCurs.dispose(); } /** * * @param index */ protected void removeChild(long index) { XmlCursor curs = newCursor(); if (moveToChild(curs, index, false, false)) { removeToken(curs); } curs.dispose(); } /** * * @param name * @return */ protected static javax.xml.namespace.QName computeQName (Object name) { if (name instanceof String) { String ns = null; String localName = null; String fullName = (String)name; localName = fullName; if (fullName.startsWith("\"")) { int idx = fullName.indexOf(":"); if (idx != -1) { ns = fullName.substring(1, idx - 1); // Don't include the "" around the namespace localName = fullName.substring(idx + 1); } } if (ns == null) { return new javax.xml.namespace.QName(localName); } else { return new javax.xml.namespace.QName(ns, localName); } } return null; } /** * * @param destCurs * @param newValue */ private void replace(XmlCursor destCurs, XML newValue) { if (destCurs.isStartdoc()) { // Can't overwrite a whole document (user really wants to overwrite the contents of). destCurs.toFirstContentToken(); } // Orphan the token -- don't delete it outright on the XmlCursor. removeToken(destCurs); XmlCursor srcCurs = newValue.newCursor(); if (srcCurs.currentTokenType().isStartdoc()) { // Cann't append a whole document (user really wants to append the contents of). srcCurs.toFirstContentToken(); } moveSrcToDest(srcCurs, destCurs, false); // Re-link a new annotation to this cursor -- we just deleted the previous annotation on entrance to replace. if (!destCurs.toPrevSibling()) { destCurs.toPrevToken(); } destCurs.setBookmark(new XScriptAnnotation(destCurs)); // todo would be nice if destCurs.toNextSibling went to where the next token if the cursor was pointing at the last token in the stream. destCurs.toEndToken(); destCurs.toNextToken(); srcCurs.dispose(); } /** * * @param currXMLNode * @param xmlValue * @return */ private boolean doPut(XMLName name, XML currXMLNode, XMLObjectImpl xmlValue) { boolean result = false; XmlCursor curs = currXMLNode.newCursor(); try { // Replace the node with this new xml value. XML xml; int toAssignLen = xmlValue.length(); for (int i = 0; i < toAssignLen; i++) { if (xmlValue instanceof XMLList) { xml = ((XMLList) xmlValue).item(i); } else { xml = (XML) xmlValue; } // If it's an attribute or text node, make text node. XmlCursor.TokenType tt = xml.tokenType(); if (tt == XmlCursor.TokenType.ATTR || tt == XmlCursor.TokenType.TEXT) { xml = makeXmlFromString(lib, name, xml.toString()); } if (i == 0) { // 1st assignment is replaceChild all others are appendChild replace(curs, xml); } else { insertChild(curs, xml); } } // We're done we've blown away the node because the rvalue was XML... result = true; } catch (Exception ex) { ex.printStackTrace(); throw ScriptRuntime.typeError(ex.getMessage()); } finally { curs.dispose(); } return result; } /** * Make a text node element with this element name and text value. * * @param name * @param value * @return */ private XML makeXmlFromString(XMLLibImpl lib, XMLName name, String value) { XML result; javax.xml.namespace.QName qname; try { qname = new javax.xml.namespace.QName(name.uri(), name.localName()); } catch(Exception e) { throw ScriptRuntime.typeError(e.getMessage()); } result = createTextElement(lib, qname, value); return result; } /** * * @param name * @return */ private XMLList matchAttributes(XMLName xmlName) { XMLList result = new XMLList(lib); XmlCursor curs = newCursor(); if (curs.currentTokenType().isStartdoc()) { curs.toFirstContentToken(); } if (curs.isStart()) { if (curs.toFirstAttribute()) { do { if (qnameMatches(xmlName, curs.getName())) { result.addToList(createAttributeObject(curs)); } } while (curs.toNextAttribute()); } } curs.dispose(); return result; } /** * * @param attrCurs * @return */ private XML createAttributeObject (XmlCursor attrCurs) { XML result = null; if (attrCurs.currentTokenType().isAttr()) { result = createAttributeXML(lib, attrCurs); } return result; } // // // methods overriding ScriptableObject // // public String getClassName () { return "XML"; } // // // methods overriding IdScriptableObject // // /** * XML[0] should return this, all other indexes are Undefined * * @param index * @param start * @return */ public Object get(int index, Scriptable start) { //Log("get index: " + index); if (index == 0) { return this; } else { return Scriptable.NOT_FOUND; } } /** * Does the named property exist * * @param xmlName * @return */ boolean hasXMLProperty(XMLName xmlName) { // Has now should return true if the property would have results > 0 return (getPropertyList(xmlName).length() > 0); } /** * * @param index * @param start * @return */ public boolean has(int index, Scriptable start) { return (index == 0); } /** * * @return */ public Object[] getIds() { Object[] enumObjs; if (prototypeFlag) { enumObjs = new Object[0]; } else { enumObjs = new Object[1]; enumObjs[0] = new Integer(0); } return enumObjs; } /** * * @return */ public Object [] getIdsForDebug() { return getIds(); } /** * * @param xmlName * @return */ Object getXMLProperty(XMLName xmlName) { return getPropertyList(xmlName); } /** * * @param xmlName * @param value */ void putXMLProperty(XMLName xmlName, Object value) { //Log("put property: " + name + " value: " + value.getClass()); if (prototypeFlag) { } else { // Special-case checks for undefined and null if (value == null) { value = "null"; } else if (value instanceof Undefined) { value = "undefined"; } // Get the named property if (xmlName.isAttributeName()) { setAttribute(xmlName, value); } else if (xmlName.uri() == null && xmlName.localName().equals("*")) { setChildren(value); } else { // Convert text into XML if needed. XMLObjectImpl xmlValue = null; if (value instanceof XMLObjectImpl) { xmlValue = (XMLObjectImpl) value; // Check for attribute type and convert to textNode if (xmlValue instanceof XML) { if (((XML) xmlValue).tokenType() == XmlCursor.TokenType.ATTR) { xmlValue = makeXmlFromString(lib, xmlName, xmlValue.toString()); } } if (xmlValue instanceof XMLList) { for (int i = 0; i < xmlValue.length(); i++) { XML xml = ((XMLList) xmlValue).item(i); if (xml.tokenType() == XmlCursor.TokenType.ATTR) { ((XMLList) xmlValue).replace(i, makeXmlFromString(lib, xmlName, xml.toString())); } } } } else { xmlValue = makeXmlFromString(lib, xmlName, ScriptRuntime.toString(value)); } XMLList matches = getPropertyList(xmlName); if (matches.length() == 0) { appendChild(xmlValue); } else { // Remove all other matches for (int i = 1; i < matches.length(); i++) { removeChild(matches.item(i).childIndex()); } // Replace first match with new value. doPut(xmlName, matches.item(0), xmlValue); } } } } /** * * @param index * @param start * @param value */ public void put(int index, Scriptable start, Object value) { // Spec says assignment to indexed XML object should return type error throw ScriptRuntime.typeError("Assignment to indexed XML is not allowed"); } /** * * @param name */ void deleteXMLProperty(XMLName name) { if (!name.isDescendants() && name.isAttributeName()) { XmlCursor curs = newCursor(); // TODO: Cover the case *::name if (name.localName().equals("*")) { // Delete all attributes. if (curs.toFirstAttribute()) { while (curs.currentTokenType().isAttr()) { curs.removeXml(); } } } else { // Delete an attribute. javax.xml.namespace.QName qname = new javax.xml.namespace.QName( name.uri(), name.localName()); curs.removeAttribute(qname); } curs.dispose(); } else { XMLList matches = getPropertyList(name); matches.remove(); } } /** * * @param index */ public void delete(int index) { if (index == 0) { remove(); } } // // // package utility functions: // // protected XScriptAnnotation getAnnotation () { return _anno; } protected void changeNS (String oldURI, String newURI) { XmlCursor curs = newCursor(); while (curs.toParent()) { /* Goto the top of the document */ } TokenType tt = curs.currentTokenType(); if (tt.isStartdoc()) { tt = curs.toFirstContentToken(); } if (tt.isStart()) { do { if (tt.isStart() || tt.isAttr() || tt.isNamespace()) { javax.xml.namespace.QName currQName = curs.getName(); if (oldURI.equals(currQName.getNamespaceURI())) { curs.setName(new javax.xml.namespace.QName(newURI, currQName.getLocalPart())); } } tt = curs.toNextToken(); } while (!tt.isEnddoc() && !tt.isNone()); } curs.dispose(); } /** * */ void remove () { XmlCursor childCurs = newCursor(); if (childCurs.currentTokenType().isStartdoc()) { // Remove on the document removes all children. TokenType tt = childCurs.toFirstContentToken(); while (!tt.isEnd() && !tt.isEnddoc()) { removeToken(childCurs); tt = childCurs.currentTokenType(); // Now see where we're pointing after the delete -- next token. } } else { removeToken(childCurs); } childCurs.dispose(); } /** * * @param value */ void replaceAll(XML value) { XmlCursor curs = newCursor(); replace(curs, value); _anno = value._anno; curs.dispose(); } /** * * @param attrName * @param value */ void setAttribute(XMLName xmlName, Object value) { if (xmlName.uri() == null && xmlName.localName().equals("*")) { throw ScriptRuntime.typeError("@* assignment not supported."); } XmlCursor curs = newCursor(); String strValue = ScriptRuntime.toString(value); if (curs.currentTokenType().isStartdoc()) { curs.toFirstContentToken(); } javax.xml.namespace.QName qName; try { qName = new javax.xml.namespace.QName(xmlName.uri(), xmlName.localName()); } catch(Exception e) { throw ScriptRuntime.typeError(e.getMessage()); } if (!curs.setAttributeText(qName, strValue)) { if (curs.currentTokenType().isStart()) { // Can only add attributes inside of a start. curs.toNextToken(); } curs.insertAttributeWithValue(qName, strValue); } curs.dispose(); } /** * * @param namespace * @return */ private XMLList allChildNodes(String namespace) { XMLList result = new XMLList(lib); XmlCursor curs = newCursor(); TokenType tt = curs.currentTokenType(); javax.xml.namespace.QName targetProperty = new javax.xml.namespace.QName(namespace, "*"); if (tt.isStartdoc()) { tt = curs.toFirstContentToken(); } if (tt.isContainer()) { tt = curs.toFirstContentToken(); while (!tt.isEnd()) { if (!tt.isStart()) { // Not an element result.addToList(findAnnotation(curs)); // Reset target property to null in this case targetProperty = null; } else { // Match namespace as well if specified if (namespace == null || namespace.length() == 0 || namespace.equals("*") || curs.getName().getNamespaceURI().equals(namespace)) { // Add it to the list result.addToList(findAnnotation(curs)); // Set target property if target name is "*", // Otherwise if target property does not match current, then // set to null if (targetProperty != null) { if (targetProperty.getLocalPart().equals("*")) { targetProperty = curs.getName(); } else if (!targetProperty.getLocalPart().equals(curs.getName().getLocalPart())) { // Not a match, unset target property targetProperty = null; } } } } // Skip over child elements if (tt.isStart()) { tt = curs.toEndToken(); } tt = curs.toNextToken(); } } curs.dispose(); // Set the targets for this XMLList. result.setTargets(this, targetProperty); return result; } /** * * @return */ private XMLList matchDescendantAttributes(XMLName xmlName) { XMLList result = new XMLList(lib); XmlCursor curs = newCursor(); TokenType tt = curs.currentTokenType(); // Set the targets for this XMLList. result.setTargets(this, null); if (tt.isStartdoc()) { tt = curs.toFirstContentToken(); } if (tt.isContainer()) { int nestLevel = 1; while (nestLevel > 0) { tt = curs.toNextToken(); // Only try to match names for attributes if (tt.isAttr()) { if (qnameMatches(xmlName, curs.getName())) { result.addToList(findAnnotation(curs)); } } if (tt.isStart()) { nestLevel++; } else if (tt.isEnd()) { nestLevel--; } else if (tt.isEnddoc()) { // Shouldn't get here, but just in case. break; } } } curs.dispose(); return result; } /** * * @return */ private XMLList matchDescendantChildren(XMLName xmlName) { XMLList result = new XMLList(lib); XmlCursor curs = newCursor(); TokenType tt = curs.currentTokenType(); // Set the targets for this XMLList. result.setTargets(this, null); if (tt.isStartdoc()) { tt = curs.toFirstContentToken(); } if (tt.isContainer()) { int nestLevel = 1; while (nestLevel > 0) { tt = curs.toNextToken(); if (!tt.isAttr() && !tt.isEnd() && !tt.isEnddoc()) { // Only try to match names for elements or processing instructions. if (!tt.isStart() && !tt.isProcinst()) { // Not an element or procinst, only add if qname is all if (xmlName.localName().equals("*")) { result.addToList(findAnnotation(curs)); } } else { if (qnameMatches(xmlName, curs.getName())) { result.addToList(findAnnotation(curs)); } } } if (tt.isStart()) { nestLevel++; } else if (tt.isEnd()) { nestLevel--; } else if (tt.isEnddoc()) { // Shouldn't get here, but just in case. break; } } } curs.dispose(); return result; } /** * * @param tokenType * @return */ private XMLList matchChildren(XmlCursor.TokenType tokenType) { return matchChildren(tokenType, XMLName.formStar()); } /** * * @return */ private XMLList matchChildren(XmlCursor.TokenType tokenType, XMLName name) { XMLList result = new XMLList(lib); XmlCursor curs = newCursor(); TokenType tt = curs.currentTokenType(); javax.xml.namespace.QName qname = new javax.xml.namespace.QName(name.uri(), name.localName()); javax.xml.namespace.QName targetProperty = qname; if (tt.isStartdoc()) { tt = curs.toFirstContentToken(); } if (tt.isContainer()) { tt = curs.toFirstContentToken(); while (!tt.isEnd()) { if (tt == tokenType) { // Only try to match names for elements or processing instructions. if (!tt.isStart() && !tt.isProcinst()) { // Not an element or no name specified. result.addToList(findAnnotation(curs)); // Reset target property to null in this case targetProperty = null; } else { // Match names as well if (qnameMatches(name, curs.getName())) { // Add it to the list result.addToList(findAnnotation(curs)); // Set target property if target name is "*", // Otherwise if target property does not match current, then // set to null if (targetProperty != null) { if (targetProperty.getLocalPart().equals("*")) { targetProperty = curs.getName(); } else if (!targetProperty.getLocalPart().equals(curs.getName().getLocalPart())) { // Not a match, unset target property targetProperty = null; } } } } } // Skip over child elements if (tt.isStart()) { tt = curs.toEndToken(); } tt = curs.toNextToken(); } } curs.dispose(); if (tokenType == XmlCursor.TokenType.START) { // Set the targets for this XMLList. result.setTargets(this, targetProperty); } return result; } /** * * @param template * @param match * @return */ private boolean qnameMatches(XMLName template, javax.xml.namespace.QName match) { boolean matches = false; if (template.uri() == null || template.uri().equals(match.getNamespaceURI())) { // URI OK, test name if (template.localName().equals("*") || template.localName().equals(match.getLocalPart())) { matches = true; } } return matches; } // // // Methods from section 12.4.4 in the spec // // /** * The addNamespace method adds a namespace declaration to the in scope * namespaces for this XML object and returns this XML object. * * @param toAdd */ XML addNamespace(Namespace ns) { // When a namespace is used it will be added automatically // to the inScopeNamespaces set. There is no need to add // Namespaces with undefined prefixes. String nsPrefix = ns.prefix(); if (nsPrefix == null) return this; XmlCursor cursor = newCursor(); try { if(!cursor.isContainer()) return this; javax.xml.namespace.QName qname = cursor.getName(); // Don't add a default namespace declarations to containers // with QNames in no namespace. if(qname.getNamespaceURI().equals("") && nsPrefix.equals("")) return this; // Get all declared namespaces that are in scope Map prefixToURI = NamespaceHelper.getAllNamespaces(lib, cursor); String uri = (String)prefixToURI.get(nsPrefix); if(uri != null) { // Check if the Namespace is not already in scope if(uri.equals(ns.uri())) return this; cursor.push(); // Let's see if we have to delete a namespace declaration while(cursor.toNextToken().isAnyAttr()) { if(cursor.isNamespace()) { qname = cursor.getName(); String prefix = qname.getLocalPart(); if(prefix.equals(nsPrefix)) { // Delete the current Namespace declaration cursor.removeXml(); break; } } } cursor.pop(); } cursor.toNextToken(); cursor.insertNamespace(nsPrefix, ns.uri()); } finally { cursor.dispose(); } return this; } /** * * @param xml * @return */ XML appendChild(Object xml) { XmlCursor curs = newCursor(); if (curs.isStartdoc()) { curs.toFirstContentToken(); } // Move the cursor to the end of this element if (curs.isStart()) { curs.toEndToken(); } insertChild(curs, xml); curs.dispose(); return this; } /** * * @param name * @return */ XMLList attribute(XMLName xmlName) { return matchAttributes(xmlName); } /** * * @return */ XMLList attributes() { XMLName xmlName = XMLName.formStar(); return matchAttributes(xmlName); } XMLList child(long index) { XMLList result = new XMLList(lib); result.setTargets(this, null); result.addToList(getXmlChild(index)); return result; } XMLList child(XMLName xmlName) { if (xmlName == null) return new XMLList(lib); XMLList result; if (xmlName.localName().equals("*")) { result = allChildNodes(xmlName.uri()); } else { result = matchChildren(XmlCursor.TokenType.START, xmlName); } return result; } /** * * @param index * @return */ XML getXmlChild(long index) { XML result = null; XmlCursor curs = newCursor(); if (moveToChild(curs, index, false, true)) { result = createXML(lib, curs); } curs.dispose(); return result; } /** * * @return */ int childIndex() { int index = 0; XmlCursor curs = newCursor(); TokenType tt = curs.currentTokenType(); while (true) { if (tt.isText()) { index++; if (!curs.toPrevSibling()) { break; } } else if (tt.isStart()) { tt = curs.toPrevToken(); if (tt.isEnd()) { curs.toNextToken(); if (!curs.toPrevSibling()) { break; } index++; } else { // Hit the parent start tag so get out we're down counting children. break; } } else if (tt.isComment() || tt.isProcinst()) { curs.toPrevToken(); } else { break; } tt = curs.currentTokenType(); } index = curs.currentTokenType().isStartdoc() ? -1 : index; curs.dispose(); return index; } /** * * @return */ XMLList children() { return allChildNodes(null); } /** * * @return */ XMLList comments() { return matchChildren(XmlCursor.TokenType.COMMENT); } /** * * @param xml * @return */ boolean contains(Object xml) { boolean result = false; if (xml instanceof XML) { result = equivalentXml(xml); } return result; } /** * * @return */ Object copy() { XmlCursor srcCurs = newCursor(); if (srcCurs.isStartdoc()) { srcCurs.toFirstContentToken(); } XML xml = createEmptyXML(lib); XmlCursor destCurs = xml.newCursor(); destCurs.toFirstContentToken(); srcCurs.copyXml(destCurs); destCurs.dispose(); srcCurs.dispose(); return xml; } /** * * @param name * @return */ XMLList descendants(XMLName xmlName) { XMLList result; if (xmlName.isAttributeName()) { result = matchDescendantAttributes(xmlName); } else { result = matchDescendantChildren(xmlName); } return result; } /** * The inScopeNamespaces method returns an Array of Namespace objects * representing the namespaces in scope for this XML object in the * context of its parent. * * @return Array of all Namespaces in scope for this XML Object. */ Object[] inScopeNamespaces() { XmlCursor cursor = newCursor(); Object[] namespaces = NamespaceHelper.inScopeNamespaces(lib, cursor); cursor.dispose(); return namespaces; } /** * * @param child * @param xml */ XML insertChildAfter(Object child, Object xml) { if (child == null) { // Spec says inserting after nothing is the same as prepending prependChild(xml); } else if (child instanceof XML) { insertChild((XML) child, xml, APPEND_CHILD); } return this; } /** * * @param child * @param xml */ XML insertChildBefore(Object child, Object xml) { if (child == null) { // Spec says inserting before nothing is the same as appending appendChild(xml); } else if (child instanceof XML) { insertChild((XML) child, xml, PREPEND_CHILD); } return this; } /** * * @return */ boolean hasOwnProperty(XMLName xmlName) { boolean hasProperty = false; if (prototypeFlag) { String property = xmlName.localName(); hasProperty = (0 != findPrototypeId(property)); } else { hasProperty = (getPropertyList(xmlName).length() > 0); } return hasProperty; } /** * * @return */ boolean hasComplexContent() { return !hasSimpleContent(); } /** * * @return */ boolean hasSimpleContent() { boolean simpleContent = false; XmlCursor curs = newCursor(); if (curs.isAttr() || curs.isText()) { return true; } if (curs.isStartdoc()) { curs.toFirstContentToken(); } simpleContent = !(curs.toFirstChild()); curs.dispose(); return simpleContent; } /** * Length of an XML object is always 1, it's a list of XML objects of size 1. * * @return */ int length() { return 1; } /** * * @return */ String localName() { XmlCursor cursor = newCursor(); if (cursor.isStartdoc()) cursor.toFirstContentToken(); String name = null; if(cursor.isStart() || cursor.isAttr() || cursor.isProcinst()) { javax.xml.namespace.QName qname = cursor.getName(); name = qname.getLocalPart(); } cursor.dispose(); return name; } /** * The name method returns the qualified name associated with this XML object. * * @return The qualified name associated with this XML object. */ QName name() { XmlCursor cursor = newCursor(); if (cursor.isStartdoc()) cursor.toFirstContentToken(); QName name = null; if(cursor.isStart() || cursor.isAttr() || cursor.isProcinst()) { javax.xml.namespace.QName qname = cursor.getName(); if(cursor.isProcinst()) { name = new QName(lib, "", qname.getLocalPart(), ""); } else { String uri = qname.getNamespaceURI(); String prefix = qname.getPrefix(); name = new QName(lib, uri, qname.getLocalPart(), prefix); } } cursor.dispose(); return name; } /** * * @param prefix * @return */ Object namespace(String prefix) { XmlCursor cursor = newCursor(); if (cursor.isStartdoc()) { cursor.toFirstContentToken(); } Object result = null; if (prefix == null) { if(cursor.isStart() || cursor.isAttr()) { Object[] inScopeNS = NamespaceHelper.inScopeNamespaces(lib, cursor); // XXX Is it reaaly necessary to create the second cursor? XmlCursor cursor2 = newCursor(); if (cursor2.isStartdoc()) cursor2.toFirstContentToken(); result = NamespaceHelper.getNamespace(lib, cursor2, inScopeNS); cursor2.dispose(); } } else { Map prefixToURI = NamespaceHelper.getAllNamespaces(lib, cursor); String uri = (String)prefixToURI.get(prefix); result = (uri == null) ? Undefined.instance : new Namespace(lib, prefix, uri); } cursor.dispose(); return result; } /** * * @return */ Object[] namespaceDeclarations() { XmlCursor cursor = newCursor(); Object[] namespaces = NamespaceHelper.namespaceDeclarations(lib, cursor); cursor.dispose(); return namespaces; } /** * * @return */ Object nodeKind() { String result; XmlCursor.TokenType tt = tokenType(); if (tt == XmlCursor.TokenType.ATTR) { result = "attribute"; } else if (tt == XmlCursor.TokenType.TEXT) { result = "text"; } else if (tt == XmlCursor.TokenType.COMMENT) { result = "comment"; } else if (tt == XmlCursor.TokenType.PROCINST) { result = "processing-instruction"; } else if (tt == XmlCursor.TokenType.START) { result = "element"; } else { // A non-existant node has the nodeKind() of text result = "text"; } return result; } /** * */ void normalize() { XmlCursor curs = newCursor(); TokenType tt = curs.currentTokenType(); // Walk through the tokens removing empty text nodes and merging adjacent text nodes. if (tt.isStartdoc()) { tt = curs.toFirstContentToken(); } if (tt.isContainer()) { int nestLevel = 1; String previousText = null; while (nestLevel > 0) { tt = curs.toNextToken(); if (tt == XmlCursor.TokenType.TEXT) { String currentText = curs.getChars().trim(); if (currentText.trim().length() == 0) { // Empty text node, remove. removeToken(curs); curs.toPrevToken(); } else if (previousText == null) { // No previous text node, reset to trimmed version previousText = currentText; } else { // It appears that this case never happens with XBeans. // Previous text node exists, concatenate String newText = previousText + currentText; curs.toPrevToken(); removeToken(curs); removeToken(curs); curs.insertChars(newText); } } else { previousText = null; } if (tt.isStart()) { nestLevel++; } else if (tt.isEnd()) { nestLevel--; } else if (tt.isEnddoc()) { // Shouldn't get here, but just in case. break; } } } curs.dispose(); } /** * * @return */ Object parent() { Object parent; XmlCursor curs = newCursor(); if (curs.isStartdoc()) { // At doc level - no parent parent = Undefined.instance; } else { if (curs.toParent()) { if (curs.isStartdoc()) { // Was top-level - no parent parent = Undefined.instance; } else { parent = getFromAnnotation(lib, findAnnotation(curs)); } } else { // No parent parent = Undefined.instance; } } curs.dispose(); return parent; } /** * * @param xml * @return */ XML prependChild (Object xml) { XmlCursor curs = newCursor(); if (curs.isStartdoc()) { curs.toFirstContentToken(); } // Move the cursor to the first content token curs.toFirstContentToken(); insertChild(curs, xml); curs.dispose(); return this; } /** * * @return */ Object processingInstructions(XMLName xmlName) { return matchChildren(XmlCursor.TokenType.PROCINST, xmlName); } /** * * @param name * @return */ boolean propertyIsEnumerable(Object name) { boolean result; if (name instanceof Integer) { result = (((Integer)name).intValue() == 0); } else if (name instanceof Number) { double x = ((Number)name).doubleValue(); // Check that number is posotive 0 result = (x == 0.0 && 1.0 / x > 0); } else { result = ScriptRuntime.toString(name).equals("0"); } return result; } /** * * @param namespace */ XML removeNamespace(Namespace ns) { XmlCursor cursor = newCursor(); try { if(cursor.isStartdoc()) cursor.toFirstContentToken(); if(!cursor.isStart()) return this; String nsPrefix = ns.prefix(); String nsURI = ns.uri(); Map prefixToURI = new HashMap(); int depth = 1; while(!(cursor.isEnd() && depth == 0)) { if(cursor.isStart()) { // Get the namespaces declared in this element. // The ones with undefined prefixes are not candidates // for removal because they are used. prefixToURI.clear(); NamespaceHelper.getNamespaces(cursor, prefixToURI); ObjArray inScopeNSBag = new ObjArray(); Iterator i = prefixToURI.entrySet().iterator(); while(i.hasNext()) { Map.Entry entry = (Map.Entry)i.next(); ns = new Namespace(lib, (String)entry.getKey(), (String)entry.getValue()); inScopeNSBag.add(ns); } // Add the URI we are looking for to avoid matching // non-existing Namespaces. ns = new Namespace(lib, nsURI); inScopeNSBag.add(ns); Object[] inScopeNS = inScopeNSBag.toArray(); // Check the element name Namespace n = NamespaceHelper.getNamespace(lib, cursor, inScopeNS); if(nsURI.equals(n.uri()) && (nsPrefix == null || nsPrefix.equals(n.prefix()))) { // This namespace is used return this; } // Check the attributes cursor.push(); boolean hasNext = cursor.toFirstAttribute(); while(hasNext) { n = NamespaceHelper.getNamespace(lib, cursor, inScopeNS); if(nsURI.equals(n.uri()) && (nsPrefix == null || nsPrefix.equals(n.prefix()))) { // This namespace is used return this; } hasNext = cursor.toNextAttribute(); } cursor.pop(); if(nsPrefix == null) { // Remove all namespaces declarations that match nsURI i = prefixToURI.entrySet().iterator(); while(i.hasNext()) { Map.Entry entry = (Map.Entry)i.next(); if(entry.getValue().equals(nsURI)) NamespaceHelper.removeNamespace(cursor, (String)entry.getKey()); } } else if(nsURI.equals(prefixToURI.get(nsPrefix))) { // Remove the namespace declaration that matches nsPrefix NamespaceHelper.removeNamespace(cursor, String.valueOf(nsPrefix)); } } switch(cursor.toNextToken().intValue()) { case XmlCursor.TokenType.INT_START: depth++; break; case XmlCursor.TokenType.INT_END: depth--; break; } } } finally { cursor.dispose(); } return this; } XML replace(long index, Object xml) { XMLList xlChildToReplace = child(index); if (xlChildToReplace.length() > 0) { // One exists an that index XML childToReplace = xlChildToReplace.item(0); insertChildAfter(childToReplace, xml); removeChild(index); } return this; } /** * * @param propertyName * @param xml * @return */ XML replace(XMLName xmlName, Object xml) { putXMLProperty(xmlName, xml); return this; } /** * * @param xml */ XML setChildren(Object xml) { // remove all children XMLName xmlName = XMLName.formStar(); XMLList matches = getPropertyList(xmlName); matches.remove(); // append new children appendChild(xml); return this; } /** * * @param name */ void setLocalName(String localName) { XmlCursor cursor = newCursor(); try { if(cursor.isStartdoc()) cursor.toFirstContentToken(); if(cursor.isText() || cursor.isComment()) return; javax.xml.namespace.QName qname = cursor.getName(); cursor.setName(new javax.xml.namespace.QName( qname.getNamespaceURI(), localName, qname.getPrefix())); } finally { cursor.dispose(); } } /** * * @param name */ void setName(QName qname) { XmlCursor cursor = newCursor(); try { if(cursor.isStartdoc()) cursor.toFirstContentToken(); if(cursor.isText() || cursor.isComment()) return; if(cursor.isProcinst()) { String localName = qname.localName(); cursor.setName(new javax.xml.namespace.QName(localName)); } else { String prefix = qname.prefix(); if (prefix == null) { prefix = ""; } cursor.setName(new javax.xml.namespace.QName( qname.uri(), qname.localName(), prefix)); } } finally { cursor.dispose(); } } /** * * @param ns */ void setNamespace(Namespace ns) { XmlCursor cursor = newCursor(); try { if(cursor.isStartdoc()) cursor.toFirstContentToken(); if(cursor.isText() || cursor.isComment() || cursor.isProcinst()) return; String prefix = ns.prefix(); if (prefix == null) { prefix = ""; } cursor.setName(new javax.xml.namespace.QName( ns.uri(), localName(), prefix)); } finally { cursor.dispose(); } } /** * * @return */ XMLList text() { return matchChildren(XmlCursor.TokenType.TEXT); } /** * * @return */ public String toString() { String result; XmlCursor curs = newCursor(); if (curs.isStartdoc()) { curs.toFirstContentToken(); } if (curs.isText()) { result = curs.getChars(); } else if (curs.isStart() && hasSimpleContent()) { result = curs.getTextValue(); } else { result = toXMLString(0); } return result; } String toSource(int indent) { // XXX Does toXMLString always return valid XML literal? return toXMLString(indent); } /** * * @return */ String toXMLString(int indent) { // XXX indent is ignored String result; XmlCursor curs = newCursor(); if (curs.isStartdoc()) { curs.toFirstContentToken(); } try { if (curs.isText()) { result = curs.getChars(); } else if (curs.isAttr()) { result = curs.getTextValue(); } else if (curs.isComment() || curs.isProcinst()) { result = XML.dumpNode(curs, getOptions()); // todo: XBeans-dependent hack here // If it's a comment or PI, take off the xml-frament stuff String start = ""; String end = ""; if (result.startsWith(start)) { result = result.substring(start.length()); } if (result.endsWith(end)) { result = result.substring(0, result.length() - end.length()); } } else { result = XML.dumpNode(curs, getOptions()); } } finally { curs.dispose(); } return result; } /** * * @return */ Object valueOf() { return this; } // // Other public Functions from XMLObject // /** * * @param target * @return */ boolean equivalentXml(Object target) { boolean result = false; if (target instanceof XML) { XML otherXml = (XML) target; // Compare with toString() if either side is text node or attribute // otherwise compare as XML XmlCursor.TokenType thisTT = tokenType(); XmlCursor.TokenType otherTT = otherXml.tokenType(); if (thisTT == XmlCursor.TokenType.ATTR || otherTT == XmlCursor.TokenType.ATTR || thisTT == XmlCursor.TokenType.TEXT || otherTT == XmlCursor.TokenType.TEXT) { result = toString().equals(otherXml.toString()); } else { XmlCursor cursOne = newCursor(); XmlCursor cursTwo = otherXml.newCursor(); result = LogicalEquality.nodesEqual(cursOne, cursTwo); cursOne.dispose(); cursTwo.dispose(); // Old way of comparing by string. // boolean orgPrettyPrinting = prototype.prettyPrinting; // prototype.prettyPrinting = true; // result = toXMLString(0).equals(otherXml.toXMLString(0)); // prototype.prettyPrinting = orgPrettyPrinting; } } else if (target instanceof XMLList) { XMLList otherList = (XMLList) target; if (otherList.length() == 1) { result = equivalentXml(otherList.getXmlFromAnnotation(0)); } } else if (hasSimpleContent()) { String otherStr = ScriptRuntime.toString(target); result = toString().equals(otherStr); } return result; } /** * * @param name * @param start * @return */ XMLList getPropertyList(XMLName name) { XMLList result; // Get the named property if (name.isDescendants()) { result = descendants(name); } else if (name.isAttributeName()) { result = attribute(name); } else { result = child(name); } return result; } protected Object jsConstructor(Context cx, boolean inNewExpr, Object[] args) { if (args.length == 0) { return createFromJS(lib, ""); } else { Object arg0 = args[0]; if (!inNewExpr && arg0 instanceof XML) { // XML(XML) returns the same object. return arg0; } return createFromJS(lib, arg0); } } /** * See ECMA 357, 11_2_2_1, Semantics, 3_f. */ public Scriptable getExtraMethodSource(Context cx) { if (hasSimpleContent()) { String src = toString(); return ScriptRuntime.toObjectOrNull(cx, src); } return null; } XmlObject getXmlObject() { XmlObject xo; XmlCursor cursor = newCursor(); try { xo = cursor.getObject(); } finally { cursor.dispose(); } return xo; } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLCtor.java000066400000000000000000000177161176760007500276540ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import org.mozilla.javascript.*; class XMLCtor extends IdFunctionObject { static final long serialVersionUID = -8708195078359817341L; private static final Object XMLCTOR_TAG = "XMLCtor"; private XMLLibImpl lib; XMLCtor(XML xml, Object tag, int id, int arity) { super(xml, tag, id, arity); this.lib = xml.lib; activatePrototypeMap(MAX_FUNCTION_ID); } private void writeSetting(Scriptable target) { for (int i = 1; i <= MAX_INSTANCE_ID; ++i) { int id = super.getMaxInstanceId() + i; String name = getInstanceIdName(id); Object value = getInstanceIdValue(id); ScriptableObject.putProperty(target, name, value); } } private void readSettings(Scriptable source) { for (int i = 1; i <= MAX_INSTANCE_ID; ++i) { int id = super.getMaxInstanceId() + i; String name = getInstanceIdName(id); Object value = ScriptableObject.getProperty(source, name); if (value == Scriptable.NOT_FOUND) { continue; } switch (i) { case Id_ignoreComments: case Id_ignoreProcessingInstructions: case Id_ignoreWhitespace: case Id_prettyPrinting: if (!(value instanceof Boolean)) { continue; } break; case Id_prettyIndent: if (!(value instanceof Number)) { continue; } break; default: throw new IllegalStateException(); } setInstanceIdValue(id, value); } } // #string_id_map# private static final int Id_ignoreComments = 1, Id_ignoreProcessingInstructions = 2, Id_ignoreWhitespace = 3, Id_prettyIndent = 4, Id_prettyPrinting = 5, MAX_INSTANCE_ID = 5; protected int getMaxInstanceId() { return super.getMaxInstanceId() + MAX_INSTANCE_ID; } protected int findInstanceIdInfo(String s) { int id; // #generated# Last update: 2004-07-19 13:03:52 CEST L0: { id = 0; String X = null; int c; L: switch (s.length()) { case 12: X="prettyIndent";id=Id_prettyIndent; break L; case 14: c=s.charAt(0); if (c=='i') { X="ignoreComments";id=Id_ignoreComments; } else if (c=='p') { X="prettyPrinting";id=Id_prettyPrinting; } break L; case 16: X="ignoreWhitespace";id=Id_ignoreWhitespace; break L; case 28: X="ignoreProcessingInstructions";id=Id_ignoreProcessingInstructions; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# if (id == 0) return super.findInstanceIdInfo(s); int attr; switch (id) { case Id_ignoreComments: case Id_ignoreProcessingInstructions: case Id_ignoreWhitespace: case Id_prettyIndent: case Id_prettyPrinting: attr = PERMANENT | DONTENUM; break; default: throw new IllegalStateException(); } return instanceIdInfo(attr, super.getMaxInstanceId() + id); } // #/string_id_map# protected String getInstanceIdName(int id) { switch (id - super.getMaxInstanceId()) { case Id_ignoreComments: return "ignoreComments"; case Id_ignoreProcessingInstructions: return "ignoreProcessingInstructions"; case Id_ignoreWhitespace: return "ignoreWhitespace"; case Id_prettyIndent: return "prettyIndent"; case Id_prettyPrinting: return "prettyPrinting"; } return super.getInstanceIdName(id); } protected Object getInstanceIdValue(int id) { switch (id - super.getMaxInstanceId()) { case Id_ignoreComments: return ScriptRuntime.wrapBoolean(lib.ignoreComments); case Id_ignoreProcessingInstructions: return ScriptRuntime.wrapBoolean(lib.ignoreProcessingInstructions); case Id_ignoreWhitespace: return ScriptRuntime.wrapBoolean(lib.ignoreWhitespace); case Id_prettyIndent: return ScriptRuntime.wrapInt(lib.prettyIndent); case Id_prettyPrinting: return ScriptRuntime.wrapBoolean(lib.prettyPrinting); } return super.getInstanceIdValue(id); } protected void setInstanceIdValue(int id, Object value) { switch (id - super.getMaxInstanceId()) { case Id_ignoreComments: lib.ignoreComments = ScriptRuntime.toBoolean(value); return; case Id_ignoreProcessingInstructions: lib.ignoreProcessingInstructions = ScriptRuntime.toBoolean(value); return; case Id_ignoreWhitespace: lib.ignoreWhitespace = ScriptRuntime.toBoolean(value); return; case Id_prettyIndent: lib.prettyIndent = ScriptRuntime.toInt32(value); return; case Id_prettyPrinting: lib.prettyPrinting = ScriptRuntime.toBoolean(value); return; } super.setInstanceIdValue(id, value); } // #string_id_map# private static final int Id_defaultSettings = 1, Id_settings = 2, Id_setSettings = 3, MAX_FUNCTION_ID = 3; protected int findPrototypeId(String s) { int id; // #generated# Last update: 2004-07-19 13:03:52 CEST L0: { id = 0; String X = null; int s_length = s.length(); if (s_length==8) { X="settings";id=Id_settings; } else if (s_length==11) { X="setSettings";id=Id_setSettings; } else if (s_length==15) { X="defaultSettings";id=Id_defaultSettings; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# return id; } // #/string_id_map# protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_defaultSettings: arity=0; s="defaultSettings"; break; case Id_settings: arity=0; s="settings"; break; case Id_setSettings: arity=1; s="setSettings"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(XMLCTOR_TAG, id, s, arity); } public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(XMLCTOR_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_defaultSettings: { lib.defaultSettings(); Scriptable obj = cx.newObject(scope); writeSetting(obj); return obj; } case Id_settings: { Scriptable obj = cx.newObject(scope); writeSetting(obj); return obj; } case Id_setSettings: { if (args.length == 0 || args[0] == null || args[0] == Undefined.instance) { lib.defaultSettings(); } else if (args[0] instanceof Scriptable) { readSettings((Scriptable)args[0]); } return Undefined.instance; } } throw new IllegalArgumentException(String.valueOf(id)); } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLLibImpl.java000066400000000000000000000527401176760007500302710ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import java.io.Serializable; import org.mozilla.javascript.*; import org.mozilla.javascript.xml.*; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlObject; public final class XMLLibImpl extends XMLLib implements Serializable { private static final long serialVersionUID = 1L; private Scriptable globalScope; XML xmlPrototype; XMLList xmlListPrototype; Namespace namespacePrototype; QName qnamePrototype; // Environment settings... boolean ignoreComments; boolean ignoreProcessingInstructions; boolean ignoreWhitespace; boolean prettyPrinting; int prettyIndent; Scriptable globalScope() { return globalScope; } private XMLLibImpl(Scriptable globalScope) { this.globalScope = globalScope; defaultSettings(); } public static void init(Context cx, Scriptable scope, boolean sealed) { // To force LinkageError if XmlObject is not available XmlObject.class.getName(); XMLLibImpl lib = new XMLLibImpl(scope); XMLLib bound = lib.bindToScope(scope); if (bound == lib) { lib.exportToScope(sealed); } } private void exportToScope(boolean sealed) { xmlPrototype = XML.createEmptyXML(this); xmlListPrototype = new XMLList(this); namespacePrototype = new Namespace(this, "", ""); qnamePrototype = new QName(this, "", "", ""); xmlPrototype.exportAsJSClass(sealed); xmlListPrototype.exportAsJSClass(sealed); namespacePrototype.exportAsJSClass(sealed); qnamePrototype.exportAsJSClass(sealed); } void defaultSettings() { ignoreComments = true; ignoreProcessingInstructions = true; ignoreWhitespace = true; prettyPrinting = true; prettyIndent = 2; } XMLName toAttributeName(Context cx, Object nameValue) { String uri; String localName; if (nameValue instanceof String) { uri = ""; localName = (String)nameValue; } else if (nameValue instanceof XMLName) { XMLName xmlName = (XMLName)nameValue; if (!xmlName.isAttributeName()) { xmlName.setAttributeName(); } return xmlName; } else if (nameValue instanceof QName) { QName qname = (QName)nameValue; uri = qname.uri(); localName = qname.localName(); } else if (nameValue instanceof Boolean || nameValue instanceof Number || nameValue == Undefined.instance || nameValue == null) { throw badXMLName(nameValue); } else { uri = ""; localName = ScriptRuntime.toString(nameValue); } XMLName xmlName = XMLName.formProperty(uri, localName); xmlName.setAttributeName(); return xmlName; } private static RuntimeException badXMLName(Object value) { String msg; if (value instanceof Number) { msg = "Can not construct XML name from number: "; } else if (value instanceof Boolean) { msg = "Can not construct XML name from boolean: "; } else if (value == Undefined.instance || value == null) { msg = "Can not construct XML name from "; } else { throw new IllegalArgumentException(value.toString()); } return ScriptRuntime.typeError(msg+ScriptRuntime.toString(value)); } XMLName toXMLName(Context cx, Object nameValue) { XMLName result; if (nameValue instanceof XMLName) { result = (XMLName)nameValue; } else if (nameValue instanceof QName) { QName qname = (QName)nameValue; result = XMLName.formProperty(qname.uri(), qname.localName()); } else if (nameValue instanceof String) { result = toXMLNameFromString(cx, (String)nameValue); } else if (nameValue instanceof Boolean || nameValue instanceof Number || nameValue == Undefined.instance || nameValue == null) { throw badXMLName(nameValue); } else { String name = ScriptRuntime.toString(nameValue); result = toXMLNameFromString(cx, name); } return result; } /** * If value represents Uint32 index, make it available through * ScriptRuntime.lastUint32Result(cx) and return null. * Otherwise return the same value as toXMLName(cx, value). */ XMLName toXMLNameOrIndex(Context cx, Object value) { XMLName result; if (value instanceof XMLName) { result = (XMLName)value; } else if (value instanceof String) { String str = (String)value; long test = ScriptRuntime.testUint32String(str); if (test >= 0) { ScriptRuntime.storeUint32Result(cx, test); result = null; } else { result = toXMLNameFromString(cx, str); } } else if (value instanceof Number) { double d = ((Number)value).doubleValue(); long l = (long)d; if (l == d && 0 <= l && l <= 0xFFFFFFFFL) { ScriptRuntime.storeUint32Result(cx, l); result = null; } else { throw badXMLName(value); } } else if (value instanceof QName) { QName qname = (QName)value; String uri = qname.uri(); boolean number = false; result = null; if (uri != null && uri.length() == 0) { // Only in this case qname.toString() can resemble uint32 long test = ScriptRuntime.testUint32String(uri); if (test >= 0) { ScriptRuntime.storeUint32Result(cx, test); number = true; } } if (!number) { result = XMLName.formProperty(uri, qname.localName()); } } else if (value instanceof Boolean || value == Undefined.instance || value == null) { throw badXMLName(value); } else { String str = ScriptRuntime.toString(value); long test = ScriptRuntime.testUint32String(str); if (test >= 0) { ScriptRuntime.storeUint32Result(cx, test); result = null; } else { result = toXMLNameFromString(cx, str); } } return result; } XMLName toXMLNameFromString(Context cx, String name) { if (name == null) throw new IllegalArgumentException(); int l = name.length(); if (l != 0) { char firstChar = name.charAt(0); if (firstChar == '*') { if (l == 1) { return XMLName.formStar(); } } else if (firstChar == '@') { XMLName xmlName = XMLName.formProperty("", name.substring(1)); xmlName.setAttributeName(); return xmlName; } } String uri = getDefaultNamespaceURI(cx); return XMLName.formProperty(uri, name); } Namespace constructNamespace(Context cx, Object uriValue) { String prefix; String uri; if (uriValue instanceof Namespace) { Namespace ns = (Namespace)uriValue; prefix = ns.prefix(); uri = ns.uri(); } else if (uriValue instanceof QName) { QName qname = (QName)uriValue; uri = qname.uri(); if (uri != null) { prefix = qname.prefix(); } else { uri = qname.toString(); prefix = null; } } else { uri = ScriptRuntime.toString(uriValue); prefix = (uri.length() == 0) ? "" : null; } return new Namespace(this, prefix, uri); } Namespace castToNamespace(Context cx, Object namescapeObj) { if (namescapeObj instanceof Namespace) { return (Namespace)namescapeObj; } return constructNamespace(cx, namescapeObj); } Namespace constructNamespace(Context cx) { return new Namespace(this, "", ""); } public Namespace constructNamespace(Context cx, Object prefixValue, Object uriValue) { String prefix; String uri; if (uriValue instanceof QName) { QName qname = (QName)uriValue; uri = qname.uri(); if (uri == null) { uri = qname.toString(); } } else { uri = ScriptRuntime.toString(uriValue); } if (uri.length() == 0) { if (prefixValue == Undefined.instance) { prefix = ""; } else { prefix = ScriptRuntime.toString(prefixValue); if (prefix.length() != 0) { throw ScriptRuntime.typeError( "Illegal prefix '"+prefix+"' for 'no namespace'."); } } } else if (prefixValue == Undefined.instance) { prefix = ""; } else if (!isXMLName(cx, prefixValue)) { prefix = ""; } else { prefix = ScriptRuntime.toString(prefixValue); } return new Namespace(this, prefix, uri); } String getDefaultNamespaceURI(Context cx) { String uri = ""; if (cx == null) { cx = Context.getCurrentContext(); } if (cx != null) { Object ns = ScriptRuntime.searchDefaultNamespace(cx); if (ns != null) { if (ns instanceof Namespace) { uri = ((Namespace)ns).uri(); } else { // Should not happen but for now it could // due to bad searchDefaultNamespace implementation. } } } return uri; } Namespace getDefaultNamespace(Context cx) { if (cx == null) { cx = Context.getCurrentContext(); if (cx == null) { return namespacePrototype; } } Namespace result; Object ns = ScriptRuntime.searchDefaultNamespace(cx); if (ns == null) { result = namespacePrototype; } else { if (ns instanceof Namespace) { result = (Namespace)ns; } else { // Should not happen but for now it could // due to bad searchDefaultNamespace implementation. result = namespacePrototype; } } return result; } QName castToQName(Context cx, Object qnameValue) { if (qnameValue instanceof QName) { return (QName)qnameValue; } return constructQName(cx, qnameValue); } QName constructQName(Context cx, Object nameValue) { QName result; if (nameValue instanceof QName) { QName qname = (QName)nameValue; result = new QName(this, qname.uri(), qname.localName(), qname.prefix()); } else { String localName = ScriptRuntime.toString(nameValue); result = constructQNameFromString(cx, localName); } return result; } /** * Optimized version of constructQName for String type */ QName constructQNameFromString(Context cx, String localName) { if (localName == null) throw new IllegalArgumentException(); String uri; String prefix; if ("*".equals(localName)) { uri = null; prefix = null; } else { Namespace ns = getDefaultNamespace(cx); uri = ns.uri(); prefix = ns.prefix(); } return new QName(this, uri, localName, prefix); } QName constructQName(Context cx, Object namespaceValue, Object nameValue) { String uri; String localName; String prefix; if (nameValue instanceof QName) { QName qname = (QName)nameValue; localName = qname.localName(); } else { localName = ScriptRuntime.toString(nameValue); } Namespace ns; if (namespaceValue == Undefined.instance) { if ("*".equals(localName)) { ns = null; } else { ns = getDefaultNamespace(cx); } } else if (namespaceValue == null) { ns = null; } else if (namespaceValue instanceof Namespace) { ns = (Namespace)namespaceValue; } else { ns = constructNamespace(cx, namespaceValue); } if (ns == null) { uri = null; prefix = null; } else { uri = ns.uri(); prefix = ns.prefix(); } return new QName(this, uri, localName, prefix); } Object addXMLObjects(Context cx, XMLObject obj1, XMLObject obj2) { XMLList listToAdd = new XMLList(this); if (obj1 instanceof XMLList) { XMLList list1 = (XMLList)obj1; if (list1.length() == 1) { listToAdd.addToList(list1.item(0)); } else { // Might be xmlFragment + xmlFragment + xmlFragment + ...; // then the result will be an XMLList which we want to be an // rValue and allow it to be assigned to an lvalue. listToAdd = new XMLList(this, obj1); } } else { listToAdd.addToList(obj1); } if (obj2 instanceof XMLList) { XMLList list2 = (XMLList)obj2; for (int i = 0; i < list2.length(); i++) { listToAdd.addToList(list2.item(i)); } } else if (obj2 instanceof XML) { listToAdd.addToList(obj2); } return listToAdd; } // // // Overriding XMLLib methods // // /** * See E4X 13.1.2.1. */ public boolean isXMLName(Context cx, Object nameObj) { String name; try { name = ScriptRuntime.toString(nameObj); } catch (EcmaError ee) { if ("TypeError".equals(ee.getName())) { return false; } throw ee; } // See http://w3.org/TR/xml-names11/#NT-NCName int length = name.length(); if (length != 0) { if (isNCNameStartChar(name.charAt(0))) { for (int i = 1; i != length; ++i) { if (!isNCNameChar(name.charAt(i))) { return false; } } return true; } } return false; } private static boolean isNCNameStartChar(int c) { if ((c & ~0x7F) == 0) { // Optimize for ASCII and use A..Z < _ < a..z if (c >= 'a') { return c <= 'z'; } else if (c >= 'A') { if (c <= 'Z') { return true; } return c == '_'; } } else if ((c & ~0x1FFF) == 0) { return (0xC0 <= c && c <= 0xD6) || (0xD8 <= c && c <= 0xF6) || (0xF8 <= c && c <= 0x2FF) || (0x370 <= c && c <= 0x37D) || 0x37F <= c; } return (0x200C <= c && c <= 0x200D) || (0x2070 <= c && c <= 0x218F) || (0x2C00 <= c && c <= 0x2FEF) || (0x3001 <= c && c <= 0xD7FF) || (0xF900 <= c && c <= 0xFDCF) || (0xFDF0 <= c && c <= 0xFFFD) || (0x10000 <= c && c <= 0xEFFFF); } private static boolean isNCNameChar(int c) { if ((c & ~0x7F) == 0) { // Optimize for ASCII and use - < . < 0..9 < A..Z < _ < a..z if (c >= 'a') { return c <= 'z'; } else if (c >= 'A') { if (c <= 'Z') { return true; } return c == '_'; } else if (c >= '0') { return c <= '9'; } else { return c == '-' || c == '.'; } } else if ((c & ~0x1FFF) == 0) { return isNCNameStartChar(c) || c == 0xB7 || (0x300 <= c && c <= 0x36F); } return isNCNameStartChar(c) || (0x203F <= c && c <= 0x2040); } XMLName toQualifiedName(Context cx, Object namespaceValue, Object nameValue) { // This is duplication of constructQName(cx, namespaceValue, nameValue) // but for XMLName String uri; String localName; if (nameValue instanceof QName) { QName qname = (QName)nameValue; localName = qname.localName(); } else { localName = ScriptRuntime.toString(nameValue); } Namespace ns; if (namespaceValue == Undefined.instance) { if ("*".equals(localName)) { ns = null; } else { ns = getDefaultNamespace(cx); } } else if (namespaceValue == null) { ns = null; } else if (namespaceValue instanceof Namespace) { ns = (Namespace)namespaceValue; } else { ns = constructNamespace(cx, namespaceValue); } if (ns == null) { uri = null; } else { uri = ns.uri(); } return XMLName.formProperty(uri, localName); } public Ref nameRef(Context cx, Object name, Scriptable scope, int memberTypeFlags) { if ((memberTypeFlags & Node.ATTRIBUTE_FLAG) == 0) { // should only be called foir cases like @name or @[expr] throw Kit.codeBug(); } XMLName xmlName = toAttributeName(cx, name); return xmlPrimaryReference(cx, xmlName, scope); } public Ref nameRef(Context cx, Object namespace, Object name, Scriptable scope, int memberTypeFlags) { XMLName xmlName = toQualifiedName(cx, namespace, name); if ((memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0) { if (!xmlName.isAttributeName()) { xmlName.setAttributeName(); } } return xmlPrimaryReference(cx, xmlName, scope); } private Ref xmlPrimaryReference(Context cx, XMLName xmlName, Scriptable scope) { XMLObjectImpl xmlObj; XMLObjectImpl firstXmlObject = null; for (;;) { // XML object can only present on scope chain as a wrapper // of XMLWithScope if (scope instanceof XMLWithScope) { xmlObj = (XMLObjectImpl)scope.getPrototype(); if (xmlObj.hasXMLProperty(xmlName)) { break; } if (firstXmlObject == null) { firstXmlObject = xmlObj; } } scope = scope.getParentScope(); if (scope == null) { xmlObj = firstXmlObject; break; } } // xmlObj == null corresponds to undefined as the target of // the reference if (xmlObj != null) { xmlName.initXMLObject(xmlObj); } return xmlName; } /** * Escapes the reserved characters in a value of an attribute * * @param value Unescaped text * @return The escaped text */ public String escapeAttributeValue(Object value) { String text = ScriptRuntime.toString(value); if (text.length() == 0) return ""; XmlObject xo = XmlObject.Factory.newInstance(); XmlCursor cursor = xo.newCursor(); cursor.toNextToken(); cursor.beginElement("a"); cursor.insertAttributeWithValue("a", text); cursor.dispose(); String elementText = xo.toString(); int begin = elementText.indexOf('"'); int end = elementText.lastIndexOf('"'); return elementText.substring(begin + 1, end); } /** * Escapes the reserved characters in a value of a text node * * @param value Unescaped text * @return The escaped text */ public String escapeTextValue(Object value) { if (value instanceof XMLObjectImpl) { return ((XMLObjectImpl)value).toXMLString(0); } String text = ScriptRuntime.toString(value); if (text.length() == 0) return text; XmlObject xo = XmlObject.Factory.newInstance(); XmlCursor cursor = xo.newCursor(); cursor.toNextToken(); cursor.beginElement("a"); cursor.insertChars(text); cursor.dispose(); String elementText = xo.toString(); int begin = elementText.indexOf('>') + 1; int end = elementText.lastIndexOf('<'); return (begin < end) ? elementText.substring(begin, end) : ""; } public Object toDefaultXmlNamespace(Context cx, Object uriValue) { return constructNamespace(cx, uriValue); } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLList.java000066400000000000000000001067641176760007500276620ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import java.util.Vector; import org.mozilla.javascript.*; import org.mozilla.javascript.xml.*; import org.apache.xmlbeans.XmlCursor; class XMLList extends XMLObjectImpl implements Function { static final long serialVersionUID = -4543618751670781135L; static class AnnotationList { private Vector v; AnnotationList () { v = new Vector(); } void add (XML.XScriptAnnotation n) { v.add(n); } XML.XScriptAnnotation item(int index) { return (XML.XScriptAnnotation)(v.get(index)); } void remove (int index) { v.remove(index); } int length() { return v.size(); } }; // Fields private AnnotationList _annos; private XMLObjectImpl targetObject = null; private javax.xml.namespace.QName targetProperty = null; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Constructors // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * */ XMLList(XMLLibImpl lib) { super(lib, lib.xmlListPrototype); _annos = new AnnotationList(); } /** * * @param inputObject */ XMLList(XMLLibImpl lib, Object inputObject) { super(lib, lib.xmlListPrototype); String frag; if (inputObject == null || inputObject instanceof Undefined) { frag = ""; } else if (inputObject instanceof XML) { XML xml = (XML) inputObject; _annos = new AnnotationList(); _annos.add(xml.getAnnotation()); } else if (inputObject instanceof XMLList) { XMLList xmll = (XMLList) inputObject; _annos = new AnnotationList(); for (int i = 0; i < xmll._annos.length(); i++) { _annos.add(xmll._annos.item(i)); } } else { frag = ScriptRuntime.toString(inputObject).trim(); if (!frag.startsWith("<>")) { frag = "<>" + frag + ""; } frag = "" + frag.substring(2); if (!frag.endsWith("")) { throw ScriptRuntime.typeError("XML with anonymous tag missing end anonymous tag"); } frag = frag.substring(0, frag.length() - 3) + ""; XML orgXML = XML.createFromJS(lib, frag); // Now orphan the children and add them to our XMLList. XMLList children = orgXML.children(); _annos = new AnnotationList(); for (int i = 0; i < children._annos.length(); i++) { // Copy here is so that they'll be orphaned (parent() will be undefined) _annos.add(((XML) children.item(i).copy()).getAnnotation()); } } } // // // TargetObject/Property accessors // // /** * * @param object * @param property */ void setTargets(XMLObjectImpl object, javax.xml.namespace.QName property) { targetObject = object; targetProperty = property; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Private functions // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** * * @param index * @return */ XML getXmlFromAnnotation(int index) { XML retVal; if (index >= 0 && index < length()) { XML.XScriptAnnotation anno = _annos.item(index); retVal = XML.getFromAnnotation(lib, anno); } else { retVal = null; } return retVal; } /** * * @param index */ private void internalRemoveFromList (int index) { _annos.remove(index); } /** * * @param index * @param xml */ void replace(int index, XML xml) { if (index < length()) { AnnotationList newAnnoList = new AnnotationList(); // Copy upto item to replace. for (int i = 0; i < index; i++) { newAnnoList.add(_annos.item(i)); } newAnnoList.add(xml.getAnnotation()); // Skip over old item we're going to replace we've already add new item on above line. for (int i = index + 1; i < length(); i++) { newAnnoList.add(_annos.item(i)); } _annos = newAnnoList; } } /** * * @param index * @param xml */ private void insert(int index, XML xml) { if (index < length()) { AnnotationList newAnnoList = new AnnotationList(); // Copy upto item to insert. for (int i = 0; i < index; i++) { newAnnoList.add(_annos.item(i)); } newAnnoList.add(xml.getAnnotation()); for (int i = index; i < length(); i++) { newAnnoList.add(_annos.item(i)); } _annos = newAnnoList; } } // // // methods overriding ScriptableObject // // public String getClassName () { return "XMLList"; } // // // methods overriding IdScriptableObject // // /** * * @param index * @param start * @return */ public Object get(int index, Scriptable start) { //Log("get index: " + index); if (index >= 0 && index < length()) { return getXmlFromAnnotation(index); } else { return Scriptable.NOT_FOUND; } } /** * * @param xmlName * @return */ boolean hasXMLProperty(XMLName xmlName) { // Has now should return true if the property would have results > 0 return (getPropertyList(xmlName).length() > 0); } /** * * @param index * @param start * @return */ public boolean has(int index, Scriptable start) { return 0 <= index && index < length(); } /** * * @param name * @param value */ void putXMLProperty(XMLName xmlName, Object value) { //Log("put property: " + name); // Special-case checks for undefined and null if (value == null) { value = "null"; } else if (value instanceof Undefined) { value = "undefined"; } if (length() > 1) { throw ScriptRuntime.typeError("Assignment to lists with more that one item is not supported"); } else if (length() == 0) { // Secret sauce for super-expandos. // We set an element here, and then add ourselves to our target. if (targetObject != null && targetProperty != null && !targetProperty.getLocalPart().equals("*")) { // Add an empty element with our targetProperty name and then set it. XML xmlValue = XML.createTextElement(lib, targetProperty, ""); addToList(xmlValue); if(xmlName.isAttributeName()) { setAttribute(xmlName, value); } else { XML xml = item(0); xml.putXMLProperty(xmlName, value); // Update the list with the new item at location 0. replace(0, item(0)); } // Now add us to our parent XMLName name2 = XMLName.formProperty(targetProperty.getNamespaceURI(), targetProperty.getLocalPart()); targetObject.putXMLProperty(name2, this); } else { throw ScriptRuntime.typeError("Assignment to empty XMLList without targets not supported"); } } else if(xmlName.isAttributeName()) { setAttribute(xmlName, value); } else { XML xml = item(0); xml.putXMLProperty(xmlName, value); // Update the list with the new item at location 0. replace(0, item(0)); } } /** * * @param name * @return */ Object getXMLProperty(XMLName name) { return getPropertyList(name); } /** * * @param index * @param value */ public void put(int index, Scriptable start, Object value) { Object parent = Undefined.instance; // Convert text into XML if needed. XMLObject xmlValue; // Special-case checks for undefined and null if (value == null) { value = "null"; } else if (value instanceof Undefined) { value = "undefined"; } if (value instanceof XMLObject) { xmlValue = (XMLObject) value; } else { if (targetProperty == null) { xmlValue = XML.createFromJS(lib, value.toString()); } else { xmlValue = XML.createTextElement(lib, targetProperty, value.toString()); } } // Find the parent if (index < length()) { parent = item(index).parent(); } else { // Appending parent = parent(); } if (parent instanceof XML) { // found parent, alter doc XML xmlParent = (XML) parent; if (index < length()) { // We're replacing the the node. XML xmlNode = getXmlFromAnnotation(index); if (xmlValue instanceof XML) { xmlNode.replaceAll((XML) xmlValue); replace(index, xmlNode); } else if (xmlValue instanceof XMLList) { // Replace the first one, and add the rest on the list. XMLList list = (XMLList) xmlValue; if (list.length() > 0) { int lastIndexAdded = xmlNode.childIndex(); xmlNode.replaceAll(list.item(0)); replace(index, list.item(0)); for (int i = 1; i < list.length(); i++) { xmlParent.insertChildAfter(xmlParent.getXmlChild(lastIndexAdded), list.item(i)); lastIndexAdded++; insert(index + i, list.item(i)); } } } } else { // Appending xmlParent.appendChild(xmlValue); addToList(xmlParent.getXmlChild(index)); } } else { // Don't all have same parent, no underlying doc to alter if (index < length()) { XML xmlNode = XML.getFromAnnotation(lib, _annos.item(index)); if (xmlValue instanceof XML) { xmlNode.replaceAll((XML) xmlValue); replace(index, xmlNode); } else if (xmlValue instanceof XMLList) { // Replace the first one, and add the rest on the list. XMLList list = (XMLList) xmlValue; if (list.length() > 0) { xmlNode.replaceAll(list.item(0)); replace(index, list.item(0)); for (int i = 1; i < list.length(); i++) { insert(index + i, list.item(i)); } } } } else { addToList(xmlValue); } } } /** * * @param name */ void deleteXMLProperty(XMLName name) { for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); if (xml.tokenType() == XmlCursor.TokenType.START) { xml.deleteXMLProperty(name); } } } /** * * @param index */ public void delete(int index) { if (index >= 0 && index < length()) { XML xml = getXmlFromAnnotation(index); xml.remove(); internalRemoveFromList(index); } } /** * * @return */ public Object[] getIds() { Object enumObjs[]; if (prototypeFlag) { enumObjs = new Object[0]; } else { enumObjs = new Object[length()]; for (int i = 0; i < enumObjs.length; i++) { enumObjs[i] = new Integer(i); } } return enumObjs; } /** * * @return */ public Object[] getIdsForDebug() { return getIds(); } // XMLList will remove will delete all items in the list (a set delete) this differs from the XMLList delete operator. void remove () { int nLen = length(); for (int i = nLen - 1; i >= 0; i--) { XML xml = getXmlFromAnnotation(i); if (xml != null) { xml.remove(); internalRemoveFromList(i); } } } /** * * @param index * @return */ XML item (int index) { return _annos != null ? getXmlFromAnnotation(index) : XML.createEmptyXML(lib); } /** * * @param name * @param value */ private void setAttribute (XMLName xmlName, Object value) { for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); xml.setAttribute(xmlName, value); } } /** * * @param toAdd */ void addToList(Object toAdd) { if (toAdd instanceof Undefined) { // Missing argument do nothing... return; } if (toAdd instanceof XMLList) { XMLList xmlSrc = (XMLList)toAdd; for (int i = 0; i < xmlSrc.length(); i++) { _annos.add((xmlSrc.item(i)).getAnnotation()); } } else if (toAdd instanceof XML) { _annos.add(((XML)(toAdd)).getAnnotation()); } else if (toAdd instanceof XML.XScriptAnnotation) { _annos.add((XML.XScriptAnnotation)toAdd); } } // // // Methods from section 12.4.4 in the spec // // /** * * @param toAdd */ XML addNamespace(Namespace ns) { if(length() == 1) { return getXmlFromAnnotation(0).addNamespace(ns); } else { throw ScriptRuntime.typeError("The addNamespace method works only on lists containing one item"); } } /** * * @param xml * @return */ XML appendChild(Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).appendChild(xml); } else { throw ScriptRuntime.typeError("The appendChild method works only on lists containing one item"); } } /** * * @param attr * @return */ XMLList attribute(XMLName xmlName) { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.attribute(xmlName)); } return result; } /** * * @return */ XMLList attributes() { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.attributes()); } return result; } XMLList child(long index) { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { result.addToList(getXmlFromAnnotation(i).child(index)); } return result; } XMLList child(XMLName xmlName) { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { result.addToList(getXmlFromAnnotation(i).child(xmlName)); } return result; } /** * * @return */ int childIndex() { if (length() == 1) { return getXmlFromAnnotation(0).childIndex(); } else { throw ScriptRuntime.typeError("The childIndex method works only on lists containing one item"); } } /** * * @return */ XMLList children() { Vector v = new Vector(); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); if (xml != null) { Object o = xml.children(); if (o instanceof XMLList) { XMLList childList = (XMLList)o; int cChildren = childList.length(); for (int j = 0; j < cChildren; j++) { v.addElement(childList.item(j)); } } } } XMLList allChildren = new XMLList(lib); int sz = v.size(); for (int i = 0; i < sz; i++) { allChildren.addToList(v.get(i)); } return allChildren; } /** * * @return */ XMLList comments() { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.comments()); } return result; } /** * * @param xml * @return */ boolean contains(Object xml) { boolean result = false; for (int i = 0; i < length(); i++) { XML member = getXmlFromAnnotation(i); if (member.equivalentXml(xml)) { result = true; break; } } return result; } /** * * @return */ Object copy() { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.copy()); } return result; } /** * * @return */ XMLList descendants(XMLName xmlName) { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.descendants(xmlName)); } return result; } /** * * @return */ Object[] inScopeNamespaces() { if(length() == 1) { return getXmlFromAnnotation(0).inScopeNamespaces(); } else { throw ScriptRuntime.typeError("The inScopeNamespaces method works only on lists containing one item"); } } /** * * @param child * @param xml */ XML insertChildAfter(Object child, Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).insertChildAfter(child, xml); } else { throw ScriptRuntime.typeError("The insertChildAfter method works only on lists containing one item"); } } /** * * @param child * @param xml */ XML insertChildBefore(Object child, Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).insertChildAfter(child, xml); } else { throw ScriptRuntime.typeError("The insertChildBefore method works only on lists containing one item"); } } /** * * @return */ boolean hasOwnProperty(XMLName xmlName) { boolean hasProperty = false; if (prototypeFlag) { String property = xmlName.localName(); hasProperty = (0 != findPrototypeId(property)); } else { hasProperty = (getPropertyList(xmlName).length() > 0); } return hasProperty; } /** * * @return */ boolean hasComplexContent() { boolean complexContent; int length = length(); if (length == 0) { complexContent = false; } else if (length == 1) { complexContent = getXmlFromAnnotation(0).hasComplexContent(); } else { complexContent = false; for (int i = 0; i < length; i++) { XML nextElement = getXmlFromAnnotation(i); if (nextElement.tokenType() == XmlCursor.TokenType.START) { complexContent = true; break; } } } return complexContent; } /** * * @return */ boolean hasSimpleContent() { boolean simpleContent; int length = length(); if (length == 0) { simpleContent = true; } else if (length == 1) { simpleContent = getXmlFromAnnotation(0).hasSimpleContent(); } else { simpleContent = true; for (int i = 0; i < length; i++) { XML nextElement = getXmlFromAnnotation(i); if (nextElement.tokenType() == XmlCursor.TokenType.START) { simpleContent = false; break; } } } return simpleContent; } /** * * @return */ int length() { int result = 0; if (_annos != null) { result = _annos.length(); } return result; } /** * * @return */ String localName() { if (length() == 1) { return name().localName(); } else { throw ScriptRuntime.typeError("The localName method works only on lists containing one item"); } } /** * * @return */ QName name() { if (length() == 1) { return getXmlFromAnnotation(0).name(); } else { throw ScriptRuntime.typeError("The name method works only on lists containing one item"); } } /** * * @param prefix * @return */ Object namespace(String prefix) { if (length() == 1) { return getXmlFromAnnotation(0).namespace(prefix); } else { throw ScriptRuntime.typeError("The namespace method works only on lists containing one item"); } } /** * * @return */ Object[] namespaceDeclarations() { if (length() == 1) { return getXmlFromAnnotation(0).namespaceDeclarations(); } else { throw ScriptRuntime.typeError("The namespaceDeclarations method works only on lists containing one item"); } } /** * * @return */ Object nodeKind() { if (length() == 1) { return getXmlFromAnnotation(0).nodeKind(); } else { throw ScriptRuntime.typeError("The nodeKind method works only on lists containing one item"); } } /** * */ void normalize() { for (int i = 0; i < length(); i++) { getXmlFromAnnotation(i).normalize(); } } /** * If list is empty, return undefined, if elements have different parents return undefined, * If they all have the same parent, return that parent. * * @return */ Object parent() { Object sameParent = Undefined.instance; if ((length() == 0) && (targetObject != null) && (targetObject instanceof XML)) { sameParent = targetObject; } else { for (int i = 0; i < length(); i++) { Object currParent = getXmlFromAnnotation(i).parent(); if (i == 0) { // Set the first for the rest to compare to. sameParent = currParent; } else if (sameParent != currParent) { sameParent = Undefined.instance; break; } } } // If everything in the list is the sameParent then return that as the parent. return sameParent; } /** * * @param xml * @return */ XML prependChild(Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).prependChild(xml); } else { throw ScriptRuntime.typeError("The prependChild method works only on lists containing one item"); } } /** * * @return */ Object processingInstructions(XMLName xmlName) { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { XML xml = getXmlFromAnnotation(i); result.addToList(xml.processingInstructions(xmlName)); } return result; } /** * * @param name * @return */ boolean propertyIsEnumerable(Object name) { long index; if (name instanceof Integer) { index = ((Integer)name).intValue(); } else if (name instanceof Number) { double x = ((Number)name).doubleValue(); index = (long)x; if (index != x) { return false; } if (index == 0 && 1.0 / x < 0) { // Negative 0 return false; } } else { String s = ScriptRuntime.toString(name); index = ScriptRuntime.testUint32String(s); } return (0 <= index && index < length()); } /** * * @param ns */ XML removeNamespace(Namespace ns) { if(length() == 1) { return getXmlFromAnnotation(0).removeNamespace(ns); } else { throw ScriptRuntime.typeError("The removeNamespace method works only on lists containing one item"); } } XML replace(long index, Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).replace(index, xml); } else { throw ScriptRuntime.typeError("The replace method works only on lists containing one item"); } } /** * * @param propertyName * @param xml * @return */ XML replace(XMLName xmlName, Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).replace(xmlName, xml); } else { throw ScriptRuntime.typeError("The replace method works only on lists containing one item"); } } /** * * @param xml */ XML setChildren(Object xml) { if (length() == 1) { return getXmlFromAnnotation(0).setChildren(xml); } else { throw ScriptRuntime.typeError("The setChildren method works only on lists containing one item"); } } /** * * @param name */ void setLocalName(String localName) { if (length() == 1) { getXmlFromAnnotation(0).setLocalName(localName); } else { throw ScriptRuntime.typeError("The setLocalName method works only on lists containing one item"); } } /** * * @param name */ void setName(QName qname) { if (length() == 1) { getXmlFromAnnotation(0).setName(qname); } else { throw ScriptRuntime.typeError("The setName method works only on lists containing one item"); } } /** * * @param ns */ void setNamespace(Namespace ns) { if (length() == 1) { getXmlFromAnnotation(0).setNamespace(ns); } else { throw ScriptRuntime.typeError("The setNamespace method works only on lists containing one item"); } } /** * * * @return */ XMLList text() { XMLList result = new XMLList(lib); for (int i = 0; i < length(); i++) { result.addToList(getXmlFromAnnotation(i).text()); } return result; } /** * * @return */ public String toString() { if (hasSimpleContent()) { StringBuffer sb = new StringBuffer(); for(int i = 0; i < length(); i++) { XML next = getXmlFromAnnotation(i); sb.append(next.toString()); } return sb.toString(); } else { return toXMLString(0); } } String toSource(int indent) { // XXX indent is ignored return "<>"+toXMLString(0)+""; } /** * * @return */ String toXMLString(int indent) { StringBuffer sb = new StringBuffer(); for(int i = 0; i < length(); i++) { if (i > 0) { sb.append('\n'); } sb.append(getXmlFromAnnotation(i).toXMLString(indent)); } return sb.toString(); } /** * * @return */ Object valueOf() { return this; } // // Other public Functions from XMLObject // /** * * @param target * @return */ boolean equivalentXml(Object target) { boolean result = false; // Zero length list should equate to undefined if (target instanceof Undefined && length() == 0) { result = true; } else if (length() == 1) { result = getXmlFromAnnotation(0).equivalentXml(target); } else if (target instanceof XMLList) { XMLList otherList = (XMLList) target; if (otherList.length() == length()) { result = true; for (int i = 0; i < length(); i++) { if (!getXmlFromAnnotation(i).equivalentXml(otherList.getXmlFromAnnotation(i))) { result = false; break; } } } } return result; } /** * * @param name * @param start * @return */ private XMLList getPropertyList(XMLName name) { XMLList propertyList = new XMLList(lib); javax.xml.namespace.QName qname = null; if (!name.isDescendants() && !name.isAttributeName()) { // Only set the targetProperty if this is a regular child get // and not a descendant or attribute get qname = new javax.xml.namespace.QName(name.uri(), name.localName()); } propertyList.setTargets(this, qname); for (int i = 0; i < length(); i++) { propertyList.addToList( getXmlFromAnnotation(i).getPropertyList(name)); } return propertyList; } private Object applyOrCall(boolean isApply, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { String methodName = isApply ? "apply" : "call"; if(!(thisObj instanceof XMLList) || ((XMLList)thisObj).targetProperty == null) throw ScriptRuntime.typeError1("msg.isnt.function", methodName); return ScriptRuntime.applyOrCall(isApply, cx, scope, thisObj, args); } protected Object jsConstructor(Context cx, boolean inNewExpr, Object[] args) { if (args.length == 0) { return new XMLList(lib); } else { Object arg0 = args[0]; if (!inNewExpr && arg0 instanceof XMLList) { // XMLList(XMLList) returns the same object. return arg0; } return new XMLList(lib, arg0); } } org.apache.xmlbeans.XmlObject getXmlObject() { if (length() == 1) { return getXmlFromAnnotation(0).getXmlObject(); } else { throw ScriptRuntime.typeError("getXmlObject method works only on lists containing one item"); } } /** * See ECMA 357, 11_2_2_1, Semantics, 3_e. */ public Scriptable getExtraMethodSource(Context cx) { if (length() == 1) { return getXmlFromAnnotation(0); } return null; } public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { // This XMLList is being called as a Function. // Let's find the real Function object. if(targetProperty == null) throw ScriptRuntime.notFunctionError(this); String methodName = targetProperty.getLocalPart(); boolean isApply = methodName.equals("apply"); if(isApply || methodName.equals("call")) return applyOrCall(isApply, cx, scope, thisObj, args); if (!(thisObj instanceof XMLObject)) { throw ScriptRuntime.typeError1("msg.incompat.call", methodName); } Object func = null; Scriptable sobj = thisObj; while (sobj instanceof XMLObject) { XMLObject xmlObject = (XMLObject) sobj; func = xmlObject.getFunctionProperty(cx, methodName); if (func != Scriptable.NOT_FOUND) { break; } sobj = xmlObject.getExtraMethodSource(cx); if (sobj != null) { thisObj = sobj; if (!(sobj instanceof XMLObject)) { func = ScriptableObject.getProperty(sobj, methodName); } } } if (!(func instanceof Callable)) { throw ScriptRuntime.notFunctionError(thisObj, func, methodName); } return ((Callable)func).call(cx, scope, thisObj, args); } public Scriptable construct(Context cx, Scriptable scope, Object[] args) { throw ScriptRuntime.typeError1("msg.not.ctor", "XMLList"); } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLName.java000066400000000000000000000067631176760007500276250ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import org.mozilla.javascript.Context; import org.mozilla.javascript.Kit; import org.mozilla.javascript.Ref; import org.mozilla.javascript.ScriptRuntime; import org.mozilla.javascript.Undefined; class XMLName extends Ref { static final long serialVersionUID = 3832176310755686977L; private String uri; private String localName; private boolean isAttributeName; private boolean isDescendants; private XMLObjectImpl xmlObject; private XMLName(String uri, String localName) { this.uri = uri; this.localName = localName; } static XMLName formStar() { return new XMLName(null, "*"); } static XMLName formProperty(String uri, String localName) { return new XMLName(uri, localName); } void initXMLObject(XMLObjectImpl xmlObject) { if (xmlObject == null) throw new IllegalArgumentException(); if (this.xmlObject != null) throw new IllegalStateException(); this.xmlObject = xmlObject; } String uri() { return uri; } String localName() { return localName; } boolean isAttributeName() { return isAttributeName; } void setAttributeName() { if (isAttributeName) throw new IllegalStateException(); isAttributeName = true; } boolean isDescendants() { return isDescendants; } void setIsDescendants() { if (isDescendants) throw new IllegalStateException(); isDescendants = true; } public boolean has(Context cx) { if (xmlObject == null) { return false; } return xmlObject.hasXMLProperty(this); } public Object get(Context cx) { if (xmlObject == null) { throw ScriptRuntime.undefReadError(Undefined.instance, toString()); } return xmlObject.getXMLProperty(this); } public Object set(Context cx, Object value) { if (xmlObject == null) { throw ScriptRuntime.undefWriteError(Undefined.instance, toString(), value); } // Assignment to descendants causes parse error on bad reference // and this should not be called if (isDescendants) throw Kit.codeBug(); xmlObject.putXMLProperty(this, value); return value; } public boolean delete(Context cx) { if (xmlObject == null) { return true; } xmlObject.deleteXMLProperty(this); return !xmlObject.hasXMLProperty(this); } public String toString() { //return qname.localName(); StringBuffer buff = new StringBuffer(); if (isDescendants) buff.append(".."); if (isAttributeName) buff.append('@'); if (uri == null) { buff.append('*'); if(localName().equals("*")) { return buff.toString(); } } else { buff.append('"').append(uri()).append('"'); } buff.append(':').append(localName()); return buff.toString(); } } rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLObjectImpl.java000066400000000000000000000652161176760007500307730ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import org.mozilla.javascript.*; import org.mozilla.javascript.xml.*; /** * This abstract class describes what all XML objects (XML, XMLList) should have in common. * * @see XML */ abstract class XMLObjectImpl extends XMLObject { private static final Object XMLOBJECT_TAG = "XMLObject"; protected final XMLLibImpl lib; protected boolean prototypeFlag; protected XMLObjectImpl(XMLLibImpl lib, XMLObject prototype) { super(lib.globalScope(), prototype); this.lib = lib; } /** * ecmaHas(cx, id) calls this after resolving when id to XMLName * and checking it is not Uint32 index. */ abstract boolean hasXMLProperty(XMLName name); /** * ecmaGet(cx, id) calls this after resolving when id to XMLName * and checking it is not Uint32 index. */ abstract Object getXMLProperty(XMLName name); /** * ecmaPut(cx, id, value) calls this after resolving when id to XMLName * and checking it is not Uint32 index. */ abstract void putXMLProperty(XMLName name, Object value); /** * ecmaDelete(cx, id) calls this after resolving when id to XMLName * and checking it is not Uint32 index. */ abstract void deleteXMLProperty(XMLName name); /** * Test XML equality with target the target. */ abstract boolean equivalentXml(Object target); // Methods from section 12.4.4 in the spec abstract XML addNamespace(Namespace ns); abstract XML appendChild(Object xml); abstract XMLList attribute(XMLName xmlName); abstract XMLList attributes(); abstract XMLList child(long index); abstract XMLList child(XMLName xmlName); abstract int childIndex(); abstract XMLList children(); abstract XMLList comments(); abstract boolean contains(Object xml); abstract Object copy(); abstract XMLList descendants(XMLName xmlName); abstract Object[] inScopeNamespaces(); abstract XML insertChildAfter(Object child, Object xml); abstract XML insertChildBefore(Object child, Object xml); abstract boolean hasOwnProperty(XMLName xmlName); abstract boolean hasComplexContent(); abstract boolean hasSimpleContent(); abstract int length(); abstract String localName(); abstract QName name(); abstract Object namespace(String prefix); abstract Object[] namespaceDeclarations(); abstract Object nodeKind(); abstract void normalize(); abstract Object parent(); abstract XML prependChild(Object xml); abstract Object processingInstructions(XMLName xmlName); abstract boolean propertyIsEnumerable(Object member); abstract XML removeNamespace(Namespace ns); abstract XML replace(long index, Object xml); abstract XML replace(XMLName name, Object xml); abstract XML setChildren(Object xml); abstract void setLocalName(String name); abstract void setName(QName xmlName); abstract void setNamespace(Namespace ns); abstract XMLList text(); public abstract String toString(); abstract String toSource(int indent); abstract String toXMLString(int indent); abstract Object valueOf(); /** * Extension to access native implementation from scripts */ abstract org.apache.xmlbeans.XmlObject getXmlObject(); protected abstract Object jsConstructor(Context cx, boolean inNewExpr, Object[] args); // // // Methods overriding ScriptableObject // // public final Object getDefaultValue(Class hint) { return toString(); } /** * XMLObject always compare with any value and equivalentValues * never returns {@link Scriptable#NOT_FOUND} for them but rather * calls equivalentXml(value) and wrap the result as Boolean. */ protected final Object equivalentValues(Object value) { boolean result = equivalentXml(value); return result ? Boolean.TRUE : Boolean.FALSE; } // // // Methods overriding XMLObject // // public final XMLLib lib() { return lib; } /** * Implementation of ECMAScript [[Has]] */ public final boolean has(Context cx, Object id) { if (cx == null) cx = Context.getCurrentContext(); XMLName xmlName = lib.toXMLNameOrIndex(cx, id); if (xmlName == null) { long index = ScriptRuntime.lastUint32Result(cx); // XXX Fix this cast return has((int)index, this); } return hasXMLProperty(xmlName); } @Override public boolean has(String name, Scriptable start) { Context cx = Context.getCurrentContext(); return hasXMLProperty(lib.toXMLNameFromString(cx, name)); } /** * Implementation of ECMAScript [[Get]] */ @Override public final Object get(Context cx, Object id) { if (cx == null) cx = Context.getCurrentContext(); XMLName xmlName = lib.toXMLNameOrIndex(cx, id); if (xmlName == null) { long index = ScriptRuntime.lastUint32Result(cx); // XXX Fix this cast Object result = get((int)index, this); if (result == Scriptable.NOT_FOUND) { result = Undefined.instance; } return result; } return getXMLProperty(xmlName); } @Override public Object get(String name, Scriptable start) { Context cx = Context.getCurrentContext(); return getXMLProperty(lib.toXMLNameFromString(cx, name)); } /** * Implementation of ECMAScript [[Put]] */ @Override public final void put(Context cx, Object id, Object value) { if (cx == null) cx = Context.getCurrentContext(); XMLName xmlName = lib.toXMLNameOrIndex(cx, id); if (xmlName == null) { long index = ScriptRuntime.lastUint32Result(cx); // XXX Fix this cast put((int)index, this, value); return; } putXMLProperty(xmlName, value); } @Override public void put(String name, Scriptable start, Object value) { Context cx = Context.getCurrentContext(); putXMLProperty(lib.toXMLNameFromString(cx, name), value); } /** * Implementation of ECMAScript [[Delete]]. */ @Override public final boolean delete(Context cx, Object id) { if (cx == null) cx = Context.getCurrentContext(); XMLName xmlName = lib.toXMLNameOrIndex(cx, id); if (xmlName == null) { long index = ScriptRuntime.lastUint32Result(cx); // XXX Fix this delete((int)index); return true; } deleteXMLProperty(xmlName); return true; } @Override public void delete(String name) { Context cx = Context.getCurrentContext(); deleteXMLProperty(lib.toXMLNameFromString(cx, name)); } @Override public Object getFunctionProperty(Context cx, int id) { if (prototypeFlag) { return super.get(id, this); } else { Scriptable proto = getPrototype(); if (proto instanceof XMLObject) { return ((XMLObject)proto).getFunctionProperty(cx, id); } } return NOT_FOUND; } @Override public Object getFunctionProperty(Context cx, String name) { if (prototypeFlag) { return super.get(name, this); } else { Scriptable proto = getPrototype(); if (proto instanceof XMLObject) { return ((XMLObject)proto).getFunctionProperty(cx, name); } } return NOT_FOUND; } public Ref memberRef(Context cx, Object elem, int memberTypeFlags) { XMLName xmlName; if ((memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0) { xmlName = lib.toAttributeName(cx, elem); } else { if ((memberTypeFlags & Node.DESCENDANTS_FLAG) == 0) { // Code generation would use ecma(Get|Has|Delete|Set) for // normal name idenrifiers so one ATTRIBUTE_FLAG // or DESCENDANTS_FLAG has to be set throw Kit.codeBug(); } xmlName = lib.toXMLName(cx, elem); } if ((memberTypeFlags & Node.DESCENDANTS_FLAG) != 0) { xmlName.setIsDescendants(); } xmlName.initXMLObject(this); return xmlName; } /** * Generic reference to implement x::ns, x.@ns::y, x..@ns::y etc. */ public Ref memberRef(Context cx, Object namespace, Object elem, int memberTypeFlags) { XMLName xmlName = lib.toQualifiedName(cx, namespace, elem); if ((memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0) { if (!xmlName.isAttributeName()) { xmlName.setAttributeName(); } } if ((memberTypeFlags & Node.DESCENDANTS_FLAG) != 0) { xmlName.setIsDescendants(); } xmlName.initXMLObject(this); return xmlName; } public NativeWith enterWith(Scriptable scope) { return new XMLWithScope(lib, scope, this); } public NativeWith enterDotQuery(Scriptable scope) { XMLWithScope xws = new XMLWithScope(lib, scope, this); xws.initAsDotQuery(); return xws; } public final Object addValues(Context cx, boolean thisIsLeft, Object value) { if (value instanceof XMLObject) { XMLObject v1, v2; if (thisIsLeft) { v1 = this; v2 = (XMLObject)value; } else { v1 = (XMLObject)value; v2 = this; } return lib.addXMLObjects(cx, v1, v2); } if (value == Undefined.instance) { // both "xml + undefined" and "undefined + xml" gives String(xml) return ScriptRuntime.toString(this); } return super.addValues(cx, thisIsLeft, value); } // // // IdScriptableObject machinery // // final void exportAsJSClass(boolean sealed) { prototypeFlag = true; exportAsJSClass(MAX_PROTOTYPE_ID, lib.globalScope(), sealed); } // #string_id_map# private final static int Id_constructor = 1, Id_addNamespace = 2, Id_appendChild = 3, Id_attribute = 4, Id_attributes = 5, Id_child = 6, Id_childIndex = 7, Id_children = 8, Id_comments = 9, Id_contains = 10, Id_copy = 11, Id_descendants = 12, Id_inScopeNamespaces = 13, Id_insertChildAfter = 14, Id_insertChildBefore = 15, Id_hasOwnProperty = 16, Id_hasComplexContent = 17, Id_hasSimpleContent = 18, Id_length = 19, Id_localName = 20, Id_name = 21, Id_namespace = 22, Id_namespaceDeclarations = 23, Id_nodeKind = 24, Id_normalize = 25, Id_parent = 26, Id_prependChild = 27, Id_processingInstructions = 28, Id_propertyIsEnumerable = 29, Id_removeNamespace = 30, Id_replace = 31, Id_setChildren = 32, Id_setLocalName = 33, Id_setName = 34, Id_setNamespace = 35, Id_text = 36, Id_toString = 37, Id_toSource = 38, Id_toXMLString = 39, Id_valueOf = 40, Id_getXmlObject = 41, MAX_PROTOTYPE_ID = 41; protected int findPrototypeId(String s) { int id; // #generated# Last update: 2004-11-10 15:38:11 CET L0: { id = 0; String X = null; int c; L: switch (s.length()) { case 4: c=s.charAt(0); if (c=='c') { X="copy";id=Id_copy; } else if (c=='n') { X="name";id=Id_name; } else if (c=='t') { X="text";id=Id_text; } break L; case 5: X="child";id=Id_child; break L; case 6: c=s.charAt(0); if (c=='l') { X="length";id=Id_length; } else if (c=='p') { X="parent";id=Id_parent; } break L; case 7: c=s.charAt(0); if (c=='r') { X="replace";id=Id_replace; } else if (c=='s') { X="setName";id=Id_setName; } else if (c=='v') { X="valueOf";id=Id_valueOf; } break L; case 8: switch (s.charAt(4)) { case 'K': X="nodeKind";id=Id_nodeKind; break L; case 'a': X="contains";id=Id_contains; break L; case 'd': X="children";id=Id_children; break L; case 'e': X="comments";id=Id_comments; break L; case 'r': X="toString";id=Id_toString; break L; case 'u': X="toSource";id=Id_toSource; break L; } break L; case 9: switch (s.charAt(2)) { case 'c': X="localName";id=Id_localName; break L; case 'm': X="namespace";id=Id_namespace; break L; case 'r': X="normalize";id=Id_normalize; break L; case 't': X="attribute";id=Id_attribute; break L; } break L; case 10: c=s.charAt(0); if (c=='a') { X="attributes";id=Id_attributes; } else if (c=='c') { X="childIndex";id=Id_childIndex; } break L; case 11: switch (s.charAt(0)) { case 'a': X="appendChild";id=Id_appendChild; break L; case 'c': X="constructor";id=Id_constructor; break L; case 'd': X="descendants";id=Id_descendants; break L; case 's': X="setChildren";id=Id_setChildren; break L; case 't': X="toXMLString";id=Id_toXMLString; break L; } break L; case 12: switch (s.charAt(0)) { case 'a': X="addNamespace";id=Id_addNamespace; break L; case 'g': X="getXmlObject";id=Id_getXmlObject; break L; case 'p': X="prependChild";id=Id_prependChild; break L; case 's': c=s.charAt(3); if (c=='L') { X="setLocalName";id=Id_setLocalName; } else if (c=='N') { X="setNamespace";id=Id_setNamespace; } break L; } break L; case 14: X="hasOwnProperty";id=Id_hasOwnProperty; break L; case 15: X="removeNamespace";id=Id_removeNamespace; break L; case 16: c=s.charAt(0); if (c=='h') { X="hasSimpleContent";id=Id_hasSimpleContent; } else if (c=='i') { X="insertChildAfter";id=Id_insertChildAfter; } break L; case 17: c=s.charAt(3); if (c=='C') { X="hasComplexContent";id=Id_hasComplexContent; } else if (c=='c') { X="inScopeNamespaces";id=Id_inScopeNamespaces; } else if (c=='e') { X="insertChildBefore";id=Id_insertChildBefore; } break L; case 20: X="propertyIsEnumerable";id=Id_propertyIsEnumerable; break L; case 21: X="namespaceDeclarations";id=Id_namespaceDeclarations; break L; case 22: X="processingInstructions";id=Id_processingInstructions; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# return id; } // #/string_id_map# protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: { IdFunctionObject ctor; if (this instanceof XML) { ctor = new XMLCtor((XML)this, XMLOBJECT_TAG, id, 1); } else { ctor = new IdFunctionObject(this, XMLOBJECT_TAG, id, 1); } initPrototypeConstructor(ctor); return; } case Id_addNamespace: arity=1; s="addNamespace"; break; case Id_appendChild: arity=1; s="appendChild"; break; case Id_attribute: arity=1; s="attribute"; break; case Id_attributes: arity=0; s="attributes"; break; case Id_child: arity=1; s="child"; break; case Id_childIndex: arity=0; s="childIndex"; break; case Id_children: arity=0; s="children"; break; case Id_comments: arity=0; s="comments"; break; case Id_contains: arity=1; s="contains"; break; case Id_copy: arity=0; s="copy"; break; case Id_descendants: arity=1; s="descendants"; break; case Id_hasComplexContent: arity=0; s="hasComplexContent"; break; case Id_hasOwnProperty: arity=1; s="hasOwnProperty"; break; case Id_hasSimpleContent: arity=0; s="hasSimpleContent"; break; case Id_inScopeNamespaces: arity=0; s="inScopeNamespaces"; break; case Id_insertChildAfter: arity=2; s="insertChildAfter"; break; case Id_insertChildBefore: arity=2; s="insertChildBefore"; break; case Id_length: arity=0; s="length"; break; case Id_localName: arity=0; s="localName"; break; case Id_name: arity=0; s="name"; break; case Id_namespace: arity=1; s="namespace"; break; case Id_namespaceDeclarations: arity=0; s="namespaceDeclarations"; break; case Id_nodeKind: arity=0; s="nodeKind"; break; case Id_normalize: arity=0; s="normalize"; break; case Id_parent: arity=0; s="parent"; break; case Id_prependChild: arity=1; s="prependChild"; break; case Id_processingInstructions: arity=1; s="processingInstructions"; break; case Id_propertyIsEnumerable: arity=1; s="propertyIsEnumerable"; break; case Id_removeNamespace: arity=1; s="removeNamespace"; break; case Id_replace: arity=2; s="replace"; break; case Id_setChildren: arity=1; s="setChildren"; break; case Id_setLocalName: arity=1; s="setLocalName"; break; case Id_setName: arity=1; s="setName"; break; case Id_setNamespace: arity=1; s="setNamespace"; break; case Id_text: arity=0; s="text"; break; case Id_toString: arity=0; s="toString"; break; case Id_toSource: arity=1; s="toSource"; break; case Id_toXMLString: arity=1; s="toXMLString"; break; case Id_valueOf: arity=0; s="valueOf"; break; case Id_getXmlObject: arity=0; s="getXmlObject"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(XMLOBJECT_TAG, id, s, arity); } /** * * @param f * @param cx * @param scope * @param thisObj * @param args * @return */ public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(XMLOBJECT_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); if (id == Id_constructor) { return jsConstructor(cx, thisObj == null, args); } // All (XML|XMLList).prototype methods require thisObj to be XML if (!(thisObj instanceof XMLObjectImpl)) throw incompatibleCallError(f); XMLObjectImpl realThis = (XMLObjectImpl)thisObj; switch (id) { case Id_addNamespace: { Namespace ns = lib.castToNamespace(cx, arg(args, 0)); return realThis.addNamespace(ns); } case Id_appendChild: return realThis.appendChild(arg(args, 0)); case Id_attribute: { XMLName xmlName = lib.toAttributeName(cx, arg(args, 0)); return realThis.attribute(xmlName); } case Id_attributes: return realThis.attributes(); case Id_child: { XMLName xmlName = lib.toXMLNameOrIndex(cx, arg(args, 0)); if (xmlName == null) { long index = ScriptRuntime.lastUint32Result(cx); return realThis.child(index); } else { return realThis.child(xmlName); } } case Id_childIndex: return ScriptRuntime.wrapInt(realThis.childIndex()); case Id_children: return realThis.children(); case Id_comments: return realThis.comments(); case Id_contains: return ScriptRuntime.wrapBoolean( realThis.contains(arg(args, 0))); case Id_copy: return realThis.copy(); case Id_descendants: { XMLName xmlName = (args.length == 0) ? XMLName.formStar() : lib.toXMLName(cx, args[0]); return realThis.descendants(xmlName); } case Id_inScopeNamespaces: { Object[] array = realThis.inScopeNamespaces(); return cx.newArray(scope, array); } case Id_insertChildAfter: return realThis.insertChildAfter(arg(args, 0), arg(args, 1)); case Id_insertChildBefore: return realThis.insertChildBefore(arg(args, 0), arg(args, 1)); case Id_hasOwnProperty: { XMLName xmlName = lib.toXMLName(cx, arg(args, 0)); return ScriptRuntime.wrapBoolean( realThis.hasOwnProperty(xmlName)); } case Id_hasComplexContent: return ScriptRuntime.wrapBoolean(realThis.hasComplexContent()); case Id_hasSimpleContent: return ScriptRuntime.wrapBoolean(realThis.hasSimpleContent()); case Id_length: return ScriptRuntime.wrapInt(realThis.length()); case Id_localName: return realThis.localName(); case Id_name: return realThis.name(); case Id_namespace: { String prefix = (args.length > 0) ? ScriptRuntime.toString(args[0]) : null; return realThis.namespace(prefix); } case Id_namespaceDeclarations: { Object[] array = realThis.namespaceDeclarations(); return cx.newArray(scope, array); } case Id_nodeKind: return realThis.nodeKind(); case Id_normalize: realThis.normalize(); return Undefined.instance; case Id_parent: return realThis.parent(); case Id_prependChild: return realThis.prependChild(arg(args, 0)); case Id_processingInstructions: { XMLName xmlName = (args.length > 0) ? lib.toXMLName(cx, args[0]) : XMLName.formStar(); return realThis.processingInstructions(xmlName); } case Id_propertyIsEnumerable: { return ScriptRuntime.wrapBoolean( realThis.propertyIsEnumerable(arg(args, 0))); } case Id_removeNamespace: { Namespace ns = lib.castToNamespace(cx, arg(args, 0)); return realThis.removeNamespace(ns); } case Id_replace: { XMLName xmlName = lib.toXMLNameOrIndex(cx, arg(args, 0)); Object arg1 = arg(args, 1); if (xmlName == null) { long index = ScriptRuntime.lastUint32Result(cx); return realThis.replace(index, arg1); } else { return realThis.replace(xmlName, arg1); } } case Id_setChildren: return realThis.setChildren(arg(args, 0)); case Id_setLocalName: { String localName; Object arg = arg(args, 0); if (arg instanceof QName) { localName = ((QName)arg).localName(); } else { localName = ScriptRuntime.toString(arg); } realThis.setLocalName(localName); return Undefined.instance; } case Id_setName: { Object arg = (args.length != 0) ? args[0] : Undefined.instance; QName qname; if (arg instanceof QName) { qname = (QName)arg; if (qname.uri() == null) { qname = lib.constructQNameFromString(cx, qname.localName()); } else { // E4X 13.4.4.35 requires to always construct QName qname = lib.constructQName(cx, qname); } } else { qname = lib.constructQName(cx, arg); } realThis.setName(qname); return Undefined.instance; } case Id_setNamespace: { Namespace ns = lib.castToNamespace(cx, arg(args, 0)); realThis.setNamespace(ns); return Undefined.instance; } case Id_text: return realThis.text(); case Id_toString: return realThis.toString(); case Id_toSource: { int indent = ScriptRuntime.toInt32(args, 0); return realThis.toSource(indent); } case Id_toXMLString: { int indent = ScriptRuntime.toInt32(args, 0); return realThis.toXMLString(indent); } case Id_valueOf: return realThis.valueOf(); case Id_getXmlObject: { org.apache.xmlbeans.XmlObject xmlObject = realThis.getXmlObject(); return Context.javaToJS(xmlObject, scope); } } throw new IllegalArgumentException(String.valueOf(id)); } private static Object arg(Object[] args, int i) { return (i < args.length) ? args[i] : Undefined.instance; } }rhino-1.7R4/deprecatedsrc/org/mozilla/javascript/xml/impl/xmlbeans/XMLWithScope.java000066400000000000000000000056631176760007500306500ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.xml.impl.xmlbeans; import org.mozilla.javascript.*; import org.mozilla.javascript.xml.*; final class XMLWithScope extends NativeWith { private static final long serialVersionUID = -696429282095170887L; private XMLLibImpl lib; private int _currIndex; private XMLList _xmlList; private XMLObject _dqPrototype; XMLWithScope(XMLLibImpl lib, Scriptable parent, XMLObject prototype) { super(parent, prototype); this.lib = lib; } void initAsDotQuery() { XMLObject prototype = (XMLObject)getPrototype(); // XMLWithScope also handles the .(xxx) DotQuery for XML // basically DotQuery is a for/in/with statement and in // the following 3 statements we setup to signal it's // DotQuery, // the index and the object being looped over. The // xws.setPrototype is the scope of the object which is // is a element of the lhs (XMLList). _currIndex = 0; _dqPrototype = prototype; if (prototype instanceof XMLList) { XMLList xl = (XMLList)prototype; if (xl.length() > 0) { setPrototype((Scriptable)(xl.get(0, null))); } } // Always return the outer-most type of XML lValue of // XML to left of dotQuery. _xmlList = new XMLList(lib); } protected Object updateDotQuery(boolean value) { // Return null to continue looping XMLObject seed = _dqPrototype; XMLList xmlL = _xmlList; if (seed instanceof XMLList) { // We're a list so keep testing each element of the list if the // result on the top of stack is true then that element is added // to our result list. If false, we try the next element. XMLList orgXmlL = (XMLList)seed; int idx = _currIndex; if (value) { xmlL.addToList(orgXmlL.get(idx, null)); } // More elements to test? if (++idx < orgXmlL.length()) { // Yes, set our new index, get the next element and // reset the expression to run with this object as // the WITH selector. _currIndex = idx; setPrototype((Scriptable)(orgXmlL.get(idx, null))); // continue looping return null; } } else { // If we're not a XMLList then there's no looping // just return DQPrototype if the result is true. if (value) { xmlL.addToList(seed); } } return xmlL; } } rhino-1.7R4/examples/000077500000000000000000000000001176760007500145355ustar00rootroot00000000000000rhino-1.7R4/examples/Control.java000066400000000000000000000046431176760007500170270ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; /** * Example of controlling the JavaScript execution engine. * * We evaluate a script and then manipulate the result. * */ public class Control { /** * Main entry point. * * Process arguments as would a normal Java program. Also * create a new Context and associate it with the current thread. * Then set up the execution environment and begin to * execute scripts. */ public static void main(String[] args) { Context cx = Context.enter(); try { // Set version to JavaScript1.2 so that we get object-literal style // printing instead of "[object Object]" cx.setLanguageVersion(Context.VERSION_1_2); // Initialize the standard objects (Object, Function, etc.) // This must be done before scripts can be executed. Scriptable scope = cx.initStandardObjects(); // Now we can evaluate a script. Let's create a new object // using the object literal notation. Object result = cx.evaluateString(scope, "obj = {a:1, b:['x','y']}", "MySource", 1, null); Scriptable obj = (Scriptable) scope.get("obj", scope); // Should print "obj == result" (Since the result of an assignment // expression is the value that was assigned) System.out.println("obj " + (obj == result ? "==" : "!=") + " result"); // Should print "obj.a == 1" System.out.println("obj.a == " + obj.get("a", obj)); Scriptable b = (Scriptable) obj.get("b", obj); // Should print "obj.b[0] == x" System.out.println("obj.b[0] == " + b.get(0, b)); // Should print "obj.b[1] == y" System.out.println("obj.b[1] == " + b.get(1, b)); // Should print {a:1, b:["x", "y"]} Function fn = (Function) ScriptableObject.getProperty(obj, "toString"); System.out.println(fn.call(cx, scope, obj, new Object[0])); } finally { Context.exit(); } } } rhino-1.7R4/examples/Counter.java000066400000000000000000000023741176760007500170250ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; import org.mozilla.javascript.annotations.JSFunction; import org.mozilla.javascript.annotations.JSConstructor; import org.mozilla.javascript.annotations.JSGetter; public class Counter extends ScriptableObject { private static final long serialVersionUID = 438270592527335642L; // The zero-argument constructor used by Rhino runtime to create instances public Counter() { } // @JSConstructor annotation defines the JavaScript constructor @JSConstructor public Counter(int a) { count = a; } // The class name is defined by the getClassName method @Override public String getClassName() { return "Counter"; } // The method getCount defines the count property. @JSGetter public int getCount() { return count++; } // Methods can be defined the @JSFunction annotation. // Here we define resetCount for JavaScript. @JSFunction public void resetCount() { count = 0; } private int count; } rhino-1.7R4/examples/CounterTest.java000066400000000000000000000027731176760007500176700ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; /** * An example illustrating how to create a JavaScript object and retrieve * properties and call methods. *

* Output should be: *

 * count = 0
 * count = 1
 * resetCount
 * count = 0
 * 
*/ public class CounterTest { public static void main(String[] args) throws Exception { Context cx = Context.enter(); try { Scriptable scope = cx.initStandardObjects(); ScriptableObject.defineClass(scope, Counter.class); Scriptable testCounter = cx.newObject(scope, "Counter"); Object count = ScriptableObject.getProperty(testCounter, "count"); System.out.println("count = " + count); count = ScriptableObject.getProperty(testCounter, "count"); System.out.println("count = " + count); ScriptableObject.callMethod(testCounter, "resetCount", new Object[0]); System.out.println("resetCount"); count = ScriptableObject.getProperty(testCounter, "count"); System.out.println("count = " + count); } finally { Context.exit(); } } } rhino-1.7R4/examples/DynamicScopes.java000066400000000000000000000140331176760007500201420ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; /** * Example of controlling the JavaScript with multiple scopes and threads. */ public class DynamicScopes { static boolean useDynamicScope; static class MyFactory extends ContextFactory { @Override protected boolean hasFeature(Context cx, int featureIndex) { if (featureIndex == Context.FEATURE_DYNAMIC_SCOPE) { return useDynamicScope; } return super.hasFeature(cx, featureIndex); } } static { ContextFactory.initGlobal(new MyFactory()); } /** * Main entry point. * * Set up the shared scope and then spawn new threads that execute * relative to that shared scope. Try to run functions with and * without dynamic scope to see the effect. * * The expected output is *
     * sharedScope
     * nested:sharedScope
     * sharedScope
     * nested:sharedScope
     * sharedScope
     * nested:sharedScope
     * thread0
     * nested:thread0
     * thread1
     * nested:thread1
     * thread2
     * nested:thread2
     * 
* The final three lines may be permuted in any order depending on * thread scheduling. */ public static void main(String[] args) { Context cx = Context.enter(); try { // Precompile source only once String source = "" +"var x = 'sharedScope';\n" +"function f() { return x; }\n" // Dynamic scope works with nested function too +"function initClosure(prefix) {\n" +" return function test() { return prefix+x; }\n" +"}\n" +"var closure = initClosure('nested:');\n" +""; Script script = cx.compileString(source, "sharedScript", 1, null); useDynamicScope = false; runScripts(cx, script); useDynamicScope = true; runScripts(cx, script); } finally { Context.exit(); } } static void runScripts(Context cx, Script script) { // Initialize the standard objects (Object, Function, etc.) // This must be done before scripts can be executed. The call // returns a new scope that we will share. ScriptableObject sharedScope = cx.initStandardObjects(null, true); // Now we can execute the precompiled script against the scope // to define x variable and f function in the shared scope. script.exec(cx, sharedScope); // Now we spawn some threads that execute a script that calls the // function 'f'. The scope chain looks like this: //
        //            ------------------                ------------------
        //           | per-thread scope | -prototype-> |   shared scope   |
        //            ------------------                ------------------
        //                    ^
        //                    |
        //               parentScope
        //                    |
        //            ------------------
        //           | f's activation   |
        //            ------------------
        // 
// Both the shared scope and the per-thread scope have variables 'x' // defined in them. If 'f' is compiled with dynamic scope enabled, // the 'x' from the per-thread scope will be used. Otherwise, the 'x' // from the shared scope will be used. The 'x' defined in 'g' (which // calls 'f') should not be seen by 'f'. final int threadCount = 3; Thread[] t = new Thread[threadCount]; for (int i=0; i < threadCount; i++) { String source2 = "" +"function g() { var x = 'local'; return f(); }\n" +"java.lang.System.out.println(g());\n" +"function g2() { var x = 'local'; return closure(); }\n" +"java.lang.System.out.println(g2());\n" +""; t[i] = new Thread(new PerThread(sharedScope, source2, "thread" + i)); } for (int i=0; i < threadCount; i++) t[i].start(); // Don't return in this thread until all the spawned threads have // completed. for (int i=0; i < threadCount; i++) { try { t[i].join(); } catch (InterruptedException e) { } } } static class PerThread implements Runnable { PerThread(Scriptable sharedScope, String source, String x) { this.sharedScope = sharedScope; this.source = source; this.x = x; } public void run() { // We need a new Context for this thread. Context cx = Context.enter(); try { // We can share the scope. Scriptable threadScope = cx.newObject(sharedScope); threadScope.setPrototype(sharedScope); // We want "threadScope" to be a new top-level // scope, so set its parent scope to null. This // means that any variables created by assignments // will be properties of "threadScope". threadScope.setParentScope(null); // Create a JavaScript property of the thread scope named // 'x' and save a value for it. threadScope.put("x", threadScope, x); cx.evaluateString(threadScope, source, "threadScript", 1, null); } finally { Context.exit(); } } private Scriptable sharedScope; private String source; private String x; } } rhino-1.7R4/examples/E4X/000077500000000000000000000000001176760007500151355ustar00rootroot00000000000000rhino-1.7R4/examples/E4X/e4x_example.js000066400000000000000000000134401176760007500177100ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ print("----------------------------------------"); // Use the XML constructor to parse an string into an XML object var John = "John25"; var Sue ="Sue32"; var tagName = "employees"; var employees = new XML("<" + tagName +">" + John + Sue + ""); print("The employees XML object constructed from a string is:\n" + employees); print("----------------------------------------"); // Use an XML literal to create an XML object var order = John Doe Big Screen Television 1299.99 1 // Construct the full customer name var name = order.customer.firstname + " " + order.customer.lastname; // Calculate the total price var total = order.item.price * order.item.quantity; print("The order XML object constructed using a literal is:\n" + order); print("The total price of " + name + "'s order is " + total); print("----------------------------------------"); // construct a new XML object using expando and super-expando properties var order = ; order.customer.name = "Fred Jones"; order.customer.address.street = "123 Long Lang"; order.customer.address.city = "Underwood"; order.customer.address.state = "CA"; order.item[0] = ""; order.item[0].description = "Small Rodents"; order.item[0].quantity = 10; order.item[0].price = 6.95; print("The order custructed using expandos and super-expandos is:\n" + order); // append a new item to the order order.item += Catapult139.95; print("----------------------------------------"); print("The order after appending a new item is:\n" + order); print("----------------------------------------"); // dynamically construct an XML element using embedded expressions var tagname = "name"; var attributename = "id"; var attributevalue = 5; var content = "Fred"; var x = <{tagname} {attributename}={attributevalue}>{content}; print("The dynamically computed element value is:\n" + x.toXMLString()); print("----------------------------------------"); // Create a SOAP message var message = DIS // declare the SOAP and stocks namespaces var soap = new Namespace("http://schemas.xmlsoap.org/soap/envelope/"); var stock = new Namespace ("http://mycompany.com/stocks"); // extract the soap encoding style and body from the soap message var encodingStyle = message.@soap::encodingStyle; print("The encoding style of the soap message is specified by:\n" + encodingStyle); // change the stock symbol message.soap::Body.stock::GetLastTradePrice.symbol = "MYCO"; var body = message.soap::Body; print("The body of the soap message is:\n" + body); print("----------------------------------------"); // create an manipulate an XML object using the default xml namespace default xml namespace = "http://default.namespace.com"; var x = ; x.a = "one"; x.b = "two"; x.c = three; print("XML object constructed using the default xml namespace:\n" + x); default xml namespace=""; print("----------------------------------------"); var order = John Doe Big Screen Television 1299.99 1 DVD Player 399.99 1 ; // get the customer element from the orderprint("The customer is:\n" + order.customer); // get the id attribute from the order print("The order id is:" + order.@id); // get all the child elements from the order element print("The children of the order are:\n" + order.*); // get the list of all item descriptions print("The order descriptions are:\n" + order.item.description); // get second item by numeric index print("The second item is:\n" + order.item[1]); // get the list of all child elements in all item elements print("The children of the items are:\n" + order.item.*); // get the second child element from the order by index print("The second child of the order is:\n" + order.*[1]); // calculate the total price of the order var totalprice = 0; for each (i in order.item) { totalprice += i.price * i.quantity; } print("The total price of the order is: " + totalprice); print("----------------------------------------"); var e = Joe20 Sue30 ; // get all the names in e print("All the employee names are:\n" + e..name); // employees with name Joe print("The employee named Joe is:\n" + e.employee.(name == "Joe")); // employees with id's 1 & 2 print("Employees with ids 1 & 2:\n" + e.employee.(@id == 1 || @id == 2)); // name of employee with id 1 print("Name of the the employee with ID=1: " + e.employee.(@id == 1).name); print("----------------------------------------"); rhino-1.7R4/examples/File.java000066400000000000000000000240571176760007500162670ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; import org.mozilla.javascript.annotations.JSConstructor; import org.mozilla.javascript.annotations.JSFunction; import org.mozilla.javascript.annotations.JSGetter; import java.io.*; import java.util.List; import java.util.ArrayList; /** * Define a simple JavaScript File object. * * This isn't intended to be any sort of definitive attempt at a * standard File object for JavaScript, but instead is an example * of a more involved definition of a host object. * * Example of use of the File object: *
 * js> defineClass("File")
 * js> file = new File("myfile.txt");
 * [object File]
 * js> file.writeLine("one");                       only now is file actually opened
 * js> file.writeLine("two");
 * js> file.writeLine("thr", "ee");
 * js> file.close();                                must close file before we can reopen for reading
 * js> var a = file.readLines();                    creates and fills an array with the contents of the file
 * js> a;
 * one,two,three
 * js>
 * 
* * * File errors or end-of-file signaled by thrown Java exceptions will * be wrapped as JavaScript exceptions when called from JavaScript, * and may be caught within JavaScript. * * @author Norris Boyd */ public class File extends ScriptableObject { /** * */ private static final long serialVersionUID = 2549960399774237828L; /** * The zero-parameter constructor. * * When Context.defineClass is called with this class, it will * construct File.prototype using this constructor. */ public File() { } /** * The Java method defining the JavaScript File constructor. * * If the constructor has one or more arguments, and the * first argument is not undefined, the argument is converted * to a string as used as the filename.

* * Otherwise System.in or System.out is assumed as appropriate * to the use. */ @JSConstructor public static Scriptable jsConstructor(Context cx, Object[] args, Function ctorObj, boolean inNewExpr) { File result = new File(); if (args.length == 0 || args[0] == Context.getUndefinedValue()) { result.name = ""; result.file = null; } else { result.name = Context.toString(args[0]); result.file = new java.io.File(result.name); } return result; } /** * Returns the name of this JavaScript class, "File". */ @Override public String getClassName() { return "File"; } /** * Get the name of the file. * * Used to define the "name" property. */ @JSGetter public String getName() { return name; } /** * Read the remaining lines in the file and return them in an array. * * Implements a JavaScript function.

* * This is a good example of creating a new array and setting * elements in that array. * * @exception IOException if an error occurred while accessing the file * associated with this object */ @JSFunction public Object readLines() throws IOException { List list = new ArrayList(); String s; while ((s = readLine()) != null) { list.add(s); } String[] lines = list.toArray(new String[list.size()]); Scriptable scope = ScriptableObject.getTopLevelScope(this); Context cx = Context.getCurrentContext(); return cx.newObject(scope, "Array", lines); } /** * Read a line. * * Implements a JavaScript function. * @exception IOException if an error occurred while accessing the file * associated with this object, or EOFException if the object * reached the end of the file */ @JSFunction public String readLine() throws IOException { return getReader().readLine(); } /** * Read a character. * * @exception IOException if an error occurred while accessing the file * associated with this object, or EOFException if the object * reached the end of the file */ @JSFunction public String readChar() throws IOException { int i = getReader().read(); if (i == -1) return null; char[] charArray = { (char) i }; return new String(charArray); } /** * Write strings. * * Implements a JavaScript function.

* * This function takes a variable number of arguments, converts * each argument to a string, and writes that string to the file. * @exception IOException if an error occurred while accessing the file * associated with this object */ @JSFunction public static void write(Context cx, Scriptable thisObj, Object[] args, Function funObj) throws IOException { write0(thisObj, args, false); } /** * Write strings and a newline. * * Implements a JavaScript function. * @exception IOException if an error occurred while accessing the file * associated with this object * */ @JSFunction public static void writeLine(Context cx, Scriptable thisObj, Object[] args, Function funObj) throws IOException { write0(thisObj, args, true); } @JSGetter public int getLineNumber() throws FileNotFoundException { return getReader().getLineNumber(); } /** * Close the file. It may be reopened. * * Implements a JavaScript function. * @exception IOException if an error occurred while accessing the file * associated with this object */ @JSFunction public void close() throws IOException { if (reader != null) { reader.close(); reader = null; } else if (writer != null) { writer.close(); writer = null; } } /** * Finalizer. * * Close the file when this object is collected. */ @Override protected void finalize() { try { close(); } catch (IOException e) { } } /** * Get the Java reader. */ @JSFunction("getReader") public Object getJSReader() { if (reader == null) return null; // Here we use toObject() to "wrap" the BufferedReader object // in a Scriptable object so that it can be manipulated by // JavaScript. Scriptable parent = ScriptableObject.getTopLevelScope(this); return Context.javaToJS(reader, parent); } /** * Get the Java writer. * * @see File#getReader * */ @JSFunction public Object getWriter() { if (writer == null) return null; Scriptable parent = ScriptableObject.getTopLevelScope(this); return Context.javaToJS(writer, parent); } /** * Get the reader, checking that we're not already writing this file. */ private LineNumberReader getReader() throws FileNotFoundException { if (writer != null) { throw Context.reportRuntimeError("already writing file \"" + name + "\""); } if (reader == null) reader = new LineNumberReader(file == null ? new InputStreamReader(System.in) : new FileReader(file)); return reader; } /** * Perform the guts of write and writeLine. * * Since the two functions differ only in whether they write a * newline character, move the code into a common subroutine. * */ private static void write0(Scriptable thisObj, Object[] args, boolean eol) throws IOException { File thisFile = checkInstance(thisObj); if (thisFile.reader != null) { throw Context.reportRuntimeError("already writing file \"" + thisFile.name + "\""); } if (thisFile.writer == null) thisFile.writer = new BufferedWriter( thisFile.file == null ? new OutputStreamWriter(System.out) : new FileWriter(thisFile.file)); for (int i=0; i < args.length; i++) { String s = Context.toString(args[i]); thisFile.writer.write(s, 0, s.length()); } if (eol) thisFile.writer.newLine(); } /** * Perform the instanceof check and return the downcasted File object. * * This is necessary since methods may reside in the File.prototype * object and scripts can dynamically alter prototype chains. For example: *

     * js> defineClass("File");
     * js> o = {};
     * [object Object]
     * js> o.__proto__ = File.prototype;
     * [object File]
     * js> o.write("hi");
     * js: called on incompatible object
     * 
* The runtime will take care of such checks when non-static Java methods * are defined as JavaScript functions. */ private static File checkInstance(Scriptable obj) { if (obj == null || !(obj instanceof File)) { throw Context.reportRuntimeError("called on incompatible object"); } return (File) obj; } /** * Some private data for this class. */ private String name; private java.io.File file; // may be null, meaning to use System.out or .in private LineNumberReader reader; private BufferedWriter writer; } rhino-1.7R4/examples/Foo.java000066400000000000000000000114721176760007500161300ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; import org.mozilla.javascript.annotations.JSFunction; import org.mozilla.javascript.annotations.JSGetter; /** * An example host object class. * * Here's a shell session showing the Foo object in action: *
 * js> defineClass("Foo")
 * js> foo = new Foo();         A constructor call, see Foo below.
 * [object Foo]                 The "Foo" here comes from getClassName.
 * js> foo.counter;             The counter property is defined by the defineProperty
 * 0                            call below and implemented by the getCounter
 * js> foo.counter;             method below.
 * 1
 * js> foo.counter;
 * 2
 * js> foo.resetCounter();      Results in a call to resetCounter.
 * js> foo.counter;             Now the counter has been reset.
 * 0
 * js> foo.counter;
 * 1
 * js> bar = new Foo(37);       Create a new instance.
 * [object Foo]
 * js> bar.counter;             This instance's counter is distinct from
 * 37                           the other instance's counter.
 * js> foo.varargs(3, "hi");    Calls varargs.
 * this = [object Foo]; args = [3, hi]
 * js> foo[7] = 34;             Since we extended ScriptableObject, we get
 * 34                           all the behavior of a JavaScript object
 * js> foo.a = 23;              for free.
 * 23
 * js> foo.a + foo[7];
 * 57
 * js>
 * 
* * @see org.mozilla.javascript.Context * @see org.mozilla.javascript.Scriptable * @see org.mozilla.javascript.ScriptableObject * * @author Norris Boyd */ public class Foo extends ScriptableObject { private static final long serialVersionUID = -3833489808933339159L; /** * The zero-parameter constructor. * * When Context.defineClass is called with this class, it will * construct Foo.prototype using this constructor. */ public Foo() { } /** * The Java method defining the JavaScript Foo constructor. * * Takes an initial value for the counter property. * Note that in the example Shell session above, we didn't * supply a argument to the Foo constructor. This means that * the Undefined value is used as the value of the argument, * and when the argument is converted to an integer, Undefined * becomes 0. */ public Foo(int counterStart) { counter = counterStart; } /** * Returns the name of this JavaScript class, "Foo". */ @Override public String getClassName() { return "Foo"; } /** * The Java method defining the JavaScript resetCounter function. * * Resets the counter to 0. */ @JSFunction public void resetCounter() { counter = 0; } /** * The Java method implementing the getter for the counter property. *

* If "setCounter" had been defined in this class, the runtime would * call the setter when the property is assigned to. */ @JSGetter public int getCounter() { return counter++; } /** * An example of a variable-arguments method. * * All variable arguments methods must have the same number and * types of parameters, and must be static.

* @param cx the Context of the current thread * @param thisObj the JavaScript 'this' value. * @param args the array of arguments for this call * @param funObj the function object of the invoked JavaScript function * This value is useful to compute a scope using * Context.getTopLevelScope(). * @return computes the string values and types of 'this' and * of each of the supplied arguments and returns them in a string. * * @see org.mozilla.javascript.ScriptableObject#getTopLevelScope */ @JSFunction public static Object varargs(Context cx, Scriptable thisObj, Object[] args, Function funObj) { StringBuffer buf = new StringBuffer(); buf.append("this = "); buf.append(Context.toString(thisObj)); buf.append("; args = ["); for (int i=0; i < args.length; i++) { buf.append(Context.toString(args[i])); if (i+1 != args.length) buf.append(", "); } buf.append("]"); return buf.toString(); } /** * A piece of private data for this class. */ private int counter; } rhino-1.7R4/examples/Matrix.java000066400000000000000000000152231176760007500166470ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; import java.util.List; import java.util.ArrayList; /** * Matrix: An example host object class that implements the Scriptable interface. * * Built-in JavaScript arrays don't handle multiple dimensions gracefully: the * script writer must create every array in an array of arrays. The Matrix class * takes care of that by automatically allocating arrays for every index that * is accessed. What's more, the Matrix constructor takes a integer argument * that specifies the dimension of the Matrix. If m is a Matrix with dimension 3, * then m[0] will be a Matrix with dimension 1, and m[0][0] will be an Array. * * Here's a shell session showing the Matrix object in action: *

 * js> defineClass("Matrix")
 * js> var m = new Matrix(2); // A constructor call, see "Matrix(int dimension)"
 * js> m                      // Object.toString will call "Matrix.getClassName()"
 * [object Matrix]
 * js> m[0][0] = 3;
 * 3
 * js> uneval(m[0]);          // an array was created automatically!
 * [3]
 * js> uneval(m[1]);          // array is created even if we don't set a value
 * []
 * js> m.dim;                 // we can access the "dim" property
 * 2
 * js> m.dim = 3;
 * 3
 * js> m.dim;                 // but not modify the "dim" property
 * 2
 * 
* * @see org.mozilla.javascript.Context * @see org.mozilla.javascript.Scriptable * * @author Norris Boyd */ public class Matrix implements Scriptable { /** * The zero-parameter constructor. * * When ScriptableObject.defineClass is called with this class, it will * construct Matrix.prototype using this constructor. */ public Matrix() { } /** * The Java constructor, also used to define the JavaScript constructor. */ public Matrix(int dimension) { if (dimension <= 0) { throw Context.reportRuntimeError( "Dimension of Matrix must be greater than zero"); } dim = dimension; list = new ArrayList(); } /** * Returns the name of this JavaScript class, "Matrix". */ public String getClassName() { return "Matrix"; } /** * Defines the "dim" property by returning true if name is * equal to "dim". *

* Defines no other properties, i.e., returns false for * all other names. * * @param name the name of the property * @param start the object where lookup began */ public boolean has(String name, Scriptable start) { return name.equals("dim"); } /** * Defines all numeric properties by returning true. * * @param index the index of the property * @param start the object where lookup began */ public boolean has(int index, Scriptable start) { return true; } /** * Get the named property. *

* Handles the "dim" property and returns NOT_FOUND for all * other names. * @param name the property name * @param start the object where the lookup began */ public Object get(String name, Scriptable start) { if (name.equals("dim")) return new Integer(dim); return NOT_FOUND; } /** * Get the indexed property. *

* Look up the element in the associated list and return * it if it exists. If it doesn't exist, create it.

* @param index the index of the integral property * @param start the object where the lookup began */ public Object get(int index, Scriptable start) { while (index >= list.size()) { list.add(null); } Object result = list.get(index); if (result != null) return result; if (dim > 2) { Matrix m = new Matrix(dim-1); m.setParentScope(getParentScope()); m.setPrototype(getPrototype()); result = m; } else { Context cx = Context.getCurrentContext(); Scriptable scope = ScriptableObject.getTopLevelScope(start); result = cx.newArray(scope, 0); } list.set(index, result); return result; } /** * Set a named property. * * We do nothing here, so all properties are effectively read-only. */ public void put(String name, Scriptable start, Object value) { } /** * Set an indexed property. * * We do nothing here, so all properties are effectively read-only. */ public void put(int index, Scriptable start, Object value) { } /** * Remove a named property. * * This method shouldn't even be called since we define all properties * as PERMANENT. */ public void delete(String id) { } /** * Remove an indexed property. * * This method shouldn't even be called since we define all properties * as PERMANENT. */ public void delete(int index) { } /** * Get prototype. */ public Scriptable getPrototype() { return prototype; } /** * Set prototype. */ public void setPrototype(Scriptable prototype) { this.prototype = prototype; } /** * Get parent. */ public Scriptable getParentScope() { return parent; } /** * Set parent. */ public void setParentScope(Scriptable parent) { this.parent = parent; } /** * Get properties. * * We return an empty array since we define all properties to be DONTENUM. */ public Object[] getIds() { return new Object[0]; } /** * Default value. * * Use the convenience method from Context that takes care of calling * toString, etc. */ public Object getDefaultValue(Class typeHint) { return "[object Matrix]"; } /** * instanceof operator. * * We mimick the normal JavaScript instanceof semantics, returning * true if this appears in value's prototype * chain. */ public boolean hasInstance(Scriptable value) { Scriptable proto = value.getPrototype(); while (proto != null) { if (proto.equals(this)) return true; proto = proto.getPrototype(); } return false; } /** * Some private data for this class. */ private int dim; private List list; private Scriptable prototype, parent; } rhino-1.7R4/examples/NervousText.html000066400000000000000000000016201176760007500177300ustar00rootroot00000000000000 This is the NervousText applet in javascript:
The test assumes that applet code is generated with:
java -classpath js.jar org.mozilla.javascript.tools.jsc.Main \
  -extends java.applet.Applet \
  -implements java.lang.Runnable \
  NervousText.js
and the resulting 2 classes, NervousText.class extending java.applet.Applet and implementing java.lang.Runnable and NervousText1.class which represents compiled JavaScript code, are placed in the same directory as NervousText.html.

The test also assumes that js.jar from Rhino distribution is available in the same directory. rhino-1.7R4/examples/NervousText.js000066400000000000000000000035551176760007500174110ustar00rootroot00000000000000/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // The Java "NervousText" example ported to JavaScript. // Compile using java org.mozilla.javascript.tools.jsc.Main -extends java.applet.Applet -implements java.lang.Runnable NervousText.js /* Adapted from Java code by Daniel Wyszynski Center for Applied Large-Scale Computing (CALC) 04-12-95 Test of text animation. kwalrath: Changed string; added thread suspension. 5-9-95 */ var Font = java.awt.Font; var Thread = java.lang.Thread; var separated; var s = null; var killme = null; var i; var x_coord = 0, y_coord = 0; var num; var speed=35; var counter =0; var threadSuspended = false; //added by kwalrath function init() { this.resize(150,50); this.setFont(new Font("TimesRoman",Font.BOLD,36)); s = this.getParameter("text"); if (s == null) { s = "Rhino"; } separated = s.split(''); } function start() { if(killme == null) { killme = new java.lang.Thread(java.lang.Runnable(this)); killme.start(); } } function stop() { killme = null; } function run() { while (killme != null) { try {Thread.sleep(100);} catch (e){} this.repaint(); } killme = null; } function paint(g) { for(i=0;i * Note that calling "new java.lang.String('foo')" in JavaScript with this * wrap factory enabled will still produce a wrapped Java object since the * WrapFactory.wrapNewObject method is not overridden. *

* The PrimitiveWrapFactory is enabled on a Context by calling setWrapFactory * on that context. */ public class PrimitiveWrapFactory extends WrapFactory { @Override public Object wrap(Context cx, Scriptable scope, Object obj, Class staticType) { if (obj instanceof String || obj instanceof Number || obj instanceof Boolean) { return obj; } else if (obj instanceof Character) { char[] a = { ((Character)obj).charValue() }; return new String(a); } return super.wrap(cx, scope, obj, staticType); } } rhino-1.7R4/examples/RunScript.java000066400000000000000000000030431176760007500173310ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; /** * RunScript: simplest example of controlling execution of Rhino. * * Collects its arguments from the command line, executes the * script, and prints the result. * * @author Norris Boyd */ public class RunScript { public static void main(String args[]) { // Creates and enters a Context. The Context stores information // about the execution environment of a script. Context cx = Context.enter(); try { // Initialize the standard objects (Object, Function, etc.) // This must be done before scripts can be executed. Returns // a scope object that we use in later calls. Scriptable scope = cx.initStandardObjects(); // Collect the arguments into a single string. String s = ""; for (int i=0; i < args.length; i++) { s += args[i]; } // Now evaluate the string we've colected. Object result = cx.evaluateString(scope, s, "", 1, null); // Convert the result to a string and print it. System.err.println(Context.toString(result)); } finally { // Exit from the context. Context.exit(); } } } rhino-1.7R4/examples/RunScript2.java000066400000000000000000000022221176760007500174110ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; /** * RunScript2: Like RunScript, but reflects the System.out into JavaScript. * * @author Norris Boyd */ public class RunScript2 { public static void main(String args[]) { Context cx = Context.enter(); try { Scriptable scope = cx.initStandardObjects(); // Add a global variable "out" that is a JavaScript reflection // of System.out Object jsOut = Context.javaToJS(System.out, scope); ScriptableObject.putProperty(scope, "out", jsOut); String s = ""; for (int i=0; i < args.length; i++) { s += args[i]; } Object result = cx.evaluateString(scope, s, "", 1, null); System.err.println(Context.toString(result)); } finally { Context.exit(); } } } rhino-1.7R4/examples/RunScript3.java000066400000000000000000000036101176760007500174140ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; /** * RunScript3: Example of using JavaScript objects * * Collects its arguments from the command line, executes the * script, and then ... * * @author Norris Boyd */ public class RunScript3 { public static void main(String args[]) { Context cx = Context.enter(); try { Scriptable scope = cx.initStandardObjects(); // Collect the arguments into a single string. String s = ""; for (int i=0; i < args.length; i++) { s += args[i]; } // Now evaluate the string we've collected. We'll ignore the result. cx.evaluateString(scope, s, "", 1, null); // Print the value of variable "x" Object x = scope.get("x", scope); if (x == Scriptable.NOT_FOUND) { System.out.println("x is not defined."); } else { System.out.println("x = " + Context.toString(x)); } // Call function "f('my arg')" and print its result. Object fObj = scope.get("f", scope); if (!(fObj instanceof Function)) { System.out.println("f is undefined or not a function."); } else { Object functionArgs[] = { "my arg" }; Function f = (Function)fObj; Object result = f.call(cx, scope, scope, functionArgs); String report = "f('my args') = " + Context.toString(result); System.out.println(report); } } finally { Context.exit(); } } } rhino-1.7R4/examples/RunScript4.java000066400000000000000000000030301176760007500174110ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; /** * RunScript4: Execute scripts in an environment that includes the * example Counter class. * * @author Norris Boyd */ public class RunScript4 { public static void main(String args[]) throws Exception { Context cx = Context.enter(); try { Scriptable scope = cx.initStandardObjects(); // Use the Counter class to define a Counter constructor // and prototype in JavaScript. ScriptableObject.defineClass(scope, Counter.class); // Create an instance of Counter and assign it to // the top-level variable "myCounter". This is // equivalent to the JavaScript code // myCounter = new Counter(7); Object[] arg = { new Integer(7) }; Scriptable myCounter = cx.newObject(scope, "Counter", arg); scope.put("myCounter", scope, myCounter); String s = ""; for (int i=0; i < args.length; i++) { s += args[i]; } Object result = cx.evaluateString(scope, s, "", 1, null); System.err.println(Context.toString(result)); } finally { Context.exit(); } } } rhino-1.7R4/examples/Shell.java000066400000000000000000000254211176760007500164530ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ import org.mozilla.javascript.*; import java.io.*; /** * The shell program. * * Can execute scripts interactively or in batch mode at the command line. * An example of controlling the JavaScript engine. * * @author Norris Boyd */ public class Shell extends ScriptableObject { private static final long serialVersionUID = -5638074146250193112L; @Override public String getClassName() { return "global"; } /** * Main entry point. * * Process arguments as would a normal Java program. Also * create a new Context and associate it with the current thread. * Then set up the execution environment and begin to * execute scripts. */ public static void main(String args[]) { // Associate a new Context with this thread Context cx = Context.enter(); try { // Initialize the standard objects (Object, Function, etc.) // This must be done before scripts can be executed. Shell shell = new Shell(); cx.initStandardObjects(shell); // Define some global functions particular to the shell. Note // that these functions are not part of ECMA. String[] names = { "print", "quit", "version", "load", "help" }; shell.defineFunctionProperties(names, Shell.class, ScriptableObject.DONTENUM); args = processOptions(cx, args); // Set up "arguments" in the global scope to contain the command // line arguments after the name of the script to execute Object[] array; if (args.length == 0) { array = new Object[0]; } else { int length = args.length - 1; array = new Object[length]; System.arraycopy(args, 1, array, 0, length); } Scriptable argsObj = cx.newArray(shell, array); shell.defineProperty("arguments", argsObj, ScriptableObject.DONTENUM); shell.processSource(cx, args.length == 0 ? null : args[0]); } finally { Context.exit(); } } /** * Parse arguments. */ public static String[] processOptions(Context cx, String args[]) { for (int i=0; i < args.length; i++) { String arg = args[i]; if (!arg.startsWith("-")) { String[] result = new String[args.length - i]; for (int j=i; j < args.length; j++) result[j-i] = args[j]; return result; } if (arg.equals("-version")) { if (++i == args.length) usage(arg); double d = Context.toNumber(args[i]); if (d != d) usage(arg); cx.setLanguageVersion((int) d); continue; } usage(arg); } return new String[0]; } /** * Print a usage message. */ private static void usage(String s) { p("Didn't understand \"" + s + "\"."); p("Valid arguments are:"); p("-version 100|110|120|130|140|150|160|170"); System.exit(1); } /** * Print a help message. * * This method is defined as a JavaScript function. */ public void help() { p(""); p("Command Description"); p("======= ==========="); p("help() Display usage and help messages. "); p("defineClass(className) Define an extension using the Java class"); p(" named with the string argument. "); p(" Uses ScriptableObject.defineClass(). "); p("load(['foo.js', ...]) Load JavaScript source files named by "); p(" string arguments. "); p("loadClass(className) Load a class named by a string argument."); p(" The class must be a script compiled to a"); p(" class file. "); p("print([expr ...]) Evaluate and print expressions. "); p("quit() Quit the shell. "); p("version([number]) Get or set the JavaScript version number."); p(""); } /** * Print the string values of its arguments. * * This method is defined as a JavaScript function. * Note that its arguments are of the "varargs" form, which * allows it to handle an arbitrary number of arguments * supplied to the JavaScript function. * */ public static void print(Context cx, Scriptable thisObj, Object[] args, Function funObj) { for (int i=0; i < args.length; i++) { if (i > 0) System.out.print(" "); // Convert the arbitrary JavaScript value into a string form. String s = Context.toString(args[i]); System.out.print(s); } System.out.println(); } /** * Quit the shell. * * This only affects the interactive mode. * * This method is defined as a JavaScript function. */ public void quit() { quitting = true; } /** * Get and set the language version. * * This method is defined as a JavaScript function. */ public static double version(Context cx, Scriptable thisObj, Object[] args, Function funObj) { double result = cx.getLanguageVersion(); if (args.length > 0) { double d = Context.toNumber(args[0]); cx.setLanguageVersion((int) d); } return result; } /** * Load and execute a set of JavaScript source files. * * This method is defined as a JavaScript function. * */ public static void load(Context cx, Scriptable thisObj, Object[] args, Function funObj) { Shell shell = (Shell)getTopLevelScope(thisObj); for (int i = 0; i < args.length; i++) { shell.processSource(cx, Context.toString(args[i])); } } /** * Evaluate JavaScript source. * * @param cx the current context * @param filename the name of the file to compile, or null * for interactive mode. */ private void processSource(Context cx, String filename) { if (filename == null) { BufferedReader in = new BufferedReader (new InputStreamReader(System.in)); String sourceName = ""; int lineno = 1; boolean hitEOF = false; do { int startline = lineno; System.err.print("js> "); System.err.flush(); try { String source = ""; // Collect lines of source to compile. while(true) { String newline; newline = in.readLine(); if (newline == null) { hitEOF = true; break; } source = source + newline + "\n"; lineno++; // Continue collecting as long as more lines // are needed to complete the current // statement. stringIsCompilableUnit is also // true if the source statement will result in // any error other than one that might be // resolved by appending more source. if (cx.stringIsCompilableUnit(source)) break; } Object result = cx.evaluateString(this, source, sourceName, startline, null); if (result != Context.getUndefinedValue()) { System.err.println(Context.toString(result)); } } catch (WrappedException we) { // Some form of exception was caught by JavaScript and // propagated up. System.err.println(we.getWrappedException().toString()); we.printStackTrace(); } catch (EvaluatorException ee) { // Some form of JavaScript error. System.err.println("js: " + ee.getMessage()); } catch (JavaScriptException jse) { // Some form of JavaScript error. System.err.println("js: " + jse.getMessage()); } catch (IOException ioe) { System.err.println(ioe.toString()); } if (quitting) { // The user executed the quit() function. break; } } while (!hitEOF); System.err.println(); } else { FileReader in = null; try { in = new FileReader(filename); } catch (FileNotFoundException ex) { Context.reportError("Couldn't open file \"" + filename + "\"."); return; } try { // Here we evalute the entire contents of the file as // a script. Text is printed only if the print() function // is called. cx.evaluateReader(this, in, filename, 1, null); } catch (WrappedException we) { System.err.println(we.getWrappedException().toString()); we.printStackTrace(); } catch (EvaluatorException ee) { System.err.println("js: " + ee.getMessage()); } catch (JavaScriptException jse) { System.err.println("js: " + jse.getMessage()); } catch (IOException ioe) { System.err.println(ioe.toString()); } finally { try { in.close(); } catch (IOException ioe) { System.err.println(ioe.toString()); } } } } private static void p(String s) { System.out.println(s); } private boolean quitting; } rhino-1.7R4/examples/SwingApplication.js000066400000000000000000000054111176760007500203470ustar00rootroot00000000000000/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * SwingApplication.js - a translation into JavaScript of * SwingApplication.java, a java.sun.com Swing example. * * @author Roger E Critchlow, Jr. */ var swingNames = JavaImporter(); swingNames.importPackage(Packages.javax.swing); swingNames.importPackage(Packages.java.awt); swingNames.importPackage(Packages.java.awt.event); function createComponents() { with (swingNames) { var labelPrefix = "Number of button clicks: "; var numClicks = 0; var label = new JLabel(labelPrefix + numClicks); var button = new JButton("I'm a Swing button!"); button.mnemonic = KeyEvent.VK_I; // Since Rhino 1.5R5 JS functions can be passed to Java method if // corresponding argument type is Java interface with single method // or all its methods have the same number of arguments and the // corresponding arguments has the same type. See also comments for // frame.addWindowListener bellow button.addActionListener(function() { numClicks += 1; label.setText(labelPrefix + numClicks); }); label.setLabelFor(button); /* * An easy way to put space between a top-level container * and its contents is to put the contents in a JPanel * that has an "empty" border. */ var pane = new JPanel(); pane.border = BorderFactory.createEmptyBorder(30, //top 30, //left 10, //bottom 30); //right pane.setLayout(new GridLayout(0, 1)); pane.add(button); pane.add(label); return pane; } } with (swingNames) { try { UIManager. setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName()); } catch (e) { } //Create the top-level container and add contents to it. var frame = new swingNames.JFrame("SwingApplication"); frame.getContentPane().add(createComponents(), BorderLayout.CENTER); // Pass JS function as implementation of WindowListener. It is allowed since // all methods in WindowListener have the same signature. To distinguish // between methods Rhino passes to JS function the name of corresponding // method as the last argument frame.addWindowListener(function(event, methodName) { if (methodName == "windowClosing") { java.lang.System.exit(0); } }); //Finish setting up the frame, and show it. frame.pack(); frame.setVisible(true); } rhino-1.7R4/examples/checkParam.js000066400000000000000000000053701176760007500171360ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * checkParam.js * * The files given as arguments on the command line are assumed to be * Java source code files. This program checks to see that the @param * tags in the documentation comments match with the parameters for * the associated Java methods. *

* Any errors found are reported. * */ defineClass("File") // Return true if "str" ends with "suffix". function stringEndsWith(str, suffix) { return str.substring(str.length - suffix.length) == suffix; } /** * Perform processing once the end of a documentation comment is seen. * * Look for a parameter list following the end of the comment and * collect the parameters and compare to the @param entries. * Report any discrepancies. * @param f the current file * @param a an array of parameters from @param comments * @param line the string containing the comment end (in case the * parameters are on the same line) */ function processCommentEnd(f, a, line) { while (line != null && !line.match(/\(/)) line = f.readLine(); while (line != null && !line.match(/\)/)) line += f.readLine(); if (line === null) return; var m = line.match(/\(([^\)]+)\)/); var args = m ? m[1].split(",") : []; if (a.length != args.length) { print('"' + f.name + '"; line ' + f.lineNumber + ' mismatch: had a different number' + ' of @param entries and parameters.'); } else { for (var i=0; i < a.length; i++) { if (!stringEndsWith(args[i], a[i])) { print('"' + f.name + '"; line ' + f.lineNumber + ' mismatch: had "' + a[i] + '" and "' + args[i] + '".'); break; } } } } /** * Process the given file, looking for mismatched @param lists and * parameter lists. * @param f the file to process */ function processFile(f) { var line; var m; var i = 0; var a = []; outer: while ((line = f.readLine()) != null) { if (line.match(/@param/)) { while (m = line.match(/@param[ ]+([^ ]+)/)) { a[i++] = m[1]; line = f.readLine(); if (line == null) break outer; } } if (i != 0 && line.match(/\*\//)) { processCommentEnd(f, a, line); i = 0; a = []; } } if (i != 0) { print('"' + f.name + '"; line ' + f.lineNumber + ' missing parameters at end of file.'); } } // main script: process each file in arguments list for (var i=0; i < arguments.length; i++) { var filename = String(arguments[i]); print("Checking " + filename + "..."); var f = new File(filename); processFile(f); } print("done."); rhino-1.7R4/examples/enum.js000066400000000000000000000021651176760007500160430ustar00rootroot00000000000000/* -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Implementing the interface java.util.Enumeration passing the object with JavaScript implementation directly to the constructor. This is a shorthand for JavaAdapter constructor: elements = new JavaAdapter(java.util.Enumeration, { index: 0, elements: array, hasMoreElements: function ... nextElement: function ... }); */ // an array to enumerate. var array = [0, 1, 2]; // create an array enumeration. var elements = new java.util.Enumeration({ index: 0, elements: array, hasMoreElements: function() { return (this.index < this.elements.length); }, nextElement: function() { return this.elements[this.index++]; } }); // now print out the array by enumerating through the Enumeration while (elements.hasMoreElements()) print(elements.nextElement()); rhino-1.7R4/examples/jsdoc.js000066400000000000000000000355411176760007500162050ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * Process a JavaScript source file and process special comments * to produce an HTML file of documentation, similar to javadoc. * @author Norris Boyd * @see rhinotip.jar * @lastmodified xx * @version 1.2 Roland Pennings: Allow multiple files for a function. * @version 1.3 Roland Pennings: Removes ../.. from the input directory name */ defineClass("File") var functionDocArray = []; var inputDirName = ""; var indexFileArray = []; var indexFile = ""; var indexFileName = "index_files"; var indexFunctionArray = []; var indexFunction = ""; var indexFunctionName = "index_functions"; var FileList = []; var DirList = []; var outputdir = null; var debug = 0; /** * Process JavaScript source file f, writing jsdoc to * file out. * @param f input file * @param fname name of the input file (without the path) * @param inputdir directory of the input file * @param out output file */ function processFile(f, fname, inputdir, out) { var s; var firstLine = true; indexFileArray[fname] = ""; // write the header of the output file out.writeLine('

' + fname + ''); if (inputdir != null) { outstr = '
Index Files ';
	  outstr += 'Index Functions

'; out.writeLine(outstr); } // process the input file var comment = ""; while ((s = f.readLine()) != null) { var m = s.match(/\/\*\*(.*)/); if (m != null) { // Found a comment start. s = "*" + m[1]; do { m = s.match(/(.*)\*\//); if (m != null) { // Found end of comment. comment += m[1]; break; } // Strip leading whitespace and "*". comment += s.replace(/^\s*\*/, ""); s = f.readLine(); } while (s != null); if (debug) print("Found comment " + comment); if (firstLine) { // We have a comment for the whole file. out.writeLine('

File ' + fname + '

'); out.writeLine(processComment(comment,firstLine,fname)); out.writeLine('
'); firstLine = false; comment = ""; continue; } } // match the beginning of the function // NB we also match functions without a comment! // if we have two comments one after another only the last one will be taken m = s.match(/^\s*function\s+((\w+)|(\w+)(\s+))\(([^)]*)\)/); if (m != null) { // Found a function start var htmlText = processFunction(m[1], m[5], comment); // sjm changed from 2nd to 5th arg // Save the text in a global variable, so we // can write out a table of contents first. functionDocArray[functionDocArray.length] = {name:m[1], text:htmlText}; // Store the function also in the indexFunctionArray // so we can have a separate file with the function table of contents if (indexFunctionArray[m[1]]) { // print("ERROR: function: " + m[1] + " is defined more than once!"); // Allow multiple files for a function with (indexFunctionArray[m[1]]) { filename = filename + "|" + fname; // print("filename = " + filename); } } else { indexFunctionArray[m[1]] = {filename:fname}; } //reset comment comment = ""; } // match a method being bound to a prototype m = s.match(/^\s*(\w*)\.prototype\.(\w*)\s*=\s*function\s*\(([^)]*)\)/); if (m != null) { // Found a method being bound to a prototype. var htmlText = processPrototypeMethod(m[1], m[2], m[3], comment); // Save the text in a global variable, so we // can write out a table of contents first. functionDocArray[functionDocArray.length] = {name:m[1]+".prototype."+m[2], text:htmlText}; // Store the function also in the indexFunctionArray // so we can have a separate file with the function table of contents if (indexFunctionArray[m[1]]) { // print("ERROR: function: " + m[1] + " is defined more than once!"); // Allow multiple files for a function with (indexFunctionArray[m[1]]) { filename = filename + "|" + fname; // print("filename = " + filename); } } else { indexFunctionArray[m[1]] = {filename:fname}; } //reset comment comment = ""; } firstLine = false; } // Write table of contents. for (var i=0; i < functionDocArray.length; i++) { with (functionDocArray[i]) { out.writeLine('function ' + name + '
'); } } out.writeLine('
'); // Now write the saved function documentation. for (i=0; i < functionDocArray.length; i++) { with (functionDocArray[i]) { out.writeLine(''); out.writeLine(text); } } out.writeLine(''); // Now clean up the doc array functionDocArray = []; } /** * Process function and associated comment. * @param name the name of the function * @param args the args of the function as a single string * @param comment the text of the comment * @return a string for the HTML text of the documentation */ function processFunction(name, args, comment) { if (debug) print("Processing " + name + " " + args + " " + comment); return "

Function " + name + "

" + "
" +
		"function " + name + "(" + args + ")" +
		"
" + processComment(comment,0,name) + "



"; } /** * Process a method being bound to a prototype. * @param proto the name of the prototype * @param name the name of the function * @param args the args of the function as a single string * @param comment the text of the comment * @return a string for the HTML text of the documentation */ function processPrototypeMethod(proto, name, args, comment) { if (debug) print("Processing " + proto + ".prototype." + name + " " + args + " " + comment); return "

Method " + proto + ".prototype." + name + "

" + "
" +
		proto + ".prototype." + name + " = function(" + args + ")" +
		"
" + processComment(comment,0,name) + "



"; } /** * Process comment. * @param comment the text of the comment * @param firstLine shows if comment is at the beginning of the file * @param fname name of the file (without path) * @return a string for the HTML text of the documentation */ function processComment(comment,firstLine,fname) { var tags = {}; // Use the "lambda" form of regular expression replace, // where the replacement object is a function rather // than a string. The function is called with the // matched text and any parenthetical matches as // arguments, and the result of the function used as the // replacement text. // Here we use the function to build up the "tags" object, // which has a property for each "@" tag that is the name // of the tag, and whose value is an array of the // text following that tag. comment = comment.replace(/@(\w+)\s+([^@]*)/g, function (s, name, text) { var a = tags[name] || []; a.push(text); tags[name] = a; return ""; }); // if we have a comment at the beginning of a file // store the comment for the index file if (firstLine) { indexFileArray[fname] = comment; } var out = comment + '

'; if (tags["param"]) { // Create a table of parameters and their descriptions. var array = tags["param"]; var params = ""; for (var i=0; i < array.length; i++) { var m = array[i].match(/(\w+)\s+(.*)/); params += ''+m[1]+'' + ''+m[2]+''; } out += ''; out += ''; out += ''; out += ''; out += params; out += '
ParameterDescription

'; } if (tags["return"]) { out += "

Returns:
"; out += tags["return"][0] + "

"; } if (tags["author"]) { // List the authors together, separated by commas. out += '

Author:
'; var array = tags["author"]; for (var i=0; i < array.length; i++) { out += array[i]; if (i+1 < array.length) out += ", "; } out += '

'; } if (tags["version"]) { // Show the version. out += '

Version:
'; var array = tags["version"]; for (var i=0; i < array.length; i++) { out += array[i]; if (i+1 < array.length) out += "
"; } out += '

'; } if (tags["see"]) { // List the see modules together, separated by
. out += '

Dependencies:
'; var array = tags["see"]; for (var i=0; i < array.length; i++) { out += array[i]; if (i+1 < array.length) out += "
"; } out += '

'; } if (tags["lastmodified"]) { // Shows a last modified description with client-side js. out += '

Last modified:
'; out += '\n'; out += '

'; } // additional tags can be added here (i.e., "if (tags["see"])...") return out; } /** * Create an html output file * @param outputdir directory to put the file * @param htmlfile name of the file */ function CreateOutputFile(outputdir,htmlfile) { if (outputdir==null) { var outname = htmlfile; } else { var separator = Packages.java.io.File.separator; var outname = outputdir + separator + htmlfile.substring(htmlfile.lastIndexOf(separator),htmlfile.length); } print("output file: " + outname); return new File(outname); } /** * Process a javascript file. Puts the generated HTML file in the outdir * @param filename name of the javascript file * @inputdir input directory of the file (default null) */ function processJSFile(filename,inputdir) { if (debug) print("filename = " + filename + " inputdir = " + inputdir); if (!filename.match(/\.js$/)) { print("Expected filename to end in '.js'; had instead " + filename + ". I don't treat the file."); } else { if (inputdir==null) { var inname = filename; } else { var separator = Packages.java.io.File.separator; var inname = inputdir + separator + filename; } print("Processing file " + inname); var f = new File(inname); // create the output file var htmlfile = filename.replace(/\.js$/, ".html"); var out = CreateOutputFile(outputdir,htmlfile); processFile(f, filename, inputdir, out); out.close(); } } /** * Generate index files containing links to the processed javascript files * and the generated functions */ function GenerateIndex(dirname) { // construct the files index file var out = CreateOutputFile(outputdir,indexFile); // write the beginning of the file out.writeLine('

File Index - directory: ' + dirname + ''); out.writeLine('

File Index - directory: ' + dirname + '

\n'); out.writeLine(''); out.writeLine(''); out.writeLine(''); out.writeLine(''); var separator = Packages.java.io.File.separator; // sort the index file array var SortedFileArray = []; for (var fname in indexFileArray) SortedFileArray.push(fname); SortedFileArray.sort(); for (var i=0; i < SortedFileArray.length; i++) { var fname = SortedFileArray[i]; var htmlfile = fname.replace(/\.js$/, ".html"); out.writeLine('\n'); } out.writeLine('
FileDescription
' + fname + ''); if (indexFileArray[fname]) out.writeLine(indexFileArray[fname]); else out.writeLine('No comments'); out.writeLine('
'); out.close(); // construct the functions index file var out = CreateOutputFile(outputdir,indexFunction); // write the beginning of the file out.writeLine('
Function Index - directory: ' + dirname + ''); out.writeLine('

Function Index - directory: ' + dirname + '

\n'); out.writeLine(''); out.writeLine(''); out.writeLine(''); out.writeLine(''); // sort the function array var SortedFunctionArray = []; for (var functionname in indexFunctionArray) SortedFunctionArray.push(functionname); SortedFunctionArray.sort(); for (var j=0; j < SortedFunctionArray.length; j++) { var funcname = SortedFunctionArray[j]; with (indexFunctionArray[funcname]) { var outstr = ''; out.writeLine(outstr); } } out.writeLine('
FunctionFiles
' + funcname + ''; var filelst = filename.split("|"); for (var i in filelst) { var htmlfile = filelst[i].replace(/\.js$/, ".html"); outstr += '' + filelst[i] + ' '; } outstr += '
'); out.close(); } /** * prints the options for JSDoc */ function PrintOptions() { print("You can use the following options:\n"); print("-d: specify an output directory for the generated html files\n"); print("-i: processes all files in an input directory (you can specify several directories)\n"); quit(); } // Main Script // first read the arguments if (! arguments) PrintOptions(); for (var i=0; i < arguments.length; i++) { if (debug) print("argument: + \'" + arguments[i] + "\'"); if (arguments[i].match(/^\-/)) { if (String(arguments[i])=="-d"){ // output directory for the generated html files outputdir = String(arguments[i+1]); if (debug) print("outputdir: + \'" + outputdir + "\'"); i++; } else if (String(arguments[i])=="-i"){ // process all files in an input directory DirList.push(String(arguments[i+1])); if (debug) print("inputdir: + \'" + arguments[i+1] + "\'"); i++; } else { print("Unknown option: " + arguments[i] + "\n"); PrintOptions(); } } else { // we have a single file if (debug) print("file: + \'" + arguments[i] + "\'"); FileList.push(String(arguments[i])); } } // first handle the single files for (var i in FileList) processJSFile(FileList[i],null); // then handle the input directories for (var j in DirList) { var inputdir = String(DirList[j]); print("Process input directory: " + inputdir); // clean up index arrays var indexFileArray = []; var indexFunctionArray = []; // for the directory name get rid of ../../ or ..\..\ inputDirName = inputdir.replace(/\.\.\/|\.\.\\/g,""); indexFile = indexFileName + "_" + inputDirName + ".html"; indexFunction = indexFunctionName + "_" + inputDirName + ".html"; print("indexFile = " + indexFile); print("indexFunction = " + indexFunction); // read the files in the directory var DirFile = new java.io.File(inputdir); var lst = DirFile.list(); var separator = Packages.java.io.File.separator; for (var i=0; i < lst.length; i++) { processJSFile(String(lst[i]),inputdir); } // generate the index files for the input directory GenerateIndex(inputDirName); } rhino-1.7R4/examples/liveConnect.js000066400000000000000000000016531176760007500173510ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * liveConnect.js: a simple demonstration of JavaScript-to-Java connectivity */ // Create a new StringBuffer. Note that the class name must be fully qualified // by its package. Packages other than "java" must start with "Packages", i.e., // "Packages.javax.servlet...". var sb = new java.lang.StringBuffer(); // Now add some stuff to the buffer. sb.append("hi, mom"); sb.append(3); // this will add "3.0" to the buffer since all JS numbers // are doubles by default sb.append(true); // Now print it out. (The toString() method of sb is automatically called // to convert the buffer to a string.) // Should print "hi, mom3.0true". print(sb); rhino-1.7R4/examples/unique.js000066400000000000000000000014511176760007500164020ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // unique.js: read the contents of a file and print out the unique lines defineClass("File") // "arguments[0]" refers to the first argument at the command line to the // script, if present. If not present, "arguments[0]" will be undefined, // which will cause f to read from System.in. var f = new File(arguments[0]); var o = {} var line; while ((line = f.readLine()) != null) { // Use JavaScript objects' inherent nature as an associative // array to provide uniqueness o[line] = true; } for (i in o) { print(i); } rhino-1.7R4/src/000077500000000000000000000000001176760007500135065ustar00rootroot00000000000000rhino-1.7R4/src/build.xml000066400000000000000000000041541176760007500153330ustar00rootroot00000000000000 rhino-1.7R4/src/manifest000066400000000000000000000003541176760007500152410ustar00rootroot00000000000000Manifest-Version: 1.0 Main-Class: org.mozilla.javascript.tools.shell.Main Implementation-Version: 1.7R4 Implementation-Title: Mozilla Rhino 1.7R4 Implementation-Vendor: Mozilla Foundation Implementation-URL: http://www.mozilla.org/rhinorhino-1.7R4/src/org/000077500000000000000000000000001176760007500142755ustar00rootroot00000000000000rhino-1.7R4/src/org/mozilla/000077500000000000000000000000001176760007500157445ustar00rootroot00000000000000rhino-1.7R4/src/org/mozilla/classfile/000077500000000000000000000000001176760007500177115ustar00rootroot00000000000000rhino-1.7R4/src/org/mozilla/classfile/ByteCode.java000066400000000000000000000130651176760007500222570ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.classfile; /** * This class provides opcode values expected by the JVM in Java class files. * * It also provides tables for internal use by the ClassFileWriter. * * @author Roger Lawrence */ public class ByteCode { /** * The byte opcodes defined by the Java Virtual Machine. */ public static final int NOP = 0x00, ACONST_NULL = 0x01, ICONST_M1 = 0x02, ICONST_0 = 0x03, ICONST_1 = 0x04, ICONST_2 = 0x05, ICONST_3 = 0x06, ICONST_4 = 0x07, ICONST_5 = 0x08, LCONST_0 = 0x09, LCONST_1 = 0x0A, FCONST_0 = 0x0B, FCONST_1 = 0x0C, FCONST_2 = 0x0D, DCONST_0 = 0x0E, DCONST_1 = 0x0F, BIPUSH = 0x10, SIPUSH = 0x11, LDC = 0x12, LDC_W = 0x13, LDC2_W = 0x14, ILOAD = 0x15, LLOAD = 0x16, FLOAD = 0x17, DLOAD = 0x18, ALOAD = 0x19, ILOAD_0 = 0x1A, ILOAD_1 = 0x1B, ILOAD_2 = 0x1C, ILOAD_3 = 0x1D, LLOAD_0 = 0x1E, LLOAD_1 = 0x1F, LLOAD_2 = 0x20, LLOAD_3 = 0x21, FLOAD_0 = 0x22, FLOAD_1 = 0x23, FLOAD_2 = 0x24, FLOAD_3 = 0x25, DLOAD_0 = 0x26, DLOAD_1 = 0x27, DLOAD_2 = 0x28, DLOAD_3 = 0x29, ALOAD_0 = 0x2A, ALOAD_1 = 0x2B, ALOAD_2 = 0x2C, ALOAD_3 = 0x2D, IALOAD = 0x2E, LALOAD = 0x2F, FALOAD = 0x30, DALOAD = 0x31, AALOAD = 0x32, BALOAD = 0x33, CALOAD = 0x34, SALOAD = 0x35, ISTORE = 0x36, LSTORE = 0x37, FSTORE = 0x38, DSTORE = 0x39, ASTORE = 0x3A, ISTORE_0 = 0x3B, ISTORE_1 = 0x3C, ISTORE_2 = 0x3D, ISTORE_3 = 0x3E, LSTORE_0 = 0x3F, LSTORE_1 = 0x40, LSTORE_2 = 0x41, LSTORE_3 = 0x42, FSTORE_0 = 0x43, FSTORE_1 = 0x44, FSTORE_2 = 0x45, FSTORE_3 = 0x46, DSTORE_0 = 0x47, DSTORE_1 = 0x48, DSTORE_2 = 0x49, DSTORE_3 = 0x4A, ASTORE_0 = 0x4B, ASTORE_1 = 0x4C, ASTORE_2 = 0x4D, ASTORE_3 = 0x4E, IASTORE = 0x4F, LASTORE = 0x50, FASTORE = 0x51, DASTORE = 0x52, AASTORE = 0x53, BASTORE = 0x54, CASTORE = 0x55, SASTORE = 0x56, POP = 0x57, POP2 = 0x58, DUP = 0x59, DUP_X1 = 0x5A, DUP_X2 = 0x5B, DUP2 = 0x5C, DUP2_X1 = 0x5D, DUP2_X2 = 0x5E, SWAP = 0x5F, IADD = 0x60, LADD = 0x61, FADD = 0x62, DADD = 0x63, ISUB = 0x64, LSUB = 0x65, FSUB = 0x66, DSUB = 0x67, IMUL = 0x68, LMUL = 0x69, FMUL = 0x6A, DMUL = 0x6B, IDIV = 0x6C, LDIV = 0x6D, FDIV = 0x6E, DDIV = 0x6F, IREM = 0x70, LREM = 0x71, FREM = 0x72, DREM = 0x73, INEG = 0x74, LNEG = 0x75, FNEG = 0x76, DNEG = 0x77, ISHL = 0x78, LSHL = 0x79, ISHR = 0x7A, LSHR = 0x7B, IUSHR = 0x7C, LUSHR = 0x7D, IAND = 0x7E, LAND = 0x7F, IOR = 0x80, LOR = 0x81, IXOR = 0x82, LXOR = 0x83, IINC = 0x84, I2L = 0x85, I2F = 0x86, I2D = 0x87, L2I = 0x88, L2F = 0x89, L2D = 0x8A, F2I = 0x8B, F2L = 0x8C, F2D = 0x8D, D2I = 0x8E, D2L = 0x8F, D2F = 0x90, I2B = 0x91, I2C = 0x92, I2S = 0x93, LCMP = 0x94, FCMPL = 0x95, FCMPG = 0x96, DCMPL = 0x97, DCMPG = 0x98, IFEQ = 0x99, IFNE = 0x9A, IFLT = 0x9B, IFGE = 0x9C, IFGT = 0x9D, IFLE = 0x9E, IF_ICMPEQ = 0x9F, IF_ICMPNE = 0xA0, IF_ICMPLT = 0xA1, IF_ICMPGE = 0xA2, IF_ICMPGT = 0xA3, IF_ICMPLE = 0xA4, IF_ACMPEQ = 0xA5, IF_ACMPNE = 0xA6, GOTO = 0xA7, JSR = 0xA8, RET = 0xA9, TABLESWITCH = 0xAA, LOOKUPSWITCH = 0xAB, IRETURN = 0xAC, LRETURN = 0xAD, FRETURN = 0xAE, DRETURN = 0xAF, ARETURN = 0xB0, RETURN = 0xB1, GETSTATIC = 0xB2, PUTSTATIC = 0xB3, GETFIELD = 0xB4, PUTFIELD = 0xB5, INVOKEVIRTUAL = 0xB6, INVOKESPECIAL = 0xB7, INVOKESTATIC = 0xB8, INVOKEINTERFACE = 0xB9, NEW = 0xBB, NEWARRAY = 0xBC, ANEWARRAY = 0xBD, ARRAYLENGTH = 0xBE, ATHROW = 0xBF, CHECKCAST = 0xC0, INSTANCEOF = 0xC1, MONITORENTER = 0xC2, MONITOREXIT = 0xC3, WIDE = 0xC4, MULTIANEWARRAY = 0xC5, IFNULL = 0xC6, IFNONNULL = 0xC7, GOTO_W = 0xC8, JSR_W = 0xC9, BREAKPOINT = 0xCA, IMPDEP1 = 0xFE, IMPDEP2 = 0xFF; /** * Types for the NEWARRAY opcode. */ public static final byte T_BOOLEAN = 4, T_CHAR = 5, T_FLOAT = 6, T_DOUBLE = 7, T_BYTE = 8, T_SHORT = 9, T_INT = 10, T_LONG = 11; } rhino-1.7R4/src/org/mozilla/classfile/ClassFileWriter.java000066400000000000000000005677371176760007500236470ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.classfile; import org.mozilla.javascript.ObjToIntMap; import org.mozilla.javascript.ObjArray; import org.mozilla.javascript.UintMap; import java.io.*; import java.util.Arrays; /** * ClassFileWriter * * A ClassFileWriter is used to write a Java class file. Methods are * provided to create fields and methods, and within methods to write * Java bytecodes. * * @author Roger Lawrence */ public class ClassFileWriter { /** * Thrown for cases where the error in generating the class file is * due to a program size constraints rather than a likely bug in the * compiler. */ public static class ClassFileFormatException extends RuntimeException { private static final long serialVersionUID = 1263998431033790599L; ClassFileFormatException(String message) { super(message); } } /** * Construct a ClassFileWriter for a class. * * @param className the name of the class to write, including * full package qualification. * @param superClassName the name of the superclass of the class * to write, including full package qualification. * @param sourceFileName the name of the source file to use for * producing debug information, or null if debug information * is not desired */ public ClassFileWriter(String className, String superClassName, String sourceFileName) { generatedClassName = className; itsConstantPool = new ConstantPool(this); itsThisClassIndex = itsConstantPool.addClass(className); itsSuperClassIndex = itsConstantPool.addClass(superClassName); if (sourceFileName != null) itsSourceFileNameIndex = itsConstantPool.addUtf8(sourceFileName); // All "new" implementations are supposed to output ACC_SUPER as a // class flag. This is specified in the first JVM spec, so it should // be old enough that it's okay to always set it. itsFlags = ACC_PUBLIC | ACC_SUPER; } public final String getClassName() { return generatedClassName; } /** * Add an interface implemented by this class. * * This method may be called multiple times for classes that * implement multiple interfaces. * * @param interfaceName a name of an interface implemented * by the class being written, including full package * qualification. */ public void addInterface(String interfaceName) { short interfaceIndex = itsConstantPool.addClass(interfaceName); itsInterfaces.add(Short.valueOf(interfaceIndex)); } public static final short ACC_PUBLIC = 0x0001, ACC_PRIVATE = 0x0002, ACC_PROTECTED = 0x0004, ACC_STATIC = 0x0008, ACC_FINAL = 0x0010, ACC_SUPER = 0x0020, ACC_SYNCHRONIZED = 0x0020, ACC_VOLATILE = 0x0040, ACC_TRANSIENT = 0x0080, ACC_NATIVE = 0x0100, ACC_ABSTRACT = 0x0400; /** * Set the class's flags. * * Flags must be a set of the following flags, bitwise or'd * together: * ACC_PUBLIC * ACC_PRIVATE * ACC_PROTECTED * ACC_FINAL * ACC_ABSTRACT * TODO: check that this is the appropriate set * @param flags the set of class flags to set */ public void setFlags(short flags) { itsFlags = flags; } static String getSlashedForm(String name) { return name.replace('.', '/'); } /** * Convert Java class name in dot notation into * "Lname-with-dots-replaced-by-slashes;" form suitable for use as * JVM type signatures. */ public static String classNameToSignature(String name) { int nameLength = name.length(); int colonPos = 1 + nameLength; char[] buf = new char[colonPos + 1]; buf[0] = 'L'; buf[colonPos] = ';'; name.getChars(0, nameLength, buf, 1); for (int i = 1; i != colonPos; ++i) { if (buf[i] == '.') { buf[i] = '/'; } } return new String(buf, 0, colonPos + 1); } /** * Add a field to the class. * * @param fieldName the name of the field * @param type the type of the field using ... * @param flags the attributes of the field, such as ACC_PUBLIC, etc. * bitwise or'd together */ public void addField(String fieldName, String type, short flags) { short fieldNameIndex = itsConstantPool.addUtf8(fieldName); short typeIndex = itsConstantPool.addUtf8(type); itsFields.add(new ClassFileField(fieldNameIndex, typeIndex, flags)); } /** * Add a field to the class. * * @param fieldName the name of the field * @param type the type of the field using ... * @param flags the attributes of the field, such as ACC_PUBLIC, etc. * bitwise or'd together * @param value an initial integral value */ public void addField(String fieldName, String type, short flags, int value) { short fieldNameIndex = itsConstantPool.addUtf8(fieldName); short typeIndex = itsConstantPool.addUtf8(type); ClassFileField field = new ClassFileField(fieldNameIndex, typeIndex, flags); field.setAttributes(itsConstantPool.addUtf8("ConstantValue"), (short)0, (short)0, itsConstantPool.addConstant(value)); itsFields.add(field); } /** * Add a field to the class. * * @param fieldName the name of the field * @param type the type of the field using ... * @param flags the attributes of the field, such as ACC_PUBLIC, etc. * bitwise or'd together * @param value an initial long value */ public void addField(String fieldName, String type, short flags, long value) { short fieldNameIndex = itsConstantPool.addUtf8(fieldName); short typeIndex = itsConstantPool.addUtf8(type); ClassFileField field = new ClassFileField(fieldNameIndex, typeIndex, flags); field.setAttributes(itsConstantPool.addUtf8("ConstantValue"), (short)0, (short)2, itsConstantPool.addConstant(value)); itsFields.add(field); } /** * Add a field to the class. * * @param fieldName the name of the field * @param type the type of the field using ... * @param flags the attributes of the field, such as ACC_PUBLIC, etc. * bitwise or'd together * @param value an initial double value */ public void addField(String fieldName, String type, short flags, double value) { short fieldNameIndex = itsConstantPool.addUtf8(fieldName); short typeIndex = itsConstantPool.addUtf8(type); ClassFileField field = new ClassFileField(fieldNameIndex, typeIndex, flags); field.setAttributes(itsConstantPool.addUtf8("ConstantValue"), (short)0, (short)2, itsConstantPool.addConstant(value)); itsFields.add(field); } /** * Add Information about java variable to use when generating the local * variable table. * * @param name variable name. * @param type variable type as bytecode descriptor string. * @param startPC the starting bytecode PC where this variable is live, * or -1 if it does not have a Java register. * @param register the Java register number of variable * or -1 if it does not have a Java register. */ public void addVariableDescriptor(String name, String type, int startPC, int register) { int nameIndex = itsConstantPool.addUtf8(name); int descriptorIndex = itsConstantPool.addUtf8(type); int [] chunk = { nameIndex, descriptorIndex, startPC, register }; if (itsVarDescriptors == null) { itsVarDescriptors = new ObjArray(); } itsVarDescriptors.add(chunk); } /** * Add a method and begin adding code. * * This method must be called before other methods for adding code, * exception tables, etc. can be invoked. * * @param methodName the name of the method * @param type a string representing the type * @param flags the attributes of the field, such as ACC_PUBLIC, etc. * bitwise or'd together */ public void startMethod(String methodName, String type, short flags) { short methodNameIndex = itsConstantPool.addUtf8(methodName); short typeIndex = itsConstantPool.addUtf8(type); itsCurrentMethod = new ClassFileMethod(methodName, methodNameIndex, type, typeIndex, flags); itsJumpFroms = new UintMap(); itsMethods.add(itsCurrentMethod); addSuperBlockStart(0); } /** * Complete generation of the method. * * After this method is called, no more code can be added to the * method begun with startMethod. * * @param maxLocals the maximum number of local variable slots * (a.k.a. Java registers) used by the method */ public void stopMethod(short maxLocals) { if (itsCurrentMethod == null) throw new IllegalStateException("No method to stop"); fixLabelGotos(); itsMaxLocals = maxLocals; StackMapTable stackMap = null; if (GenerateStackMap) { finalizeSuperBlockStarts(); stackMap = new StackMapTable(); stackMap.generate(); } int lineNumberTableLength = 0; if (itsLineNumberTable != null) { // 6 bytes for the attribute header // 2 bytes for the line number count // 4 bytes for each entry lineNumberTableLength = 6 + 2 + (itsLineNumberTableTop * 4); } int variableTableLength = 0; if (itsVarDescriptors != null) { // 6 bytes for the attribute header // 2 bytes for the variable count // 10 bytes for each entry variableTableLength = 6 + 2 + (itsVarDescriptors.size() * 10); } int stackMapTableLength = 0; if (stackMap != null) { int stackMapWriteSize = stackMap.computeWriteSize(); if (stackMapWriteSize > 0) { stackMapTableLength = 6 + stackMapWriteSize; } } int attrLength = 2 + // attribute_name_index 4 + // attribute_length 2 + // max_stack 2 + // max_locals 4 + // code_length itsCodeBufferTop + 2 + // exception_table_length (itsExceptionTableTop * 8) + 2 + // attributes_count lineNumberTableLength + variableTableLength + stackMapTableLength; if (attrLength > 65536) { // See http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html, // section 4.10, "The amount of code per non-native, non-abstract // method is limited to 65536 bytes... throw new ClassFileFormatException( "generated bytecode for method exceeds 64K limit."); } byte[] codeAttribute = new byte[attrLength]; int index = 0; int codeAttrIndex = itsConstantPool.addUtf8("Code"); index = putInt16(codeAttrIndex, codeAttribute, index); attrLength -= 6; // discount the attribute header index = putInt32(attrLength, codeAttribute, index); index = putInt16(itsMaxStack, codeAttribute, index); index = putInt16(itsMaxLocals, codeAttribute, index); index = putInt32(itsCodeBufferTop, codeAttribute, index); System.arraycopy(itsCodeBuffer, 0, codeAttribute, index, itsCodeBufferTop); index += itsCodeBufferTop; if (itsExceptionTableTop > 0) { index = putInt16(itsExceptionTableTop, codeAttribute, index); for (int i = 0; i < itsExceptionTableTop; i++) { ExceptionTableEntry ete = itsExceptionTable[i]; short startPC = (short)getLabelPC(ete.itsStartLabel); short endPC = (short)getLabelPC(ete.itsEndLabel); short handlerPC = (short)getLabelPC(ete.itsHandlerLabel); short catchType = ete.itsCatchType; if (startPC == -1) throw new IllegalStateException("start label not defined"); if (endPC == -1) throw new IllegalStateException("end label not defined"); if (handlerPC == -1) throw new IllegalStateException( "handler label not defined"); index = putInt16(startPC, codeAttribute, index); index = putInt16(endPC, codeAttribute, index); index = putInt16(handlerPC, codeAttribute, index); index = putInt16(catchType, codeAttribute, index); } } else { // write 0 as exception table length index = putInt16(0, codeAttribute, index); } int attributeCount = 0; if (itsLineNumberTable != null) attributeCount++; if (itsVarDescriptors != null) attributeCount++; if (stackMapTableLength > 0) { attributeCount++; } index = putInt16(attributeCount, codeAttribute, index); if (itsLineNumberTable != null) { int lineNumberTableAttrIndex = itsConstantPool.addUtf8("LineNumberTable"); index = putInt16(lineNumberTableAttrIndex, codeAttribute, index); int tableAttrLength = 2 + (itsLineNumberTableTop * 4); index = putInt32(tableAttrLength, codeAttribute, index); index = putInt16(itsLineNumberTableTop, codeAttribute, index); for (int i = 0; i < itsLineNumberTableTop; i++) { index = putInt32(itsLineNumberTable[i], codeAttribute, index); } } if (itsVarDescriptors != null) { int variableTableAttrIndex = itsConstantPool.addUtf8("LocalVariableTable"); index = putInt16(variableTableAttrIndex, codeAttribute, index); int varCount = itsVarDescriptors.size(); int tableAttrLength = 2 + (varCount * 10); index = putInt32(tableAttrLength, codeAttribute, index); index = putInt16(varCount, codeAttribute, index); for (int i = 0; i < varCount; i++) { int[] chunk = (int[])itsVarDescriptors.get(i); int nameIndex = chunk[0]; int descriptorIndex = chunk[1]; int startPC = chunk[2]; int register = chunk[3]; int length = itsCodeBufferTop - startPC; index = putInt16(startPC, codeAttribute, index); index = putInt16(length, codeAttribute, index); index = putInt16(nameIndex, codeAttribute, index); index = putInt16(descriptorIndex, codeAttribute, index); index = putInt16(register, codeAttribute, index); } } if (stackMapTableLength > 0) { int stackMapTableAttrIndex = itsConstantPool.addUtf8("StackMapTable"); int start = index; index = putInt16(stackMapTableAttrIndex, codeAttribute, index); index = stackMap.write(codeAttribute, index); } itsCurrentMethod.setCodeAttribute(codeAttribute); itsExceptionTable = null; itsExceptionTableTop = 0; itsLineNumberTableTop = 0; itsCodeBufferTop = 0; itsCurrentMethod = null; itsMaxStack = 0; itsStackTop = 0; itsLabelTableTop = 0; itsFixupTableTop = 0; itsVarDescriptors = null; itsSuperBlockStarts = null; itsSuperBlockStartsTop = 0; itsJumpFroms = null; } /** * Add the single-byte opcode to the current method. * * @param theOpCode the opcode of the bytecode */ public void add(int theOpCode) { if (opcodeCount(theOpCode) != 0) throw new IllegalArgumentException("Unexpected operands"); int newStack = itsStackTop + stackChange(theOpCode); if (newStack < 0 || Short.MAX_VALUE < newStack) badStack(newStack); if (DEBUGCODE) System.out.println("Add " + bytecodeStr(theOpCode)); addToCodeBuffer(theOpCode); itsStackTop = (short)newStack; if (newStack > itsMaxStack) itsMaxStack = (short)newStack; if (DEBUGSTACK) { System.out.println("After "+bytecodeStr(theOpCode) +" stack = "+itsStackTop); } if (theOpCode == ByteCode.ATHROW) { addSuperBlockStart(itsCodeBufferTop); } } /** * Add a single-operand opcode to the current method. * * @param theOpCode the opcode of the bytecode * @param theOperand the operand of the bytecode */ public void add(int theOpCode, int theOperand) { if (DEBUGCODE) { System.out.println("Add "+bytecodeStr(theOpCode) +", "+Integer.toHexString(theOperand)); } int newStack = itsStackTop + stackChange(theOpCode); if (newStack < 0 || Short.MAX_VALUE < newStack) badStack(newStack); switch (theOpCode) { case ByteCode.GOTO : // This is necessary because dead code is seemingly being // generated and Sun's verifier is expecting type state to be // placed even at dead blocks of code. addSuperBlockStart(itsCodeBufferTop + 3); // fallthru... case ByteCode.IFEQ : case ByteCode.IFNE : case ByteCode.IFLT : case ByteCode.IFGE : case ByteCode.IFGT : case ByteCode.IFLE : case ByteCode.IF_ICMPEQ : case ByteCode.IF_ICMPNE : case ByteCode.IF_ICMPLT : case ByteCode.IF_ICMPGE : case ByteCode.IF_ICMPGT : case ByteCode.IF_ICMPLE : case ByteCode.IF_ACMPEQ : case ByteCode.IF_ACMPNE : case ByteCode.JSR : case ByteCode.IFNULL : case ByteCode.IFNONNULL : { if ((theOperand & 0x80000000) != 0x80000000) { if ((theOperand < 0) || (theOperand > 65535)) throw new IllegalArgumentException( "Bad label for branch"); } int branchPC = itsCodeBufferTop; addToCodeBuffer(theOpCode); if ((theOperand & 0x80000000) != 0x80000000) { // hard displacement addToCodeInt16(theOperand); int target = theOperand + branchPC; addSuperBlockStart(target); itsJumpFroms.put(target, branchPC); } else { // a label int targetPC = getLabelPC(theOperand); if (DEBUGLABELS) { int theLabel = theOperand & 0x7FFFFFFF; System.out.println("Fixing branch to " + theLabel + " at " + targetPC + " from " + branchPC); } if (targetPC != -1) { int offset = targetPC - branchPC; addToCodeInt16(offset); addSuperBlockStart(targetPC); itsJumpFroms.put(targetPC, branchPC); } else { addLabelFixup(theOperand, branchPC + 1); addToCodeInt16(0); } } } break; case ByteCode.BIPUSH : if ((byte)theOperand != theOperand) throw new IllegalArgumentException("out of range byte"); addToCodeBuffer(theOpCode); addToCodeBuffer((byte)theOperand); break; case ByteCode.SIPUSH : if ((short)theOperand != theOperand) throw new IllegalArgumentException("out of range short"); addToCodeBuffer(theOpCode); addToCodeInt16(theOperand); break; case ByteCode.NEWARRAY : if (!(0 <= theOperand && theOperand < 256)) throw new IllegalArgumentException("out of range index"); addToCodeBuffer(theOpCode); addToCodeBuffer(theOperand); break; case ByteCode.GETFIELD : case ByteCode.PUTFIELD : if (!(0 <= theOperand && theOperand < 65536)) throw new IllegalArgumentException("out of range field"); addToCodeBuffer(theOpCode); addToCodeInt16(theOperand); break; case ByteCode.LDC : case ByteCode.LDC_W : case ByteCode.LDC2_W : if (!(0 <= theOperand && theOperand < 65536)) throw new IllegalArgumentException("out of range index"); if (theOperand >= 256 || theOpCode == ByteCode.LDC_W || theOpCode == ByteCode.LDC2_W) { if (theOpCode == ByteCode.LDC) { addToCodeBuffer(ByteCode.LDC_W); } else { addToCodeBuffer(theOpCode); } addToCodeInt16(theOperand); } else { addToCodeBuffer(theOpCode); addToCodeBuffer(theOperand); } break; case ByteCode.RET : case ByteCode.ILOAD : case ByteCode.LLOAD : case ByteCode.FLOAD : case ByteCode.DLOAD : case ByteCode.ALOAD : case ByteCode.ISTORE : case ByteCode.LSTORE : case ByteCode.FSTORE : case ByteCode.DSTORE : case ByteCode.ASTORE : if (!(0 <= theOperand && theOperand < 65536)) throw new ClassFileFormatException("out of range variable"); if (theOperand >= 256) { addToCodeBuffer(ByteCode.WIDE); addToCodeBuffer(theOpCode); addToCodeInt16(theOperand); } else { addToCodeBuffer(theOpCode); addToCodeBuffer(theOperand); } break; default : throw new IllegalArgumentException( "Unexpected opcode for 1 operand"); } itsStackTop = (short)newStack; if (newStack > itsMaxStack) itsMaxStack = (short)newStack; if (DEBUGSTACK) { System.out.println("After "+bytecodeStr(theOpCode) +" stack = "+itsStackTop); } } /** * Generate the load constant bytecode for the given integer. * * @param k the constant */ public void addLoadConstant(int k) { switch (k) { case 0: add(ByteCode.ICONST_0); break; case 1: add(ByteCode.ICONST_1); break; case 2: add(ByteCode.ICONST_2); break; case 3: add(ByteCode.ICONST_3); break; case 4: add(ByteCode.ICONST_4); break; case 5: add(ByteCode.ICONST_5); break; default: add(ByteCode.LDC, itsConstantPool.addConstant(k)); break; } } /** * Generate the load constant bytecode for the given long. * * @param k the constant */ public void addLoadConstant(long k) { add(ByteCode.LDC2_W, itsConstantPool.addConstant(k)); } /** * Generate the load constant bytecode for the given float. * * @param k the constant */ public void addLoadConstant(float k) { add(ByteCode.LDC, itsConstantPool.addConstant(k)); } /** * Generate the load constant bytecode for the given double. * * @param k the constant */ public void addLoadConstant(double k) { add(ByteCode.LDC2_W, itsConstantPool.addConstant(k)); } /** * Generate the load constant bytecode for the given string. * * @param k the constant */ public void addLoadConstant(String k) { add(ByteCode.LDC, itsConstantPool.addConstant(k)); } /** * Add the given two-operand bytecode to the current method. * * @param theOpCode the opcode of the bytecode * @param theOperand1 the first operand of the bytecode * @param theOperand2 the second operand of the bytecode */ public void add(int theOpCode, int theOperand1, int theOperand2) { if (DEBUGCODE) { System.out.println("Add "+bytecodeStr(theOpCode) +", "+Integer.toHexString(theOperand1) +", "+Integer.toHexString(theOperand2)); } int newStack = itsStackTop + stackChange(theOpCode); if (newStack < 0 || Short.MAX_VALUE < newStack) badStack(newStack); if (theOpCode == ByteCode.IINC) { if (!(0 <= theOperand1 && theOperand1 < 65536)) throw new ClassFileFormatException("out of range variable"); if (!(0 <= theOperand2 && theOperand2 < 65536)) throw new ClassFileFormatException("out of range increment"); if (theOperand1 > 255 || theOperand2 < -128 || theOperand2 > 127) { addToCodeBuffer(ByteCode.WIDE); addToCodeBuffer(ByteCode.IINC); addToCodeInt16(theOperand1); addToCodeInt16(theOperand2); } else { addToCodeBuffer(ByteCode.IINC); addToCodeBuffer(theOperand1); addToCodeBuffer(theOperand2); } } else if (theOpCode == ByteCode.MULTIANEWARRAY) { if (!(0 <= theOperand1 && theOperand1 < 65536)) throw new IllegalArgumentException("out of range index"); if (!(0 <= theOperand2 && theOperand2 < 256)) throw new IllegalArgumentException("out of range dimensions"); addToCodeBuffer(ByteCode.MULTIANEWARRAY); addToCodeInt16(theOperand1); addToCodeBuffer(theOperand2); } else { throw new IllegalArgumentException( "Unexpected opcode for 2 operands"); } itsStackTop = (short)newStack; if (newStack > itsMaxStack) itsMaxStack = (short)newStack; if (DEBUGSTACK) { System.out.println("After "+bytecodeStr(theOpCode) +" stack = "+itsStackTop); } } public void add(int theOpCode, String className) { if (DEBUGCODE) { System.out.println("Add "+bytecodeStr(theOpCode) +", "+className); } int newStack = itsStackTop + stackChange(theOpCode); if (newStack < 0 || Short.MAX_VALUE < newStack) badStack(newStack); switch (theOpCode) { case ByteCode.NEW : case ByteCode.ANEWARRAY : case ByteCode.CHECKCAST : case ByteCode.INSTANCEOF : { short classIndex = itsConstantPool.addClass(className); addToCodeBuffer(theOpCode); addToCodeInt16(classIndex); } break; default : throw new IllegalArgumentException( "bad opcode for class reference"); } itsStackTop = (short)newStack; if (newStack > itsMaxStack) itsMaxStack = (short)newStack; if (DEBUGSTACK) { System.out.println("After "+bytecodeStr(theOpCode) +" stack = "+itsStackTop); } } public void add(int theOpCode, String className, String fieldName, String fieldType) { if (DEBUGCODE) { System.out.println("Add "+bytecodeStr(theOpCode) +", "+className+", "+fieldName+", "+fieldType); } int newStack = itsStackTop + stackChange(theOpCode); char fieldTypeChar = fieldType.charAt(0); int fieldSize = (fieldTypeChar == 'J' || fieldTypeChar == 'D') ? 2 : 1; switch (theOpCode) { case ByteCode.GETFIELD : case ByteCode.GETSTATIC : newStack += fieldSize; break; case ByteCode.PUTSTATIC : case ByteCode.PUTFIELD : newStack -= fieldSize; break; default : throw new IllegalArgumentException( "bad opcode for field reference"); } if (newStack < 0 || Short.MAX_VALUE < newStack) badStack(newStack); short fieldRefIndex = itsConstantPool.addFieldRef(className, fieldName, fieldType); addToCodeBuffer(theOpCode); addToCodeInt16(fieldRefIndex); itsStackTop = (short)newStack; if (newStack > itsMaxStack) itsMaxStack = (short)newStack; if (DEBUGSTACK) { System.out.println("After "+bytecodeStr(theOpCode) +" stack = "+itsStackTop); } } public void addInvoke(int theOpCode, String className, String methodName, String methodType) { if (DEBUGCODE) { System.out.println("Add "+bytecodeStr(theOpCode) +", "+className+", "+methodName+", " +methodType); } int parameterInfo = sizeOfParameters(methodType); int parameterCount = parameterInfo >>> 16; int stackDiff = (short)parameterInfo; int newStack = itsStackTop + stackDiff; newStack += stackChange(theOpCode); // adjusts for 'this' if (newStack < 0 || Short.MAX_VALUE < newStack) badStack(newStack); switch (theOpCode) { case ByteCode.INVOKEVIRTUAL : case ByteCode.INVOKESPECIAL : case ByteCode.INVOKESTATIC : case ByteCode.INVOKEINTERFACE : { addToCodeBuffer(theOpCode); if (theOpCode == ByteCode.INVOKEINTERFACE) { short ifMethodRefIndex = itsConstantPool.addInterfaceMethodRef( className, methodName, methodType); addToCodeInt16(ifMethodRefIndex); addToCodeBuffer(parameterCount + 1); addToCodeBuffer(0); } else { short methodRefIndex = itsConstantPool.addMethodRef( className, methodName, methodType); addToCodeInt16(methodRefIndex); } } break; default : throw new IllegalArgumentException( "bad opcode for method reference"); } itsStackTop = (short)newStack; if (newStack > itsMaxStack) itsMaxStack = (short)newStack; if (DEBUGSTACK) { System.out.println("After "+bytecodeStr(theOpCode) +" stack = "+itsStackTop); } } /** * Generate code to load the given integer on stack. * * @param k the constant */ public void addPush(int k) { if ((byte)k == k) { if (k == -1) { add(ByteCode.ICONST_M1); } else if (0 <= k && k <= 5) { add((byte)(ByteCode.ICONST_0 + k)); } else { add(ByteCode.BIPUSH, (byte)k); } } else if ((short)k == k) { add(ByteCode.SIPUSH, (short)k); } else { addLoadConstant(k); } } public void addPush(boolean k) { add(k ? ByteCode.ICONST_1 : ByteCode.ICONST_0); } /** * Generate code to load the given long on stack. * * @param k the constant */ public void addPush(long k) { int ik = (int)k; if (ik == k) { addPush(ik); add(ByteCode.I2L); } else { addLoadConstant(k); } } /** * Generate code to load the given double on stack. * * @param k the constant */ public void addPush(double k) { if (k == 0.0) { // zero add(ByteCode.DCONST_0); if (1.0 / k < 0) { // Negative zero add(ByteCode.DNEG); } } else if (k == 1.0 || k == -1.0) { add(ByteCode.DCONST_1); if (k < 0) { add(ByteCode.DNEG); } } else { addLoadConstant(k); } } /** * Generate the code to leave on stack the given string even if the * string encoding exeeds the class file limit for single string constant * * @param k the constant */ public void addPush(String k) { int length = k.length(); int limit = itsConstantPool.getUtfEncodingLimit(k, 0, length); if (limit == length) { addLoadConstant(k); return; } // Split string into picies fitting the UTF limit and generate code for // StringBuffer sb = new StringBuffer(length); // sb.append(loadConstant(piece_1)); // ... // sb.append(loadConstant(piece_N)); // sb.toString(); final String SB = "java/lang/StringBuffer"; add(ByteCode.NEW, SB); add(ByteCode.DUP); addPush(length); addInvoke(ByteCode.INVOKESPECIAL, SB, "", "(I)V"); int cursor = 0; for (;;) { add(ByteCode.DUP); String s = k.substring(cursor, limit); addLoadConstant(s); addInvoke(ByteCode.INVOKEVIRTUAL, SB, "append", "(Ljava/lang/String;)Ljava/lang/StringBuffer;"); add(ByteCode.POP); if (limit == length) { break; } cursor = limit; limit = itsConstantPool.getUtfEncodingLimit(k, limit, length); } addInvoke(ByteCode.INVOKEVIRTUAL, SB, "toString", "()Ljava/lang/String;"); } /** * Check if k fits limit on string constant size imposed by class file * format. * * @param k the string constant */ public boolean isUnderStringSizeLimit(String k) { return itsConstantPool.isUnderUtfEncodingLimit(k); } /** * Store integer from stack top into the given local. * * @param local number of local register */ public void addIStore(int local) { xop(ByteCode.ISTORE_0, ByteCode.ISTORE, local); } /** * Store long from stack top into the given local. * * @param local number of local register */ public void addLStore(int local) { xop(ByteCode.LSTORE_0, ByteCode.LSTORE, local); } /** * Store float from stack top into the given local. * * @param local number of local register */ public void addFStore(int local) { xop(ByteCode.FSTORE_0, ByteCode.FSTORE, local); } /** * Store double from stack top into the given local. * * @param local number of local register */ public void addDStore(int local) { xop(ByteCode.DSTORE_0, ByteCode.DSTORE, local); } /** * Store object from stack top into the given local. * * @param local number of local register */ public void addAStore(int local) { xop(ByteCode.ASTORE_0, ByteCode.ASTORE, local); } /** * Load integer from the given local into stack. * * @param local number of local register */ public void addILoad(int local) { xop(ByteCode.ILOAD_0, ByteCode.ILOAD, local); } /** * Load long from the given local into stack. * * @param local number of local register */ public void addLLoad(int local) { xop(ByteCode.LLOAD_0, ByteCode.LLOAD, local); } /** * Load float from the given local into stack. * * @param local number of local register */ public void addFLoad(int local) { xop(ByteCode.FLOAD_0, ByteCode.FLOAD, local); } /** * Load double from the given local into stack. * * @param local number of local register */ public void addDLoad(int local) { xop(ByteCode.DLOAD_0, ByteCode.DLOAD, local); } /** * Load object from the given local into stack. * * @param local number of local register */ public void addALoad(int local) { xop(ByteCode.ALOAD_0, ByteCode.ALOAD, local); } /** * Load "this" into stack. */ public void addLoadThis() { add(ByteCode.ALOAD_0); } private void xop(int shortOp, int op, int local) { switch (local) { case 0: add(shortOp); break; case 1: add(shortOp + 1); break; case 2: add(shortOp + 2); break; case 3: add(shortOp + 3); break; default: add(op, local); } } public int addTableSwitch(int low, int high) { if (DEBUGCODE) { System.out.println("Add "+bytecodeStr(ByteCode.TABLESWITCH) +" "+low+" "+high); } if (low > high) throw new ClassFileFormatException("Bad bounds: "+low+' '+ high); int newStack = itsStackTop + stackChange(ByteCode.TABLESWITCH); if (newStack < 0 || Short.MAX_VALUE < newStack) badStack(newStack); int entryCount = high - low + 1; int padSize = 3 & ~itsCodeBufferTop; // == 3 - itsCodeBufferTop % 4 int N = addReservedCodeSpace(1 + padSize + 4 * (1 + 2 + entryCount)); int switchStart = N; itsCodeBuffer[N++] = (byte)ByteCode.TABLESWITCH; while (padSize != 0) { itsCodeBuffer[N++] = 0; --padSize; } N += 4; // skip default offset N = putInt32(low, itsCodeBuffer, N); putInt32(high, itsCodeBuffer, N); itsStackTop = (short)newStack; if (newStack > itsMaxStack) itsMaxStack = (short)newStack; if (DEBUGSTACK) { System.out.println("After "+bytecodeStr(ByteCode.TABLESWITCH) +" stack = "+itsStackTop); } return switchStart; } public final void markTableSwitchDefault(int switchStart) { addSuperBlockStart(itsCodeBufferTop); itsJumpFroms.put(itsCodeBufferTop, switchStart); setTableSwitchJump(switchStart, -1, itsCodeBufferTop); } public final void markTableSwitchCase(int switchStart, int caseIndex) { addSuperBlockStart(itsCodeBufferTop); itsJumpFroms.put(itsCodeBufferTop, switchStart); setTableSwitchJump(switchStart, caseIndex, itsCodeBufferTop); } public final void markTableSwitchCase(int switchStart, int caseIndex, int stackTop) { if (!(0 <= stackTop && stackTop <= itsMaxStack)) throw new IllegalArgumentException("Bad stack index: "+stackTop); itsStackTop = (short)stackTop; addSuperBlockStart(itsCodeBufferTop); itsJumpFroms.put(itsCodeBufferTop, switchStart); setTableSwitchJump(switchStart, caseIndex, itsCodeBufferTop); } /** * Set a jump case for a tableswitch instruction. The jump target should * be marked as a super block start for stack map generation. */ public void setTableSwitchJump(int switchStart, int caseIndex, int jumpTarget) { if (!(0 <= jumpTarget && jumpTarget <= itsCodeBufferTop)) throw new IllegalArgumentException("Bad jump target: "+jumpTarget); if (!(caseIndex >= -1)) throw new IllegalArgumentException("Bad case index: "+caseIndex); int padSize = 3 & ~switchStart; // == 3 - switchStart % 4 int caseOffset; if (caseIndex < 0) { // default label caseOffset = switchStart + 1 + padSize; } else { caseOffset = switchStart + 1 + padSize + 4 * (3 + caseIndex); } if (!(0 <= switchStart && switchStart <= itsCodeBufferTop - 4 * 4 - padSize - 1)) { throw new IllegalArgumentException( switchStart+" is outside a possible range of tableswitch" +" in already generated code"); } if ((0xFF & itsCodeBuffer[switchStart]) != ByteCode.TABLESWITCH) { throw new IllegalArgumentException( switchStart+" is not offset of tableswitch statement"); } if (!(0 <= caseOffset && caseOffset + 4 <= itsCodeBufferTop)) { // caseIndex >= -1 does not guarantee that caseOffset >= 0 due // to a possible overflow. throw new ClassFileFormatException( "Too big case index: "+caseIndex); } // ALERT: perhaps check against case bounds? putInt32(jumpTarget - switchStart, itsCodeBuffer, caseOffset); } public int acquireLabel() { int top = itsLabelTableTop; if (itsLabelTable == null || top == itsLabelTable.length) { if (itsLabelTable == null) { itsLabelTable = new int[MIN_LABEL_TABLE_SIZE]; }else { int[] tmp = new int[itsLabelTable.length * 2]; System.arraycopy(itsLabelTable, 0, tmp, 0, top); itsLabelTable = tmp; } } itsLabelTableTop = top + 1; itsLabelTable[top] = -1; return top | 0x80000000; } public void markLabel(int label) { if (!(label < 0)) throw new IllegalArgumentException("Bad label, no biscuit"); label &= 0x7FFFFFFF; if (label > itsLabelTableTop) throw new IllegalArgumentException("Bad label"); if (itsLabelTable[label] != -1) { throw new IllegalStateException("Can only mark label once"); } itsLabelTable[label] = itsCodeBufferTop; } public void markLabel(int label, short stackTop) { markLabel(label); itsStackTop = stackTop; } public void markHandler(int theLabel) { itsStackTop = 1; markLabel(theLabel); } public int getLabelPC(int label) { if (!(label < 0)) throw new IllegalArgumentException("Bad label, no biscuit"); label &= 0x7FFFFFFF; if (!(label < itsLabelTableTop)) throw new IllegalArgumentException("Bad label"); return itsLabelTable[label]; } private void addLabelFixup(int label, int fixupSite) { if (!(label < 0)) throw new IllegalArgumentException("Bad label, no biscuit"); label &= 0x7FFFFFFF; if (!(label < itsLabelTableTop)) throw new IllegalArgumentException("Bad label"); int top = itsFixupTableTop; if (itsFixupTable == null || top == itsFixupTable.length) { if (itsFixupTable == null) { itsFixupTable = new long[MIN_FIXUP_TABLE_SIZE]; }else { long[] tmp = new long[itsFixupTable.length * 2]; System.arraycopy(itsFixupTable, 0, tmp, 0, top); itsFixupTable = tmp; } } itsFixupTableTop = top + 1; itsFixupTable[top] = ((long)label << 32) | fixupSite; } private void fixLabelGotos() { byte[] codeBuffer = itsCodeBuffer; for (int i = 0; i < itsFixupTableTop; i++) { long fixup = itsFixupTable[i]; int label = (int)(fixup >> 32); int fixupSite = (int)fixup; int pc = itsLabelTable[label]; if (pc == -1) { // Unlocated label throw new RuntimeException(); } // -1 to get delta from instruction start addSuperBlockStart(pc); itsJumpFroms.put(pc, fixupSite - 1); int offset = pc - (fixupSite - 1); if ((short)offset != offset) { throw new ClassFileFormatException ("Program too complex: too big jump offset"); } codeBuffer[fixupSite] = (byte)(offset >> 8); codeBuffer[fixupSite + 1] = (byte)offset; } itsFixupTableTop = 0; } /** * Get the current offset into the code of the current method. * * @return an integer representing the offset */ public int getCurrentCodeOffset() { return itsCodeBufferTop; } public short getStackTop() { return itsStackTop; } public void setStackTop(short n) { itsStackTop = n; } public void adjustStackTop(int delta) { int newStack = itsStackTop + delta; if (newStack < 0 || Short.MAX_VALUE < newStack) badStack(newStack); itsStackTop = (short)newStack; if (newStack > itsMaxStack) itsMaxStack = (short)newStack; if (DEBUGSTACK) { System.out.println("After "+"adjustStackTop("+delta+")" +" stack = "+itsStackTop); } } private void addToCodeBuffer(int b) { int N = addReservedCodeSpace(1); itsCodeBuffer[N] = (byte)b; } private void addToCodeInt16(int value) { int N = addReservedCodeSpace(2); putInt16(value, itsCodeBuffer, N); } private int addReservedCodeSpace(int size) { if (itsCurrentMethod == null) throw new IllegalArgumentException("No method to add to"); int oldTop = itsCodeBufferTop; int newTop = oldTop + size; if (newTop > itsCodeBuffer.length) { int newSize = itsCodeBuffer.length * 2; if (newTop > newSize) { newSize = newTop; } byte[] tmp = new byte[newSize]; System.arraycopy(itsCodeBuffer, 0, tmp, 0, oldTop); itsCodeBuffer = tmp; } itsCodeBufferTop = newTop; return oldTop; } public void addExceptionHandler(int startLabel, int endLabel, int handlerLabel, String catchClassName) { if ((startLabel & 0x80000000) != 0x80000000) throw new IllegalArgumentException("Bad startLabel"); if ((endLabel & 0x80000000) != 0x80000000) throw new IllegalArgumentException("Bad endLabel"); if ((handlerLabel & 0x80000000) != 0x80000000) throw new IllegalArgumentException("Bad handlerLabel"); /* * If catchClassName is null, use 0 for the catch_type_index; which * means catch everything. (Even when the verifier has let you throw * something other than a Throwable.) */ short catch_type_index = (catchClassName == null) ? 0 : itsConstantPool.addClass(catchClassName); ExceptionTableEntry newEntry = new ExceptionTableEntry( startLabel, endLabel, handlerLabel, catch_type_index); int N = itsExceptionTableTop; if (N == 0) { itsExceptionTable = new ExceptionTableEntry[ExceptionTableSize]; } else if (N == itsExceptionTable.length) { ExceptionTableEntry[] tmp = new ExceptionTableEntry[N * 2]; System.arraycopy(itsExceptionTable, 0, tmp, 0, N); itsExceptionTable = tmp; } itsExceptionTable[N] = newEntry; itsExceptionTableTop = N + 1; } public void addLineNumberEntry(short lineNumber) { if (itsCurrentMethod == null) throw new IllegalArgumentException("No method to stop"); int N = itsLineNumberTableTop; if (N == 0) { itsLineNumberTable = new int[LineNumberTableSize]; } else if (N == itsLineNumberTable.length) { int[] tmp = new int[N * 2]; System.arraycopy(itsLineNumberTable, 0, tmp, 0, N); itsLineNumberTable = tmp; } itsLineNumberTable[N] = (itsCodeBufferTop << 16) + lineNumber; itsLineNumberTableTop = N + 1; } /** * A stack map table is a code attribute introduced in Java 6 that * gives type information at key points in the method body (namely, at * the beginning of each super block after the first). Each frame of a * stack map table contains the state of local variable and operand stack * for a given super block. */ final class StackMapTable { StackMapTable() { superBlocks = null; locals = stack = null; workList = null; rawStackMap = null; localsTop = 0; stackTop = 0; workListTop = 0; rawStackMapTop = 0; wide = false; } void generate() { superBlocks = new SuperBlock[itsSuperBlockStartsTop]; int[] initialLocals = createInitialLocals(); for (int i = 0; i < itsSuperBlockStartsTop; i++) { int start = itsSuperBlockStarts[i]; int end; if (i == itsSuperBlockStartsTop - 1) { end = itsCodeBufferTop; } else { end = itsSuperBlockStarts[i + 1]; } superBlocks[i] = new SuperBlock(i, start, end, initialLocals); } if (DEBUGSTACKMAP) { System.out.println("super blocks: "); for (int i = 0; i < superBlocks.length && superBlocks[i] != null; i++) { System.out.println("sb " + i + ": [" + superBlocks[i].getStart() + ", " + superBlocks[i].getEnd() + ")"); } } superBlockDeps = getSuperBlockDependencies(); verify(); if (DEBUGSTACKMAP) { System.out.println("type information:"); for (int i = 0; i < superBlocks.length; i++) { SuperBlock sb = superBlocks[i]; System.out.println("sb " + i + ":"); TypeInfo.print(sb.getLocals(), sb.getStack(), itsConstantPool); } } } private SuperBlock getSuperBlockFromOffset(int offset) { for (int i = 0; i < superBlocks.length; i++) { SuperBlock sb = superBlocks[i]; if (sb == null) { break; } else if (offset >= sb.getStart() && offset < sb.getEnd()) { return sb; } } throw new IllegalArgumentException("bad offset: " + offset); } /** * Determine whether or not an opcode is an actual end to a super * block. This includes any returns or unconditional jumps. */ private boolean isSuperBlockEnd(int opcode) { switch (opcode) { case ByteCode.ARETURN: case ByteCode.FRETURN: case ByteCode.IRETURN: case ByteCode.LRETURN: case ByteCode.RETURN: case ByteCode.ATHROW: case ByteCode.GOTO: case ByteCode.GOTO_W: case ByteCode.TABLESWITCH: case ByteCode.LOOKUPSWITCH: return true; default: return false; } } /** * Calculate partial dependencies for super blocks. * * This is used as a workaround for dead code that is generated. Only * one dependency per super block is given. */ private SuperBlock[] getSuperBlockDependencies() { SuperBlock[] deps = new SuperBlock[superBlocks.length]; for (int i = 0; i < itsExceptionTableTop; i++) { ExceptionTableEntry ete = itsExceptionTable[i]; short startPC = (short) getLabelPC(ete.itsStartLabel); short handlerPC = (short) getLabelPC(ete.itsHandlerLabel); SuperBlock handlerSB = getSuperBlockFromOffset(handlerPC); SuperBlock dep = getSuperBlockFromOffset(startPC); deps[handlerSB.getIndex()] = dep; } int[] targetPCs = itsJumpFroms.getKeys(); for (int i = 0; i < targetPCs.length; i++) { int targetPC = targetPCs[i]; int branchPC = itsJumpFroms.getInt(targetPC, -1); SuperBlock branchSB = getSuperBlockFromOffset(branchPC); SuperBlock targetSB = getSuperBlockFromOffset(targetPC); deps[targetSB.getIndex()] = branchSB; } return deps; } /** * Get the target super block of a branch instruction. * * @param bci the index of the branch instruction in the code buffer */ private SuperBlock getBranchTarget(int bci) { int target; if ((itsCodeBuffer[bci] & 0xFF) == ByteCode.GOTO_W) { target = bci + getOperand(bci + 1, 4); } else { target = bci + (short) getOperand(bci + 1, 2); } return getSuperBlockFromOffset(target); } /** * Determine whether or not an opcode is a conditional or unconditional * jump. */ private boolean isBranch(int opcode) { switch (opcode) { case ByteCode.GOTO: case ByteCode.GOTO_W: case ByteCode.IFEQ: case ByteCode.IFGE: case ByteCode.IFGT: case ByteCode.IFLE: case ByteCode.IFLT: case ByteCode.IFNE: case ByteCode.IFNONNULL: case ByteCode.IFNULL: case ByteCode.IF_ACMPEQ: case ByteCode.IF_ACMPNE: case ByteCode.IF_ICMPEQ: case ByteCode.IF_ICMPGE: case ByteCode.IF_ICMPGT: case ByteCode.IF_ICMPLE: case ByteCode.IF_ICMPLT: case ByteCode.IF_ICMPNE: return true; default: return false; } } private int getOperand(int offset) { return getOperand(offset, 1); } /** * Extract a logical operand from the byte code. * * This is used, for example, to get branch offsets. */ private int getOperand(int start, int size) { int result = 0; if (size > 4) { throw new IllegalArgumentException("bad operand size"); } for (int i = 0; i < size; i++) { result = (result << 8) | (itsCodeBuffer[start + i] & 0xFF); } return result; } /** * Calculate initial local variable and op stack types for each super * block in the method. */ private void verify() { int[] initialLocals = createInitialLocals(); superBlocks[0].merge(initialLocals, initialLocals.length, new int[0], 0, itsConstantPool); // Start from the top of the method and queue up block dependencies // as they come along. workList = new SuperBlock[] { superBlocks[0] }; workListTop = 1; executeWorkList(); // Replace dead code with no-ops. for (int i = 0; i < superBlocks.length; i++) { SuperBlock sb = superBlocks[i]; if (!sb.isInitialized()) { killSuperBlock(sb); } } executeWorkList(); } /** * Replace the contents of a super block with no-ops. * * The above description is not strictly true; the last instruction is * an athrow instruction. This technique is borrowed from ASM's * developer guide: http://asm.ow2.org/doc/developer-guide.html#deadcode * * The proposed algorithm fills a block with nop, ending it with an * athrow. The stack map generated would be empty locals with an * exception on the stack. In theory, it shouldn't matter what the * locals are, as long as the stack has an exception for the athrow bit. * However, it turns out that if the code being modified falls into an * exception handler, it causes problems. Therefore, if it does, then * we steal the locals from the exception block. * * If the block itself is an exception handler, we remove it from the * exception table to simplify block dependencies. */ private void killSuperBlock(SuperBlock sb) { int[] locals = new int[0]; int[] stack = new int[] { TypeInfo.OBJECT("java/lang/Throwable", itsConstantPool) }; // If the super block is handled by any exception handler, use its // locals as the killed block's locals. Ignore uninitialized // handlers, because they will also be killed and removed from the // exception table. for (int i = 0; i < itsExceptionTableTop; i++) { ExceptionTableEntry ete = itsExceptionTable[i]; int eteStart = getLabelPC(ete.itsStartLabel); int eteEnd = getLabelPC(ete.itsEndLabel); int handlerPC = getLabelPC(ete.itsHandlerLabel); SuperBlock handlerSB = getSuperBlockFromOffset(handlerPC); if ((sb.getStart() > eteStart && sb.getStart() < eteEnd) || (eteStart > sb.getStart() && eteStart < sb.getEnd()) && handlerSB.isInitialized()) { locals = handlerSB.getLocals(); break; } } // Remove any exception table entry whose handler is the killed // block. This removes block dependencies to make stack maps for // dead blocks easier to create. for (int i = 0; i < itsExceptionTableTop; i++) { ExceptionTableEntry ete = itsExceptionTable[i]; int eteStart = getLabelPC(ete.itsStartLabel); if (eteStart == sb.getStart()) { for (int j = i + 1; j < itsExceptionTableTop; j++) { itsExceptionTable[j - 1] = itsExceptionTable[j]; } itsExceptionTableTop--; i--; } } sb.merge(locals, locals.length, stack, stack.length, itsConstantPool); int end = sb.getEnd() - 1; itsCodeBuffer[end] = (byte) ByteCode.ATHROW; for (int bci = sb.getStart(); bci < end; bci++) { itsCodeBuffer[bci] = (byte) ByteCode.NOP; } } private void executeWorkList() { while (workListTop > 0) { SuperBlock work = workList[--workListTop]; work.setInQueue(false); locals = work.getLocals(); stack = work.getStack(); localsTop = locals.length; stackTop = stack.length; executeBlock(work); } } /** * Simulate the local variable and op stack for a super block. */ private void executeBlock(SuperBlock work) { int bc = 0; int next = 0; if (DEBUGSTACKMAP) { System.out.println("working on sb " + work.getIndex()); System.out.println("initial type state:"); TypeInfo.print(locals, localsTop, stack, stackTop, itsConstantPool); } for (int bci = work.getStart(); bci < work.getEnd(); bci += next) { bc = itsCodeBuffer[bci] & 0xFF; next = execute(bci); // If we have a branch to some super block, we need to merge // the current state of the local table and op stack with what's // currently stored as the initial state of the super block. If // something actually changed, we need to add it to the work // list. if (isBranch(bc)) { SuperBlock targetSB = getBranchTarget(bci); if (DEBUGSTACKMAP) { System.out.println("sb " + work.getIndex() + " points to sb " + targetSB.getIndex() + " (offset " + bci + " -> " + targetSB.getStart() + ")"); System.out.println("type state at " + bci + ":"); TypeInfo.print(locals, localsTop, stack, stackTop, itsConstantPool); } flowInto(targetSB); if (DEBUGSTACKMAP) { System.out.println("type state of " + targetSB + " after merge:"); TypeInfo.print(targetSB.getLocals(), targetSB.getStack(), itsConstantPool); } } else if (bc == ByteCode.TABLESWITCH) { int switchStart = bci + 1 + (3 & ~bci); // 3 - bci % 4 int defaultOffset = getOperand(switchStart, 4); SuperBlock targetSB = getSuperBlockFromOffset(bci + defaultOffset); if (DEBUGSTACK) { System.out.println("merging sb " + work.getIndex() + " with sb " + targetSB.getIndex()); } flowInto(targetSB); int low = getOperand(switchStart + 4, 4); int high = getOperand(switchStart + 8, 4); int numCases = high - low + 1; int caseBase = switchStart + 12; for (int i = 0; i < numCases; i++) { int label = bci + getOperand(caseBase + 4 * i, 4); targetSB = getSuperBlockFromOffset(label); if (DEBUGSTACKMAP) { System.out.println("merging sb " + work.getIndex() + " with sb " + targetSB.getIndex()); } flowInto(targetSB); } } for (int i = 0; i < itsExceptionTableTop; i++) { ExceptionTableEntry ete = itsExceptionTable[i]; short startPC = (short) getLabelPC(ete.itsStartLabel); short endPC = (short) getLabelPC(ete.itsEndLabel); if (bci < startPC || bci >= endPC) { continue; } short handlerPC = (short) getLabelPC(ete.itsHandlerLabel); SuperBlock sb = getSuperBlockFromOffset(handlerPC); int exceptionType; if (ete.itsCatchType == 0) { exceptionType = TypeInfo.OBJECT( itsConstantPool.addClass("java/lang/Throwable")); } else { exceptionType = TypeInfo.OBJECT(ete.itsCatchType); } sb.merge(locals, localsTop, new int[] { exceptionType }, 1, itsConstantPool); addToWorkList(sb); } } if (DEBUGSTACKMAP) { System.out.println("end of sb " + work.getIndex() + ":"); TypeInfo.print(locals, localsTop, stack, stackTop, itsConstantPool); } // Check the last instruction to see if it is a true end of a // super block (ie., if the instruction is a return). If it // isn't, we need to continue processing the next chunk. if (!isSuperBlockEnd(bc)) { int nextIndex = work.getIndex() + 1; if (nextIndex < superBlocks.length) { if (DEBUGSTACKMAP) { System.out.println("continuing from sb " + work.getIndex() + " into sb " + nextIndex); } flowInto(superBlocks[nextIndex]); } } } /** * Perform a merge of type state and add the super block to the work * list if the merge changed anything. */ private void flowInto(SuperBlock sb) { if (sb.merge(locals, localsTop, stack, stackTop, itsConstantPool)) { addToWorkList(sb); } } private void addToWorkList(SuperBlock sb) { if (!sb.isInQueue()) { sb.setInQueue(true); sb.setInitialized(true); if (workListTop == workList.length) { SuperBlock[] tmp = new SuperBlock[workListTop * 2]; System.arraycopy(workList, 0, tmp, 0, workListTop); workList = tmp; } workList[workListTop++] = sb; } } /** * Execute a single byte code instruction. * * @param bci the index of the byte code instruction to execute * @return the length of the byte code instruction */ private int execute(int bci) { int bc = itsCodeBuffer[bci] & 0xFF; int type, type2, index; int length = 0; long lType, lType2; String className; switch (bc) { case ByteCode.NOP: case ByteCode.IINC: case ByteCode.GOTO: case ByteCode.GOTO_W: // No change break; case ByteCode.CHECKCAST: pop(); push(TypeInfo.OBJECT(getOperand(bci + 1, 2))); break; case ByteCode.IASTORE: // pop; pop; pop case ByteCode.LASTORE: case ByteCode.FASTORE: case ByteCode.DASTORE: case ByteCode.AASTORE: case ByteCode.BASTORE: case ByteCode.CASTORE: case ByteCode.SASTORE: pop(); case ByteCode.PUTFIELD: // pop; pop case ByteCode.IF_ICMPEQ: case ByteCode.IF_ICMPNE: case ByteCode.IF_ICMPLT: case ByteCode.IF_ICMPGE: case ByteCode.IF_ICMPGT: case ByteCode.IF_ICMPLE: case ByteCode.IF_ACMPEQ: case ByteCode.IF_ACMPNE: pop(); case ByteCode.IFEQ: // pop case ByteCode.IFNE: case ByteCode.IFLT: case ByteCode.IFGE: case ByteCode.IFGT: case ByteCode.IFLE: case ByteCode.IFNULL: case ByteCode.IFNONNULL: case ByteCode.POP: case ByteCode.MONITORENTER: case ByteCode.MONITOREXIT: case ByteCode.PUTSTATIC: pop(); break; case ByteCode.POP2: pop2(); break; case ByteCode.ACONST_NULL: push(TypeInfo.NULL); break; case ByteCode.IALOAD: // pop; pop; push(INTEGER) case ByteCode.BALOAD: case ByteCode.CALOAD: case ByteCode.SALOAD: case ByteCode.IADD: case ByteCode.ISUB: case ByteCode.IMUL: case ByteCode.IDIV: case ByteCode.IREM: case ByteCode.ISHL: case ByteCode.ISHR: case ByteCode.IUSHR: case ByteCode.IAND: case ByteCode.IOR: case ByteCode.IXOR: case ByteCode.LCMP: case ByteCode.FCMPL: case ByteCode.FCMPG: case ByteCode.DCMPL: case ByteCode.DCMPG: pop(); case ByteCode.INEG: // pop; push(INTEGER) case ByteCode.L2I: case ByteCode.F2I: case ByteCode.D2I: case ByteCode.I2B: case ByteCode.I2C: case ByteCode.I2S: case ByteCode.ARRAYLENGTH: case ByteCode.INSTANCEOF: pop(); case ByteCode.ICONST_M1: // push(INTEGER) case ByteCode.ICONST_0: case ByteCode.ICONST_1: case ByteCode.ICONST_2: case ByteCode.ICONST_3: case ByteCode.ICONST_4: case ByteCode.ICONST_5: case ByteCode.ILOAD: case ByteCode.ILOAD_0: case ByteCode.ILOAD_1: case ByteCode.ILOAD_2: case ByteCode.ILOAD_3: case ByteCode.BIPUSH: case ByteCode.SIPUSH: push(TypeInfo.INTEGER); break; case ByteCode.LALOAD: // pop; pop; push(LONG) case ByteCode.LADD: case ByteCode.LSUB: case ByteCode.LMUL: case ByteCode.LDIV: case ByteCode.LREM: case ByteCode.LSHL: case ByteCode.LSHR: case ByteCode.LUSHR: case ByteCode.LAND: case ByteCode.LOR: case ByteCode.LXOR: pop(); case ByteCode.LNEG: // pop; push(LONG) case ByteCode.I2L: case ByteCode.F2L: case ByteCode.D2L: pop(); case ByteCode.LCONST_0: // push(LONG) case ByteCode.LCONST_1: case ByteCode.LLOAD: case ByteCode.LLOAD_0: case ByteCode.LLOAD_1: case ByteCode.LLOAD_2: case ByteCode.LLOAD_3: push(TypeInfo.LONG); break; case ByteCode.FALOAD: // pop; pop; push(FLOAT) case ByteCode.FADD: case ByteCode.FSUB: case ByteCode.FMUL: case ByteCode.FDIV: case ByteCode.FREM: pop(); case ByteCode.FNEG: // pop; push(FLOAT) case ByteCode.I2F: case ByteCode.L2F: case ByteCode.D2F: pop(); case ByteCode.FCONST_0: // push(FLOAT) case ByteCode.FCONST_1: case ByteCode.FCONST_2: case ByteCode.FLOAD: case ByteCode.FLOAD_0: case ByteCode.FLOAD_1: case ByteCode.FLOAD_2: case ByteCode.FLOAD_3: push(TypeInfo.FLOAT); break; case ByteCode.DALOAD: // pop; pop; push(DOUBLE) case ByteCode.DADD: case ByteCode.DSUB: case ByteCode.DMUL: case ByteCode.DDIV: case ByteCode.DREM: pop(); case ByteCode.DNEG: // pop; push(DOUBLE) case ByteCode.I2D: case ByteCode.L2D: case ByteCode.F2D: pop(); case ByteCode.DCONST_0: // push(DOUBLE) case ByteCode.DCONST_1: case ByteCode.DLOAD: case ByteCode.DLOAD_0: case ByteCode.DLOAD_1: case ByteCode.DLOAD_2: case ByteCode.DLOAD_3: push(TypeInfo.DOUBLE); break; case ByteCode.ISTORE: executeStore(getOperand(bci + 1, wide ? 2 : 1), TypeInfo.INTEGER); break; case ByteCode.ISTORE_0: case ByteCode.ISTORE_1: case ByteCode.ISTORE_2: case ByteCode.ISTORE_3: executeStore(bc - ByteCode.ISTORE_0, TypeInfo.INTEGER); break; case ByteCode.LSTORE: executeStore(getOperand(bci + 1, wide ? 2 : 1), TypeInfo.LONG); break; case ByteCode.LSTORE_0: case ByteCode.LSTORE_1: case ByteCode.LSTORE_2: case ByteCode.LSTORE_3: executeStore(bc - ByteCode.LSTORE_0, TypeInfo.LONG); break; case ByteCode.FSTORE: executeStore(getOperand(bci + 1, wide ? 2 : 1), TypeInfo.FLOAT); break; case ByteCode.FSTORE_0: case ByteCode.FSTORE_1: case ByteCode.FSTORE_2: case ByteCode.FSTORE_3: executeStore(bc - ByteCode.FSTORE_0, TypeInfo.FLOAT); break; case ByteCode.DSTORE: executeStore(getOperand(bci + 1, wide ? 2 : 1), TypeInfo.DOUBLE); break; case ByteCode.DSTORE_0: case ByteCode.DSTORE_1: case ByteCode.DSTORE_2: case ByteCode.DSTORE_3: executeStore(bc - ByteCode.DSTORE_0, TypeInfo.DOUBLE); break; case ByteCode.ALOAD: executeALoad(getOperand(bci + 1, wide ? 2 : 1)); break; case ByteCode.ALOAD_0: case ByteCode.ALOAD_1: case ByteCode.ALOAD_2: case ByteCode.ALOAD_3: executeALoad(bc - ByteCode.ALOAD_0); break; case ByteCode.ASTORE: executeAStore(getOperand(bci + 1, wide ? 2 : 1)); break; case ByteCode.ASTORE_0: case ByteCode.ASTORE_1: case ByteCode.ASTORE_2: case ByteCode.ASTORE_3: executeAStore(bc - ByteCode.ASTORE_0); break; case ByteCode.IRETURN: case ByteCode.LRETURN: case ByteCode.FRETURN: case ByteCode.DRETURN: case ByteCode.ARETURN: case ByteCode.RETURN: clearStack(); break; case ByteCode.ATHROW: type = pop(); clearStack(); push(type); break; case ByteCode.SWAP: type = pop(); type2 = pop(); push(type); push(type2); break; case ByteCode.LDC: case ByteCode.LDC_W: case ByteCode.LDC2_W: if (bc == ByteCode.LDC) { index = getOperand(bci + 1); } else { index = getOperand(bci + 1, 2); } byte constType = itsConstantPool.getConstantType(index); switch (constType) { case ConstantPool.CONSTANT_Double: push(TypeInfo.DOUBLE); break; case ConstantPool.CONSTANT_Float: push(TypeInfo.FLOAT); break; case ConstantPool.CONSTANT_Long: push(TypeInfo.LONG); break; case ConstantPool.CONSTANT_Integer: push(TypeInfo.INTEGER); break; case ConstantPool.CONSTANT_String: push(TypeInfo.OBJECT("java/lang/String", itsConstantPool)); break; default: throw new IllegalArgumentException( "bad const type " + constType); } break; case ByteCode.NEW: push(TypeInfo.UNINITIALIZED_VARIABLE(bci)); break; case ByteCode.NEWARRAY: pop(); char componentType = arrayTypeToName(itsCodeBuffer[bci + 1]); index = itsConstantPool.addClass("[" + componentType); push(TypeInfo.OBJECT((short) index)); break; case ByteCode.ANEWARRAY: index = getOperand(bci + 1, 2); className = (String) itsConstantPool.getConstantData(index); pop(); push(TypeInfo.OBJECT("[L" + className + ';', itsConstantPool)); break; case ByteCode.INVOKEVIRTUAL: case ByteCode.INVOKESPECIAL: case ByteCode.INVOKESTATIC: case ByteCode.INVOKEINTERFACE: index = getOperand(bci + 1, 2); FieldOrMethodRef m = (FieldOrMethodRef) itsConstantPool.getConstantData(index); String methodType = m.getType(); String methodName = m.getName(); int parameterCount = sizeOfParameters(methodType) >>> 16; for (int i = 0; i < parameterCount; i++) { pop(); } if (bc != ByteCode.INVOKESTATIC) { int instType = pop(); int tag = TypeInfo.getTag(instType); if (tag == TypeInfo.UNINITIALIZED_VARIABLE(0) || tag == TypeInfo.UNINITIALIZED_THIS) { if ("".equals(methodName)) { int newType = TypeInfo.OBJECT(itsThisClassIndex); initializeTypeInfo(instType, newType); } else { throw new IllegalStateException("bad instance"); } } } int rParen = methodType.indexOf(')'); String returnType = methodType.substring(rParen + 1); returnType = descriptorToInternalName(returnType); if (!returnType.equals("V")) { push(TypeInfo.fromType(returnType, itsConstantPool)); } break; case ByteCode.GETFIELD: pop(); case ByteCode.GETSTATIC: index = getOperand(bci + 1, 2); FieldOrMethodRef f = (FieldOrMethodRef) itsConstantPool.getConstantData(index); String fieldType = descriptorToInternalName(f.getType()); push(TypeInfo.fromType(fieldType, itsConstantPool)); break; case ByteCode.DUP: type = pop(); push(type); push(type); break; case ByteCode.DUP_X1: type = pop(); type2 = pop(); push(type); push(type2); push(type); break; case ByteCode.DUP_X2: type = pop(); lType = pop2(); push(type); push2(lType); push(type); break; case ByteCode.DUP2: lType = pop2(); push2(lType); push2(lType); break; case ByteCode.DUP2_X1: lType = pop2(); type = pop(); push2(lType); push(type); push2(lType); break; case ByteCode.DUP2_X2: lType = pop2(); lType2 = pop2(); push2(lType); push2(lType2); push2(lType); break; case ByteCode.TABLESWITCH: int switchStart = bci + 1 + (3 & ~bci); int low = getOperand(switchStart + 4, 4); int high = getOperand(switchStart + 8, 4); length = 4 * (high - low + 4) + switchStart - bci; pop(); break; case ByteCode.AALOAD: pop(); int typeIndex = pop() >>> 8; className = (String) itsConstantPool.getConstantData(typeIndex); String arrayType = className; if (arrayType.charAt(0) != '[') { throw new IllegalStateException("bad array type"); } String elementDesc = arrayType.substring(1); String elementType = descriptorToInternalName(elementDesc); typeIndex = itsConstantPool.addClass(elementType); push(TypeInfo.OBJECT(typeIndex)); break; case ByteCode.WIDE: // Alters behaviour of next instruction wide = true; break; case ByteCode.MULTIANEWARRAY: case ByteCode.LOOKUPSWITCH: // Currently not used in any part of Rhino, so ignore it case ByteCode.JSR: // TODO: JSR is deprecated case ByteCode.RET: case ByteCode.JSR_W: default: throw new IllegalArgumentException("bad opcode: " + bc); } if (length == 0) { length = opcodeLength(bc, wide); } if (wide && bc != ByteCode.WIDE) { wide = false; } return length; } private void executeALoad(int localIndex) { int type = getLocal(localIndex); int tag = TypeInfo.getTag(type); if (tag == TypeInfo.OBJECT_TAG || tag == TypeInfo.UNINITIALIZED_THIS || tag == TypeInfo.UNINITIALIZED_VAR_TAG || tag == TypeInfo.NULL) { push(type); } else { throw new IllegalStateException("bad local variable type: " + type + " at index: " + localIndex); } } private void executeAStore(int localIndex) { setLocal(localIndex, pop()); } private void executeStore(int localIndex, int typeInfo) { pop(); setLocal(localIndex, typeInfo); } /** * Change an UNINITIALIZED_OBJECT or UNINITIALIZED_THIS to the proper * type of the object. This occurs when the proper constructor is * invoked. */ private void initializeTypeInfo(int prevType, int newType) { initializeTypeInfo(prevType, newType, locals, localsTop); initializeTypeInfo(prevType, newType, stack, stackTop); } private void initializeTypeInfo(int prevType, int newType, int[] data, int dataTop) { for (int i = 0; i < dataTop; i++) { if (data[i] == prevType) { data[i] = newType; } } } private int getLocal(int localIndex) { if (localIndex < localsTop) { return locals[localIndex]; } else { return TypeInfo.TOP; } } private void setLocal(int localIndex, int typeInfo) { if (localIndex >= localsTop) { int[] tmp = new int[localIndex + 1]; System.arraycopy(locals, 0, tmp, 0, localsTop); locals = tmp; localsTop = localIndex + 1; } locals[localIndex] = typeInfo; } private void push(int typeInfo) { if (stackTop == stack.length) { int[] tmp = new int[Math.max(stackTop * 2, 4)]; System.arraycopy(stack, 0, tmp, 0, stackTop); stack = tmp; } stack[stackTop++] = typeInfo; } private int pop() { return stack[--stackTop]; } /** * Push two words onto the op stack. * * This is only meant to be used as a complement to pop2(), and both * methods are helpers for the more complex DUP operations. */ private void push2(long typeInfo) { push((int) (typeInfo & 0xFFFFFF)); typeInfo >>>= 32; if (typeInfo != 0) { push((int) (typeInfo & 0xFFFFFF)); } } /** * Pop two words from the op stack. * * If the top of the stack is a DOUBLE or LONG, then the bottom 32 bits * reflects the appropriate type and the top 32 bits are 0. Otherwise, * the top 32 bits are the first word on the stack and the lower 32 * bits are the second word on the stack. */ private long pop2() { long type = pop(); if (TypeInfo.isTwoWords((int) type)) { return type; } else { return type << 32 | (pop() & 0xFFFFFF); } } private void clearStack() { stackTop = 0; } /** * Compute the output size of the stack map table. * * Because this would share much in common with actual writing of the * stack map table, we instead just write the stack map table to a * buffer and return the size from it. The buffer is later used in * the actual writing of bytecode. */ int computeWriteSize() { // Allocate a buffer that can handle the worst case size of the // stack map to prevent lots of reallocations. int writeSize = getWorstCaseWriteSize(); rawStackMap = new byte[writeSize]; computeRawStackMap(); return rawStackMapTop + 2; } int write(byte[] data, int offset) { offset = putInt32(rawStackMapTop + 2, data, offset); offset = putInt16(superBlocks.length - 1, data, offset); System.arraycopy(rawStackMap, 0, data, offset, rawStackMapTop); return offset + rawStackMapTop; } /** * Compute a space-optimal stack map table. */ private void computeRawStackMap() { SuperBlock prev = superBlocks[0]; int[] prevLocals = prev.getTrimmedLocals(); int prevOffset = -1; for (int i = 1; i < superBlocks.length; i++) { SuperBlock current = superBlocks[i]; int[] currentLocals = current.getTrimmedLocals(); int[] currentStack = current.getStack(); int offsetDelta = current.getStart() - prevOffset - 1; if (currentStack.length == 0) { int last = prevLocals.length > currentLocals.length ? currentLocals.length : prevLocals.length; int delta = Math.abs(prevLocals.length - currentLocals.length); int j; // Compare locals until one is different or the end of a // local variable array is reached for (j = 0; j < last; j++) { if (prevLocals[j] != currentLocals[j]) { break; } } if (j == currentLocals.length && delta == 0) { // All of the compared locals are equal and the local // arrays are of equal size writeSameFrame(currentLocals, offsetDelta); } else if (j == currentLocals.length && delta <= 3) { // All of the compared locals are equal and the current // frame has less locals than the previous frame writeChopFrame(delta, offsetDelta); } else if (j == prevLocals.length && delta <= 3) { // All of the compared locals are equal and the current // frame has more locals than the previous frame writeAppendFrame(currentLocals, delta, offsetDelta); } else { // Not all locals were compared were equal, so a full // frame is necessary writeFullFrame(currentLocals, currentStack, offsetDelta); } } else if (currentStack.length == 1) { if (Arrays.equals(prevLocals, currentLocals)) { writeSameLocalsOneStackItemFrame(currentLocals, currentStack, offsetDelta); } else { // Output a full frame, since no other frame types have // one operand stack item. writeFullFrame(currentLocals, currentStack, offsetDelta); } } else { // Any stack map frame that has more than one operand stack // item has to be a full frame. All other frame types have // at most one item on the stack. writeFullFrame(currentLocals, currentStack, offsetDelta); } prev = current; prevLocals = currentLocals; prevOffset = current.getStart(); } } /** * Get the worst case write size of the stack map table. * * This computes how much full frames would take, if each full frame * contained the maximum number of locals and stack operands, and each * verification type was 3 bytes. */ private int getWorstCaseWriteSize() { return (superBlocks.length - 1) * (7 + itsMaxLocals * 3 + itsMaxStack * 3); } private void writeSameFrame(int[] locals, int offsetDelta) { if (offsetDelta <= 63) { // Output a same_frame frame. Despite the name, // the operand stack may differ, but the current // operand stack must be empty. rawStackMap[rawStackMapTop++] = (byte) offsetDelta; } else { // Output a same_frame_extended frame. Similar to // the above, except with a larger offset delta. rawStackMap[rawStackMapTop++] = (byte) 251; rawStackMapTop = putInt16(offsetDelta, rawStackMap, rawStackMapTop); } } private void writeSameLocalsOneStackItemFrame(int[] locals, int[] stack, int offsetDelta) { if (offsetDelta <= 63) { // Output a same_locals_1_stack_item frame. Similar // to same_frame, only with one item on the operand // stack instead of zero. rawStackMap[rawStackMapTop++] = (byte) (64 + offsetDelta); } else { // Output a same_locals_1_stack_item_extended frame. // Similar to same_frame_extended, only with one // item on the operand stack instead of zero. rawStackMap[rawStackMapTop++] = (byte) 247; rawStackMapTop = putInt16(offsetDelta, rawStackMap, rawStackMapTop); } writeType(stack[0]); } private void writeFullFrame(int[] locals, int[] stack, int offsetDelta) { rawStackMap[rawStackMapTop++] = (byte) 255; rawStackMapTop = putInt16(offsetDelta, rawStackMap, rawStackMapTop); rawStackMapTop = putInt16(locals.length, rawStackMap, rawStackMapTop); rawStackMapTop = writeTypes(locals); rawStackMapTop = putInt16(stack.length, rawStackMap, rawStackMapTop); rawStackMapTop = writeTypes(stack); } private void writeAppendFrame(int[] locals, int localsDelta, int offsetDelta) { int start = locals.length - localsDelta; rawStackMap[rawStackMapTop++] = (byte) (251 + localsDelta); rawStackMapTop = putInt16(offsetDelta, rawStackMap, rawStackMapTop); rawStackMapTop = writeTypes(locals, start); } private void writeChopFrame(int localsDelta, int offsetDelta) { rawStackMap[rawStackMapTop++] = (byte) (251 - localsDelta); rawStackMapTop = putInt16(offsetDelta, rawStackMap, rawStackMapTop); } private int writeTypes(int[] types) { return writeTypes(types, 0); } private int writeTypes(int[] types, int start) { int startOffset = rawStackMapTop; for (int i = start; i < types.length; i++) { rawStackMapTop = writeType(types[i]); } return rawStackMapTop; } private int writeType(int type) { int tag = type & 0xFF; rawStackMap[rawStackMapTop++] = (byte) tag; if (tag == TypeInfo.OBJECT_TAG || tag == TypeInfo.UNINITIALIZED_VAR_TAG) { rawStackMapTop = putInt16(type >>> 8, rawStackMap, rawStackMapTop); } return rawStackMapTop; } // Intermediate operand stack and local variable state. During // execution of a block, these are initialized to copies of the initial // block type state and are modified by the actual stack/local // emulation. private int[] locals; private int localsTop; private int[] stack; private int stackTop; private SuperBlock[] workList; private int workListTop; private SuperBlock[] superBlocks; private SuperBlock[] superBlockDeps; private byte[] rawStackMap; private int rawStackMapTop; private boolean wide; static final boolean DEBUGSTACKMAP = false; } /** * Convert a newarray operand into an internal type. */ private static char arrayTypeToName(int type) { switch (type) { case ByteCode.T_BOOLEAN: return 'Z'; case ByteCode.T_CHAR: return 'C'; case ByteCode.T_FLOAT: return 'F'; case ByteCode.T_DOUBLE: return 'D'; case ByteCode.T_BYTE: return 'B'; case ByteCode.T_SHORT: return 'S'; case ByteCode.T_INT: return 'I'; case ByteCode.T_LONG: return 'J'; default: throw new IllegalArgumentException("bad operand"); } } /** * Convert a class descriptor into an internal name. * * For example, descriptor Ljava/lang/Object; becomes java/lang/Object. */ private static String classDescriptorToInternalName(String descriptor) { return descriptor.substring(1, descriptor.length() - 1); } /** * Convert a non-method type descriptor into an internal type. * * @param descriptor the simple type descriptor to convert */ private static String descriptorToInternalName(String descriptor) { switch (descriptor.charAt(0)) { case 'B': case 'C': case 'D': case 'F': case 'I': case 'J': case 'S': case 'Z': case 'V': case '[': return descriptor; case 'L': return classDescriptorToInternalName(descriptor); default: throw new IllegalArgumentException("bad descriptor:" + descriptor); } } /** * Compute the initial local variable array for the current method. * * Creates an array of the size of the method's max locals, regardless of * the number of parameters in the method. */ private int[] createInitialLocals() { int[] initialLocals = new int[itsMaxLocals]; int localsTop = 0; // Instance methods require the first local variable in the array // to be "this". However, if the method being created is a // constructor, aka the method is , then the type of "this" // should be StackMapTable.UNINITIALIZED_THIS if ((itsCurrentMethod.getFlags() & ACC_STATIC) == 0) { if ("".equals(itsCurrentMethod.getName())) { initialLocals[localsTop++] = TypeInfo.UNINITIALIZED_THIS; } else { initialLocals[localsTop++] = TypeInfo.OBJECT(itsThisClassIndex); } } // No error checking should be necessary, sizeOfParameters does this String type = itsCurrentMethod.getType(); int lParenIndex = type.indexOf('('); int rParenIndex = type.indexOf(')'); if (lParenIndex != 0 || rParenIndex < 0) { throw new IllegalArgumentException("bad method type"); } int start = lParenIndex + 1; StringBuilder paramType = new StringBuilder(); while (start < rParenIndex) { switch (type.charAt(start)) { case 'B': case 'C': case 'D': case 'F': case 'I': case 'J': case 'S': case 'Z': paramType.append(type.charAt(start)); ++start; break; case 'L': int end = type.indexOf(';', start) + 1; String name = type.substring(start, end); paramType.append(name); start = end; break; case '[': paramType.append('['); ++start; continue; } String internalType = descriptorToInternalName(paramType.toString()); int typeInfo = TypeInfo.fromType(internalType, itsConstantPool); initialLocals[localsTop++] = typeInfo; if (TypeInfo.isTwoWords(typeInfo)) { localsTop++; } paramType.setLength(0); } return initialLocals; } /** * Write the class file to the OutputStream. * * @param oStream the stream to write to * @throws IOException if writing to the stream produces an exception */ public void write(OutputStream oStream) throws IOException { byte[] array = toByteArray(); oStream.write(array); } private int getWriteSize() { int size = 0; if (itsSourceFileNameIndex != 0) { itsConstantPool.addUtf8("SourceFile"); } size += 8; //writeLong(FileHeaderConstant); size += itsConstantPool.getWriteSize(); size += 2; //writeShort(itsFlags); size += 2; //writeShort(itsThisClassIndex); size += 2; //writeShort(itsSuperClassIndex); size += 2; //writeShort(itsInterfaces.size()); size += 2 * itsInterfaces.size(); size += 2; //writeShort(itsFields.size()); for (int i = 0; i < itsFields.size(); i++) { size += ((ClassFileField)(itsFields.get(i))).getWriteSize(); } size += 2; //writeShort(itsMethods.size()); for (int i = 0; i < itsMethods.size(); i++) { size += ((ClassFileMethod)(itsMethods.get(i))).getWriteSize(); } if (itsSourceFileNameIndex != 0) { size += 2; //writeShort(1); attributes count size += 2; //writeShort(sourceFileAttributeNameIndex); size += 4; //writeInt(2); size += 2; //writeShort(itsSourceFileNameIndex); }else { size += 2; //out.writeShort(0); no attributes } return size; } /** * Get the class file as array of bytesto the OutputStream. */ public byte[] toByteArray() { int dataSize = getWriteSize(); byte[] data = new byte[dataSize]; int offset = 0; short sourceFileAttributeNameIndex = 0; if (itsSourceFileNameIndex != 0) { sourceFileAttributeNameIndex = itsConstantPool.addUtf8( "SourceFile"); } offset = putInt32(FileHeaderConstant, data, offset); offset = putInt16(MinorVersion, data, offset); offset = putInt16(MajorVersion, data, offset); offset = itsConstantPool.write(data, offset); offset = putInt16(itsFlags, data, offset); offset = putInt16(itsThisClassIndex, data, offset); offset = putInt16(itsSuperClassIndex, data, offset); offset = putInt16(itsInterfaces.size(), data, offset); for (int i = 0; i < itsInterfaces.size(); i++) { int interfaceIndex = ((Short)(itsInterfaces.get(i))).shortValue(); offset = putInt16(interfaceIndex, data, offset); } offset = putInt16(itsFields.size(), data, offset); for (int i = 0; i < itsFields.size(); i++) { ClassFileField field = (ClassFileField)itsFields.get(i); offset = field.write(data, offset); } offset = putInt16(itsMethods.size(), data, offset); for (int i = 0; i < itsMethods.size(); i++) { ClassFileMethod method = (ClassFileMethod)itsMethods.get(i); offset = method.write(data, offset); } if (itsSourceFileNameIndex != 0) { offset = putInt16(1, data, offset); // attributes count offset = putInt16(sourceFileAttributeNameIndex, data, offset); offset = putInt32(2, data, offset); offset = putInt16(itsSourceFileNameIndex, data, offset); } else { offset = putInt16(0, data, offset); // no attributes } if (offset != dataSize) { // Check getWriteSize is consistent with write! throw new RuntimeException(); } return data; } static int putInt64(long value, byte[] array, int offset) { offset = putInt32((int)(value >>> 32), array, offset); return putInt32((int)value, array, offset); } private static void badStack(int value) { String s; if (value < 0) { s = "Stack underflow: "+value; } else { s = "Too big stack: "+value; } throw new IllegalStateException(s); } /* Really weird. Returns an int with # parameters in hi 16 bits, and stack difference removal of parameters from stack and pushing the result (it does not take into account removal of this in case of non-static methods). If Java really supported references we wouldn't have to be this perverted. */ private static int sizeOfParameters(String pString) { int length = pString.length(); int rightParenthesis = pString.lastIndexOf(')'); if (3 <= length /* minimal signature takes at least 3 chars: ()V */ && pString.charAt(0) == '(' && 1 <= rightParenthesis && rightParenthesis + 1 < length) { boolean ok = true; int index = 1; int stackDiff = 0; int count = 0; stringLoop: while (index != rightParenthesis) { switch (pString.charAt(index)) { default: ok = false; break stringLoop; case 'J' : case 'D' : --stackDiff; // fall thru case 'B' : case 'S' : case 'C' : case 'I' : case 'Z' : case 'F' : --stackDiff; ++count; ++index; continue; case '[' : ++index; int c = pString.charAt(index); while (c == '[') { ++index; c = pString.charAt(index); } switch (c) { default: ok = false; break stringLoop; case 'J' : case 'D' : case 'B' : case 'S' : case 'C' : case 'I' : case 'Z' : case 'F' : --stackDiff; ++count; ++index; continue; case 'L': // fall thru } // fall thru case 'L' : { --stackDiff; ++count; ++index; int semicolon = pString.indexOf(';', index); if (!(index + 1 <= semicolon && semicolon < rightParenthesis)) { ok = false; break stringLoop; } index = semicolon + 1; continue; } } } if (ok) { switch (pString.charAt(rightParenthesis + 1)) { default: ok = false; break; case 'J' : case 'D' : ++stackDiff; // fall thru case 'B' : case 'S' : case 'C' : case 'I' : case 'Z' : case 'F' : case 'L' : case '[' : ++stackDiff; // fall thru case 'V' : break; } if (ok) { return ((count << 16) | (0xFFFF & stackDiff)); } } } throw new IllegalArgumentException( "Bad parameter signature: "+pString); } static int putInt16(int value, byte[] array, int offset) { array[offset + 0] = (byte)(value >>> 8); array[offset + 1] = (byte)value; return offset + 2; } static int putInt32(int value, byte[] array, int offset) { array[offset + 0] = (byte)(value >>> 24); array[offset + 1] = (byte)(value >>> 16); array[offset + 2] = (byte)(value >>> 8); array[offset + 3] = (byte)value; return offset + 4; } /** * Size of a bytecode instruction, counting the opcode and its operands. * * This is different from opcodeCount, since opcodeCount counts logical * operands. */ static int opcodeLength(int opcode, boolean wide) { switch (opcode) { case ByteCode.AALOAD: case ByteCode.AASTORE: case ByteCode.ACONST_NULL: case ByteCode.ALOAD_0: case ByteCode.ALOAD_1: case ByteCode.ALOAD_2: case ByteCode.ALOAD_3: case ByteCode.ARETURN: case ByteCode.ARRAYLENGTH: case ByteCode.ASTORE_0: case ByteCode.ASTORE_1: case ByteCode.ASTORE_2: case ByteCode.ASTORE_3: case ByteCode.ATHROW: case ByteCode.BALOAD: case ByteCode.BASTORE: case ByteCode.BREAKPOINT: case ByteCode.CALOAD: case ByteCode.CASTORE: case ByteCode.D2F: case ByteCode.D2I: case ByteCode.D2L: case ByteCode.DADD: case ByteCode.DALOAD: case ByteCode.DASTORE: case ByteCode.DCMPG: case ByteCode.DCMPL: case ByteCode.DCONST_0: case ByteCode.DCONST_1: case ByteCode.DDIV: case ByteCode.DLOAD_0: case ByteCode.DLOAD_1: case ByteCode.DLOAD_2: case ByteCode.DLOAD_3: case ByteCode.DMUL: case ByteCode.DNEG: case ByteCode.DREM: case ByteCode.DRETURN: case ByteCode.DSTORE_0: case ByteCode.DSTORE_1: case ByteCode.DSTORE_2: case ByteCode.DSTORE_3: case ByteCode.DSUB: case ByteCode.DUP: case ByteCode.DUP2: case ByteCode.DUP2_X1: case ByteCode.DUP2_X2: case ByteCode.DUP_X1: case ByteCode.DUP_X2: case ByteCode.F2D: case ByteCode.F2I: case ByteCode.F2L: case ByteCode.FADD: case ByteCode.FALOAD: case ByteCode.FASTORE: case ByteCode.FCMPG: case ByteCode.FCMPL: case ByteCode.FCONST_0: case ByteCode.FCONST_1: case ByteCode.FCONST_2: case ByteCode.FDIV: case ByteCode.FLOAD_0: case ByteCode.FLOAD_1: case ByteCode.FLOAD_2: case ByteCode.FLOAD_3: case ByteCode.FMUL: case ByteCode.FNEG: case ByteCode.FREM: case ByteCode.FRETURN: case ByteCode.FSTORE_0: case ByteCode.FSTORE_1: case ByteCode.FSTORE_2: case ByteCode.FSTORE_3: case ByteCode.FSUB: case ByteCode.I2B: case ByteCode.I2C: case ByteCode.I2D: case ByteCode.I2F: case ByteCode.I2L: case ByteCode.I2S: case ByteCode.IADD: case ByteCode.IALOAD: case ByteCode.IAND: case ByteCode.IASTORE: case ByteCode.ICONST_0: case ByteCode.ICONST_1: case ByteCode.ICONST_2: case ByteCode.ICONST_3: case ByteCode.ICONST_4: case ByteCode.ICONST_5: case ByteCode.ICONST_M1: case ByteCode.IDIV: case ByteCode.ILOAD_0: case ByteCode.ILOAD_1: case ByteCode.ILOAD_2: case ByteCode.ILOAD_3: case ByteCode.IMPDEP1: case ByteCode.IMPDEP2: case ByteCode.IMUL: case ByteCode.INEG: case ByteCode.IOR: case ByteCode.IREM: case ByteCode.IRETURN: case ByteCode.ISHL: case ByteCode.ISHR: case ByteCode.ISTORE_0: case ByteCode.ISTORE_1: case ByteCode.ISTORE_2: case ByteCode.ISTORE_3: case ByteCode.ISUB: case ByteCode.IUSHR: case ByteCode.IXOR: case ByteCode.L2D: case ByteCode.L2F: case ByteCode.L2I: case ByteCode.LADD: case ByteCode.LALOAD: case ByteCode.LAND: case ByteCode.LASTORE: case ByteCode.LCMP: case ByteCode.LCONST_0: case ByteCode.LCONST_1: case ByteCode.LDIV: case ByteCode.LLOAD_0: case ByteCode.LLOAD_1: case ByteCode.LLOAD_2: case ByteCode.LLOAD_3: case ByteCode.LMUL: case ByteCode.LNEG: case ByteCode.LOR: case ByteCode.LREM: case ByteCode.LRETURN: case ByteCode.LSHL: case ByteCode.LSHR: case ByteCode.LSTORE_0: case ByteCode.LSTORE_1: case ByteCode.LSTORE_2: case ByteCode.LSTORE_3: case ByteCode.LSUB: case ByteCode.LUSHR: case ByteCode.LXOR: case ByteCode.MONITORENTER: case ByteCode.MONITOREXIT: case ByteCode.NOP: case ByteCode.POP: case ByteCode.POP2: case ByteCode.RETURN: case ByteCode.SALOAD: case ByteCode.SASTORE: case ByteCode.SWAP: case ByteCode.WIDE: return 1; case ByteCode.BIPUSH: case ByteCode.LDC: case ByteCode.NEWARRAY: return 2; case ByteCode.ALOAD: case ByteCode.ASTORE: case ByteCode.DLOAD: case ByteCode.DSTORE: case ByteCode.FLOAD: case ByteCode.FSTORE: case ByteCode.ILOAD: case ByteCode.ISTORE: case ByteCode.LLOAD: case ByteCode.LSTORE: case ByteCode.RET: return wide ? 3 : 2; case ByteCode.ANEWARRAY: case ByteCode.CHECKCAST: case ByteCode.GETFIELD: case ByteCode.GETSTATIC: case ByteCode.GOTO: case ByteCode.IFEQ: case ByteCode.IFGE: case ByteCode.IFGT: case ByteCode.IFLE: case ByteCode.IFLT: case ByteCode.IFNE: case ByteCode.IFNONNULL: case ByteCode.IFNULL: case ByteCode.IF_ACMPEQ: case ByteCode.IF_ACMPNE: case ByteCode.IF_ICMPEQ: case ByteCode.IF_ICMPGE: case ByteCode.IF_ICMPGT: case ByteCode.IF_ICMPLE: case ByteCode.IF_ICMPLT: case ByteCode.IF_ICMPNE: case ByteCode.INSTANCEOF: case ByteCode.INVOKESPECIAL: case ByteCode.INVOKESTATIC: case ByteCode.INVOKEVIRTUAL: case ByteCode.JSR: case ByteCode.LDC_W: case ByteCode.LDC2_W: case ByteCode.NEW: case ByteCode.PUTFIELD: case ByteCode.PUTSTATIC: case ByteCode.SIPUSH: return 3; case ByteCode.IINC: return wide ? 5 : 3; case ByteCode.MULTIANEWARRAY: return 4; case ByteCode.GOTO_W: case ByteCode.INVOKEINTERFACE: case ByteCode.JSR_W: return 5; /* case ByteCode.LOOKUPSWITCH: case ByteCode.TABLESWITCH: return -1; */ } throw new IllegalArgumentException("Bad opcode: " + opcode); } /** * Number of operands accompanying the opcode. */ static int opcodeCount(int opcode) { switch (opcode) { case ByteCode.AALOAD: case ByteCode.AASTORE: case ByteCode.ACONST_NULL: case ByteCode.ALOAD_0: case ByteCode.ALOAD_1: case ByteCode.ALOAD_2: case ByteCode.ALOAD_3: case ByteCode.ARETURN: case ByteCode.ARRAYLENGTH: case ByteCode.ASTORE_0: case ByteCode.ASTORE_1: case ByteCode.ASTORE_2: case ByteCode.ASTORE_3: case ByteCode.ATHROW: case ByteCode.BALOAD: case ByteCode.BASTORE: case ByteCode.BREAKPOINT: case ByteCode.CALOAD: case ByteCode.CASTORE: case ByteCode.D2F: case ByteCode.D2I: case ByteCode.D2L: case ByteCode.DADD: case ByteCode.DALOAD: case ByteCode.DASTORE: case ByteCode.DCMPG: case ByteCode.DCMPL: case ByteCode.DCONST_0: case ByteCode.DCONST_1: case ByteCode.DDIV: case ByteCode.DLOAD_0: case ByteCode.DLOAD_1: case ByteCode.DLOAD_2: case ByteCode.DLOAD_3: case ByteCode.DMUL: case ByteCode.DNEG: case ByteCode.DREM: case ByteCode.DRETURN: case ByteCode.DSTORE_0: case ByteCode.DSTORE_1: case ByteCode.DSTORE_2: case ByteCode.DSTORE_3: case ByteCode.DSUB: case ByteCode.DUP: case ByteCode.DUP2: case ByteCode.DUP2_X1: case ByteCode.DUP2_X2: case ByteCode.DUP_X1: case ByteCode.DUP_X2: case ByteCode.F2D: case ByteCode.F2I: case ByteCode.F2L: case ByteCode.FADD: case ByteCode.FALOAD: case ByteCode.FASTORE: case ByteCode.FCMPG: case ByteCode.FCMPL: case ByteCode.FCONST_0: case ByteCode.FCONST_1: case ByteCode.FCONST_2: case ByteCode.FDIV: case ByteCode.FLOAD_0: case ByteCode.FLOAD_1: case ByteCode.FLOAD_2: case ByteCode.FLOAD_3: case ByteCode.FMUL: case ByteCode.FNEG: case ByteCode.FREM: case ByteCode.FRETURN: case ByteCode.FSTORE_0: case ByteCode.FSTORE_1: case ByteCode.FSTORE_2: case ByteCode.FSTORE_3: case ByteCode.FSUB: case ByteCode.I2B: case ByteCode.I2C: case ByteCode.I2D: case ByteCode.I2F: case ByteCode.I2L: case ByteCode.I2S: case ByteCode.IADD: case ByteCode.IALOAD: case ByteCode.IAND: case ByteCode.IASTORE: case ByteCode.ICONST_0: case ByteCode.ICONST_1: case ByteCode.ICONST_2: case ByteCode.ICONST_3: case ByteCode.ICONST_4: case ByteCode.ICONST_5: case ByteCode.ICONST_M1: case ByteCode.IDIV: case ByteCode.ILOAD_0: case ByteCode.ILOAD_1: case ByteCode.ILOAD_2: case ByteCode.ILOAD_3: case ByteCode.IMPDEP1: case ByteCode.IMPDEP2: case ByteCode.IMUL: case ByteCode.INEG: case ByteCode.IOR: case ByteCode.IREM: case ByteCode.IRETURN: case ByteCode.ISHL: case ByteCode.ISHR: case ByteCode.ISTORE_0: case ByteCode.ISTORE_1: case ByteCode.ISTORE_2: case ByteCode.ISTORE_3: case ByteCode.ISUB: case ByteCode.IUSHR: case ByteCode.IXOR: case ByteCode.L2D: case ByteCode.L2F: case ByteCode.L2I: case ByteCode.LADD: case ByteCode.LALOAD: case ByteCode.LAND: case ByteCode.LASTORE: case ByteCode.LCMP: case ByteCode.LCONST_0: case ByteCode.LCONST_1: case ByteCode.LDIV: case ByteCode.LLOAD_0: case ByteCode.LLOAD_1: case ByteCode.LLOAD_2: case ByteCode.LLOAD_3: case ByteCode.LMUL: case ByteCode.LNEG: case ByteCode.LOR: case ByteCode.LREM: case ByteCode.LRETURN: case ByteCode.LSHL: case ByteCode.LSHR: case ByteCode.LSTORE_0: case ByteCode.LSTORE_1: case ByteCode.LSTORE_2: case ByteCode.LSTORE_3: case ByteCode.LSUB: case ByteCode.LUSHR: case ByteCode.LXOR: case ByteCode.MONITORENTER: case ByteCode.MONITOREXIT: case ByteCode.NOP: case ByteCode.POP: case ByteCode.POP2: case ByteCode.RETURN: case ByteCode.SALOAD: case ByteCode.SASTORE: case ByteCode.SWAP: case ByteCode.WIDE: return 0; case ByteCode.ALOAD: case ByteCode.ANEWARRAY: case ByteCode.ASTORE: case ByteCode.BIPUSH: case ByteCode.CHECKCAST: case ByteCode.DLOAD: case ByteCode.DSTORE: case ByteCode.FLOAD: case ByteCode.FSTORE: case ByteCode.GETFIELD: case ByteCode.GETSTATIC: case ByteCode.GOTO: case ByteCode.GOTO_W: case ByteCode.IFEQ: case ByteCode.IFGE: case ByteCode.IFGT: case ByteCode.IFLE: case ByteCode.IFLT: case ByteCode.IFNE: case ByteCode.IFNONNULL: case ByteCode.IFNULL: case ByteCode.IF_ACMPEQ: case ByteCode.IF_ACMPNE: case ByteCode.IF_ICMPEQ: case ByteCode.IF_ICMPGE: case ByteCode.IF_ICMPGT: case ByteCode.IF_ICMPLE: case ByteCode.IF_ICMPLT: case ByteCode.IF_ICMPNE: case ByteCode.ILOAD: case ByteCode.INSTANCEOF: case ByteCode.INVOKEINTERFACE: case ByteCode.INVOKESPECIAL: case ByteCode.INVOKESTATIC: case ByteCode.INVOKEVIRTUAL: case ByteCode.ISTORE: case ByteCode.JSR: case ByteCode.JSR_W: case ByteCode.LDC: case ByteCode.LDC2_W: case ByteCode.LDC_W: case ByteCode.LLOAD: case ByteCode.LSTORE: case ByteCode.NEW: case ByteCode.NEWARRAY: case ByteCode.PUTFIELD: case ByteCode.PUTSTATIC: case ByteCode.RET: case ByteCode.SIPUSH: return 1; case ByteCode.IINC: case ByteCode.MULTIANEWARRAY: return 2; case ByteCode.LOOKUPSWITCH: case ByteCode.TABLESWITCH: return -1; } throw new IllegalArgumentException("Bad opcode: "+opcode); } /** * The effect on the operand stack of a given opcode. */ static int stackChange(int opcode) { // For INVOKE... accounts only for popping this (unless static), // ignoring parameters and return type switch (opcode) { case ByteCode.DASTORE: case ByteCode.LASTORE: return -4; case ByteCode.AASTORE: case ByteCode.BASTORE: case ByteCode.CASTORE: case ByteCode.DCMPG: case ByteCode.DCMPL: case ByteCode.FASTORE: case ByteCode.IASTORE: case ByteCode.LCMP: case ByteCode.SASTORE: return -3; case ByteCode.DADD: case ByteCode.DDIV: case ByteCode.DMUL: case ByteCode.DREM: case ByteCode.DRETURN: case ByteCode.DSTORE: case ByteCode.DSTORE_0: case ByteCode.DSTORE_1: case ByteCode.DSTORE_2: case ByteCode.DSTORE_3: case ByteCode.DSUB: case ByteCode.IF_ACMPEQ: case ByteCode.IF_ACMPNE: case ByteCode.IF_ICMPEQ: case ByteCode.IF_ICMPGE: case ByteCode.IF_ICMPGT: case ByteCode.IF_ICMPLE: case ByteCode.IF_ICMPLT: case ByteCode.IF_ICMPNE: case ByteCode.LADD: case ByteCode.LAND: case ByteCode.LDIV: case ByteCode.LMUL: case ByteCode.LOR: case ByteCode.LREM: case ByteCode.LRETURN: case ByteCode.LSTORE: case ByteCode.LSTORE_0: case ByteCode.LSTORE_1: case ByteCode.LSTORE_2: case ByteCode.LSTORE_3: case ByteCode.LSUB: case ByteCode.LXOR: case ByteCode.POP2: return -2; case ByteCode.AALOAD: case ByteCode.ARETURN: case ByteCode.ASTORE: case ByteCode.ASTORE_0: case ByteCode.ASTORE_1: case ByteCode.ASTORE_2: case ByteCode.ASTORE_3: case ByteCode.ATHROW: case ByteCode.BALOAD: case ByteCode.CALOAD: case ByteCode.D2F: case ByteCode.D2I: case ByteCode.FADD: case ByteCode.FALOAD: case ByteCode.FCMPG: case ByteCode.FCMPL: case ByteCode.FDIV: case ByteCode.FMUL: case ByteCode.FREM: case ByteCode.FRETURN: case ByteCode.FSTORE: case ByteCode.FSTORE_0: case ByteCode.FSTORE_1: case ByteCode.FSTORE_2: case ByteCode.FSTORE_3: case ByteCode.FSUB: case ByteCode.GETFIELD: case ByteCode.IADD: case ByteCode.IALOAD: case ByteCode.IAND: case ByteCode.IDIV: case ByteCode.IFEQ: case ByteCode.IFGE: case ByteCode.IFGT: case ByteCode.IFLE: case ByteCode.IFLT: case ByteCode.IFNE: case ByteCode.IFNONNULL: case ByteCode.IFNULL: case ByteCode.IMUL: case ByteCode.INVOKEINTERFACE: // case ByteCode.INVOKESPECIAL: // but needs to account for case ByteCode.INVOKEVIRTUAL: // pops 'this' (unless static) case ByteCode.IOR: case ByteCode.IREM: case ByteCode.IRETURN: case ByteCode.ISHL: case ByteCode.ISHR: case ByteCode.ISTORE: case ByteCode.ISTORE_0: case ByteCode.ISTORE_1: case ByteCode.ISTORE_2: case ByteCode.ISTORE_3: case ByteCode.ISUB: case ByteCode.IUSHR: case ByteCode.IXOR: case ByteCode.L2F: case ByteCode.L2I: case ByteCode.LOOKUPSWITCH: case ByteCode.LSHL: case ByteCode.LSHR: case ByteCode.LUSHR: case ByteCode.MONITORENTER: case ByteCode.MONITOREXIT: case ByteCode.POP: case ByteCode.PUTFIELD: case ByteCode.SALOAD: case ByteCode.TABLESWITCH: return -1; case ByteCode.ANEWARRAY: case ByteCode.ARRAYLENGTH: case ByteCode.BREAKPOINT: case ByteCode.CHECKCAST: case ByteCode.D2L: case ByteCode.DALOAD: case ByteCode.DNEG: case ByteCode.F2I: case ByteCode.FNEG: case ByteCode.GETSTATIC: case ByteCode.GOTO: case ByteCode.GOTO_W: case ByteCode.I2B: case ByteCode.I2C: case ByteCode.I2F: case ByteCode.I2S: case ByteCode.IINC: case ByteCode.IMPDEP1: case ByteCode.IMPDEP2: case ByteCode.INEG: case ByteCode.INSTANCEOF: case ByteCode.INVOKESTATIC: case ByteCode.L2D: case ByteCode.LALOAD: case ByteCode.LNEG: case ByteCode.NEWARRAY: case ByteCode.NOP: case ByteCode.PUTSTATIC: case ByteCode.RET: case ByteCode.RETURN: case ByteCode.SWAP: case ByteCode.WIDE: return 0; case ByteCode.ACONST_NULL: case ByteCode.ALOAD: case ByteCode.ALOAD_0: case ByteCode.ALOAD_1: case ByteCode.ALOAD_2: case ByteCode.ALOAD_3: case ByteCode.BIPUSH: case ByteCode.DUP: case ByteCode.DUP_X1: case ByteCode.DUP_X2: case ByteCode.F2D: case ByteCode.F2L: case ByteCode.FCONST_0: case ByteCode.FCONST_1: case ByteCode.FCONST_2: case ByteCode.FLOAD: case ByteCode.FLOAD_0: case ByteCode.FLOAD_1: case ByteCode.FLOAD_2: case ByteCode.FLOAD_3: case ByteCode.I2D: case ByteCode.I2L: case ByteCode.ICONST_0: case ByteCode.ICONST_1: case ByteCode.ICONST_2: case ByteCode.ICONST_3: case ByteCode.ICONST_4: case ByteCode.ICONST_5: case ByteCode.ICONST_M1: case ByteCode.ILOAD: case ByteCode.ILOAD_0: case ByteCode.ILOAD_1: case ByteCode.ILOAD_2: case ByteCode.ILOAD_3: case ByteCode.JSR: case ByteCode.JSR_W: case ByteCode.LDC: case ByteCode.LDC_W: case ByteCode.MULTIANEWARRAY: case ByteCode.NEW: case ByteCode.SIPUSH: return 1; case ByteCode.DCONST_0: case ByteCode.DCONST_1: case ByteCode.DLOAD: case ByteCode.DLOAD_0: case ByteCode.DLOAD_1: case ByteCode.DLOAD_2: case ByteCode.DLOAD_3: case ByteCode.DUP2: case ByteCode.DUP2_X1: case ByteCode.DUP2_X2: case ByteCode.LCONST_0: case ByteCode.LCONST_1: case ByteCode.LDC2_W: case ByteCode.LLOAD: case ByteCode.LLOAD_0: case ByteCode.LLOAD_1: case ByteCode.LLOAD_2: case ByteCode.LLOAD_3: return 2; } throw new IllegalArgumentException("Bad opcode: "+opcode); } /* * Number of bytes of operands generated after the opcode. * Not in use currently. */ /* int extra(int opcode) { switch (opcode) { case ByteCode.AALOAD: case ByteCode.AASTORE: case ByteCode.ACONST_NULL: case ByteCode.ALOAD_0: case ByteCode.ALOAD_1: case ByteCode.ALOAD_2: case ByteCode.ALOAD_3: case ByteCode.ARETURN: case ByteCode.ARRAYLENGTH: case ByteCode.ASTORE_0: case ByteCode.ASTORE_1: case ByteCode.ASTORE_2: case ByteCode.ASTORE_3: case ByteCode.ATHROW: case ByteCode.BALOAD: case ByteCode.BASTORE: case ByteCode.BREAKPOINT: case ByteCode.CALOAD: case ByteCode.CASTORE: case ByteCode.D2F: case ByteCode.D2I: case ByteCode.D2L: case ByteCode.DADD: case ByteCode.DALOAD: case ByteCode.DASTORE: case ByteCode.DCMPG: case ByteCode.DCMPL: case ByteCode.DCONST_0: case ByteCode.DCONST_1: case ByteCode.DDIV: case ByteCode.DLOAD_0: case ByteCode.DLOAD_1: case ByteCode.DLOAD_2: case ByteCode.DLOAD_3: case ByteCode.DMUL: case ByteCode.DNEG: case ByteCode.DREM: case ByteCode.DRETURN: case ByteCode.DSTORE_0: case ByteCode.DSTORE_1: case ByteCode.DSTORE_2: case ByteCode.DSTORE_3: case ByteCode.DSUB: case ByteCode.DUP2: case ByteCode.DUP2_X1: case ByteCode.DUP2_X2: case ByteCode.DUP: case ByteCode.DUP_X1: case ByteCode.DUP_X2: case ByteCode.F2D: case ByteCode.F2I: case ByteCode.F2L: case ByteCode.FADD: case ByteCode.FALOAD: case ByteCode.FASTORE: case ByteCode.FCMPG: case ByteCode.FCMPL: case ByteCode.FCONST_0: case ByteCode.FCONST_1: case ByteCode.FCONST_2: case ByteCode.FDIV: case ByteCode.FLOAD_0: case ByteCode.FLOAD_1: case ByteCode.FLOAD_2: case ByteCode.FLOAD_3: case ByteCode.FMUL: case ByteCode.FNEG: case ByteCode.FREM: case ByteCode.FRETURN: case ByteCode.FSTORE_0: case ByteCode.FSTORE_1: case ByteCode.FSTORE_2: case ByteCode.FSTORE_3: case ByteCode.FSUB: case ByteCode.I2B: case ByteCode.I2C: case ByteCode.I2D: case ByteCode.I2F: case ByteCode.I2L: case ByteCode.I2S: case ByteCode.IADD: case ByteCode.IALOAD: case ByteCode.IAND: case ByteCode.IASTORE: case ByteCode.ICONST_0: case ByteCode.ICONST_1: case ByteCode.ICONST_2: case ByteCode.ICONST_3: case ByteCode.ICONST_4: case ByteCode.ICONST_5: case ByteCode.ICONST_M1: case ByteCode.IDIV: case ByteCode.ILOAD_0: case ByteCode.ILOAD_1: case ByteCode.ILOAD_2: case ByteCode.ILOAD_3: case ByteCode.IMPDEP1: case ByteCode.IMPDEP2: case ByteCode.IMUL: case ByteCode.INEG: case ByteCode.IOR: case ByteCode.IREM: case ByteCode.IRETURN: case ByteCode.ISHL: case ByteCode.ISHR: case ByteCode.ISTORE_0: case ByteCode.ISTORE_1: case ByteCode.ISTORE_2: case ByteCode.ISTORE_3: case ByteCode.ISUB: case ByteCode.IUSHR: case ByteCode.IXOR: case ByteCode.L2D: case ByteCode.L2F: case ByteCode.L2I: case ByteCode.LADD: case ByteCode.LALOAD: case ByteCode.LAND: case ByteCode.LASTORE: case ByteCode.LCMP: case ByteCode.LCONST_0: case ByteCode.LCONST_1: case ByteCode.LDIV: case ByteCode.LLOAD_0: case ByteCode.LLOAD_1: case ByteCode.LLOAD_2: case ByteCode.LLOAD_3: case ByteCode.LMUL: case ByteCode.LNEG: case ByteCode.LOR: case ByteCode.LREM: case ByteCode.LRETURN: case ByteCode.LSHL: case ByteCode.LSHR: case ByteCode.LSTORE_0: case ByteCode.LSTORE_1: case ByteCode.LSTORE_2: case ByteCode.LSTORE_3: case ByteCode.LSUB: case ByteCode.LUSHR: case ByteCode.LXOR: case ByteCode.MONITORENTER: case ByteCode.MONITOREXIT: case ByteCode.NOP: case ByteCode.POP2: case ByteCode.POP: case ByteCode.RETURN: case ByteCode.SALOAD: case ByteCode.SASTORE: case ByteCode.SWAP: case ByteCode.WIDE: return 0; case ByteCode.ALOAD: case ByteCode.ASTORE: case ByteCode.BIPUSH: case ByteCode.DLOAD: case ByteCode.DSTORE: case ByteCode.FLOAD: case ByteCode.FSTORE: case ByteCode.ILOAD: case ByteCode.ISTORE: case ByteCode.LDC: case ByteCode.LLOAD: case ByteCode.LSTORE: case ByteCode.NEWARRAY: case ByteCode.RET: return 1; case ByteCode.ANEWARRAY: case ByteCode.CHECKCAST: case ByteCode.GETFIELD: case ByteCode.GETSTATIC: case ByteCode.GOTO: case ByteCode.IFEQ: case ByteCode.IFGE: case ByteCode.IFGT: case ByteCode.IFLE: case ByteCode.IFLT: case ByteCode.IFNE: case ByteCode.IFNONNULL: case ByteCode.IFNULL: case ByteCode.IF_ACMPEQ: case ByteCode.IF_ACMPNE: case ByteCode.IF_ICMPEQ: case ByteCode.IF_ICMPGE: case ByteCode.IF_ICMPGT: case ByteCode.IF_ICMPLE: case ByteCode.IF_ICMPLT: case ByteCode.IF_ICMPNE: case ByteCode.IINC: case ByteCode.INSTANCEOF: case ByteCode.INVOKEINTERFACE: case ByteCode.INVOKESPECIAL: case ByteCode.INVOKESTATIC: case ByteCode.INVOKEVIRTUAL: case ByteCode.JSR: case ByteCode.LDC2_W: case ByteCode.LDC_W: case ByteCode.NEW: case ByteCode.PUTFIELD: case ByteCode.PUTSTATIC: case ByteCode.SIPUSH: return 2; case ByteCode.MULTIANEWARRAY: return 3; case ByteCode.GOTO_W: case ByteCode.JSR_W: return 4; case ByteCode.LOOKUPSWITCH: // depends on alignment case ByteCode.TABLESWITCH: // depends on alignment return -1; } throw new IllegalArgumentException("Bad opcode: "+opcode); } */ private static String bytecodeStr(int code) { if (DEBUGSTACK || DEBUGCODE) { switch (code) { case ByteCode.NOP: return "nop"; case ByteCode.ACONST_NULL: return "aconst_null"; case ByteCode.ICONST_M1: return "iconst_m1"; case ByteCode.ICONST_0: return "iconst_0"; case ByteCode.ICONST_1: return "iconst_1"; case ByteCode.ICONST_2: return "iconst_2"; case ByteCode.ICONST_3: return "iconst_3"; case ByteCode.ICONST_4: return "iconst_4"; case ByteCode.ICONST_5: return "iconst_5"; case ByteCode.LCONST_0: return "lconst_0"; case ByteCode.LCONST_1: return "lconst_1"; case ByteCode.FCONST_0: return "fconst_0"; case ByteCode.FCONST_1: return "fconst_1"; case ByteCode.FCONST_2: return "fconst_2"; case ByteCode.DCONST_0: return "dconst_0"; case ByteCode.DCONST_1: return "dconst_1"; case ByteCode.BIPUSH: return "bipush"; case ByteCode.SIPUSH: return "sipush"; case ByteCode.LDC: return "ldc"; case ByteCode.LDC_W: return "ldc_w"; case ByteCode.LDC2_W: return "ldc2_w"; case ByteCode.ILOAD: return "iload"; case ByteCode.LLOAD: return "lload"; case ByteCode.FLOAD: return "fload"; case ByteCode.DLOAD: return "dload"; case ByteCode.ALOAD: return "aload"; case ByteCode.ILOAD_0: return "iload_0"; case ByteCode.ILOAD_1: return "iload_1"; case ByteCode.ILOAD_2: return "iload_2"; case ByteCode.ILOAD_3: return "iload_3"; case ByteCode.LLOAD_0: return "lload_0"; case ByteCode.LLOAD_1: return "lload_1"; case ByteCode.LLOAD_2: return "lload_2"; case ByteCode.LLOAD_3: return "lload_3"; case ByteCode.FLOAD_0: return "fload_0"; case ByteCode.FLOAD_1: return "fload_1"; case ByteCode.FLOAD_2: return "fload_2"; case ByteCode.FLOAD_3: return "fload_3"; case ByteCode.DLOAD_0: return "dload_0"; case ByteCode.DLOAD_1: return "dload_1"; case ByteCode.DLOAD_2: return "dload_2"; case ByteCode.DLOAD_3: return "dload_3"; case ByteCode.ALOAD_0: return "aload_0"; case ByteCode.ALOAD_1: return "aload_1"; case ByteCode.ALOAD_2: return "aload_2"; case ByteCode.ALOAD_3: return "aload_3"; case ByteCode.IALOAD: return "iaload"; case ByteCode.LALOAD: return "laload"; case ByteCode.FALOAD: return "faload"; case ByteCode.DALOAD: return "daload"; case ByteCode.AALOAD: return "aaload"; case ByteCode.BALOAD: return "baload"; case ByteCode.CALOAD: return "caload"; case ByteCode.SALOAD: return "saload"; case ByteCode.ISTORE: return "istore"; case ByteCode.LSTORE: return "lstore"; case ByteCode.FSTORE: return "fstore"; case ByteCode.DSTORE: return "dstore"; case ByteCode.ASTORE: return "astore"; case ByteCode.ISTORE_0: return "istore_0"; case ByteCode.ISTORE_1: return "istore_1"; case ByteCode.ISTORE_2: return "istore_2"; case ByteCode.ISTORE_3: return "istore_3"; case ByteCode.LSTORE_0: return "lstore_0"; case ByteCode.LSTORE_1: return "lstore_1"; case ByteCode.LSTORE_2: return "lstore_2"; case ByteCode.LSTORE_3: return "lstore_3"; case ByteCode.FSTORE_0: return "fstore_0"; case ByteCode.FSTORE_1: return "fstore_1"; case ByteCode.FSTORE_2: return "fstore_2"; case ByteCode.FSTORE_3: return "fstore_3"; case ByteCode.DSTORE_0: return "dstore_0"; case ByteCode.DSTORE_1: return "dstore_1"; case ByteCode.DSTORE_2: return "dstore_2"; case ByteCode.DSTORE_3: return "dstore_3"; case ByteCode.ASTORE_0: return "astore_0"; case ByteCode.ASTORE_1: return "astore_1"; case ByteCode.ASTORE_2: return "astore_2"; case ByteCode.ASTORE_3: return "astore_3"; case ByteCode.IASTORE: return "iastore"; case ByteCode.LASTORE: return "lastore"; case ByteCode.FASTORE: return "fastore"; case ByteCode.DASTORE: return "dastore"; case ByteCode.AASTORE: return "aastore"; case ByteCode.BASTORE: return "bastore"; case ByteCode.CASTORE: return "castore"; case ByteCode.SASTORE: return "sastore"; case ByteCode.POP: return "pop"; case ByteCode.POP2: return "pop2"; case ByteCode.DUP: return "dup"; case ByteCode.DUP_X1: return "dup_x1"; case ByteCode.DUP_X2: return "dup_x2"; case ByteCode.DUP2: return "dup2"; case ByteCode.DUP2_X1: return "dup2_x1"; case ByteCode.DUP2_X2: return "dup2_x2"; case ByteCode.SWAP: return "swap"; case ByteCode.IADD: return "iadd"; case ByteCode.LADD: return "ladd"; case ByteCode.FADD: return "fadd"; case ByteCode.DADD: return "dadd"; case ByteCode.ISUB: return "isub"; case ByteCode.LSUB: return "lsub"; case ByteCode.FSUB: return "fsub"; case ByteCode.DSUB: return "dsub"; case ByteCode.IMUL: return "imul"; case ByteCode.LMUL: return "lmul"; case ByteCode.FMUL: return "fmul"; case ByteCode.DMUL: return "dmul"; case ByteCode.IDIV: return "idiv"; case ByteCode.LDIV: return "ldiv"; case ByteCode.FDIV: return "fdiv"; case ByteCode.DDIV: return "ddiv"; case ByteCode.IREM: return "irem"; case ByteCode.LREM: return "lrem"; case ByteCode.FREM: return "frem"; case ByteCode.DREM: return "drem"; case ByteCode.INEG: return "ineg"; case ByteCode.LNEG: return "lneg"; case ByteCode.FNEG: return "fneg"; case ByteCode.DNEG: return "dneg"; case ByteCode.ISHL: return "ishl"; case ByteCode.LSHL: return "lshl"; case ByteCode.ISHR: return "ishr"; case ByteCode.LSHR: return "lshr"; case ByteCode.IUSHR: return "iushr"; case ByteCode.LUSHR: return "lushr"; case ByteCode.IAND: return "iand"; case ByteCode.LAND: return "land"; case ByteCode.IOR: return "ior"; case ByteCode.LOR: return "lor"; case ByteCode.IXOR: return "ixor"; case ByteCode.LXOR: return "lxor"; case ByteCode.IINC: return "iinc"; case ByteCode.I2L: return "i2l"; case ByteCode.I2F: return "i2f"; case ByteCode.I2D: return "i2d"; case ByteCode.L2I: return "l2i"; case ByteCode.L2F: return "l2f"; case ByteCode.L2D: return "l2d"; case ByteCode.F2I: return "f2i"; case ByteCode.F2L: return "f2l"; case ByteCode.F2D: return "f2d"; case ByteCode.D2I: return "d2i"; case ByteCode.D2L: return "d2l"; case ByteCode.D2F: return "d2f"; case ByteCode.I2B: return "i2b"; case ByteCode.I2C: return "i2c"; case ByteCode.I2S: return "i2s"; case ByteCode.LCMP: return "lcmp"; case ByteCode.FCMPL: return "fcmpl"; case ByteCode.FCMPG: return "fcmpg"; case ByteCode.DCMPL: return "dcmpl"; case ByteCode.DCMPG: return "dcmpg"; case ByteCode.IFEQ: return "ifeq"; case ByteCode.IFNE: return "ifne"; case ByteCode.IFLT: return "iflt"; case ByteCode.IFGE: return "ifge"; case ByteCode.IFGT: return "ifgt"; case ByteCode.IFLE: return "ifle"; case ByteCode.IF_ICMPEQ: return "if_icmpeq"; case ByteCode.IF_ICMPNE: return "if_icmpne"; case ByteCode.IF_ICMPLT: return "if_icmplt"; case ByteCode.IF_ICMPGE: return "if_icmpge"; case ByteCode.IF_ICMPGT: return "if_icmpgt"; case ByteCode.IF_ICMPLE: return "if_icmple"; case ByteCode.IF_ACMPEQ: return "if_acmpeq"; case ByteCode.IF_ACMPNE: return "if_acmpne"; case ByteCode.GOTO: return "goto"; case ByteCode.JSR: return "jsr"; case ByteCode.RET: return "ret"; case ByteCode.TABLESWITCH: return "tableswitch"; case ByteCode.LOOKUPSWITCH: return "lookupswitch"; case ByteCode.IRETURN: return "ireturn"; case ByteCode.LRETURN: return "lreturn"; case ByteCode.FRETURN: return "freturn"; case ByteCode.DRETURN: return "dreturn"; case ByteCode.ARETURN: return "areturn"; case ByteCode.RETURN: return "return"; case ByteCode.GETSTATIC: return "getstatic"; case ByteCode.PUTSTATIC: return "putstatic"; case ByteCode.GETFIELD: return "getfield"; case ByteCode.PUTFIELD: return "putfield"; case ByteCode.INVOKEVIRTUAL: return "invokevirtual"; case ByteCode.INVOKESPECIAL: return "invokespecial"; case ByteCode.INVOKESTATIC: return "invokestatic"; case ByteCode.INVOKEINTERFACE: return "invokeinterface"; case ByteCode.NEW: return "new"; case ByteCode.NEWARRAY: return "newarray"; case ByteCode.ANEWARRAY: return "anewarray"; case ByteCode.ARRAYLENGTH: return "arraylength"; case ByteCode.ATHROW: return "athrow"; case ByteCode.CHECKCAST: return "checkcast"; case ByteCode.INSTANCEOF: return "instanceof"; case ByteCode.MONITORENTER: return "monitorenter"; case ByteCode.MONITOREXIT: return "monitorexit"; case ByteCode.WIDE: return "wide"; case ByteCode.MULTIANEWARRAY: return "multianewarray"; case ByteCode.IFNULL: return "ifnull"; case ByteCode.IFNONNULL: return "ifnonnull"; case ByteCode.GOTO_W: return "goto_w"; case ByteCode.JSR_W: return "jsr_w"; case ByteCode.BREAKPOINT: return "breakpoint"; case ByteCode.IMPDEP1: return "impdep1"; case ByteCode.IMPDEP2: return "impdep2"; } } return ""; } final char[] getCharBuffer(int minimalSize) { if (minimalSize > tmpCharBuffer.length) { int newSize = tmpCharBuffer.length * 2; if (minimalSize > newSize) { newSize = minimalSize; } tmpCharBuffer = new char[newSize]; } return tmpCharBuffer; } /** * Add a pc as the start of super block. * * A pc is the beginning of a super block if: * - pc == 0 * - it is the target of a branch instruction * - it is the beginning of an exception handler * - it is directly after an unconditional jump */ private void addSuperBlockStart(int pc) { if (GenerateStackMap) { if (itsSuperBlockStarts == null) { itsSuperBlockStarts = new int[SuperBlockStartsSize]; } else if (itsSuperBlockStarts.length == itsSuperBlockStartsTop) { int[] tmp = new int[itsSuperBlockStartsTop * 2]; System.arraycopy(itsSuperBlockStarts, 0, tmp, 0, itsSuperBlockStartsTop); itsSuperBlockStarts = tmp; } itsSuperBlockStarts[itsSuperBlockStartsTop++] = pc; } } /** * Sort the list of recorded super block starts and remove duplicates. * * Also adds exception handling blocks as block starts, since there is no * explicit control flow to these. Used for stack map table generation. */ private void finalizeSuperBlockStarts() { if (GenerateStackMap) { for (int i = 0; i < itsExceptionTableTop; i++) { ExceptionTableEntry ete = itsExceptionTable[i]; short handlerPC = (short) getLabelPC(ete.itsHandlerLabel); addSuperBlockStart(handlerPC); } Arrays.sort(itsSuperBlockStarts, 0, itsSuperBlockStartsTop); int prev = itsSuperBlockStarts[0]; int copyTo = 1; for (int i = 1; i < itsSuperBlockStartsTop; i++) { int curr = itsSuperBlockStarts[i]; if (prev != curr) { if (copyTo != i) { itsSuperBlockStarts[copyTo] = curr; } copyTo++; prev = curr; } } itsSuperBlockStartsTop = copyTo; if (itsSuperBlockStarts[copyTo - 1] == itsCodeBufferTop) { itsSuperBlockStartsTop--; } } } private int[] itsSuperBlockStarts = null; private int itsSuperBlockStartsTop = 0; private static final int SuperBlockStartsSize = 4; // Used to find blocks of code with no dependencies (aka dead code). // Necessary for generating type information for dead code, which is // expected by the Sun verifier. It is only necessary to store a single // jump source to determine if a block is reachable or not. private UintMap itsJumpFroms = null; private static final int LineNumberTableSize = 16; private static final int ExceptionTableSize = 4; private static final int MajorVersion; private static final int MinorVersion; private static final boolean GenerateStackMap; static { // Figure out which classfile version should be generated. This assumes // that the runtime used to compile the JavaScript files is the same as // the one used to run them. This is important because there are cases // when bytecode is generated at runtime, where it is not easy to pass // along what version is necessary. Instead, we grab the version numbers // from the bytecode of this class and use that. // // Based on the version numbers we scrape, we can also determine what // bytecode features we need. For example, Java 6 bytecode (classfile // version 50) should have stack maps generated. InputStream is = null; int major = 48, minor = 0; try { is = ClassFileWriter.class.getResourceAsStream("ClassFileWriter.class"); if (is == null) { is = ClassLoader.getSystemResourceAsStream( "org/mozilla/classfile/ClassFileWriter.class"); } byte[] header = new byte[8]; // read loop is required since JDK7 will only provide 2 bytes // on the first read() - see bug #630111 int read = 0; while (read < 8) { int c = is.read(header, read, 8 - read); if (c < 0) throw new IOException(); read += c; } minor = (header[4] << 8) | (header[5] & 0xff); major = (header[6] << 8) | (header[7] & 0xff); } catch (Exception e) { // Unable to get class file, use default bytecode version } finally { MinorVersion = minor; MajorVersion = major; GenerateStackMap = major >= 50; if (is != null) { try { is.close(); } catch (IOException e) { } } } } private final static int FileHeaderConstant = 0xCAFEBABE; // Set DEBUG flags to true to get better checking and progress info. private static final boolean DEBUGSTACK = false; private static final boolean DEBUGLABELS = false; private static final boolean DEBUGCODE = false; private String generatedClassName; private ExceptionTableEntry itsExceptionTable[]; private int itsExceptionTableTop; private int itsLineNumberTable[]; // pack start_pc & line_number together private int itsLineNumberTableTop; private byte[] itsCodeBuffer = new byte[256]; private int itsCodeBufferTop; private ConstantPool itsConstantPool; private ClassFileMethod itsCurrentMethod; private short itsStackTop; private short itsMaxStack; private short itsMaxLocals; private ObjArray itsMethods = new ObjArray(); private ObjArray itsFields = new ObjArray(); private ObjArray itsInterfaces = new ObjArray(); private short itsFlags; private short itsThisClassIndex; private short itsSuperClassIndex; private short itsSourceFileNameIndex; private static final int MIN_LABEL_TABLE_SIZE = 32; private int[] itsLabelTable; private int itsLabelTableTop; // itsFixupTable[i] = (label_index << 32) | fixup_site private static final int MIN_FIXUP_TABLE_SIZE = 40; private long[] itsFixupTable; private int itsFixupTableTop; private ObjArray itsVarDescriptors; private char[] tmpCharBuffer = new char[64]; } final class ExceptionTableEntry { ExceptionTableEntry(int startLabel, int endLabel, int handlerLabel, short catchType) { itsStartLabel = startLabel; itsEndLabel = endLabel; itsHandlerLabel = handlerLabel; itsCatchType = catchType; } int itsStartLabel; int itsEndLabel; int itsHandlerLabel; short itsCatchType; } final class ClassFileField { ClassFileField(short nameIndex, short typeIndex, short flags) { itsNameIndex = nameIndex; itsTypeIndex = typeIndex; itsFlags = flags; itsHasAttributes = false; } void setAttributes(short attr1, short attr2, short attr3, int index) { itsHasAttributes = true; itsAttr1 = attr1; itsAttr2 = attr2; itsAttr3 = attr3; itsIndex = index; } int write(byte[] data, int offset) { offset = ClassFileWriter.putInt16(itsFlags, data, offset); offset = ClassFileWriter.putInt16(itsNameIndex, data, offset); offset = ClassFileWriter.putInt16(itsTypeIndex, data, offset); if (!itsHasAttributes) { // write 0 attributes offset = ClassFileWriter.putInt16(0, data, offset); } else { offset = ClassFileWriter.putInt16(1, data, offset); offset = ClassFileWriter.putInt16(itsAttr1, data, offset); offset = ClassFileWriter.putInt16(itsAttr2, data, offset); offset = ClassFileWriter.putInt16(itsAttr3, data, offset); offset = ClassFileWriter.putInt16(itsIndex, data, offset); } return offset; } int getWriteSize() { int size = 2 * 3; if (!itsHasAttributes) { size += 2; } else { size += 2 + 2 * 4; } return size; } private short itsNameIndex; private short itsTypeIndex; private short itsFlags; private boolean itsHasAttributes; private short itsAttr1, itsAttr2, itsAttr3; private int itsIndex; } final class ClassFileMethod { ClassFileMethod(String name, short nameIndex, String type, short typeIndex, short flags) { itsName = name; itsNameIndex = nameIndex; itsType = type; itsTypeIndex = typeIndex; itsFlags = flags; } void setCodeAttribute(byte codeAttribute[]) { itsCodeAttribute = codeAttribute; } int write(byte[] data, int offset) { offset = ClassFileWriter.putInt16(itsFlags, data, offset); offset = ClassFileWriter.putInt16(itsNameIndex, data, offset); offset = ClassFileWriter.putInt16(itsTypeIndex, data, offset); // Code attribute only offset = ClassFileWriter.putInt16(1, data, offset); System.arraycopy(itsCodeAttribute, 0, data, offset, itsCodeAttribute.length); offset += itsCodeAttribute.length; return offset; } int getWriteSize() { return 2 * 4 + itsCodeAttribute.length; } String getName() { return itsName; } String getType() { return itsType; } short getFlags() { return itsFlags; } private String itsName; private String itsType; private short itsNameIndex; private short itsTypeIndex; private short itsFlags; private byte[] itsCodeAttribute; } final class ConstantPool { ConstantPool(ClassFileWriter cfw) { this.cfw = cfw; itsTopIndex = 1; // the zero'th entry is reserved itsPool = new byte[ConstantPoolSize]; itsTop = 0; } private static final int ConstantPoolSize = 256; static final byte CONSTANT_Class = 7, CONSTANT_Fieldref = 9, CONSTANT_Methodref = 10, CONSTANT_InterfaceMethodref = 11, CONSTANT_String = 8, CONSTANT_Integer = 3, CONSTANT_Float = 4, CONSTANT_Long = 5, CONSTANT_Double = 6, CONSTANT_NameAndType = 12, CONSTANT_Utf8 = 1; int write(byte[] data, int offset) { offset = ClassFileWriter.putInt16((short)itsTopIndex, data, offset); System.arraycopy(itsPool, 0, data, offset, itsTop); offset += itsTop; return offset; } int getWriteSize() { return 2 + itsTop; } int addConstant(int k) { ensure(5); itsPool[itsTop++] = CONSTANT_Integer; itsTop = ClassFileWriter.putInt32(k, itsPool, itsTop); itsPoolTypes.put(itsTopIndex, CONSTANT_Integer); return (short)(itsTopIndex++); } int addConstant(long k) { ensure(9); itsPool[itsTop++] = CONSTANT_Long; itsTop = ClassFileWriter.putInt64(k, itsPool, itsTop); int index = itsTopIndex; itsTopIndex += 2; itsPoolTypes.put(index, CONSTANT_Long); return index; } int addConstant(float k) { ensure(5); itsPool[itsTop++] = CONSTANT_Float; int bits = Float.floatToIntBits(k); itsTop = ClassFileWriter.putInt32(bits, itsPool, itsTop); itsPoolTypes.put(itsTopIndex, CONSTANT_Float); return itsTopIndex++; } int addConstant(double k) { ensure(9); itsPool[itsTop++] = CONSTANT_Double; long bits = Double.doubleToLongBits(k); itsTop = ClassFileWriter.putInt64(bits, itsPool, itsTop); int index = itsTopIndex; itsTopIndex += 2; itsPoolTypes.put(index, CONSTANT_Double); return index; } int addConstant(String k) { int utf8Index = 0xFFFF & addUtf8(k); int theIndex = itsStringConstHash.getInt(utf8Index, -1); if (theIndex == -1) { theIndex = itsTopIndex++; ensure(3); itsPool[itsTop++] = CONSTANT_String; itsTop = ClassFileWriter.putInt16(utf8Index, itsPool, itsTop); itsStringConstHash.put(utf8Index, theIndex); } itsPoolTypes.put(theIndex, CONSTANT_String); return theIndex; } boolean isUnderUtfEncodingLimit(String s) { int strLen = s.length(); if (strLen * 3 <= MAX_UTF_ENCODING_SIZE) { return true; } else if (strLen > MAX_UTF_ENCODING_SIZE) { return false; } return strLen == getUtfEncodingLimit(s, 0, strLen); } /** * Get maximum i such that start <= i <= end and * s.substring(start, i) fits JVM UTF string encoding limit. */ int getUtfEncodingLimit(String s, int start, int end) { if ((end - start) * 3 <= MAX_UTF_ENCODING_SIZE) { return end; } int limit = MAX_UTF_ENCODING_SIZE; for (int i = start; i != end; i++) { int c = s.charAt(i); if (0 != c && c <= 0x7F) { --limit; } else if (c < 0x7FF) { limit -= 2; } else { limit -= 3; } if (limit < 0) { return i; } } return end; } short addUtf8(String k) { int theIndex = itsUtf8Hash.get(k, -1); if (theIndex == -1) { int strLen = k.length(); boolean tooBigString; if (strLen > MAX_UTF_ENCODING_SIZE) { tooBigString = true; } else { tooBigString = false; // Ask for worst case scenario buffer when each char takes 3 // bytes ensure(1 + 2 + strLen * 3); int top = itsTop; itsPool[top++] = CONSTANT_Utf8; top += 2; // skip length char[] chars = cfw.getCharBuffer(strLen); k.getChars(0, strLen, chars, 0); for (int i = 0; i != strLen; i++) { int c = chars[i]; if (c != 0 && c <= 0x7F) { itsPool[top++] = (byte)c; } else if (c > 0x7FF) { itsPool[top++] = (byte)(0xE0 | (c >> 12)); itsPool[top++] = (byte)(0x80 | ((c >> 6) & 0x3F)); itsPool[top++] = (byte)(0x80 | (c & 0x3F)); } else { itsPool[top++] = (byte)(0xC0 | (c >> 6)); itsPool[top++] = (byte)(0x80 | (c & 0x3F)); } } int utfLen = top - (itsTop + 1 + 2); if (utfLen > MAX_UTF_ENCODING_SIZE) { tooBigString = true; } else { // Write back length itsPool[itsTop + 1] = (byte)(utfLen >>> 8); itsPool[itsTop + 2] = (byte)utfLen; itsTop = top; theIndex = itsTopIndex++; itsUtf8Hash.put(k, theIndex); } } if (tooBigString) { throw new IllegalArgumentException("Too big string"); } } setConstantData(theIndex, k); itsPoolTypes.put(theIndex, CONSTANT_Utf8); return (short)theIndex; } private short addNameAndType(String name, String type) { short nameIndex = addUtf8(name); short typeIndex = addUtf8(type); ensure(5); itsPool[itsTop++] = CONSTANT_NameAndType; itsTop = ClassFileWriter.putInt16(nameIndex, itsPool, itsTop); itsTop = ClassFileWriter.putInt16(typeIndex, itsPool, itsTop); itsPoolTypes.put(itsTopIndex, CONSTANT_NameAndType); return (short)(itsTopIndex++); } short addClass(String className) { int theIndex = itsClassHash.get(className, -1); if (theIndex == -1) { String slashed = className; if (className.indexOf('.') > 0) { slashed = ClassFileWriter.getSlashedForm(className); theIndex = itsClassHash.get(slashed, -1); if (theIndex != -1) { itsClassHash.put(className, theIndex); } } if (theIndex == -1) { int utf8Index = addUtf8(slashed); ensure(3); itsPool[itsTop++] = CONSTANT_Class; itsTop = ClassFileWriter.putInt16(utf8Index, itsPool, itsTop); theIndex = itsTopIndex++; itsClassHash.put(slashed, theIndex); if (className != slashed) { itsClassHash.put(className, theIndex); } } } setConstantData(theIndex, className); itsPoolTypes.put(theIndex, CONSTANT_Class); return (short)theIndex; } short addFieldRef(String className, String fieldName, String fieldType) { FieldOrMethodRef ref = new FieldOrMethodRef(className, fieldName, fieldType); int theIndex = itsFieldRefHash.get(ref, -1); if (theIndex == -1) { short ntIndex = addNameAndType(fieldName, fieldType); short classIndex = addClass(className); ensure(5); itsPool[itsTop++] = CONSTANT_Fieldref; itsTop = ClassFileWriter.putInt16(classIndex, itsPool, itsTop); itsTop = ClassFileWriter.putInt16(ntIndex, itsPool, itsTop); theIndex = itsTopIndex++; itsFieldRefHash.put(ref, theIndex); } setConstantData(theIndex, ref); itsPoolTypes.put(theIndex, CONSTANT_Fieldref); return (short)theIndex; } short addMethodRef(String className, String methodName, String methodType) { FieldOrMethodRef ref = new FieldOrMethodRef(className, methodName, methodType); int theIndex = itsMethodRefHash.get(ref, -1); if (theIndex == -1) { short ntIndex = addNameAndType(methodName, methodType); short classIndex = addClass(className); ensure(5); itsPool[itsTop++] = CONSTANT_Methodref; itsTop = ClassFileWriter.putInt16(classIndex, itsPool, itsTop); itsTop = ClassFileWriter.putInt16(ntIndex, itsPool, itsTop); theIndex = itsTopIndex++; itsMethodRefHash.put(ref, theIndex); } setConstantData(theIndex, ref); itsPoolTypes.put(theIndex, CONSTANT_Methodref); return (short)theIndex; } short addInterfaceMethodRef(String className, String methodName, String methodType) { short ntIndex = addNameAndType(methodName, methodType); short classIndex = addClass(className); ensure(5); itsPool[itsTop++] = CONSTANT_InterfaceMethodref; itsTop = ClassFileWriter.putInt16(classIndex, itsPool, itsTop); itsTop = ClassFileWriter.putInt16(ntIndex, itsPool, itsTop); FieldOrMethodRef r = new FieldOrMethodRef(className, methodName, methodType); setConstantData(itsTopIndex, r); itsPoolTypes.put(itsTopIndex, CONSTANT_InterfaceMethodref); return (short)(itsTopIndex++); } Object getConstantData(int index) { return itsConstantData.getObject(index); } void setConstantData(int index, Object data) { itsConstantData.put(index, data); } byte getConstantType(int index) { return (byte) itsPoolTypes.getInt(index, 0); } void ensure(int howMuch) { if (itsTop + howMuch > itsPool.length) { int newCapacity = itsPool.length * 2; if (itsTop + howMuch > newCapacity) { newCapacity = itsTop + howMuch; } byte[] tmp = new byte[newCapacity]; System.arraycopy(itsPool, 0, tmp, 0, itsTop); itsPool = tmp; } } private ClassFileWriter cfw; private static final int MAX_UTF_ENCODING_SIZE = 65535; private UintMap itsStringConstHash = new UintMap(); private ObjToIntMap itsUtf8Hash = new ObjToIntMap(); private ObjToIntMap itsFieldRefHash = new ObjToIntMap(); private ObjToIntMap itsMethodRefHash = new ObjToIntMap(); private ObjToIntMap itsClassHash = new ObjToIntMap(); private int itsTop; private int itsTopIndex; private UintMap itsConstantData = new UintMap(); private UintMap itsPoolTypes = new UintMap(); private byte itsPool[]; } final class FieldOrMethodRef { FieldOrMethodRef(String className, String name, String type) { this.className = className; this.name = name; this.type = type; } public String getClassName() { return className; } public String getName() { return name; } public String getType() { return type; } @Override public boolean equals(Object obj) { if (!(obj instanceof FieldOrMethodRef)) { return false; } FieldOrMethodRef x = (FieldOrMethodRef)obj; return className.equals(x.className) && name.equals(x.name) && type.equals(x.type); } @Override public int hashCode() { if (hashCode == -1) { int h1 = className.hashCode(); int h2 = name.hashCode(); int h3 = type.hashCode(); hashCode = h1 ^ h2 ^ h3; } return hashCode; } private String className; private String name; private String type; private int hashCode = -1; } /** * A super block is defined as a contiguous chunk of code with a single entry * point and multiple exit points (therefore ending in an unconditional jump * or the end of the method). This is used to emulate OpenJDK's compiler, which * outputs stack map frames at the start of every super block except the method * start. */ final class SuperBlock { SuperBlock(int index, int start, int end, int[] initialLocals) { this.index = index; this.start = start; this.end = end; locals = new int[initialLocals.length]; System.arraycopy(initialLocals, 0, locals, 0, initialLocals.length); stack = new int[0]; isInitialized = false; isInQueue = false; } int getIndex() { return index; } int[] getLocals() { int[] copy = new int[locals.length]; System.arraycopy(locals, 0, copy, 0, locals.length); return copy; } /** * Get a copy of the super block's locals without any trailing TOP types. * * This is useful for actual writing stack maps; during the computation of * stack map types, all local arrays have the same size; the max locals for * the method. In addition, DOUBLE and LONG types have trailing TOP types * because they occupy two words. For writing purposes, these are not * useful. */ int[] getTrimmedLocals() { int last = locals.length - 1; // Exclude all of the trailing TOPs not bound to a DOUBLE/LONG while (last >= 0 && locals[last] == TypeInfo.TOP && !TypeInfo.isTwoWords(locals[last - 1])) { last--; } last++; // Exclude trailing TOPs following a DOUBLE/LONG int size = last; for (int i = 0; i < last; i++) { if (TypeInfo.isTwoWords(locals[i])) { size--; } } int[] copy = new int[size]; for (int i = 0, j = 0; i < size; i++, j++) { copy[i] = locals[j]; if (TypeInfo.isTwoWords(locals[j])) { j++; } } return copy; } int[] getStack() { int[] copy = new int[stack.length]; System.arraycopy(stack, 0, copy, 0, stack.length); return copy; } boolean merge(int[] locals, int localsTop, int[] stack, int stackTop, ConstantPool pool) { if (!isInitialized) { System.arraycopy(locals, 0, this.locals, 0, localsTop); this.stack = new int[stackTop]; System.arraycopy(stack, 0, this.stack, 0, stackTop); isInitialized = true; return true; } else if (this.locals.length == localsTop && this.stack.length == stackTop) { boolean localsChanged = mergeState(this.locals, locals, localsTop, pool); boolean stackChanged = mergeState(this.stack, stack, stackTop, pool); return localsChanged || stackChanged; } else { if (ClassFileWriter.StackMapTable.DEBUGSTACKMAP) { System.out.println("bad merge"); System.out.println("current type state:"); TypeInfo.print(this.locals, this.stack, pool); System.out.println("incoming type state:"); TypeInfo.print(locals, localsTop, stack, stackTop, pool); } throw new IllegalArgumentException("bad merge attempt"); } } /** * Merge an operand stack or local variable array with incoming state. * * They are treated the same way; by this point, it should already be * ensured that the array sizes are the same, which is the only additional * constraint that is imposed on merging operand stacks (the local variable * array is always the same size). */ private boolean mergeState(int[] current, int[] incoming, int size, ConstantPool pool) { boolean changed = false; for (int i = 0; i < size; i++) { int currentType = current[i]; current[i] = TypeInfo.merge(current[i], incoming[i], pool); if (currentType != current[i]) { changed = true; } } return changed; } int getStart() { return start; } int getEnd() { return end; } @Override public String toString() { return "sb " + index; } boolean isInitialized() { return isInitialized; } void setInitialized(boolean b) { isInitialized = b; } boolean isInQueue() { return isInQueue; } void setInQueue(boolean b) { isInQueue = b; } private int index; private int start; private int end; private int[] locals; private int[] stack; private boolean isInitialized; private boolean isInQueue; } /** * Helper class for internal representations of type information. In most * cases, type information can be represented by a constant, but in some * cases, a payload is included. Despite the payload coming after the type * tag in the output, we store it in bits 8-23 for uniformity; the tag is * always in bits 0-7. */ final class TypeInfo { private TypeInfo() { } static final int TOP = 0; static final int INTEGER = 1; static final int FLOAT = 2; static final int DOUBLE = 3; static final int LONG = 4; static final int NULL = 5; static final int UNINITIALIZED_THIS = 6; static final int OBJECT_TAG = 7; static final int UNINITIALIZED_VAR_TAG = 8; static final int OBJECT(int constantPoolIndex) { return ((constantPoolIndex & 0xFFFF) << 8) | OBJECT_TAG; } static final int OBJECT(String type, ConstantPool pool) { return OBJECT(pool.addClass(type)); } static final int UNINITIALIZED_VARIABLE(int bytecodeOffset) { return ((bytecodeOffset & 0xFFFF) << 8) | UNINITIALIZED_VAR_TAG; } static final int getTag(int typeInfo) { return typeInfo & 0xFF; } static final int getPayload(int typeInfo) { return typeInfo >>> 8; } /** * Treat the result of getPayload as a constant pool index and fetch the * corresponding String mapped to it. * * Only works on OBJECT types. */ static final String getPayloadAsType(int typeInfo, ConstantPool pool) { if (getTag(typeInfo) == OBJECT_TAG) { return (String) pool.getConstantData(getPayload(typeInfo)); } throw new IllegalArgumentException("expecting object type"); } /** * Create type information from an internal type. */ static final int fromType(String type, ConstantPool pool) { if (type.length() == 1) { switch (type.charAt(0)) { case 'B': // sbyte case 'C': // unicode char case 'S': // short case 'Z': // boolean case 'I': // all of the above are verified as integers return INTEGER; case 'D': return DOUBLE; case 'F': return FLOAT; case 'J': return LONG; default: throw new IllegalArgumentException("bad type"); } } return TypeInfo.OBJECT(type, pool); } static boolean isTwoWords(int type) { return type == DOUBLE || type == LONG; } /** * Merge two verification types. * * In most cases, the verification types must be the same. For example, * INTEGER and DOUBLE cannot be merged and an exception will be thrown. * The basic rules are: * * - If the types are equal, simply return one. * - If either type is TOP, return TOP. * - If either type is NULL, return the other type. * - If both types are objects, find the lowest common ancestor in the * class hierarchy. * * This method uses reflection to traverse the class hierarchy. Therefore, * it is assumed that the current class being generated is never the target * of a full object-object merge, which would need to load the current * class reflectively. */ static int merge(int current, int incoming, ConstantPool pool) { int currentTag = getTag(current); int incomingTag = getTag(incoming); boolean currentIsObject = currentTag == TypeInfo.OBJECT_TAG; boolean incomingIsObject = incomingTag == TypeInfo.OBJECT_TAG; if (current == incoming || (currentIsObject && incoming == NULL)) { return current; } else if (currentTag == TypeInfo.TOP || incomingTag == TypeInfo.TOP) { return TypeInfo.TOP; } else if (current == NULL && incomingIsObject) { return incoming; } else if (currentIsObject && incomingIsObject) { String currentName = getPayloadAsType(current, pool); String incomingName = getPayloadAsType(incoming, pool); // The class file always has the class and super names in the same // spot. The constant order is: class_data, class_name, super_data, // super_name. String currentlyGeneratedName = (String) pool.getConstantData(2); String currentlyGeneratedSuperName = (String) pool.getConstantData(4); // If any of the merged types are the class that's currently being // generated, automatically start at the super class instead. At // this point, we already know the classes are different, so we // don't need to handle that case. if (currentName.equals(currentlyGeneratedName)) { currentName = currentlyGeneratedSuperName; } if (incomingName.equals(currentlyGeneratedName)) { incomingName = currentlyGeneratedSuperName; } Class currentClass = getClassFromInternalName(currentName); Class incomingClass = getClassFromInternalName(incomingName); if (currentClass.isAssignableFrom(incomingClass)) { return current; } else if (incomingClass.isAssignableFrom(currentClass)) { return incoming; } else if (incomingClass.isInterface() || currentClass.isInterface()) { // For verification purposes, Sun specifies that interfaces are // subtypes of Object. Therefore, we know that the merge result // involving interfaces where one is not assignable to the // other results in Object. return OBJECT("java/lang/Object", pool); } else { Class commonClass = incomingClass.getSuperclass(); while (commonClass != null) { if (commonClass.isAssignableFrom(currentClass)) { String name = commonClass.getName(); name = ClassFileWriter.getSlashedForm(name); return OBJECT(name, pool); } commonClass = commonClass.getSuperclass(); } } } throw new IllegalArgumentException("bad merge attempt between " + toString(current, pool) + " and " + toString(incoming, pool)); } static String toString(int type, ConstantPool pool) { int tag = getTag(type); switch (tag) { case TypeInfo.TOP: return "top"; case TypeInfo.INTEGER: return "int"; case TypeInfo.FLOAT: return "float"; case TypeInfo.DOUBLE: return "double"; case TypeInfo.LONG: return "long"; case TypeInfo.NULL: return "null"; case TypeInfo.UNINITIALIZED_THIS: return "uninitialized_this"; default: if (tag == TypeInfo.OBJECT_TAG) { return getPayloadAsType(type, pool); } else if (tag == TypeInfo.UNINITIALIZED_VAR_TAG) { return "uninitialized"; } else { throw new IllegalArgumentException("bad type"); } } } /** * Take an internal name and return a java.lang.Class instance that * represents it. * * For example, given "java/lang/Object", returns the equivalent of * Class.forName("java.lang.Object"), but also handles exceptions. */ static Class getClassFromInternalName(String internalName) { try { return Class.forName(internalName.replace('/', '.')); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } } static String toString(int[] types, ConstantPool pool) { return toString(types, types.length, pool); } static String toString(int[] types, int typesTop, ConstantPool pool) { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < typesTop; i++) { if (i > 0) { sb.append(", "); } sb.append(toString(types[i], pool)); } sb.append("]"); return sb.toString(); } static void print(int[] locals, int[] stack, ConstantPool pool) { print(locals, locals.length, stack, stack.length, pool); } static void print(int[] locals, int localsTop, int[] stack, int stackTop, ConstantPool pool) { System.out.print("locals: "); System.out.println(toString(locals, localsTop, pool)); System.out.print("stack: "); System.out.println(toString(stack, stackTop, pool)); System.out.println(); } } rhino-1.7R4/src/org/mozilla/javascript/000077500000000000000000000000001176760007500201125ustar00rootroot00000000000000rhino-1.7R4/src/org/mozilla/javascript/Arguments.java000066400000000000000000000256011176760007500227260ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * This class implements the "arguments" object. * * See ECMA 10.1.8 * * @see org.mozilla.javascript.NativeCall * @author Norris Boyd */ final class Arguments extends IdScriptableObject { static final long serialVersionUID = 4275508002492040609L; private static final String FTAG = "Arguments"; public Arguments(NativeCall activation) { this.activation = activation; Scriptable parent = activation.getParentScope(); setParentScope(parent); setPrototype(ScriptableObject.getObjectPrototype(parent)); args = activation.originalArgs; lengthObj = Integer.valueOf(args.length); NativeFunction f = activation.function; calleeObj = f; Scriptable topLevel = getTopLevelScope(parent); constructor = getProperty(topLevel, "Object"); int version = f.getLanguageVersion(); if (version <= Context.VERSION_1_3 && version != Context.VERSION_DEFAULT) { callerObj = null; } else { callerObj = NOT_FOUND; } } @Override public String getClassName() { return FTAG; } private Object arg(int index) { if (index < 0 || args.length <= index) return NOT_FOUND; return args[index]; } // the following helper methods assume that 0 < index < args.length private void putIntoActivation(int index, Object value) { String argName = activation.function.getParamOrVarName(index); activation.put(argName, activation, value); } private Object getFromActivation(int index) { String argName = activation.function.getParamOrVarName(index); return activation.get(argName, activation); } private void replaceArg(int index, Object value) { if (sharedWithActivation(index)) { putIntoActivation(index, value); } synchronized (this) { if (args == activation.originalArgs) { args = args.clone(); } args[index] = value; } } private void removeArg(int index) { synchronized (this) { if (args[index] != NOT_FOUND) { if (args == activation.originalArgs) { args = args.clone(); } args[index] = NOT_FOUND; } } } // end helpers @Override public boolean has(int index, Scriptable start) { if (arg(index) != NOT_FOUND) { return true; } return super.has(index, start); } @Override public Object get(int index, Scriptable start) { final Object value = arg(index); if (value == NOT_FOUND) { return super.get(index, start); } else { if (sharedWithActivation(index)) { return getFromActivation(index); } else { return value; } } } private boolean sharedWithActivation(int index) { NativeFunction f = activation.function; int definedCount = f.getParamCount(); if (index < definedCount) { // Check if argument is not hidden by later argument with the same // name as hidden arguments are not shared with activation if (index < definedCount - 1) { String argName = f.getParamOrVarName(index); for (int i = index + 1; i < definedCount; i++) { if (argName.equals(f.getParamOrVarName(i))) { return false; } } } return true; } return false; } @Override public void put(int index, Scriptable start, Object value) { if (arg(index) == NOT_FOUND) { super.put(index, start, value); } else { replaceArg(index, value); } } @Override public void delete(int index) { if (0 <= index && index < args.length) { removeArg(index); } super.delete(index); } // #string_id_map# private static final int Id_callee = 1, Id_length = 2, Id_caller = 3, Id_constructor = 4, MAX_INSTANCE_ID = Id_constructor; @Override protected int getMaxInstanceId() { return MAX_INSTANCE_ID; } @Override protected int findInstanceIdInfo(String s) { int id; // #generated# Last update: 2010-01-06 05:48:21 ARST L0: { id = 0; String X = null; int c; int s_length = s.length(); if (s_length==6) { c=s.charAt(5); if (c=='e') { X="callee";id=Id_callee; } else if (c=='h') { X="length";id=Id_length; } else if (c=='r') { X="caller";id=Id_caller; } } else if (s_length==11) { X="constructor";id=Id_constructor; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# if (id == 0) return super.findInstanceIdInfo(s); int attr; switch (id) { case Id_callee: case Id_caller: case Id_length: case Id_constructor: attr = DONTENUM; break; default: throw new IllegalStateException(); } return instanceIdInfo(attr, id); } // #/string_id_map# @Override protected String getInstanceIdName(int id) { switch (id) { case Id_callee: return "callee"; case Id_length: return "length"; case Id_caller: return "caller"; case Id_constructor: return "constructor"; } return null; } @Override protected Object getInstanceIdValue(int id) { switch (id) { case Id_callee: return calleeObj; case Id_length: return lengthObj; case Id_caller: { Object value = callerObj; if (value == UniqueTag.NULL_VALUE) { value = null; } else if (value == null) { NativeCall caller = activation.parentActivationCall; if (caller != null) { value = caller.get("arguments", caller); } } return value; } case Id_constructor: return constructor; } return super.getInstanceIdValue(id); } @Override protected void setInstanceIdValue(int id, Object value) { switch (id) { case Id_callee: calleeObj = value; return; case Id_length: lengthObj = value; return; case Id_caller: callerObj = (value != null) ? value : UniqueTag.NULL_VALUE; return; case Id_constructor: constructor = value; return; } super.setInstanceIdValue(id, value); } @Override Object[] getIds(boolean getAll) { Object[] ids = super.getIds(getAll); if (args.length != 0) { boolean[] present = new boolean[args.length]; int extraCount = args.length; for (int i = 0; i != ids.length; ++i) { Object id = ids[i]; if (id instanceof Integer) { int index = ((Integer)id).intValue(); if (0 <= index && index < args.length) { if (!present[index]) { present[index] = true; extraCount--; } } } } if (!getAll) { // avoid adding args which were redefined to non-enumerable for (int i = 0; i < present.length; i++) { if (!present[i] && super.has(i, this)) { present[i] = true; extraCount--; } } } if (extraCount != 0) { Object[] tmp = new Object[extraCount + ids.length]; System.arraycopy(ids, 0, tmp, extraCount, ids.length); ids = tmp; int offset = 0; for (int i = 0; i != args.length; ++i) { if (present == null || !present[i]) { ids[offset] = Integer.valueOf(i); ++offset; } } if (offset != extraCount) Kit.codeBug(); } } return ids; } @Override protected ScriptableObject getOwnPropertyDescriptor(Context cx, Object id) { double d = ScriptRuntime.toNumber(id); int index = (int) d; if (d != index) { return super.getOwnPropertyDescriptor(cx, id); } Object value = arg(index); if (value == NOT_FOUND) { return super.getOwnPropertyDescriptor(cx, id); } if (sharedWithActivation(index)) { value = getFromActivation(index); } if (super.has(index, this)) { // the descriptor has been redefined ScriptableObject desc = super.getOwnPropertyDescriptor(cx, id); desc.put("value", desc, value); return desc; } else { Scriptable scope = getParentScope(); if (scope == null) scope = this; return buildDataDescriptor(scope, value, EMPTY); } } @Override protected void defineOwnProperty(Context cx, Object id, ScriptableObject desc, boolean checkValid) { super.defineOwnProperty(cx, id, desc, checkValid); double d = ScriptRuntime.toNumber(id); int index = (int) d; if (d != index) return; Object value = arg(index); if (value == NOT_FOUND) return; if (isAccessorDescriptor(desc)) { removeArg(index); return; } Object newValue = getProperty(desc, "value"); if (newValue == NOT_FOUND) return; replaceArg(index, newValue); if (isFalse(getProperty(desc, "writable"))) { removeArg(index); } } // Fields to hold caller, callee and length properties, // where NOT_FOUND value tags deleted properties. // In addition if callerObj == NULL_VALUE, it tags null for scripts, as // initial callerObj == null means access to caller arguments available // only in JS <= 1.3 scripts private Object callerObj; private Object calleeObj; private Object lengthObj; private Object constructor; private NativeCall activation; // Initially args holds activation.getOriginalArgs(), but any modification // of its elements triggers creation of a copy. If its element holds NOT_FOUND, // it indicates deleted index, in which case super class is queried. private Object[] args; } rhino-1.7R4/src/org/mozilla/javascript/BaseFunction.java000066400000000000000000000457441176760007500233530ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * The base class for Function objects * See ECMA 15.3. * @author Norris Boyd */ public class BaseFunction extends IdScriptableObject implements Function { static final long serialVersionUID = 5311394446546053859L; private static final Object FUNCTION_TAG = "Function"; static void init(Scriptable scope, boolean sealed) { BaseFunction obj = new BaseFunction(); // Function.prototype attributes: see ECMA 15.3.3.1 obj.prototypePropertyAttributes = DONTENUM | READONLY | PERMANENT; obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } public BaseFunction() { } public BaseFunction(Scriptable scope, Scriptable prototype) { super(scope, prototype); } @Override public String getClassName() { return "Function"; } /** * Gets the value returned by calling the typeof operator on this object. * @see org.mozilla.javascript.ScriptableObject#getTypeOf() * @return "function" or "undefined" if {@link #avoidObjectDetection()} returns true */ @Override public String getTypeOf() { return avoidObjectDetection() ? "undefined" : "function"; } /** * Implements the instanceof operator for JavaScript Function objects. *

* * foo = new Foo();
* foo instanceof Foo; // true
*
* * @param instance The value that appeared on the LHS of the instanceof * operator * @return true if the "prototype" property of "this" appears in * value's prototype chain * */ @Override public boolean hasInstance(Scriptable instance) { Object protoProp = ScriptableObject.getProperty(this, "prototype"); if (protoProp instanceof Scriptable) { return ScriptRuntime.jsDelegatesTo(instance, (Scriptable)protoProp); } throw ScriptRuntime.typeError1("msg.instanceof.bad.prototype", getFunctionName()); } // #string_id_map# private static final int Id_length = 1, Id_arity = 2, Id_name = 3, Id_prototype = 4, Id_arguments = 5, MAX_INSTANCE_ID = 5; @Override protected int getMaxInstanceId() { return MAX_INSTANCE_ID; } @Override protected int findInstanceIdInfo(String s) { int id; // #generated# Last update: 2007-05-09 08:15:15 EDT L0: { id = 0; String X = null; int c; L: switch (s.length()) { case 4: X="name";id=Id_name; break L; case 5: X="arity";id=Id_arity; break L; case 6: X="length";id=Id_length; break L; case 9: c=s.charAt(0); if (c=='a') { X="arguments";id=Id_arguments; } else if (c=='p') { X="prototype";id=Id_prototype; } break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# // #/string_id_map# if (id == 0) return super.findInstanceIdInfo(s); int attr; switch (id) { case Id_length: case Id_arity: case Id_name: attr = DONTENUM | READONLY | PERMANENT; break; case Id_prototype: // some functions such as built-ins don't have a prototype property if (!hasPrototypeProperty()) { return 0; } attr = prototypePropertyAttributes; break; case Id_arguments: attr = DONTENUM | PERMANENT; break; default: throw new IllegalStateException(); } return instanceIdInfo(attr, id); } @Override protected String getInstanceIdName(int id) { switch (id) { case Id_length: return "length"; case Id_arity: return "arity"; case Id_name: return "name"; case Id_prototype: return "prototype"; case Id_arguments: return "arguments"; } return super.getInstanceIdName(id); } @Override protected Object getInstanceIdValue(int id) { switch (id) { case Id_length: return ScriptRuntime.wrapInt(getLength()); case Id_arity: return ScriptRuntime.wrapInt(getArity()); case Id_name: return getFunctionName(); case Id_prototype: return getPrototypeProperty(); case Id_arguments: return getArguments(); } return super.getInstanceIdValue(id); } @Override protected void setInstanceIdValue(int id, Object value) { switch (id) { case Id_prototype: if ((prototypePropertyAttributes & READONLY) == 0) { prototypeProperty = (value != null) ? value : UniqueTag.NULL_VALUE; } return; case Id_arguments: if (value == NOT_FOUND) { // This should not be called since "arguments" is PERMANENT Kit.codeBug(); } defaultPut("arguments", value); return; case Id_name: case Id_arity: case Id_length: return; } super.setInstanceIdValue(id, value); } @Override protected void fillConstructorProperties(IdFunctionObject ctor) { // Fix up bootstrapping problem: getPrototype of the IdFunctionObject // can not return Function.prototype because Function object is not // yet defined. ctor.setPrototype(this); super.fillConstructorProperties(ctor); } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=1; s="constructor"; break; case Id_toString: arity=1; s="toString"; break; case Id_toSource: arity=1; s="toSource"; break; case Id_apply: arity=2; s="apply"; break; case Id_call: arity=1; s="call"; break; case Id_bind: arity=1; s="bind"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(FUNCTION_TAG, id, s, arity); } static boolean isApply(IdFunctionObject f) { return f.hasTag(FUNCTION_TAG) && f.methodId() == Id_apply; } static boolean isApplyOrCall(IdFunctionObject f) { if(f.hasTag(FUNCTION_TAG)) { switch(f.methodId()) { case Id_apply: case Id_call: return true; } } return false; } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(FUNCTION_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_constructor: return jsConstructor(cx, scope, args); case Id_toString: { BaseFunction realf = realFunction(thisObj, f); int indent = ScriptRuntime.toInt32(args, 0); return realf.decompile(indent, 0); } case Id_toSource: { BaseFunction realf = realFunction(thisObj, f); int indent = 0; int flags = Decompiler.TO_SOURCE_FLAG; if (args.length != 0) { indent = ScriptRuntime.toInt32(args[0]); if (indent >= 0) { flags = 0; } else { indent = 0; } } return realf.decompile(indent, flags); } case Id_apply: case Id_call: return ScriptRuntime.applyOrCall(id == Id_apply, cx, scope, thisObj, args); case Id_bind: if ( !(thisObj instanceof Callable) ) { throw ScriptRuntime.notFunctionError(thisObj); } Callable targetFunction = (Callable) thisObj; int argc = args.length; final Scriptable boundThis; final Object[] boundArgs; if (argc > 0) { boundThis = ScriptRuntime.toObjectOrNull(cx, args[0], scope); boundArgs = new Object[argc-1]; System.arraycopy(args, 1, boundArgs, 0, argc-1); } else { boundThis = null; boundArgs = ScriptRuntime.emptyArgs; } return new BoundFunction(cx, scope, targetFunction, boundThis, boundArgs); } throw new IllegalArgumentException(String.valueOf(id)); } private BaseFunction realFunction(Scriptable thisObj, IdFunctionObject f) { Object x = thisObj.getDefaultValue(ScriptRuntime.FunctionClass); if (x instanceof BaseFunction) { return (BaseFunction)x; } throw ScriptRuntime.typeError1("msg.incompat.call", f.getFunctionName()); } /** * Make value as DontEnum, DontDelete, ReadOnly * prototype property of this Function object */ public void setImmunePrototypeProperty(Object value) { if ((prototypePropertyAttributes & READONLY) != 0) { throw new IllegalStateException(); } prototypeProperty = (value != null) ? value : UniqueTag.NULL_VALUE; prototypePropertyAttributes = DONTENUM | PERMANENT | READONLY; } protected Scriptable getClassPrototype() { Object protoVal = getPrototypeProperty(); if (protoVal instanceof Scriptable) { return (Scriptable) protoVal; } return ScriptableObject.getObjectPrototype(this); } /** * Should be overridden. */ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { return Undefined.instance; } public Scriptable construct(Context cx, Scriptable scope, Object[] args) { Scriptable result = createObject(cx, scope); if (result != null) { Object val = call(cx, scope, result, args); if (val instanceof Scriptable) { result = (Scriptable)val; } } else { Object val = call(cx, scope, null, args); if (!(val instanceof Scriptable)) { // It is program error not to return Scriptable from // the call method if createObject returns null. throw new IllegalStateException( "Bad implementaion of call as constructor, name=" +getFunctionName()+" in "+getClass().getName()); } result = (Scriptable)val; if (result.getPrototype() == null) { Scriptable proto = getClassPrototype(); if (result != proto) { result.setPrototype(proto); } } if (result.getParentScope() == null) { Scriptable parent = getParentScope(); if (result != parent) { result.setParentScope(parent); } } } return result; } /** * Creates new script object. * The default implementation of {@link #construct} uses the method to * to get the value for thisObj argument when invoking * {@link #call}. * The methos is allowed to return null to indicate that * {@link #call} will create a new object itself. In this case * {@link #construct} will set scope and prototype on the result * {@link #call} unless they are already set. */ public Scriptable createObject(Context cx, Scriptable scope) { Scriptable newInstance = new NativeObject(); newInstance.setPrototype(getClassPrototype()); newInstance.setParentScope(getParentScope()); return newInstance; } /** * Decompile the source information associated with this js * function/script back into a string. * * @param indent How much to indent the decompiled result. * * @param flags Flags specifying format of decompilation output. */ String decompile(int indent, int flags) { StringBuffer sb = new StringBuffer(); boolean justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); if (!justbody) { sb.append("function "); sb.append(getFunctionName()); sb.append("() {\n\t"); } sb.append("[native code, arity="); sb.append(getArity()); sb.append("]\n"); if (!justbody) { sb.append("}\n"); } return sb.toString(); } public int getArity() { return 0; } public int getLength() { return 0; } public String getFunctionName() { return ""; } protected boolean hasPrototypeProperty() { return prototypeProperty != null || this instanceof NativeFunction; } protected Object getPrototypeProperty() { Object result = prototypeProperty; if (result == null) { // only create default prototype on native JavaScript functions, // not on built-in functions, java methods, host objects etc. if (this instanceof NativeFunction) { result = setupDefaultPrototype(); } else { result = Undefined.instance; } } else if (result == UniqueTag.NULL_VALUE) { result = null; } return result; } private synchronized Object setupDefaultPrototype() { if (prototypeProperty != null) { return prototypeProperty; } NativeObject obj = new NativeObject(); final int attr = ScriptableObject.DONTENUM; obj.defineProperty("constructor", this, attr); // put the prototype property into the object now, then in the // wacky case of a user defining a function Object(), we don't // get an infinite loop trying to find the prototype. prototypeProperty = obj; Scriptable proto = getObjectPrototype(this); if (proto != obj) { // not the one we just made, it must remain grounded obj.setPrototype(proto); } return obj; } private Object getArguments() { // .arguments is deprecated, so we use a slow // way of getting it that doesn't add to the invocation cost. // TODO: add warning, error based on version Object value = defaultGet("arguments"); if (value != NOT_FOUND) { // Should after changing .arguments its // activation still be available during Function call? // This code assumes it should not: // defaultGet("arguments") != NOT_FOUND // means assigned arguments return value; } Context cx = Context.getContext(); NativeCall activation = ScriptRuntime.findFunctionActivation(cx, this); return (activation == null) ? null : activation.get("arguments", activation); } private static Object jsConstructor(Context cx, Scriptable scope, Object[] args) { int arglen = args.length; StringBuffer sourceBuf = new StringBuffer(); sourceBuf.append("function "); /* version != 1.2 Function constructor behavior - * print 'anonymous' as the function name if the * version (under which the function was compiled) is * less than 1.2... or if it's greater than 1.2, because * we need to be closer to ECMA. */ if (cx.getLanguageVersion() != Context.VERSION_1_2) { sourceBuf.append("anonymous"); } sourceBuf.append('('); // Append arguments as coma separated strings for (int i = 0; i < arglen - 1; i++) { if (i > 0) { sourceBuf.append(','); } sourceBuf.append(ScriptRuntime.toString(args[i])); } sourceBuf.append(") {"); if (arglen != 0) { // append function body String funBody = ScriptRuntime.toString(args[arglen - 1]); sourceBuf.append(funBody); } sourceBuf.append("\n}"); String source = sourceBuf.toString(); int[] linep = new int[1]; String filename = Context.getSourcePositionFromStack(linep); if (filename == null) { filename = ""; linep[0] = 1; } String sourceURI = ScriptRuntime. makeUrlForGeneratedScript(false, filename, linep[0]); Scriptable global = ScriptableObject.getTopLevelScope(scope); ErrorReporter reporter; reporter = DefaultErrorReporter.forEval(cx.getErrorReporter()); Evaluator evaluator = Context.createInterpreter(); if (evaluator == null) { throw new JavaScriptException("Interpreter not present", filename, linep[0]); } // Compile with explicit interpreter instance to force interpreter // mode. return cx.compileFunction(global, source, evaluator, reporter, sourceURI, 1, null); } @Override protected int findPrototypeId(String s) { int id; // #string_id_map# // #generated# Last update: 2009-07-24 16:00:52 EST L0: { id = 0; String X = null; int c; L: switch (s.length()) { case 4: c=s.charAt(0); if (c=='b') { X="bind";id=Id_bind; } else if (c=='c') { X="call";id=Id_call; } break L; case 5: X="apply";id=Id_apply; break L; case 8: c=s.charAt(3); if (c=='o') { X="toSource";id=Id_toSource; } else if (c=='t') { X="toString";id=Id_toString; } break L; case 11: X="constructor";id=Id_constructor; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# return id; } private static final int Id_constructor = 1, Id_toString = 2, Id_toSource = 3, Id_apply = 4, Id_call = 5, Id_bind = 6, MAX_PROTOTYPE_ID = Id_bind; // #/string_id_map# private Object prototypeProperty; // For function object instances, attributes are // {configurable:false, enumerable:false}; // see ECMA 15.3.5.2 private int prototypePropertyAttributes = PERMANENT|DONTENUM; } rhino-1.7R4/src/org/mozilla/javascript/BoundFunction.java000066400000000000000000000053651176760007500235430ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * The class for results of the Function.bind operation * EcmaScript 5 spec, 15.3.4.5 * @author Raphael Speyer */ public class BoundFunction extends BaseFunction { static final long serialVersionUID = 2118137342826470729L; private final Callable targetFunction; private final Scriptable boundThis; private final Object[] boundArgs; private final int length; public BoundFunction(Context cx, Scriptable scope, Callable targetFunction, Scriptable boundThis, Object[] boundArgs) { this.targetFunction = targetFunction; this.boundThis = boundThis; this.boundArgs = boundArgs; if (targetFunction instanceof BaseFunction) { length = Math.max(0, ((BaseFunction) targetFunction).getLength() - boundArgs.length); } else { length = 0; } ScriptRuntime.setFunctionProtoAndParent(this, scope); Function thrower = ScriptRuntime.typeErrorThrower(); NativeObject throwing = new NativeObject(); throwing.put("get", throwing, thrower); throwing.put("set", throwing, thrower); throwing.put("enumerable", throwing, false); throwing.put("configurable", throwing, false); throwing.preventExtensions(); this.defineOwnProperty(cx, "caller", throwing, false); this.defineOwnProperty(cx, "arguments", throwing, false); } @Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] extraArgs) { Scriptable callThis = boundThis != null ? boundThis : ScriptRuntime.getTopCallScope(cx); return targetFunction.call(cx, scope, callThis, concat(boundArgs, extraArgs)); } @Override public Scriptable construct(Context cx, Scriptable scope, Object[] extraArgs) { if (targetFunction instanceof Function) { return ((Function) targetFunction).construct(cx, scope, concat(boundArgs, extraArgs)); } throw ScriptRuntime.typeError0("msg.not.ctor"); } @Override public boolean hasInstance(Scriptable instance) { if (targetFunction instanceof Function) { return ((Function) targetFunction).hasInstance(instance); } throw ScriptRuntime.typeError0("msg.not.ctor"); } @Override public int getLength() { return length; } private Object[] concat(Object[] first, Object[] second) { Object[] args = new Object[first.length + second.length]; System.arraycopy(first, 0, args, 0, first.length); System.arraycopy(second, 0, args, first.length, second.length); return args; } } rhino-1.7R4/src/org/mozilla/javascript/Callable.java000066400000000000000000000016361176760007500224620ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * Generic notion of callable object that can execute some script-related code * upon request with specified values for script scope and this objects. */ public interface Callable { /** * Perform the call. * * @param cx the current Context for this thread * @param scope the scope to use to resolve properties. * @param thisObj the JavaScript this object * @param args the array of arguments * @return the result of the call */ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args); } rhino-1.7R4/src/org/mozilla/javascript/ClassCache.java000066400000000000000000000141161176760007500227510ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.util.Map; import java.util.HashMap; import java.io.Serializable; /** * Cache of generated classes and data structures to access Java runtime * from JavaScript. * * @author Igor Bukanov * * @since Rhino 1.5 Release 5 */ public class ClassCache implements Serializable { private static final long serialVersionUID = -8866246036237312215L; private static final Object AKEY = "ClassCache"; private volatile boolean cachingIsEnabled = true; private transient HashMap,JavaMembers> classTable; private transient HashMap> classAdapterCache; private transient HashMap,Object> interfaceAdapterCache; private int generatedClassSerial; private Scriptable associatedScope; /** * Search for ClassCache object in the given scope. * The method first calls * {@link ScriptableObject#getTopLevelScope(Scriptable scope)} * to get the top most scope and then tries to locate associated * ClassCache object in the prototype chain of the top scope. * * @param scope scope to search for ClassCache object. * @return previously associated ClassCache object or a new instance of * ClassCache if no ClassCache object was found. * * @see #associate(ScriptableObject topScope) */ public static ClassCache get(Scriptable scope) { ClassCache cache = (ClassCache) ScriptableObject.getTopScopeValue(scope, AKEY); if (cache == null) { throw new RuntimeException("Can't find top level scope for " + "ClassCache.get"); } return cache; } /** * Associate ClassCache object with the given top-level scope. * The ClassCache object can only be associated with the given scope once. * * @param topScope scope to associate this ClassCache object with. * @return true if no previous ClassCache objects were embedded into * the scope and this ClassCache were successfully associated * or false otherwise. * * @see #get(Scriptable scope) */ public boolean associate(ScriptableObject topScope) { if (topScope.getParentScope() != null) { // Can only associate cache with top level scope throw new IllegalArgumentException(); } if (this == topScope.associateValue(AKEY, this)) { associatedScope = topScope; return true; } return false; } /** * Empty caches of generated Java classes and Java reflection information. */ public synchronized void clearCaches() { classTable = null; classAdapterCache = null; interfaceAdapterCache = null; } /** * Check if generated Java classes and Java reflection information * is cached. */ public final boolean isCachingEnabled() { return cachingIsEnabled; } /** * Set whether to cache some values. *

* By default, the engine will cache the results of * Class.getMethods() and similar calls. * This can speed execution dramatically, but increases the memory * footprint. Also, with caching enabled, references may be held to * objects past the lifetime of any real usage. *

* If caching is enabled and this method is called with a * false argument, the caches will be emptied. *

* Caching is enabled by default. * * @param enabled if true, caching is enabled * * @see #clearCaches() */ public synchronized void setCachingEnabled(boolean enabled) { if (enabled == cachingIsEnabled) return; if (!enabled) clearCaches(); cachingIsEnabled = enabled; } /** * @return a map from classes to associated JavaMembers objects */ Map,JavaMembers> getClassCacheMap() { if (classTable == null) { classTable = new HashMap,JavaMembers>(); } return classTable; } Map> getInterfaceAdapterCacheMap() { if (classAdapterCache == null) { classAdapterCache = new HashMap>(); } return classAdapterCache; } /** * @deprecated * The method always returns false. * @see #setInvokerOptimizationEnabled(boolean enabled) */ public boolean isInvokerOptimizationEnabled() { return false; } /** * @deprecated * The method does nothing. * Invoker optimization is no longer used by Rhino. * On modern JDK like 1.4 or 1.5 the disadvantages of the optimization * like increased memory usage or longer initialization time overweight * small speed increase that can be gained using generated proxy class * to replace reflection. */ public synchronized void setInvokerOptimizationEnabled(boolean enabled) { } /** * Internal engine method to return serial number for generated classes * to ensure name uniqueness. */ public final synchronized int newClassSerialNumber() { return ++generatedClassSerial; } Object getInterfaceAdapter(Class cl) { return interfaceAdapterCache == null ? null : interfaceAdapterCache.get(cl); } synchronized void cacheInterfaceAdapter(Class cl, Object iadapter) { if (cachingIsEnabled) { if (interfaceAdapterCache == null) { interfaceAdapterCache = new HashMap,Object>(); } interfaceAdapterCache.put(cl, iadapter); } } Scriptable getAssociatedScope() { return associatedScope; } } rhino-1.7R4/src/org/mozilla/javascript/ClassShutter.java000066400000000000000000000046441176760007500234110ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** Embeddings that wish to filter Java classes that are visible to scripts through the LiveConnect, should implement this interface. @see Context#setClassShutter(ClassShutter) @since 1.5 Release 4 @author Norris Boyd */ public interface ClassShutter { /** * Return true iff the Java class with the given name should be exposed * to scripts. *

* An embedding may filter which Java classes are exposed through * LiveConnect to JavaScript scripts. *

* Due to the fact that there is no package reflection in Java, * this method will also be called with package names. There * is no way for Rhino to tell if "Packages.a.b" is a package name * or a class that doesn't exist. What Rhino does is attempt * to load each segment of "Packages.a.b.c": It first attempts to * load class "a", then attempts to load class "a.b", then * finally attempts to load class "a.b.c". On a Rhino installation * without any ClassShutter set, and without any of the * above classes, the expression "Packages.a.b.c" will result in * a [JavaPackage a.b.c] and not an error. *

* With ClassShutter supplied, Rhino will first call * visibleToScripts before attempting to look up the class name. If * visibleToScripts returns false, the class name lookup is not * performed and subsequent Rhino execution assumes the class is * not present. So for "java.lang.System.out.println" the lookup * of "java.lang.System" is skipped and thus Rhino assumes that * "java.lang.System" doesn't exist. So then for "java.lang.System.out", * Rhino attempts to load the class "java.lang.System.out" because * it assumes that "java.lang.System" is a package name. *

* @param fullClassName the full name of the class (including the package * name, with '.' as a delimiter). For example the * standard string class is "java.lang.String" * @return whether or not to reveal this class to scripts */ public boolean visibleToScripts(String fullClassName); } rhino-1.7R4/src/org/mozilla/javascript/CodeGenerator.java000066400000000000000000001367571176760007500235210ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import org.mozilla.javascript.ast.AstRoot; import org.mozilla.javascript.ast.ScriptNode; import org.mozilla.javascript.ast.Jump; import org.mozilla.javascript.ast.FunctionNode; /** * Generates bytecode for the Interpreter. */ class CodeGenerator extends Icode { private static final int MIN_LABEL_TABLE_SIZE = 32; private static final int MIN_FIXUP_TABLE_SIZE = 40; private CompilerEnvirons compilerEnv; private boolean itsInFunctionFlag; private boolean itsInTryFlag; private InterpreterData itsData; private ScriptNode scriptOrFn; private int iCodeTop; private int stackDepth; private int lineNumber; private int doubleTableTop; private ObjToIntMap strings = new ObjToIntMap(20); private int localTop; private int[] labelTable; private int labelTableTop; // fixupTable[i] = (label_index << 32) | fixup_site private long[] fixupTable; private int fixupTableTop; private ObjArray literalIds = new ObjArray(); private int exceptionTableTop; // ECF_ or Expression Context Flags constants: for now only TAIL private static final int ECF_TAIL = 1 << 0; public InterpreterData compile(CompilerEnvirons compilerEnv, ScriptNode tree, String encodedSource, boolean returnFunction) { this.compilerEnv = compilerEnv; if (Token.printTrees) { System.out.println("before transform:"); System.out.println(tree.toStringTree(tree)); } new NodeTransformer().transform(tree); if (Token.printTrees) { System.out.println("after transform:"); System.out.println(tree.toStringTree(tree)); } if (returnFunction) { scriptOrFn = tree.getFunctionNode(0); } else { scriptOrFn = tree; } itsData = new InterpreterData(compilerEnv.getLanguageVersion(), scriptOrFn.getSourceName(), encodedSource, ((AstRoot)tree).isInStrictMode()); itsData.topLevel = true; if (returnFunction) { generateFunctionICode(); } else { generateICodeFromTree(scriptOrFn); } return itsData; } private void generateFunctionICode() { itsInFunctionFlag = true; FunctionNode theFunction = (FunctionNode)scriptOrFn; itsData.itsFunctionType = theFunction.getFunctionType(); itsData.itsNeedsActivation = theFunction.requiresActivation(); if (theFunction.getFunctionName() != null) { itsData.itsName = theFunction.getName(); } if (theFunction.isGenerator()) { addIcode(Icode_GENERATOR); addUint16(theFunction.getBaseLineno() & 0xFFFF); } generateICodeFromTree(theFunction.getLastChild()); } private void generateICodeFromTree(Node tree) { generateNestedFunctions(); generateRegExpLiterals(); visitStatement(tree, 0); fixLabelGotos(); // add RETURN_RESULT only to scripts as function always ends with RETURN if (itsData.itsFunctionType == 0) { addToken(Token.RETURN_RESULT); } if (itsData.itsICode.length != iCodeTop) { // Make itsData.itsICode length exactly iCodeTop to save memory // and catch bugs with jumps beyond icode as early as possible byte[] tmp = new byte[iCodeTop]; System.arraycopy(itsData.itsICode, 0, tmp, 0, iCodeTop); itsData.itsICode = tmp; } if (strings.size() == 0) { itsData.itsStringTable = null; } else { itsData.itsStringTable = new String[strings.size()]; ObjToIntMap.Iterator iter = strings.newIterator(); for (iter.start(); !iter.done(); iter.next()) { String str = (String)iter.getKey(); int index = iter.getValue(); if (itsData.itsStringTable[index] != null) Kit.codeBug(); itsData.itsStringTable[index] = str; } } if (doubleTableTop == 0) { itsData.itsDoubleTable = null; } else if (itsData.itsDoubleTable.length != doubleTableTop) { double[] tmp = new double[doubleTableTop]; System.arraycopy(itsData.itsDoubleTable, 0, tmp, 0, doubleTableTop); itsData.itsDoubleTable = tmp; } if (exceptionTableTop != 0 && itsData.itsExceptionTable.length != exceptionTableTop) { int[] tmp = new int[exceptionTableTop]; System.arraycopy(itsData.itsExceptionTable, 0, tmp, 0, exceptionTableTop); itsData.itsExceptionTable = tmp; } itsData.itsMaxVars = scriptOrFn.getParamAndVarCount(); // itsMaxFrameArray: interpret method needs this amount for its // stack and sDbl arrays itsData.itsMaxFrameArray = itsData.itsMaxVars + itsData.itsMaxLocals + itsData.itsMaxStack; itsData.argNames = scriptOrFn.getParamAndVarNames(); itsData.argIsConst = scriptOrFn.getParamAndVarConst(); itsData.argCount = scriptOrFn.getParamCount(); itsData.encodedSourceStart = scriptOrFn.getEncodedSourceStart(); itsData.encodedSourceEnd = scriptOrFn.getEncodedSourceEnd(); if (literalIds.size() != 0) { itsData.literalIds = literalIds.toArray(); } if (Token.printICode) Interpreter.dumpICode(itsData); } private void generateNestedFunctions() { int functionCount = scriptOrFn.getFunctionCount(); if (functionCount == 0) return; InterpreterData[] array = new InterpreterData[functionCount]; for (int i = 0; i != functionCount; i++) { FunctionNode fn = scriptOrFn.getFunctionNode(i); CodeGenerator gen = new CodeGenerator(); gen.compilerEnv = compilerEnv; gen.scriptOrFn = fn; gen.itsData = new InterpreterData(itsData); gen.generateFunctionICode(); array[i] = gen.itsData; } itsData.itsNestedFunctions = array; } private void generateRegExpLiterals() { int N = scriptOrFn.getRegexpCount(); if (N == 0) return; Context cx = Context.getContext(); RegExpProxy rep = ScriptRuntime.checkRegExpProxy(cx); Object[] array = new Object[N]; for (int i = 0; i != N; i++) { String string = scriptOrFn.getRegexpString(i); String flags = scriptOrFn.getRegexpFlags(i); array[i] = rep.compileRegExp(cx, string, flags); } itsData.itsRegExpLiterals = array; } private void updateLineNumber(Node node) { int lineno = node.getLineno(); if (lineno != lineNumber && lineno >= 0) { if (itsData.firstLinePC < 0) { itsData.firstLinePC = lineno; } lineNumber = lineno; addIcode(Icode_LINE); addUint16(lineno & 0xFFFF); } } private RuntimeException badTree(Node node) { throw new RuntimeException(node.toString()); } private void visitStatement(Node node, int initialStackDepth) { int type = node.getType(); Node child = node.getFirstChild(); switch (type) { case Token.FUNCTION: { int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); int fnType = scriptOrFn.getFunctionNode(fnIndex). getFunctionType(); // Only function expressions or function expression // statements need closure code creating new function // object on stack as function statements are initialized // at script/function start. // In addition, function expressions can not be present here // at statement level, they must only be present as expressions. if (fnType == FunctionNode.FUNCTION_EXPRESSION_STATEMENT) { addIndexOp(Icode_CLOSURE_STMT, fnIndex); } else { if (fnType != FunctionNode.FUNCTION_STATEMENT) { throw Kit.codeBug(); } } // For function statements or function expression statements // in scripts, we need to ensure that the result of the script // is the function if it is the last statement in the script. // For example, eval("function () {}") should return a // function, not undefined. if (!itsInFunctionFlag) { addIndexOp(Icode_CLOSURE_EXPR, fnIndex); stackChange(1); addIcode(Icode_POP_RESULT); stackChange(-1); } } break; case Token.LABEL: case Token.LOOP: case Token.BLOCK: case Token.EMPTY: case Token.WITH: updateLineNumber(node); case Token.SCRIPT: // fall through while (child != null) { visitStatement(child, initialStackDepth); child = child.getNext(); } break; case Token.ENTERWITH: visitExpression(child, 0); addToken(Token.ENTERWITH); stackChange(-1); break; case Token.LEAVEWITH: addToken(Token.LEAVEWITH); break; case Token.LOCAL_BLOCK: { int local = allocLocal(); node.putIntProp(Node.LOCAL_PROP, local); updateLineNumber(node); while (child != null) { visitStatement(child, initialStackDepth); child = child.getNext(); } addIndexOp(Icode_LOCAL_CLEAR, local); releaseLocal(local); } break; case Token.DEBUGGER: addIcode(Icode_DEBUGGER); break; case Token.SWITCH: updateLineNumber(node); // See comments in IRFactory.createSwitch() for description // of SWITCH node { visitExpression(child, 0); for (Jump caseNode = (Jump)child.getNext(); caseNode != null; caseNode = (Jump)caseNode.getNext()) { if (caseNode.getType() != Token.CASE) throw badTree(caseNode); Node test = caseNode.getFirstChild(); addIcode(Icode_DUP); stackChange(1); visitExpression(test, 0); addToken(Token.SHEQ); stackChange(-1); // If true, Icode_IFEQ_POP will jump and remove case // value from stack addGoto(caseNode.target, Icode_IFEQ_POP); stackChange(-1); } addIcode(Icode_POP); stackChange(-1); } break; case Token.TARGET: markTargetLabel(node); break; case Token.IFEQ : case Token.IFNE : { Node target = ((Jump)node).target; visitExpression(child, 0); addGoto(target, type); stackChange(-1); } break; case Token.GOTO: { Node target = ((Jump)node).target; addGoto(target, type); } break; case Token.JSR: { Node target = ((Jump)node).target; addGoto(target, Icode_GOSUB); } break; case Token.FINALLY: { // Account for incomming GOTOSUB address stackChange(1); int finallyRegister = getLocalBlockRef(node); addIndexOp(Icode_STARTSUB, finallyRegister); stackChange(-1); while (child != null) { visitStatement(child, initialStackDepth); child = child.getNext(); } addIndexOp(Icode_RETSUB, finallyRegister); } break; case Token.EXPR_VOID: case Token.EXPR_RESULT: updateLineNumber(node); visitExpression(child, 0); addIcode((type == Token.EXPR_VOID) ? Icode_POP : Icode_POP_RESULT); stackChange(-1); break; case Token.TRY: { Jump tryNode = (Jump)node; int exceptionObjectLocal = getLocalBlockRef(tryNode); int scopeLocal = allocLocal(); addIndexOp(Icode_SCOPE_SAVE, scopeLocal); int tryStart = iCodeTop; boolean savedFlag = itsInTryFlag; itsInTryFlag = true; while (child != null) { visitStatement(child, initialStackDepth); child = child.getNext(); } itsInTryFlag = savedFlag; Node catchTarget = tryNode.target; if (catchTarget != null) { int catchStartPC = labelTable[getTargetLabel(catchTarget)]; addExceptionHandler( tryStart, catchStartPC, catchStartPC, false, exceptionObjectLocal, scopeLocal); } Node finallyTarget = tryNode.getFinally(); if (finallyTarget != null) { int finallyStartPC = labelTable[getTargetLabel(finallyTarget)]; addExceptionHandler( tryStart, finallyStartPC, finallyStartPC, true, exceptionObjectLocal, scopeLocal); } addIndexOp(Icode_LOCAL_CLEAR, scopeLocal); releaseLocal(scopeLocal); } break; case Token.CATCH_SCOPE: { int localIndex = getLocalBlockRef(node); int scopeIndex = node.getExistingIntProp(Node.CATCH_SCOPE_PROP); String name = child.getString(); child = child.getNext(); visitExpression(child, 0); // load expression object addStringPrefix(name); addIndexPrefix(localIndex); addToken(Token.CATCH_SCOPE); addUint8(scopeIndex != 0 ? 1 : 0); stackChange(-1); } break; case Token.THROW: updateLineNumber(node); visitExpression(child, 0); addToken(Token.THROW); addUint16(lineNumber & 0xFFFF); stackChange(-1); break; case Token.RETHROW: updateLineNumber(node); addIndexOp(Token.RETHROW, getLocalBlockRef(node)); break; case Token.RETURN: updateLineNumber(node); if (node.getIntProp(Node.GENERATOR_END_PROP, 0) != 0) { // We're in a generator, so change RETURN to GENERATOR_END addIcode(Icode_GENERATOR_END); addUint16(lineNumber & 0xFFFF); } else if (child != null) { visitExpression(child, ECF_TAIL); addToken(Token.RETURN); stackChange(-1); } else { addIcode(Icode_RETUNDEF); } break; case Token.RETURN_RESULT: updateLineNumber(node); addToken(Token.RETURN_RESULT); break; case Token.ENUM_INIT_KEYS: case Token.ENUM_INIT_VALUES: case Token.ENUM_INIT_ARRAY: visitExpression(child, 0); addIndexOp(type, getLocalBlockRef(node)); stackChange(-1); break; case Icode_GENERATOR: break; default: throw badTree(node); } if (stackDepth != initialStackDepth) { throw Kit.codeBug(); } } private void visitExpression(Node node, int contextFlags) { int type = node.getType(); Node child = node.getFirstChild(); int savedStackDepth = stackDepth; switch (type) { case Token.FUNCTION: { int fnIndex = node.getExistingIntProp(Node.FUNCTION_PROP); FunctionNode fn = scriptOrFn.getFunctionNode(fnIndex); // See comments in visitStatement for Token.FUNCTION case if (fn.getFunctionType() != FunctionNode.FUNCTION_EXPRESSION) { throw Kit.codeBug(); } addIndexOp(Icode_CLOSURE_EXPR, fnIndex); stackChange(1); } break; case Token.LOCAL_LOAD: { int localIndex = getLocalBlockRef(node); addIndexOp(Token.LOCAL_LOAD, localIndex); stackChange(1); } break; case Token.COMMA: { Node lastChild = node.getLastChild(); while (child != lastChild) { visitExpression(child, 0); addIcode(Icode_POP); stackChange(-1); child = child.getNext(); } // Preserve tail context flag if any visitExpression(child, contextFlags & ECF_TAIL); } break; case Token.USE_STACK: // Indicates that stack was modified externally, // like placed catch object stackChange(1); break; case Token.REF_CALL: case Token.CALL: case Token.NEW: { if (type == Token.NEW) { visitExpression(child, 0); } else { generateCallFunAndThis(child); } int argCount = 0; while ((child = child.getNext()) != null) { visitExpression(child, 0); ++argCount; } int callType = node.getIntProp(Node.SPECIALCALL_PROP, Node.NON_SPECIALCALL); if (callType != Node.NON_SPECIALCALL) { // embed line number and source filename addIndexOp(Icode_CALLSPECIAL, argCount); addUint8(callType); addUint8(type == Token.NEW ? 1 : 0); addUint16(lineNumber & 0xFFFF); } else { // Only use the tail call optimization if we're not in a try // or we're not generating debug info (since the // optimization will confuse the debugger) if (type == Token.CALL && (contextFlags & ECF_TAIL) != 0 && !compilerEnv.isGenerateDebugInfo() && !itsInTryFlag) { type = Icode_TAIL_CALL; } addIndexOp(type, argCount); } // adjust stack if (type == Token.NEW) { // new: f, args -> result stackChange(-argCount); } else { // call: f, thisObj, args -> result // ref_call: f, thisObj, args -> ref stackChange(-1 - argCount); } if (argCount > itsData.itsMaxCalleeArgs) { itsData.itsMaxCalleeArgs = argCount; } } break; case Token.AND: case Token.OR: { visitExpression(child, 0); addIcode(Icode_DUP); stackChange(1); int afterSecondJumpStart = iCodeTop; int jump = (type == Token.AND) ? Token.IFNE : Token.IFEQ; addGotoOp(jump); stackChange(-1); addIcode(Icode_POP); stackChange(-1); child = child.getNext(); // Preserve tail context flag if any visitExpression(child, contextFlags & ECF_TAIL); resolveForwardGoto(afterSecondJumpStart); } break; case Token.HOOK: { Node ifThen = child.getNext(); Node ifElse = ifThen.getNext(); visitExpression(child, 0); int elseJumpStart = iCodeTop; addGotoOp(Token.IFNE); stackChange(-1); // Preserve tail context flag if any visitExpression(ifThen, contextFlags & ECF_TAIL); int afterElseJumpStart = iCodeTop; addGotoOp(Token.GOTO); resolveForwardGoto(elseJumpStart); stackDepth = savedStackDepth; // Preserve tail context flag if any visitExpression(ifElse, contextFlags & ECF_TAIL); resolveForwardGoto(afterElseJumpStart); } break; case Token.GETPROP: case Token.GETPROPNOWARN: visitExpression(child, 0); child = child.getNext(); addStringOp(type, child.getString()); break; case Token.DELPROP: boolean isName = child.getType() == Token.BINDNAME; visitExpression(child, 0); child = child.getNext(); visitExpression(child, 0); if (isName) { // special handling for delete name addIcode(Icode_DELNAME); } else { addToken(Token.DELPROP); } stackChange(-1); break; case Token.GETELEM: case Token.BITAND: case Token.BITOR: case Token.BITXOR: case Token.LSH: case Token.RSH: case Token.URSH: case Token.ADD: case Token.SUB: case Token.MOD: case Token.DIV: case Token.MUL: case Token.EQ: case Token.NE: case Token.SHEQ: case Token.SHNE: case Token.IN: case Token.INSTANCEOF: case Token.LE: case Token.LT: case Token.GE: case Token.GT: visitExpression(child, 0); child = child.getNext(); visitExpression(child, 0); addToken(type); stackChange(-1); break; case Token.POS: case Token.NEG: case Token.NOT: case Token.BITNOT: case Token.TYPEOF: case Token.VOID: visitExpression(child, 0); if (type == Token.VOID) { addIcode(Icode_POP); addIcode(Icode_UNDEF); } else { addToken(type); } break; case Token.GET_REF: case Token.DEL_REF: visitExpression(child, 0); addToken(type); break; case Token.SETPROP: case Token.SETPROP_OP: { visitExpression(child, 0); child = child.getNext(); String property = child.getString(); child = child.getNext(); if (type == Token.SETPROP_OP) { addIcode(Icode_DUP); stackChange(1); addStringOp(Token.GETPROP, property); // Compensate for the following USE_STACK stackChange(-1); } visitExpression(child, 0); addStringOp(Token.SETPROP, property); stackChange(-1); } break; case Token.SETELEM: case Token.SETELEM_OP: visitExpression(child, 0); child = child.getNext(); visitExpression(child, 0); child = child.getNext(); if (type == Token.SETELEM_OP) { addIcode(Icode_DUP2); stackChange(2); addToken(Token.GETELEM); stackChange(-1); // Compensate for the following USE_STACK stackChange(-1); } visitExpression(child, 0); addToken(Token.SETELEM); stackChange(-2); break; case Token.SET_REF: case Token.SET_REF_OP: visitExpression(child, 0); child = child.getNext(); if (type == Token.SET_REF_OP) { addIcode(Icode_DUP); stackChange(1); addToken(Token.GET_REF); // Compensate for the following USE_STACK stackChange(-1); } visitExpression(child, 0); addToken(Token.SET_REF); stackChange(-1); break; case Token.STRICT_SETNAME: case Token.SETNAME: { String name = child.getString(); visitExpression(child, 0); child = child.getNext(); visitExpression(child, 0); addStringOp(type, name); stackChange(-1); } break; case Token.SETCONST: { String name = child.getString(); visitExpression(child, 0); child = child.getNext(); visitExpression(child, 0); addStringOp(Icode_SETCONST, name); stackChange(-1); } break; case Token.TYPEOFNAME: { int index = -1; // use typeofname if an activation frame exists // since the vars all exist there instead of in jregs if (itsInFunctionFlag && !itsData.itsNeedsActivation) index = scriptOrFn.getIndexForNameNode(node); if (index == -1) { addStringOp(Icode_TYPEOFNAME, node.getString()); stackChange(1); } else { addVarOp(Token.GETVAR, index); stackChange(1); addToken(Token.TYPEOF); } } break; case Token.BINDNAME: case Token.NAME: case Token.STRING: addStringOp(type, node.getString()); stackChange(1); break; case Token.INC: case Token.DEC: visitIncDec(node, child); break; case Token.NUMBER: { double num = node.getDouble(); int inum = (int)num; if (inum == num) { if (inum == 0) { addIcode(Icode_ZERO); // Check for negative zero if (1.0 / num < 0.0) { addToken(Token.NEG); } } else if (inum == 1) { addIcode(Icode_ONE); } else if ((short)inum == inum) { addIcode(Icode_SHORTNUMBER); // write short as uin16 bit pattern addUint16(inum & 0xFFFF); } else { addIcode(Icode_INTNUMBER); addInt(inum); } } else { int index = getDoubleIndex(num); addIndexOp(Token.NUMBER, index); } stackChange(1); } break; case Token.GETVAR: { if (itsData.itsNeedsActivation) Kit.codeBug(); int index = scriptOrFn.getIndexForNameNode(node); addVarOp(Token.GETVAR, index); stackChange(1); } break; case Token.SETVAR: { if (itsData.itsNeedsActivation) Kit.codeBug(); int index = scriptOrFn.getIndexForNameNode(child); child = child.getNext(); visitExpression(child, 0); addVarOp(Token.SETVAR, index); } break; case Token.SETCONSTVAR: { if (itsData.itsNeedsActivation) Kit.codeBug(); int index = scriptOrFn.getIndexForNameNode(child); child = child.getNext(); visitExpression(child, 0); addVarOp(Token.SETCONSTVAR, index); } break; case Token.NULL: case Token.THIS: case Token.THISFN: case Token.FALSE: case Token.TRUE: addToken(type); stackChange(1); break; case Token.ENUM_NEXT: case Token.ENUM_ID: addIndexOp(type, getLocalBlockRef(node)); stackChange(1); break; case Token.REGEXP: { int index = node.getExistingIntProp(Node.REGEXP_PROP); addIndexOp(Token.REGEXP, index); stackChange(1); } break; case Token.ARRAYLIT: case Token.OBJECTLIT: visitLiteral(node, child); break; case Token.ARRAYCOMP: visitArrayComprehension(node, child, child.getNext()); break; case Token.REF_SPECIAL: visitExpression(child, 0); addStringOp(type, (String)node.getProp(Node.NAME_PROP)); break; case Token.REF_MEMBER: case Token.REF_NS_MEMBER: case Token.REF_NAME: case Token.REF_NS_NAME: { int memberTypeFlags = node.getIntProp(Node.MEMBER_TYPE_PROP, 0); // generate possible target, possible namespace and member int childCount = 0; do { visitExpression(child, 0); ++childCount; child = child.getNext(); } while (child != null); addIndexOp(type, memberTypeFlags); stackChange(1 - childCount); } break; case Token.DOTQUERY: { int queryPC; updateLineNumber(node); visitExpression(child, 0); addIcode(Icode_ENTERDQ); stackChange(-1); queryPC = iCodeTop; visitExpression(child.getNext(), 0); addBackwardGoto(Icode_LEAVEDQ, queryPC); } break; case Token.DEFAULTNAMESPACE : case Token.ESCXMLATTR : case Token.ESCXMLTEXT : visitExpression(child, 0); addToken(type); break; case Token.YIELD: if (child != null) { visitExpression(child, 0); } else { addIcode(Icode_UNDEF); stackChange(1); } addToken(Token.YIELD); addUint16(node.getLineno() & 0xFFFF); break; case Token.WITHEXPR: { Node enterWith = node.getFirstChild(); Node with = enterWith.getNext(); visitExpression(enterWith.getFirstChild(), 0); addToken(Token.ENTERWITH); stackChange(-1); visitExpression(with.getFirstChild(), 0); addToken(Token.LEAVEWITH); break; } default: throw badTree(node); } if (savedStackDepth + 1 != stackDepth) { Kit.codeBug(); } } private void generateCallFunAndThis(Node left) { // Generate code to place on stack function and thisObj int type = left.getType(); switch (type) { case Token.NAME: { String name = left.getString(); // stack: ... -> ... function thisObj addStringOp(Icode_NAME_AND_THIS, name); stackChange(2); break; } case Token.GETPROP: case Token.GETELEM: { Node target = left.getFirstChild(); visitExpression(target, 0); Node id = target.getNext(); if (type == Token.GETPROP) { String property = id.getString(); // stack: ... target -> ... function thisObj addStringOp(Icode_PROP_AND_THIS, property); stackChange(1); } else { visitExpression(id, 0); // stack: ... target id -> ... function thisObj addIcode(Icode_ELEM_AND_THIS); } break; } default: // Including Token.GETVAR visitExpression(left, 0); // stack: ... value -> ... function thisObj addIcode(Icode_VALUE_AND_THIS); stackChange(1); break; } } private void visitIncDec(Node node, Node child) { int incrDecrMask = node.getExistingIntProp(Node.INCRDECR_PROP); int childType = child.getType(); switch (childType) { case Token.GETVAR : { if (itsData.itsNeedsActivation) Kit.codeBug(); int i = scriptOrFn.getIndexForNameNode(child); addVarOp(Icode_VAR_INC_DEC, i); addUint8(incrDecrMask); stackChange(1); break; } case Token.NAME : { String name = child.getString(); addStringOp(Icode_NAME_INC_DEC, name); addUint8(incrDecrMask); stackChange(1); break; } case Token.GETPROP : { Node object = child.getFirstChild(); visitExpression(object, 0); String property = object.getNext().getString(); addStringOp(Icode_PROP_INC_DEC, property); addUint8(incrDecrMask); break; } case Token.GETELEM : { Node object = child.getFirstChild(); visitExpression(object, 0); Node index = object.getNext(); visitExpression(index, 0); addIcode(Icode_ELEM_INC_DEC); addUint8(incrDecrMask); stackChange(-1); break; } case Token.GET_REF : { Node ref = child.getFirstChild(); visitExpression(ref, 0); addIcode(Icode_REF_INC_DEC); addUint8(incrDecrMask); break; } default : { throw badTree(node); } } } private void visitLiteral(Node node, Node child) { int type = node.getType(); int count; Object[] propertyIds = null; if (type == Token.ARRAYLIT) { count = 0; for (Node n = child; n != null; n = n.getNext()) { ++count; } } else if (type == Token.OBJECTLIT) { propertyIds = (Object[])node.getProp(Node.OBJECT_IDS_PROP); count = propertyIds.length; } else { throw badTree(node); } addIndexOp(Icode_LITERAL_NEW, count); stackChange(2); while (child != null) { int childType = child.getType(); if (childType == Token.GET) { visitExpression(child.getFirstChild(), 0); addIcode(Icode_LITERAL_GETTER); } else if (childType == Token.SET) { visitExpression(child.getFirstChild(), 0); addIcode(Icode_LITERAL_SETTER); } else { visitExpression(child, 0); addIcode(Icode_LITERAL_SET); } stackChange(-1); child = child.getNext(); } if (type == Token.ARRAYLIT) { int[] skipIndexes = (int[])node.getProp(Node.SKIP_INDEXES_PROP); if (skipIndexes == null) { addToken(Token.ARRAYLIT); } else { int index = literalIds.size(); literalIds.add(skipIndexes); addIndexOp(Icode_SPARE_ARRAYLIT, index); } } else { int index = literalIds.size(); literalIds.add(propertyIds); addIndexOp(Token.OBJECTLIT, index); } stackChange(-1); } private void visitArrayComprehension(Node node, Node initStmt, Node expr) { // A bit of a hack: array comprehensions are implemented using // statement nodes for the iteration, yet they appear in an // expression context. So we pass the current stack depth to // visitStatement so it can check that the depth is not altered // by statements. visitStatement(initStmt, stackDepth); visitExpression(expr, 0); } private int getLocalBlockRef(Node node) { Node localBlock = (Node)node.getProp(Node.LOCAL_BLOCK_PROP); return localBlock.getExistingIntProp(Node.LOCAL_PROP); } private int getTargetLabel(Node target) { int label = target.labelId(); if (label != -1) { return label; } label = labelTableTop; if (labelTable == null || label == labelTable.length) { if (labelTable == null) { labelTable = new int[MIN_LABEL_TABLE_SIZE]; }else { int[] tmp = new int[labelTable.length * 2]; System.arraycopy(labelTable, 0, tmp, 0, label); labelTable = tmp; } } labelTableTop = label + 1; labelTable[label] = -1; target.labelId(label); return label; } private void markTargetLabel(Node target) { int label = getTargetLabel(target); if (labelTable[label] != -1) { // Can mark label only once Kit.codeBug(); } labelTable[label] = iCodeTop; } private void addGoto(Node target, int gotoOp) { int label = getTargetLabel(target); if (!(label < labelTableTop)) Kit.codeBug(); int targetPC = labelTable[label]; if (targetPC != -1) { addBackwardGoto(gotoOp, targetPC); } else { int gotoPC = iCodeTop; addGotoOp(gotoOp); int top = fixupTableTop; if (fixupTable == null || top == fixupTable.length) { if (fixupTable == null) { fixupTable = new long[MIN_FIXUP_TABLE_SIZE]; } else { long[] tmp = new long[fixupTable.length * 2]; System.arraycopy(fixupTable, 0, tmp, 0, top); fixupTable = tmp; } } fixupTableTop = top + 1; fixupTable[top] = ((long)label << 32) | gotoPC; } } private void fixLabelGotos() { for (int i = 0; i < fixupTableTop; i++) { long fixup = fixupTable[i]; int label = (int)(fixup >> 32); int jumpSource = (int)fixup; int pc = labelTable[label]; if (pc == -1) { // Unlocated label throw Kit.codeBug(); } resolveGoto(jumpSource, pc); } fixupTableTop = 0; } private void addBackwardGoto(int gotoOp, int jumpPC) { int fromPC = iCodeTop; // Ensure that this is a jump backward if (fromPC <= jumpPC) throw Kit.codeBug(); addGotoOp(gotoOp); resolveGoto(fromPC, jumpPC); } private void resolveForwardGoto(int fromPC) { // Ensure that forward jump skips at least self bytecode if (iCodeTop < fromPC + 3) throw Kit.codeBug(); resolveGoto(fromPC, iCodeTop); } private void resolveGoto(int fromPC, int jumpPC) { int offset = jumpPC - fromPC; // Ensure that jumps do not overlap if (0 <= offset && offset <= 2) throw Kit.codeBug(); int offsetSite = fromPC + 1; if (offset != (short)offset) { if (itsData.longJumps == null) { itsData.longJumps = new UintMap(); } itsData.longJumps.put(offsetSite, jumpPC); offset = 0; } byte[] array = itsData.itsICode; array[offsetSite] = (byte)(offset >> 8); array[offsetSite + 1] = (byte)offset; } private void addToken(int token) { if (!Icode.validTokenCode(token)) throw Kit.codeBug(); addUint8(token); } private void addIcode(int icode) { if (!Icode.validIcode(icode)) throw Kit.codeBug(); // Write negative icode as uint8 bits addUint8(icode & 0xFF); } private void addUint8(int value) { if ((value & ~0xFF) != 0) throw Kit.codeBug(); byte[] array = itsData.itsICode; int top = iCodeTop; if (top == array.length) { array = increaseICodeCapacity(1); } array[top] = (byte)value; iCodeTop = top + 1; } private void addUint16(int value) { if ((value & ~0xFFFF) != 0) throw Kit.codeBug(); byte[] array = itsData.itsICode; int top = iCodeTop; if (top + 2 > array.length) { array = increaseICodeCapacity(2); } array[top] = (byte)(value >>> 8); array[top + 1] = (byte)value; iCodeTop = top + 2; } private void addInt(int i) { byte[] array = itsData.itsICode; int top = iCodeTop; if (top + 4 > array.length) { array = increaseICodeCapacity(4); } array[top] = (byte)(i >>> 24); array[top + 1] = (byte)(i >>> 16); array[top + 2] = (byte)(i >>> 8); array[top + 3] = (byte)i; iCodeTop = top + 4; } private int getDoubleIndex(double num) { int index = doubleTableTop; if (index == 0) { itsData.itsDoubleTable = new double[64]; } else if (itsData.itsDoubleTable.length == index) { double[] na = new double[index * 2]; System.arraycopy(itsData.itsDoubleTable, 0, na, 0, index); itsData.itsDoubleTable = na; } itsData.itsDoubleTable[index] = num; doubleTableTop = index + 1; return index; } private void addGotoOp(int gotoOp) { byte[] array = itsData.itsICode; int top = iCodeTop; if (top + 3 > array.length) { array = increaseICodeCapacity(3); } array[top] = (byte)gotoOp; // Offset would written later iCodeTop = top + 1 + 2; } private void addVarOp(int op, int varIndex) { switch (op) { case Token.SETCONSTVAR: if (varIndex < 128) { addIcode(Icode_SETCONSTVAR1); addUint8(varIndex); return; } addIndexOp(Icode_SETCONSTVAR, varIndex); return; case Token.GETVAR: case Token.SETVAR: if (varIndex < 128) { addIcode(op == Token.GETVAR ? Icode_GETVAR1 : Icode_SETVAR1); addUint8(varIndex); return; } // fallthrough case Icode_VAR_INC_DEC: addIndexOp(op, varIndex); return; } throw Kit.codeBug(); } private void addStringOp(int op, String str) { addStringPrefix(str); if (Icode.validIcode(op)) { addIcode(op); } else { addToken(op); } } private void addIndexOp(int op, int index) { addIndexPrefix(index); if (Icode.validIcode(op)) { addIcode(op); } else { addToken(op); } } private void addStringPrefix(String str) { int index = strings.get(str, -1); if (index == -1) { index = strings.size(); strings.put(str, index); } if (index < 4) { addIcode(Icode_REG_STR_C0 - index); } else if (index <= 0xFF) { addIcode(Icode_REG_STR1); addUint8(index); } else if (index <= 0xFFFF) { addIcode(Icode_REG_STR2); addUint16(index); } else { addIcode(Icode_REG_STR4); addInt(index); } } private void addIndexPrefix(int index) { if (index < 0) Kit.codeBug(); if (index < 6) { addIcode(Icode_REG_IND_C0 - index); } else if (index <= 0xFF) { addIcode(Icode_REG_IND1); addUint8(index); } else if (index <= 0xFFFF) { addIcode(Icode_REG_IND2); addUint16(index); } else { addIcode(Icode_REG_IND4); addInt(index); } } private void addExceptionHandler(int icodeStart, int icodeEnd, int handlerStart, boolean isFinally, int exceptionObjectLocal, int scopeLocal) { int top = exceptionTableTop; int[] table = itsData.itsExceptionTable; if (table == null) { if (top != 0) Kit.codeBug(); table = new int[Interpreter.EXCEPTION_SLOT_SIZE * 2]; itsData.itsExceptionTable = table; } else if (table.length == top) { table = new int[table.length * 2]; System.arraycopy(itsData.itsExceptionTable, 0, table, 0, top); itsData.itsExceptionTable = table; } table[top + Interpreter.EXCEPTION_TRY_START_SLOT] = icodeStart; table[top + Interpreter.EXCEPTION_TRY_END_SLOT] = icodeEnd; table[top + Interpreter.EXCEPTION_HANDLER_SLOT] = handlerStart; table[top + Interpreter.EXCEPTION_TYPE_SLOT] = isFinally ? 1 : 0; table[top + Interpreter.EXCEPTION_LOCAL_SLOT] = exceptionObjectLocal; table[top + Interpreter.EXCEPTION_SCOPE_SLOT] = scopeLocal; exceptionTableTop = top + Interpreter.EXCEPTION_SLOT_SIZE; } private byte[] increaseICodeCapacity(int extraSize) { int capacity = itsData.itsICode.length; int top = iCodeTop; if (top + extraSize <= capacity) throw Kit.codeBug(); capacity *= 2; if (top + extraSize > capacity) { capacity = top + extraSize; } byte[] array = new byte[capacity]; System.arraycopy(itsData.itsICode, 0, array, 0, top); itsData.itsICode = array; return array; } private void stackChange(int change) { if (change <= 0) { stackDepth += change; } else { int newDepth = stackDepth + change; if (newDepth > itsData.itsMaxStack) { itsData.itsMaxStack = newDepth; } stackDepth = newDepth; } } private int allocLocal() { int localSlot = localTop; ++localTop; if (localTop > itsData.itsMaxLocals) { itsData.itsMaxLocals = localTop; } return localSlot; } private void releaseLocal(int localSlot) { --localTop; if (localSlot != localTop) Kit.codeBug(); } } rhino-1.7R4/src/org/mozilla/javascript/CompilerEnvirons.java000066400000000000000000000206421176760007500242570ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.util.Set; import org.mozilla.javascript.ast.ErrorCollector; public class CompilerEnvirons { public CompilerEnvirons() { errorReporter = DefaultErrorReporter.instance; languageVersion = Context.VERSION_DEFAULT; generateDebugInfo = true; reservedKeywordAsIdentifier = true; allowMemberExprAsFunctionName = false; xmlAvailable = true; optimizationLevel = 0; generatingSource = true; strictMode = false; warningAsError = false; generateObserverCount = false; allowSharpComments = false; } public void initFromContext(Context cx) { setErrorReporter(cx.getErrorReporter()); languageVersion = cx.getLanguageVersion(); generateDebugInfo = (!cx.isGeneratingDebugChanged() || cx.isGeneratingDebug()); reservedKeywordAsIdentifier = cx.hasFeature(Context.FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER); allowMemberExprAsFunctionName = cx.hasFeature(Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME); strictMode = cx.hasFeature(Context.FEATURE_STRICT_MODE); warningAsError = cx.hasFeature(Context.FEATURE_WARNING_AS_ERROR); xmlAvailable = cx.hasFeature(Context.FEATURE_E4X); optimizationLevel = cx.getOptimizationLevel(); generatingSource = cx.isGeneratingSource(); activationNames = cx.activationNames; // Observer code generation in compiled code : generateObserverCount = cx.generateObserverCount; } public final ErrorReporter getErrorReporter() { return errorReporter; } public void setErrorReporter(ErrorReporter errorReporter) { if (errorReporter == null) throw new IllegalArgumentException(); this.errorReporter = errorReporter; } public final int getLanguageVersion() { return languageVersion; } public void setLanguageVersion(int languageVersion) { Context.checkLanguageVersion(languageVersion); this.languageVersion = languageVersion; } public final boolean isGenerateDebugInfo() { return generateDebugInfo; } public void setGenerateDebugInfo(boolean flag) { this.generateDebugInfo = flag; } public final boolean isReservedKeywordAsIdentifier() { return reservedKeywordAsIdentifier; } public void setReservedKeywordAsIdentifier(boolean flag) { reservedKeywordAsIdentifier = flag; } /** * Extension to ECMA: if 'function <name>' is not followed * by '(', assume <name> starts a {@code memberExpr} */ public final boolean isAllowMemberExprAsFunctionName() { return allowMemberExprAsFunctionName; } public void setAllowMemberExprAsFunctionName(boolean flag) { allowMemberExprAsFunctionName = flag; } public final boolean isXmlAvailable() { return xmlAvailable; } public void setXmlAvailable(boolean flag) { xmlAvailable = flag; } public final int getOptimizationLevel() { return optimizationLevel; } public void setOptimizationLevel(int level) { Context.checkOptimizationLevel(level); this.optimizationLevel = level; } public final boolean isGeneratingSource() { return generatingSource; } public boolean getWarnTrailingComma() { return warnTrailingComma; } public void setWarnTrailingComma(boolean warn) { warnTrailingComma = warn; } public final boolean isStrictMode() { return strictMode; } public void setStrictMode(boolean strict) { strictMode = strict; } public final boolean reportWarningAsError() { return warningAsError; } /** * Specify whether or not source information should be generated. *

* Without source information, evaluating the "toString" method * on JavaScript functions produces only "[native code]" for * the body of the function. * Note that code generated without source is not fully ECMA * conformant. */ public void setGeneratingSource(boolean generatingSource) { this.generatingSource = generatingSource; } /** * @return true iff code will be generated with callbacks to enable * instruction thresholds */ public boolean isGenerateObserverCount() { return generateObserverCount; } /** * Turn on or off generation of code with callbacks to * track the count of executed instructions. * Currently only affects JVM byte code generation: this slows down the * generated code, but code generated without the callbacks will not * be counted toward instruction thresholds. Rhino's interpretive * mode does instruction counting without inserting callbacks, so * there is no requirement to compile code differently. * @param generateObserverCount if true, generated code will contain * calls to accumulate an estimate of the instructions executed. */ public void setGenerateObserverCount(boolean generateObserverCount) { this.generateObserverCount = generateObserverCount; } public boolean isRecordingComments() { return recordingComments; } public void setRecordingComments(boolean record) { recordingComments = record; } public boolean isRecordingLocalJsDocComments() { return recordingLocalJsDocComments; } public void setRecordingLocalJsDocComments(boolean record) { recordingLocalJsDocComments = record; } /** * Turn on or off full error recovery. In this mode, parse errors do not * throw an exception, and the parser attempts to build a full syntax tree * from the input. Useful for IDEs and other frontends. */ public void setRecoverFromErrors(boolean recover) { recoverFromErrors = recover; } public boolean recoverFromErrors() { return recoverFromErrors; } /** * Puts the parser in "IDE" mode. This enables some slightly more expensive * computations, such as figuring out helpful error bounds. */ public void setIdeMode(boolean ide) { ideMode = ide; } public boolean isIdeMode() { return ideMode; } public Set getActivationNames() { return activationNames; } public void setActivationNames(Set activationNames) { this.activationNames = activationNames; } /** * Mozilla sources use the C preprocessor. */ public void setAllowSharpComments(boolean allow) { allowSharpComments = allow; } public boolean getAllowSharpComments() { return allowSharpComments; } /** * Returns a {@code CompilerEnvirons} suitable for using Rhino * in an IDE environment. Most features are enabled by default. * The {@link ErrorReporter} is set to an {@link ErrorCollector}. */ public static CompilerEnvirons ideEnvirons() { CompilerEnvirons env = new CompilerEnvirons(); env.setRecoverFromErrors(true); env.setRecordingComments(true); env.setStrictMode(true); env.setWarnTrailingComma(true); env.setLanguageVersion(170); env.setReservedKeywordAsIdentifier(true); env.setIdeMode(true); env.setErrorReporter(new ErrorCollector()); return env; } private ErrorReporter errorReporter; private int languageVersion; private boolean generateDebugInfo; private boolean reservedKeywordAsIdentifier; private boolean allowMemberExprAsFunctionName; private boolean xmlAvailable; private int optimizationLevel; private boolean generatingSource; private boolean strictMode; private boolean warningAsError; private boolean generateObserverCount; private boolean recordingComments; private boolean recordingLocalJsDocComments; private boolean recoverFromErrors; private boolean warnTrailingComma; private boolean ideMode; private boolean allowSharpComments; Set activationNames; } rhino-1.7R4/src/org/mozilla/javascript/ConsString.java000066400000000000000000000056751176760007500230630ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.io.Serializable; /** *

This class represents a string composed of two components, each of which * may be a java.lang.String or another ConsString.

* *

This string representation is optimized for concatenation using the "+" * operator. Instead of immediately copying both components to a new character * array, ConsString keeps references to the original components and only * converts them to a String if either toString() is called or a certain depth * level is reached.

* *

Note that instances of this class are only immutable if both parts are * immutable, i.e. either Strings or ConsStrings that are ultimately composed * of Strings.

* *

Both the name and the concept are borrowed from V8.

*/ public class ConsString implements CharSequence, Serializable { private static final long serialVersionUID = -8432806714471372570L; private CharSequence s1, s2; private final int length; private int depth; public ConsString(CharSequence str1, CharSequence str2) { s1 = str1; s2 = str2; length = str1.length() + str2.length(); depth = 1; if (str1 instanceof ConsString) { depth += ((ConsString)str1).depth; } if (str2 instanceof ConsString) { depth += ((ConsString)str2).depth; } // Don't let it grow too deep, can cause stack overflows if (depth > 2000) { flatten(); } } // Replace with string representation when serializing private Object writeReplace() { return this.toString(); } public String toString() { return depth == 0 ? (String)s1 : flatten(); } private synchronized String flatten() { if (depth > 0) { StringBuilder b = new StringBuilder(length); appendTo(b); s1 = b.toString(); s2 = ""; depth = 0; } return (String)s1; } private synchronized void appendTo(StringBuilder b) { appendFragment(s1, b); appendFragment(s2, b); } private static void appendFragment(CharSequence s, StringBuilder b) { if (s instanceof ConsString) { ((ConsString)s).appendTo(b); } else { b.append(s); } } public int length() { return length; } public char charAt(int index) { String str = depth == 0 ? (String)s1 : flatten(); return str.charAt(index); } public CharSequence subSequence(int start, int end) { String str = depth == 0 ? (String)s1 : flatten(); return str.substring(start, end); } } rhino-1.7R4/src/org/mozilla/javascript/ConstProperties.java000066400000000000000000000070141176760007500241220ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; public interface ConstProperties { /** * Sets a named const property in this object. *

* The property is specified by a string name * as defined for Scriptable.get. *

* The possible values that may be passed in are as defined for * Scriptable.get. A class that implements this method may choose * to ignore calls to set certain properties, in which case those * properties are effectively read-only.

* For properties defined in a prototype chain, * use putProperty in ScriptableObject.

* Note that if a property a is defined in the prototype p * of an object o, then evaluating o.a = 23 will cause * set to be called on the prototype p with * o as the start parameter. * To preserve JavaScript semantics, it is the Scriptable * object's responsibility to modify o.

* This design allows properties to be defined in prototypes and implemented * in terms of getters and setters of Java values without consuming slots * in each instance.

*

* The values that may be set are limited to the following: *

    *
  • java.lang.Boolean objects
  • *
  • java.lang.String objects
  • *
  • java.lang.Number objects
  • *
  • org.mozilla.javascript.Scriptable objects
  • *
  • null
  • *
  • The value returned by Context.getUndefinedValue()
  • *

* Arbitrary Java objects may be wrapped in a Scriptable by first calling * Context.toObject. This allows the property of a JavaScript * object to contain an arbitrary Java object as a value.

* Note that has will be called by the runtime first before * set is called to determine in which object the * property is defined. * Note that this method is not expected to traverse the prototype chain, * which is different from the ECMA [[Put]] operation. * @param name the name of the property * @param start the object whose property is being set * @param value value to set the property to * @see org.mozilla.javascript.Scriptable#has(String, Scriptable) * @see org.mozilla.javascript.Scriptable#get(String, Scriptable) * @see org.mozilla.javascript.ScriptableObject#putProperty(Scriptable, String, Object) * @see org.mozilla.javascript.Context#toObject(Object, Scriptable) */ public void putConst(String name, Scriptable start, Object value); /** * Reserves a definition spot for a const. This will set up a definition * of the const property, but set its value to undefined. The semantics of * the start parameter is the same as for putConst. * @param name The name of the property. * @param start The object whose property is being reserved. */ public void defineConst(String name, Scriptable start); /** * Returns true if the named property is defined as a const on this object. * @param name * @return true if the named property is defined as a const, false * otherwise. */ public boolean isConst(String name); } rhino-1.7R4/src/org/mozilla/javascript/Context.java000066400000000000000000002744461176760007500224220ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.CharArrayWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.HashSet; import java.util.Locale; import org.mozilla.javascript.ast.AstRoot; import org.mozilla.javascript.ast.ScriptNode; import org.mozilla.javascript.debug.DebuggableScript; import org.mozilla.javascript.debug.Debugger; import org.mozilla.javascript.xml.XMLLib; /** * This class represents the runtime context of an executing script. * * Before executing a script, an instance of Context must be created * and associated with the thread that will be executing the script. * The Context will be used to store information about the executing * of the script such as the call stack. Contexts are associated with * the current thread using the {@link #call(ContextAction)} * or {@link #enter()} methods.

* * Different forms of script execution are supported. Scripts may be * evaluated from the source directly, or first compiled and then later * executed. Interactive execution is also supported.

* * Some aspects of script execution, such as type conversions and * object creation, may be accessed directly through methods of * Context. * * @see Scriptable * @author Norris Boyd * @author Brendan Eich */ public class Context { /** * Language versions. * * All integral values are reserved for future version numbers. */ /** * The unknown version. */ public static final int VERSION_UNKNOWN = -1; /** * The default version. */ public static final int VERSION_DEFAULT = 0; /** * JavaScript 1.0 */ public static final int VERSION_1_0 = 100; /** * JavaScript 1.1 */ public static final int VERSION_1_1 = 110; /** * JavaScript 1.2 */ public static final int VERSION_1_2 = 120; /** * JavaScript 1.3 */ public static final int VERSION_1_3 = 130; /** * JavaScript 1.4 */ public static final int VERSION_1_4 = 140; /** * JavaScript 1.5 */ public static final int VERSION_1_5 = 150; /** * JavaScript 1.6 */ public static final int VERSION_1_6 = 160; /** * JavaScript 1.7 */ public static final int VERSION_1_7 = 170; /** * JavaScript 1.8 */ public static final int VERSION_1_8 = 180; /** * Controls behaviour of Date.prototype.getYear(). * If hasFeature(FEATURE_NON_ECMA_GET_YEAR) returns true, * Date.prototype.getYear subtructs 1900 only if 1900 <= date < 2000. * The default behavior of {@link #hasFeature(int)} is always to subtruct * 1900 as rquired by ECMAScript B.2.4. */ public static final int FEATURE_NON_ECMA_GET_YEAR = 1; /** * Control if member expression as function name extension is available. * If hasFeature(FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME) returns * true, allow function memberExpression(args) { body } to be * syntax sugar for memberExpression = function(args) { body }, * when memberExpression is not a simple identifier. * See ECMAScript-262, section 11.2 for definition of memberExpression. * By default {@link #hasFeature(int)} returns false. */ public static final int FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME = 2; /** * Control if reserved keywords are treated as identifiers. * If hasFeature(RESERVED_KEYWORD_AS_IDENTIFIER) returns true, * treat future reserved keyword (see Ecma-262, section 7.5.3) as ordinary * identifiers but warn about this usage. * * By default {@link #hasFeature(int)} returns false. */ public static final int FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER = 3; /** * Control if toString() should returns the same result * as toSource() when applied to objects and arrays. * If hasFeature(FEATURE_TO_STRING_AS_SOURCE) returns true, * calling toString() on JS objects gives the same result as * calling toSource(). That is it returns JS source with code * to create an object with all enumeratable fields of the original object * instead of printing [object result of * {@link Scriptable#getClassName()}]. *

* By default {@link #hasFeature(int)} returns true only if * the current JS version is set to {@link #VERSION_1_2}. */ public static final int FEATURE_TO_STRING_AS_SOURCE = 4; /** * Control if properties __proto__ and __parent__ * are treated specially. * If hasFeature(FEATURE_PARENT_PROTO_PROPERTIES) returns true, * treat __parent__ and __proto__ as special properties. *

* The properties allow to query and set scope and prototype chains for the * objects. The special meaning of the properties is available * only when they are used as the right hand side of the dot operator. * For example, while x.__proto__ = y changes the prototype * chain of the object x to point to y, * x["__proto__"] = y simply assigns a new value to the property * __proto__ in x even when the feature is on. * * By default {@link #hasFeature(int)} returns true. */ public static final int FEATURE_PARENT_PROTO_PROPERTIES = 5; /** * @deprecated In previous releases, this name was given to * FEATURE_PARENT_PROTO_PROPERTIES. */ public static final int FEATURE_PARENT_PROTO_PROPRTIES = 5; /** * Control if support for E4X(ECMAScript for XML) extension is available. * If hasFeature(FEATURE_E4X) returns true, the XML syntax is available. *

* By default {@link #hasFeature(int)} returns true if * the current JS version is set to {@link #VERSION_DEFAULT} * or is at least {@link #VERSION_1_6}. * @since 1.6 Release 1 */ public static final int FEATURE_E4X = 6; /** * Control if dynamic scope should be used for name access. * If hasFeature(FEATURE_DYNAMIC_SCOPE) returns true, then the name lookup * during name resolution will use the top scope of the script or function * which is at the top of JS execution stack instead of the top scope of the * script or function from the current stack frame if the top scope of * the top stack frame contains the top scope of the current stack frame * on its prototype chain. *

* This is useful to define shared scope containing functions that can * be called from scripts and functions using private scopes. *

* By default {@link #hasFeature(int)} returns false. * @since 1.6 Release 1 */ public static final int FEATURE_DYNAMIC_SCOPE = 7; /** * Control if strict variable mode is enabled. * When the feature is on Rhino reports runtime errors if assignment * to a global variable that does not exist is executed. When the feature * is off such assignments create a new variable in the global scope as * required by ECMA 262. *

* By default {@link #hasFeature(int)} returns false. * @since 1.6 Release 1 */ public static final int FEATURE_STRICT_VARS = 8; /** * Control if strict eval mode is enabled. * When the feature is on Rhino reports runtime errors if non-string * argument is passed to the eval function. When the feature is off * eval simply return non-string argument as is without performing any * evaluation as required by ECMA 262. *

* By default {@link #hasFeature(int)} returns false. * @since 1.6 Release 1 */ public static final int FEATURE_STRICT_EVAL = 9; /** * When the feature is on Rhino will add a "fileName" and "lineNumber" * properties to Error objects automatically. When the feature is off, you * have to explicitly pass them as the second and third argument to the * Error constructor. Note that neither behavior is fully ECMA 262 * compliant (as 262 doesn't specify a three-arg constructor), but keeping * the feature off results in Error objects that don't have * additional non-ECMA properties when constructed using the ECMA-defined * single-arg constructor and is thus desirable if a stricter ECMA * compliance is desired, specifically adherence to the point 15.11.5. of * the standard. *

* By default {@link #hasFeature(int)} returns false. * @since 1.6 Release 6 */ public static final int FEATURE_LOCATION_INFORMATION_IN_ERROR = 10; /** * Controls whether JS 1.5 'strict mode' is enabled. * When the feature is on, Rhino reports more than a dozen different * warnings. When the feature is off, these warnings are not generated. * FEATURE_STRICT_MODE implies FEATURE_STRICT_VARS and FEATURE_STRICT_EVAL. *

* By default {@link #hasFeature(int)} returns false. * @since 1.6 Release 6 */ public static final int FEATURE_STRICT_MODE = 11; /** * Controls whether a warning should be treated as an error. * @since 1.6 Release 6 */ public static final int FEATURE_WARNING_AS_ERROR = 12; /** * Enables enhanced access to Java. * Specifically, controls whether private and protected members can be * accessed, and whether scripts can catch all Java exceptions. *

* Note that this feature should only be enabled for trusted scripts. *

* By default {@link #hasFeature(int)} returns false. * @since 1.7 Release 1 */ public static final int FEATURE_ENHANCED_JAVA_ACCESS = 13; public static final String languageVersionProperty = "language version"; public static final String errorReporterProperty = "error reporter"; /** * Convenient value to use as zero-length array of objects. */ public static final Object[] emptyArgs = ScriptRuntime.emptyArgs; /** * Creates a new Context. The context will be associated with the {@link * ContextFactory#getGlobal() global context factory}. * * Note that the Context must be associated with a thread before * it can be used to execute a script. * @deprecated this constructor is deprecated because it creates a * dependency on a static singleton context factory. Use * {@link ContextFactory#enter()} or * {@link ContextFactory#call(ContextAction)} instead. If you subclass * this class, consider using {@link #Context(ContextFactory)} constructor * instead in the subclasses' constructors. */ public Context() { this(ContextFactory.getGlobal()); } /** * Creates a new context. Provided as a preferred super constructor for * subclasses in place of the deprecated default public constructor. * @param factory the context factory associated with this context (most * likely, the one that created the context). Can not be null. The context * features are inherited from the factory, and the context will also * otherwise use its factory's services. * @throws IllegalArgumentException if factory parameter is null. */ protected Context(ContextFactory factory) { if(factory == null) { throw new IllegalArgumentException("factory == null"); } this.factory = factory; version = VERSION_DEFAULT; optimizationLevel = codegenClass != null ? 0 : -1; maximumInterpreterStackDepth = Integer.MAX_VALUE; } /** * Get the current Context. * * The current Context is per-thread; this method looks up * the Context associated with the current thread.

* * @return the Context associated with the current thread, or * null if no context is associated with the current * thread. * @see ContextFactory#enterContext() * @see ContextFactory#call(ContextAction) */ public static Context getCurrentContext() { Object helper = VMBridge.instance.getThreadContextHelper(); return VMBridge.instance.getContext(helper); } /** * Same as calling {@link ContextFactory#enterContext()} on the global * ContextFactory instance. * @return a Context associated with the current thread * @see #getCurrentContext() * @see #exit() * @see #call(ContextAction) */ public static Context enter() { return enter(null); } /** * Get a Context associated with the current thread, using * the given Context if need be. *

* The same as enter() except that cx * is associated with the current thread and returned if * the current thread has no associated context and cx * is not associated with any other thread. * @param cx a Context to associate with the thread if possible * @return a Context associated with the current thread * @deprecated use {@link ContextFactory#enterContext(Context)} instead as * this method relies on usage of a static singleton "global" ContextFactory. * @see ContextFactory#enterContext(Context) * @see ContextFactory#call(ContextAction) */ public static Context enter(Context cx) { return enter(cx, ContextFactory.getGlobal()); } static final Context enter(Context cx, ContextFactory factory) { Object helper = VMBridge.instance.getThreadContextHelper(); Context old = VMBridge.instance.getContext(helper); if (old != null) { cx = old; } else { if (cx == null) { cx = factory.makeContext(); if (cx.enterCount != 0) { throw new IllegalStateException("factory.makeContext() returned Context instance already associated with some thread"); } factory.onContextCreated(cx); if (factory.isSealed() && !cx.isSealed()) { cx.seal(null); } } else { if (cx.enterCount != 0) { throw new IllegalStateException("can not use Context instance already associated with some thread"); } } VMBridge.instance.setContext(helper, cx); } ++cx.enterCount; return cx; } /** * Exit a block of code requiring a Context. * * Calling exit() will remove the association between * the current thread and a Context if the prior call to * {@link ContextFactory#enterContext()} on this thread newly associated a * Context with this thread. Once the current thread no longer has an * associated Context, it cannot be used to execute JavaScript until it is * again associated with a Context. * @see ContextFactory#enterContext() */ public static void exit() { Object helper = VMBridge.instance.getThreadContextHelper(); Context cx = VMBridge.instance.getContext(helper); if (cx == null) { throw new IllegalStateException( "Calling Context.exit without previous Context.enter"); } if (cx.enterCount < 1) Kit.codeBug(); if (--cx.enterCount == 0) { VMBridge.instance.setContext(helper, null); cx.factory.onContextReleased(cx); } } /** * Call {@link ContextAction#run(Context cx)} * using the Context instance associated with the current thread. * If no Context is associated with the thread, then * ContextFactory.getGlobal().makeContext() will be called to * construct new Context instance. The instance will be temporary * associated with the thread during call to * {@link ContextAction#run(Context)}. * @deprecated use {@link ContextFactory#call(ContextAction)} instead as * this method relies on usage of a static singleton "global" * ContextFactory. * @return The result of {@link ContextAction#run(Context)}. */ public static Object call(ContextAction action) { return call(ContextFactory.getGlobal(), action); } /** * Call {@link * Callable#call(Context cx, Scriptable scope, Scriptable thisObj, * Object[] args)} * using the Context instance associated with the current thread. * If no Context is associated with the thread, then * {@link ContextFactory#makeContext()} will be called to construct * new Context instance. The instance will be temporary associated * with the thread during call to {@link ContextAction#run(Context)}. *

* It is allowed but not advisable to use null for factory * argument in which case the global static singleton ContextFactory * instance will be used to create new context instances. * @see ContextFactory#call(ContextAction) */ public static Object call(ContextFactory factory, final Callable callable, final Scriptable scope, final Scriptable thisObj, final Object[] args) { if(factory == null) { factory = ContextFactory.getGlobal(); } return call(factory, new ContextAction() { public Object run(Context cx) { return callable.call(cx, scope, thisObj, args); } }); } /** * The method implements {@link ContextFactory#call(ContextAction)} logic. */ static Object call(ContextFactory factory, ContextAction action) { Context cx = enter(null, factory); try { return action.run(cx); } finally { exit(); } } /** * @deprecated * @see ContextFactory#addListener(org.mozilla.javascript.ContextFactory.Listener) * @see ContextFactory#getGlobal() */ public static void addContextListener(ContextListener listener) { // Special workaround for the debugger String DBG = "org.mozilla.javascript.tools.debugger.Main"; if (DBG.equals(listener.getClass().getName())) { Class cl = listener.getClass(); Class factoryClass = Kit.classOrNull( "org.mozilla.javascript.ContextFactory"); Class[] sig = { factoryClass }; Object[] args = { ContextFactory.getGlobal() }; try { Method m = cl.getMethod("attachTo", sig); m.invoke(listener, args); } catch (Exception ex) { RuntimeException rex = new RuntimeException(); Kit.initCause(rex, ex); throw rex; } return; } ContextFactory.getGlobal().addListener(listener); } /** * @deprecated * @see ContextFactory#removeListener(org.mozilla.javascript.ContextFactory.Listener) * @see ContextFactory#getGlobal() */ public static void removeContextListener(ContextListener listener) { ContextFactory.getGlobal().addListener(listener); } /** * Return {@link ContextFactory} instance used to create this Context. */ public final ContextFactory getFactory() { return factory; } /** * Checks if this is a sealed Context. A sealed Context instance does not * allow to modify any of its properties and will throw an exception * on any such attempt. * @see #seal(Object sealKey) */ public final boolean isSealed() { return sealed; } /** * Seal this Context object so any attempt to modify any of its properties * including calling {@link #enter()} and {@link #exit()} methods will * throw an exception. *

* If sealKey is not null, calling * {@link #unseal(Object sealKey)} with the same key unseals * the object. If sealKey is null, unsealing is no longer possible. * * @see #isSealed() * @see #unseal(Object) */ public final void seal(Object sealKey) { if (sealed) onSealedMutation(); sealed = true; this.sealKey = sealKey; } /** * Unseal previously sealed Context object. * The sealKey argument should not be null and should match * sealKey suplied with the last call to * {@link #seal(Object)} or an exception will be thrown. * * @see #isSealed() * @see #seal(Object sealKey) */ public final void unseal(Object sealKey) { if (sealKey == null) throw new IllegalArgumentException(); if (this.sealKey != sealKey) throw new IllegalArgumentException(); if (!sealed) throw new IllegalStateException(); sealed = false; this.sealKey = null; } static void onSealedMutation() { throw new IllegalStateException(); } /** * Get the current language version. *

* The language version number affects JavaScript semantics as detailed * in the overview documentation. * * @return an integer that is one of VERSION_1_0, VERSION_1_1, etc. */ public final int getLanguageVersion() { return version; } /** * Set the language version. * *

* Setting the language version will affect functions and scripts compiled * subsequently. See the overview documentation for version-specific * behavior. * * @param version the version as specified by VERSION_1_0, VERSION_1_1, etc. */ public void setLanguageVersion(int version) { if (sealed) onSealedMutation(); checkLanguageVersion(version); Object listeners = propertyListeners; if (listeners != null && version != this.version) { firePropertyChangeImpl(listeners, languageVersionProperty, Integer.valueOf(this.version), Integer.valueOf(version)); } this.version = version; } public static boolean isValidLanguageVersion(int version) { switch (version) { case VERSION_DEFAULT: case VERSION_1_0: case VERSION_1_1: case VERSION_1_2: case VERSION_1_3: case VERSION_1_4: case VERSION_1_5: case VERSION_1_6: case VERSION_1_7: case VERSION_1_8: return true; } return false; } public static void checkLanguageVersion(int version) { if (isValidLanguageVersion(version)) { return; } throw new IllegalArgumentException("Bad language version: "+version); } /** * Get the implementation version. * *

* The implementation version is of the form *

     *    "name langVer release relNum date"
     * 
* where name is the name of the product, langVer is * the language version, relNum is the release number, and * date is the release date for that specific * release in the form "yyyy mm dd". * * @return a string that encodes the product, language version, release * number, and date. */ public final String getImplementationVersion() { // XXX Probably it would be better to embed this directly into source // with special build preprocessing but that would require some ant // tweaking and then replacing token in resource files was simpler if (implementationVersion == null) { implementationVersion = ScriptRuntime.getMessage0("implementation.version"); } return implementationVersion; } /** * Get the current error reporter. * * @see org.mozilla.javascript.ErrorReporter */ public final ErrorReporter getErrorReporter() { if (errorReporter == null) { return DefaultErrorReporter.instance; } return errorReporter; } /** * Change the current error reporter. * * @return the previous error reporter * @see org.mozilla.javascript.ErrorReporter */ public final ErrorReporter setErrorReporter(ErrorReporter reporter) { if (sealed) onSealedMutation(); if (reporter == null) throw new IllegalArgumentException(); ErrorReporter old = getErrorReporter(); if (reporter == old) { return old; } Object listeners = propertyListeners; if (listeners != null) { firePropertyChangeImpl(listeners, errorReporterProperty, old, reporter); } this.errorReporter = reporter; return old; } /** * Get the current locale. Returns the default locale if none has * been set. * * @see java.util.Locale */ public final Locale getLocale() { if (locale == null) locale = Locale.getDefault(); return locale; } /** * Set the current locale. * * @see java.util.Locale */ public final Locale setLocale(Locale loc) { if (sealed) onSealedMutation(); Locale result = locale; locale = loc; return result; } /** * Register an object to receive notifications when a bound property * has changed * @see java.beans.PropertyChangeEvent * @see #removePropertyChangeListener(java.beans.PropertyChangeListener) * @param l the listener */ public final void addPropertyChangeListener(PropertyChangeListener l) { if (sealed) onSealedMutation(); propertyListeners = Kit.addListener(propertyListeners, l); } /** * Remove an object from the list of objects registered to receive * notification of changes to a bounded property * @see java.beans.PropertyChangeEvent * @see #addPropertyChangeListener(java.beans.PropertyChangeListener) * @param l the listener */ public final void removePropertyChangeListener(PropertyChangeListener l) { if (sealed) onSealedMutation(); propertyListeners = Kit.removeListener(propertyListeners, l); } /** * Notify any registered listeners that a bounded property has changed * @see #addPropertyChangeListener(java.beans.PropertyChangeListener) * @see #removePropertyChangeListener(java.beans.PropertyChangeListener) * @see java.beans.PropertyChangeListener * @see java.beans.PropertyChangeEvent * @param property the bound property * @param oldValue the old value * @param newValue the new value */ final void firePropertyChange(String property, Object oldValue, Object newValue) { Object listeners = propertyListeners; if (listeners != null) { firePropertyChangeImpl(listeners, property, oldValue, newValue); } } private void firePropertyChangeImpl(Object listeners, String property, Object oldValue, Object newValue) { for (int i = 0; ; ++i) { Object l = Kit.getListener(listeners, i); if (l == null) break; if (l instanceof PropertyChangeListener) { PropertyChangeListener pcl = (PropertyChangeListener)l; pcl.propertyChange(new PropertyChangeEvent( this, property, oldValue, newValue)); } } } /** * Report a warning using the error reporter for the current thread. * * @param message the warning message to report * @param sourceName a string describing the source, such as a filename * @param lineno the starting line number * @param lineSource the text of the line (may be null) * @param lineOffset the offset into lineSource where problem was detected * @see org.mozilla.javascript.ErrorReporter */ public static void reportWarning(String message, String sourceName, int lineno, String lineSource, int lineOffset) { Context cx = Context.getContext(); if (cx.hasFeature(FEATURE_WARNING_AS_ERROR)) reportError(message, sourceName, lineno, lineSource, lineOffset); else cx.getErrorReporter().warning(message, sourceName, lineno, lineSource, lineOffset); } /** * Report a warning using the error reporter for the current thread. * * @param message the warning message to report * @see org.mozilla.javascript.ErrorReporter */ public static void reportWarning(String message) { int[] linep = { 0 }; String filename = getSourcePositionFromStack(linep); Context.reportWarning(message, filename, linep[0], null, 0); } public static void reportWarning(String message, Throwable t) { int[] linep = { 0 }; String filename = getSourcePositionFromStack(linep); Writer sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); pw.println(message); t.printStackTrace(pw); pw.flush(); Context.reportWarning(sw.toString(), filename, linep[0], null, 0); } /** * Report an error using the error reporter for the current thread. * * @param message the error message to report * @param sourceName a string describing the source, such as a filename * @param lineno the starting line number * @param lineSource the text of the line (may be null) * @param lineOffset the offset into lineSource where problem was detected * @see org.mozilla.javascript.ErrorReporter */ public static void reportError(String message, String sourceName, int lineno, String lineSource, int lineOffset) { Context cx = getCurrentContext(); if (cx != null) { cx.getErrorReporter().error(message, sourceName, lineno, lineSource, lineOffset); } else { throw new EvaluatorException(message, sourceName, lineno, lineSource, lineOffset); } } /** * Report an error using the error reporter for the current thread. * * @param message the error message to report * @see org.mozilla.javascript.ErrorReporter */ public static void reportError(String message) { int[] linep = { 0 }; String filename = getSourcePositionFromStack(linep); Context.reportError(message, filename, linep[0], null, 0); } /** * Report a runtime error using the error reporter for the current thread. * * @param message the error message to report * @param sourceName a string describing the source, such as a filename * @param lineno the starting line number * @param lineSource the text of the line (may be null) * @param lineOffset the offset into lineSource where problem was detected * @return a runtime exception that will be thrown to terminate the * execution of the script * @see org.mozilla.javascript.ErrorReporter */ public static EvaluatorException reportRuntimeError(String message, String sourceName, int lineno, String lineSource, int lineOffset) { Context cx = getCurrentContext(); if (cx != null) { return cx.getErrorReporter(). runtimeError(message, sourceName, lineno, lineSource, lineOffset); } else { throw new EvaluatorException(message, sourceName, lineno, lineSource, lineOffset); } } static EvaluatorException reportRuntimeError0(String messageId) { String msg = ScriptRuntime.getMessage0(messageId); return reportRuntimeError(msg); } static EvaluatorException reportRuntimeError1(String messageId, Object arg1) { String msg = ScriptRuntime.getMessage1(messageId, arg1); return reportRuntimeError(msg); } static EvaluatorException reportRuntimeError2(String messageId, Object arg1, Object arg2) { String msg = ScriptRuntime.getMessage2(messageId, arg1, arg2); return reportRuntimeError(msg); } static EvaluatorException reportRuntimeError3(String messageId, Object arg1, Object arg2, Object arg3) { String msg = ScriptRuntime.getMessage3(messageId, arg1, arg2, arg3); return reportRuntimeError(msg); } static EvaluatorException reportRuntimeError4(String messageId, Object arg1, Object arg2, Object arg3, Object arg4) { String msg = ScriptRuntime.getMessage4(messageId, arg1, arg2, arg3, arg4); return reportRuntimeError(msg); } /** * Report a runtime error using the error reporter for the current thread. * * @param message the error message to report * @see org.mozilla.javascript.ErrorReporter */ public static EvaluatorException reportRuntimeError(String message) { int[] linep = { 0 }; String filename = getSourcePositionFromStack(linep); return Context.reportRuntimeError(message, filename, linep[0], null, 0); } /** * Initialize the standard objects. * * Creates instances of the standard objects and their constructors * (Object, String, Number, Date, etc.), setting up 'scope' to act * as a global object as in ECMA 15.1.

* * This method must be called to initialize a scope before scripts * can be evaluated in that scope.

* * This method does not affect the Context it is called upon. * * @return the initialized scope */ public final ScriptableObject initStandardObjects() { return initStandardObjects(null, false); } /** * Initialize the standard objects. * * Creates instances of the standard objects and their constructors * (Object, String, Number, Date, etc.), setting up 'scope' to act * as a global object as in ECMA 15.1.

* * This method must be called to initialize a scope before scripts * can be evaluated in that scope.

* * This method does not affect the Context it is called upon. * * @param scope the scope to initialize, or null, in which case a new * object will be created to serve as the scope * @return the initialized scope. The method returns the value of the scope * argument if it is not null or newly allocated scope object which * is an instance {@link ScriptableObject}. */ public final Scriptable initStandardObjects(ScriptableObject scope) { return initStandardObjects(scope, false); } /** * Initialize the standard objects. * * Creates instances of the standard objects and their constructors * (Object, String, Number, Date, etc.), setting up 'scope' to act * as a global object as in ECMA 15.1.

* * This method must be called to initialize a scope before scripts * can be evaluated in that scope.

* * This method does not affect the Context it is called upon.

* * This form of the method also allows for creating "sealed" standard * objects. An object that is sealed cannot have properties added, changed, * or removed. This is useful to create a "superglobal" that can be shared * among several top-level objects. Note that sealing is not allowed in * the current ECMA/ISO language specification, but is likely for * the next version. * * @param scope the scope to initialize, or null, in which case a new * object will be created to serve as the scope * @param sealed whether or not to create sealed standard objects that * cannot be modified. * @return the initialized scope. The method returns the value of the scope * argument if it is not null or newly allocated scope object. * @since 1.4R3 */ public ScriptableObject initStandardObjects(ScriptableObject scope, boolean sealed) { return ScriptRuntime.initStandardObjects(this, scope, sealed); } /** * Get the singleton object that represents the JavaScript Undefined value. */ public static Object getUndefinedValue() { return Undefined.instance; } /** * Evaluate a JavaScript source string. * * The provided source name and line number are used for error messages * and for producing debug information. * * @param scope the scope to execute in * @param source the JavaScript source * @param sourceName a string describing the source, such as a filename * @param lineno the starting line number * @param securityDomain an arbitrary object that specifies security * information about the origin or owner of the script. For * implementations that don't care about security, this value * may be null. * @return the result of evaluating the string * @see org.mozilla.javascript.SecurityController */ public final Object evaluateString(Scriptable scope, String source, String sourceName, int lineno, Object securityDomain) { Script script = compileString(source, sourceName, lineno, securityDomain); if (script != null) { return script.exec(this, scope); } else { return null; } } /** * Evaluate a reader as JavaScript source. * * All characters of the reader are consumed. * * @param scope the scope to execute in * @param in the Reader to get JavaScript source from * @param sourceName a string describing the source, such as a filename * @param lineno the starting line number * @param securityDomain an arbitrary object that specifies security * information about the origin or owner of the script. For * implementations that don't care about security, this value * may be null. * @return the result of evaluating the source * * @exception IOException if an IOException was generated by the Reader */ public final Object evaluateReader(Scriptable scope, Reader in, String sourceName, int lineno, Object securityDomain) throws IOException { Script script = compileReader(scope, in, sourceName, lineno, securityDomain); if (script != null) { return script.exec(this, scope); } else { return null; } } /** * Execute script that may pause execution by capturing a continuation. * Caller must be prepared to catch a ContinuationPending exception * and resume execution by calling * {@link #resumeContinuation(Object, Scriptable, Object)}. * @param script The script to execute. Script must have been compiled * with interpreted mode (optimization level -1) * @param scope The scope to execute the script against * @throws ContinuationPending if the script calls a function that results * in a call to {@link #captureContinuation()} * @since 1.7 Release 2 */ public Object executeScriptWithContinuations(Script script, Scriptable scope) throws ContinuationPending { if (!(script instanceof InterpretedFunction) || !((InterpretedFunction)script).isScript()) { // Can only be applied to scripts throw new IllegalArgumentException("Script argument was not" + " a script or was not created by interpreted mode "); } return callFunctionWithContinuations((InterpretedFunction) script, scope, ScriptRuntime.emptyArgs); } /** * Call function that may pause execution by capturing a continuation. * Caller must be prepared to catch a ContinuationPending exception * and resume execution by calling * {@link #resumeContinuation(Object, Scriptable, Object)}. * @param function The function to call. The function must have been * compiled with interpreted mode (optimization level -1) * @param scope The scope to execute the script against * @param args The arguments for the function * @throws ContinuationPending if the script calls a function that results * in a call to {@link #captureContinuation()} * @since 1.7 Release 2 */ public Object callFunctionWithContinuations(Callable function, Scriptable scope, Object[] args) throws ContinuationPending { if (!(function instanceof InterpretedFunction)) { // Can only be applied to scripts throw new IllegalArgumentException("Function argument was not" + " created by interpreted mode "); } if (ScriptRuntime.hasTopCall(this)) { throw new IllegalStateException("Cannot have any pending top " + "calls when executing a script with continuations"); } // Annotate so we can check later to ensure no java code in // intervening frames isContinuationsTopCall = true; return ScriptRuntime.doTopCall(function, this, scope, scope, args); } /** * Capture a continuation from the current execution. The execution must * have been started via a call to * {@link #executeScriptWithContinuations(Script, Scriptable)} or * {@link #callFunctionWithContinuations(Callable, Scriptable, Object[])}. * This implies that the code calling * this method must have been called as a function from the * JavaScript script. Also, there cannot be any non-JavaScript code * between the JavaScript frames (e.g., a call to eval()). The * ContinuationPending exception returned must be thrown. * @return A ContinuationPending exception that must be thrown * @since 1.7 Release 2 */ public ContinuationPending captureContinuation() { return new ContinuationPending( Interpreter.captureContinuation(this)); } /** * Restarts execution of the JavaScript suspended at the call * to {@link #captureContinuation()}. Execution of the code will resume * with the functionResult as the result of the call that captured the * continuation. * Execution of the script will either conclude normally and the * result returned, another continuation will be captured and * thrown, or the script will terminate abnormally and throw an exception. * @param continuation The value returned by * {@link ContinuationPending#getContinuation()} * @param functionResult This value will appear to the code being resumed * as the result of the function that captured the continuation * @throws ContinuationPending if another continuation is captured before * the code terminates * @since 1.7 Release 2 */ public Object resumeContinuation(Object continuation, Scriptable scope, Object functionResult) throws ContinuationPending { Object[] args = { functionResult }; return Interpreter.restartContinuation( (org.mozilla.javascript.NativeContinuation) continuation, this, scope, args); } /** * Check whether a string is ready to be compiled. *

* stringIsCompilableUnit is intended to support interactive compilation of * JavaScript. If compiling the string would result in an error * that might be fixed by appending more source, this method * returns false. In every other case, it returns true. *

* Interactive shells may accumulate source lines, using this * method after each new line is appended to check whether the * statement being entered is complete. * * @param source the source buffer to check * @return whether the source is ready for compilation * @since 1.4 Release 2 */ public final boolean stringIsCompilableUnit(String source) { boolean errorseen = false; CompilerEnvirons compilerEnv = new CompilerEnvirons(); compilerEnv.initFromContext(this); // no source name or source text manager, because we're just // going to throw away the result. compilerEnv.setGeneratingSource(false); Parser p = new Parser(compilerEnv, DefaultErrorReporter.instance); try { p.parse(source, null, 1); } catch (EvaluatorException ee) { errorseen = true; } // Return false only if an error occurred as a result of reading past // the end of the file, i.e. if the source could be fixed by // appending more source. if (errorseen && p.eof()) return false; else return true; } /** * @deprecated * @see #compileReader(Reader in, String sourceName, int lineno, * Object securityDomain) */ public final Script compileReader(Scriptable scope, Reader in, String sourceName, int lineno, Object securityDomain) throws IOException { return compileReader(in, sourceName, lineno, securityDomain); } /** * Compiles the source in the given reader. *

* Returns a script that may later be executed. * Will consume all the source in the reader. * * @param in the input reader * @param sourceName a string describing the source, such as a filename * @param lineno the starting line number for reporting errors * @param securityDomain an arbitrary object that specifies security * information about the origin or owner of the script. For * implementations that don't care about security, this value * may be null. * @return a script that may later be executed * @exception IOException if an IOException was generated by the Reader * @see org.mozilla.javascript.Script */ public final Script compileReader(Reader in, String sourceName, int lineno, Object securityDomain) throws IOException { if (lineno < 0) { // For compatibility IllegalArgumentException can not be thrown here lineno = 0; } return (Script) compileImpl(null, in, null, sourceName, lineno, securityDomain, false, null, null); } /** * Compiles the source in the given string. *

* Returns a script that may later be executed. * * @param source the source string * @param sourceName a string describing the source, such as a filename * @param lineno the starting line number for reporting errors. Use * 0 if the line number is unknown. * @param securityDomain an arbitrary object that specifies security * information about the origin or owner of the script. For * implementations that don't care about security, this value * may be null. * @return a script that may later be executed * @see org.mozilla.javascript.Script */ public final Script compileString(String source, String sourceName, int lineno, Object securityDomain) { if (lineno < 0) { // For compatibility IllegalArgumentException can not be thrown here lineno = 0; } return compileString(source, null, null, sourceName, lineno, securityDomain); } final Script compileString(String source, Evaluator compiler, ErrorReporter compilationErrorReporter, String sourceName, int lineno, Object securityDomain) { try { return (Script) compileImpl(null, null, source, sourceName, lineno, securityDomain, false, compiler, compilationErrorReporter); } catch (IOException ex) { // Should not happen when dealing with source as string throw new RuntimeException(); } } /** * Compile a JavaScript function. *

* The function source must be a function definition as defined by * ECMA (e.g., "function f(a) { return a; }"). * * @param scope the scope to compile relative to * @param source the function definition source * @param sourceName a string describing the source, such as a filename * @param lineno the starting line number * @param securityDomain an arbitrary object that specifies security * information about the origin or owner of the script. For * implementations that don't care about security, this value * may be null. * @return a Function that may later be called * @see org.mozilla.javascript.Function */ public final Function compileFunction(Scriptable scope, String source, String sourceName, int lineno, Object securityDomain) { return compileFunction(scope, source, null, null, sourceName, lineno, securityDomain); } final Function compileFunction(Scriptable scope, String source, Evaluator compiler, ErrorReporter compilationErrorReporter, String sourceName, int lineno, Object securityDomain) { try { return (Function) compileImpl(scope, null, source, sourceName, lineno, securityDomain, true, compiler, compilationErrorReporter); } catch (IOException ioe) { // Should never happen because we just made the reader // from a String throw new RuntimeException(); } } /** * Decompile the script. *

* The canonical source of the script is returned. * * @param script the script to decompile * @param indent the number of spaces to indent the result * @return a string representing the script source */ public final String decompileScript(Script script, int indent) { NativeFunction scriptImpl = (NativeFunction) script; return scriptImpl.decompile(indent, 0); } /** * Decompile a JavaScript Function. *

* Decompiles a previously compiled JavaScript function object to * canonical source. *

* Returns function body of '[native code]' if no decompilation * information is available. * * @param fun the JavaScript function to decompile * @param indent the number of spaces to indent the result * @return a string representing the function source */ public final String decompileFunction(Function fun, int indent) { if (fun instanceof BaseFunction) return ((BaseFunction)fun).decompile(indent, 0); else return "function " + fun.getClassName() + "() {\n\t[native code]\n}\n"; } /** * Decompile the body of a JavaScript Function. *

* Decompiles the body a previously compiled JavaScript Function * object to canonical source, omitting the function header and * trailing brace. * * Returns '[native code]' if no decompilation information is available. * * @param fun the JavaScript function to decompile * @param indent the number of spaces to indent the result * @return a string representing the function body source. */ public final String decompileFunctionBody(Function fun, int indent) { if (fun instanceof BaseFunction) { BaseFunction bf = (BaseFunction)fun; return bf.decompile(indent, Decompiler.ONLY_BODY_FLAG); } // ALERT: not sure what the right response here is. return "[native code]\n"; } /** * Create a new JavaScript object. * * Equivalent to evaluating "new Object()". * @param scope the scope to search for the constructor and to evaluate * against * @return the new object */ public Scriptable newObject(Scriptable scope) { NativeObject result = new NativeObject(); ScriptRuntime.setBuiltinProtoAndParent(result, scope, TopLevel.Builtins.Object); return result; } /** * Create a new JavaScript object by executing the named constructor. * * The call newObject(scope, "Foo") is equivalent to * evaluating "new Foo()". * * @param scope the scope to search for the constructor and to evaluate against * @param constructorName the name of the constructor to call * @return the new object */ public Scriptable newObject(Scriptable scope, String constructorName) { return newObject(scope, constructorName, ScriptRuntime.emptyArgs); } /** * Creates a new JavaScript object by executing the named constructor. * * Searches scope for the named constructor, calls it with * the given arguments, and returns the result.

* * The code *

     * Object[] args = { "a", "b" };
     * newObject(scope, "Foo", args)
* is equivalent to evaluating "new Foo('a', 'b')", assuming that the Foo * constructor has been defined in scope. * * @param scope The scope to search for the constructor and to evaluate * against * @param constructorName the name of the constructor to call * @param args the array of arguments for the constructor * @return the new object */ public Scriptable newObject(Scriptable scope, String constructorName, Object[] args) { scope = ScriptableObject.getTopLevelScope(scope); Function ctor = ScriptRuntime.getExistingCtor(this, scope, constructorName); if (args == null) { args = ScriptRuntime.emptyArgs; } return ctor.construct(this, scope, args); } /** * Create an array with a specified initial length. *

* @param scope the scope to create the object in * @param length the initial length (JavaScript arrays may have * additional properties added dynamically). * @return the new array object */ public Scriptable newArray(Scriptable scope, int length) { NativeArray result = new NativeArray(length); ScriptRuntime.setBuiltinProtoAndParent(result, scope, TopLevel.Builtins.Array); return result; } /** * Create an array with a set of initial elements. * * @param scope the scope to create the object in. * @param elements the initial elements. Each object in this array * must be an acceptable JavaScript type and type * of array should be exactly Object[], not * SomeObjectSubclass[]. * @return the new array object. */ public Scriptable newArray(Scriptable scope, Object[] elements) { if (elements.getClass().getComponentType() != ScriptRuntime.ObjectClass) throw new IllegalArgumentException(); NativeArray result = new NativeArray(elements); ScriptRuntime.setBuiltinProtoAndParent(result, scope, TopLevel.Builtins.Array); return result; } /** * Get the elements of a JavaScript array. *

* If the object defines a length property convertible to double number, * then the number is converted Uint32 value as defined in Ecma 9.6 * and Java array of that size is allocated. * The array is initialized with the values obtained by * calling get() on object for each value of i in [0,length-1]. If * there is not a defined value for a property the Undefined value * is used to initialize the corresponding element in the array. The * Java array is then returned. * If the object doesn't define a length property or it is not a number, * empty array is returned. * @param object the JavaScript array or array-like object * @return a Java array of objects * @since 1.4 release 2 */ public final Object[] getElements(Scriptable object) { return ScriptRuntime.getArrayElements(object); } /** * Convert the value to a JavaScript boolean value. *

* See ECMA 9.2. * * @param value a JavaScript value * @return the corresponding boolean value converted using * the ECMA rules */ public static boolean toBoolean(Object value) { return ScriptRuntime.toBoolean(value); } /** * Convert the value to a JavaScript Number value. *

* Returns a Java double for the JavaScript Number. *

* See ECMA 9.3. * * @param value a JavaScript value * @return the corresponding double value converted using * the ECMA rules */ public static double toNumber(Object value) { return ScriptRuntime.toNumber(value); } /** * Convert the value to a JavaScript String value. *

* See ECMA 9.8. *

* @param value a JavaScript value * @return the corresponding String value converted using * the ECMA rules */ public static String toString(Object value) { return ScriptRuntime.toString(value); } /** * Convert the value to an JavaScript object value. *

* Note that a scope must be provided to look up the constructors * for Number, Boolean, and String. *

* See ECMA 9.9. *

* Additionally, arbitrary Java objects and classes will be * wrapped in a Scriptable object with its Java fields and methods * reflected as JavaScript properties of the object. * * @param value any Java object * @param scope global scope containing constructors for Number, * Boolean, and String * @return new JavaScript object */ public static Scriptable toObject(Object value, Scriptable scope) { return ScriptRuntime.toObject(scope, value); } /** * @deprecated * @see #toObject(Object, Scriptable) */ public static Scriptable toObject(Object value, Scriptable scope, Class staticType) { return ScriptRuntime.toObject(scope, value); } /** * Convenient method to convert java value to its closest representation * in JavaScript. *

* If value is an instance of String, Number, Boolean, Function or * Scriptable, it is returned as it and will be treated as the corresponding * JavaScript type of string, number, boolean, function and object. *

* Note that for Number instances during any arithmetic operation in * JavaScript the engine will always use the result of * Number.doubleValue() resulting in a precision loss if * the number can not fit into double. *

* If value is an instance of Character, it will be converted to string of * length 1 and its JavaScript type will be string. *

* The rest of values will be wrapped as LiveConnect objects * by calling {@link WrapFactory#wrap(Context cx, Scriptable scope, * Object obj, Class staticType)} as in: *

     *    Context cx = Context.getCurrentContext();
     *    return cx.getWrapFactory().wrap(cx, scope, value, null);
     * 
* * @param value any Java object * @param scope top scope object * @return value suitable to pass to any API that takes JavaScript values. */ public static Object javaToJS(Object value, Scriptable scope) { if (value instanceof String || value instanceof Number || value instanceof Boolean || value instanceof Scriptable) { return value; } else if (value instanceof Character) { return String.valueOf(((Character)value).charValue()); } else { Context cx = Context.getContext(); return cx.getWrapFactory().wrap(cx, scope, value, null); } } /** * Convert a JavaScript value into the desired type. * Uses the semantics defined with LiveConnect3 and throws an * Illegal argument exception if the conversion cannot be performed. * @param value the JavaScript value to convert * @param desiredType the Java type to convert to. Primitive Java * types are represented using the TYPE fields in the corresponding * wrapper class in java.lang. * @return the converted value * @throws EvaluatorException if the conversion cannot be performed */ public static Object jsToJava(Object value, Class desiredType) throws EvaluatorException { return NativeJavaObject.coerceTypeImpl(desiredType, value); } /** * @deprecated * @see #jsToJava(Object, Class) * @throws IllegalArgumentException if the conversion cannot be performed. * Note that {@link #jsToJava(Object, Class)} throws * {@link EvaluatorException} instead. */ public static Object toType(Object value, Class desiredType) throws IllegalArgumentException { try { return jsToJava(value, desiredType); } catch (EvaluatorException ex) { IllegalArgumentException ex2 = new IllegalArgumentException(ex.getMessage()); Kit.initCause(ex2, ex); throw ex2; } } /** * Rethrow the exception wrapping it as the script runtime exception. * Unless the exception is instance of {@link EcmaError} or * {@link EvaluatorException} it will be wrapped as * {@link WrappedException}, a subclass of {@link EvaluatorException}. * The resulting exception object always contains * source name and line number of script that triggered exception. *

* This method always throws an exception, its return value is provided * only for convenience to allow a usage like: *

     * throw Context.throwAsScriptRuntimeEx(ex);
     * 
* to indicate that code after the method is unreachable. * @throws EvaluatorException * @throws EcmaError */ public static RuntimeException throwAsScriptRuntimeEx(Throwable e) { while ((e instanceof InvocationTargetException)) { e = ((InvocationTargetException) e).getTargetException(); } // special handling of Error so scripts would not catch them if (e instanceof Error) { Context cx = getContext(); if (cx == null || !cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)) { throw (Error)e; } } if (e instanceof RhinoException) { throw (RhinoException)e; } throw new WrappedException(e); } /** * Tell whether debug information is being generated. * @since 1.3 */ public final boolean isGeneratingDebug() { return generatingDebug; } /** * Specify whether or not debug information should be generated. *

* Setting the generation of debug information on will set the * optimization level to zero. * @since 1.3 */ public final void setGeneratingDebug(boolean generatingDebug) { if (sealed) onSealedMutation(); generatingDebugChanged = true; if (generatingDebug && getOptimizationLevel() > 0) setOptimizationLevel(0); this.generatingDebug = generatingDebug; } /** * Tell whether source information is being generated. * @since 1.3 */ public final boolean isGeneratingSource() { return generatingSource; } /** * Specify whether or not source information should be generated. *

* Without source information, evaluating the "toString" method * on JavaScript functions produces only "[native code]" for * the body of the function. * Note that code generated without source is not fully ECMA * conformant. * @since 1.3 */ public final void setGeneratingSource(boolean generatingSource) { if (sealed) onSealedMutation(); this.generatingSource = generatingSource; } /** * Get the current optimization level. *

* The optimization level is expressed as an integer between -1 and * 9. * @since 1.3 * */ public final int getOptimizationLevel() { return optimizationLevel; } /** * Set the current optimization level. *

* The optimization level is expected to be an integer between -1 and * 9. Any negative values will be interpreted as -1, and any values * greater than 9 will be interpreted as 9. * An optimization level of -1 indicates that interpretive mode will * always be used. Levels 0 through 9 indicate that class files may * be generated. Higher optimization levels trade off compile time * performance for runtime performance. * The optimizer level can't be set greater than -1 if the optimizer * package doesn't exist at run time. * @param optimizationLevel an integer indicating the level of * optimization to perform * @since 1.3 * */ public final void setOptimizationLevel(int optimizationLevel) { if (sealed) onSealedMutation(); if (optimizationLevel == -2) { // To be compatible with Cocoon fork optimizationLevel = -1; } checkOptimizationLevel(optimizationLevel); if (codegenClass == null) optimizationLevel = -1; this.optimizationLevel = optimizationLevel; } public static boolean isValidOptimizationLevel(int optimizationLevel) { return -1 <= optimizationLevel && optimizationLevel <= 9; } public static void checkOptimizationLevel(int optimizationLevel) { if (isValidOptimizationLevel(optimizationLevel)) { return; } throw new IllegalArgumentException( "Optimization level outside [-1..9]: "+optimizationLevel); } /** * Returns the maximum stack depth (in terms of number of call frames) * allowed in a single invocation of interpreter. If the set depth would be * exceeded, the interpreter will throw an EvaluatorException in the script. * Defaults to Integer.MAX_VALUE. The setting only has effect for * interpreted functions (those compiled with optimization level set to -1). * As the interpreter doesn't use the Java stack but rather manages its own * stack in the heap memory, a runaway recursion in interpreted code would * eventually consume all available memory and cause OutOfMemoryError * instead of a StackOverflowError limited to only a single thread. This * setting helps prevent such situations. * * @return The current maximum interpreter stack depth. */ public final int getMaximumInterpreterStackDepth() { return maximumInterpreterStackDepth; } /** * Sets the maximum stack depth (in terms of number of call frames) * allowed in a single invocation of interpreter. If the set depth would be * exceeded, the interpreter will throw an EvaluatorException in the script. * Defaults to Integer.MAX_VALUE. The setting only has effect for * interpreted functions (those compiled with optimization level set to -1). * As the interpreter doesn't use the Java stack but rather manages its own * stack in the heap memory, a runaway recursion in interpreted code would * eventually consume all available memory and cause OutOfMemoryError * instead of a StackOverflowError limited to only a single thread. This * setting helps prevent such situations. * * @param max the new maximum interpreter stack depth * @throws IllegalStateException if this context's optimization level is not * -1 * @throws IllegalArgumentException if the new depth is not at least 1 */ public final void setMaximumInterpreterStackDepth(int max) { if(sealed) onSealedMutation(); if(optimizationLevel != -1) { throw new IllegalStateException("Cannot set maximumInterpreterStackDepth when optimizationLevel != -1"); } if(max < 1) { throw new IllegalArgumentException("Cannot set maximumInterpreterStackDepth to less than 1"); } maximumInterpreterStackDepth = max; } /** * Set the security controller for this context. *

SecurityController may only be set if it is currently null * and {@link SecurityController#hasGlobal()} is false. * Otherwise a SecurityException is thrown. * @param controller a SecurityController object * @throws SecurityException if there is already a SecurityController * object for this Context or globally installed. * @see SecurityController#initGlobal(SecurityController controller) * @see SecurityController#hasGlobal() */ public final void setSecurityController(SecurityController controller) { if (sealed) onSealedMutation(); if (controller == null) throw new IllegalArgumentException(); if (securityController != null) { throw new SecurityException("Can not overwrite existing SecurityController object"); } if (SecurityController.hasGlobal()) { throw new SecurityException("Can not overwrite existing global SecurityController object"); } securityController = controller; } /** * Set the LiveConnect access filter for this context. *

{@link ClassShutter} may only be set if it is currently null. * Otherwise a SecurityException is thrown. * @param shutter a ClassShutter object * @throws SecurityException if there is already a ClassShutter * object for this Context */ public synchronized final void setClassShutter(ClassShutter shutter) { if (sealed) onSealedMutation(); if (shutter == null) throw new IllegalArgumentException(); if (hasClassShutter) { throw new SecurityException("Cannot overwrite existing " + "ClassShutter object"); } classShutter = shutter; hasClassShutter = true; } final synchronized ClassShutter getClassShutter() { return classShutter; } public interface ClassShutterSetter { public void setClassShutter(ClassShutter shutter); public ClassShutter getClassShutter(); } public final synchronized ClassShutterSetter getClassShutterSetter() { if (hasClassShutter) return null; hasClassShutter = true; return new ClassShutterSetter() { public void setClassShutter(ClassShutter shutter) { classShutter = shutter; } public ClassShutter getClassShutter() { return classShutter; } }; } /** * Get a value corresponding to a key. *

* Since the Context is associated with a thread it can be * used to maintain values that can be later retrieved using * the current thread. *

* Note that the values are maintained with the Context, so * if the Context is disassociated from the thread the values * cannot be retrieved. Also, if private data is to be maintained * in this manner the key should be a java.lang.Object * whose reference is not divulged to untrusted code. * @param key the key used to lookup the value * @return a value previously stored using putThreadLocal. */ public final Object getThreadLocal(Object key) { if (threadLocalMap == null) return null; return threadLocalMap.get(key); } /** * Put a value that can later be retrieved using a given key. *

* @param key the key used to index the value * @param value the value to save */ public synchronized final void putThreadLocal(Object key, Object value) { if (sealed) onSealedMutation(); if (threadLocalMap == null) threadLocalMap = new HashMap(); threadLocalMap.put(key, value); } /** * Remove values from thread-local storage. * @param key the key for the entry to remove. * @since 1.5 release 2 */ public final void removeThreadLocal(Object key) { if (sealed) onSealedMutation(); if (threadLocalMap == null) return; threadLocalMap.remove(key); } /** * @deprecated * @see ClassCache#get(Scriptable) * @see ClassCache#setCachingEnabled(boolean) */ public static void setCachingEnabled(boolean cachingEnabled) { } /** * Set a WrapFactory for this Context. *

* The WrapFactory allows custom object wrapping behavior for * Java object manipulated with JavaScript. * @see WrapFactory * @since 1.5 Release 4 */ public final void setWrapFactory(WrapFactory wrapFactory) { if (sealed) onSealedMutation(); if (wrapFactory == null) throw new IllegalArgumentException(); this.wrapFactory = wrapFactory; } /** * Return the current WrapFactory, or null if none is defined. * @see WrapFactory * @since 1.5 Release 4 */ public final WrapFactory getWrapFactory() { if (wrapFactory == null) { wrapFactory = new WrapFactory(); } return wrapFactory; } /** * Return the current debugger. * @return the debugger, or null if none is attached. */ public final Debugger getDebugger() { return debugger; } /** * Return the debugger context data associated with current context. * @return the debugger data, or null if debugger is not attached */ public final Object getDebuggerContextData() { return debuggerData; } /** * Set the associated debugger. * @param debugger the debugger to be used on callbacks from * the engine. * @param contextData arbitrary object that debugger can use to store * per Context data. */ public final void setDebugger(Debugger debugger, Object contextData) { if (sealed) onSealedMutation(); this.debugger = debugger; debuggerData = contextData; } /** * Return DebuggableScript instance if any associated with the script. * If callable supports DebuggableScript implementation, the method * returns it. Otherwise null is returned. */ public static DebuggableScript getDebuggableView(Script script) { if (script instanceof NativeFunction) { return ((NativeFunction)script).getDebuggableView(); } return null; } /** * Controls certain aspects of script semantics. * Should be overwritten to alter default behavior. *

* The default implementation calls * {@link ContextFactory#hasFeature(Context cx, int featureIndex)} * that allows to customize Context behavior without introducing * Context subclasses. {@link ContextFactory} documentation gives * an example of hasFeature implementation. * * @param featureIndex feature index to check * @return true if the featureIndex feature is turned on * @see #FEATURE_NON_ECMA_GET_YEAR * @see #FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME * @see #FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER * @see #FEATURE_TO_STRING_AS_SOURCE * @see #FEATURE_PARENT_PROTO_PROPRTIES * @see #FEATURE_E4X * @see #FEATURE_DYNAMIC_SCOPE * @see #FEATURE_STRICT_VARS * @see #FEATURE_STRICT_EVAL * @see #FEATURE_LOCATION_INFORMATION_IN_ERROR * @see #FEATURE_STRICT_MODE * @see #FEATURE_WARNING_AS_ERROR * @see #FEATURE_ENHANCED_JAVA_ACCESS */ public boolean hasFeature(int featureIndex) { ContextFactory f = getFactory(); return f.hasFeature(this, featureIndex); } /** * Returns an object which specifies an E4X implementation to use within * this Context. Note that the XMLLib.Factory interface should * be considered experimental. * * The default implementation uses the implementation provided by this * Context's {@link ContextFactory}. * * @return An XMLLib.Factory. Should not return null if * {@link #FEATURE_E4X} is enabled. See {@link #hasFeature}. */ public XMLLib.Factory getE4xImplementationFactory() { return getFactory().getE4xImplementationFactory(); } /** * Get threshold of executed instructions counter that triggers call to * observeInstructionCount(). * When the threshold is zero, instruction counting is disabled, * otherwise each time the run-time executes at least the threshold value * of script instructions, observeInstructionCount() will * be called. */ public final int getInstructionObserverThreshold() { return instructionThreshold; } /** * Set threshold of executed instructions counter that triggers call to * observeInstructionCount(). * When the threshold is zero, instruction counting is disabled, * otherwise each time the run-time executes at least the threshold value * of script instructions, observeInstructionCount() will * be called.

* Note that the meaning of "instruction" is not guaranteed to be * consistent between compiled and interpretive modes: executing a given * script or function in the different modes will result in different * instruction counts against the threshold. * {@link #setGenerateObserverCount} is called with true if * threshold is greater than zero, false otherwise. * @param threshold The instruction threshold */ public final void setInstructionObserverThreshold(int threshold) { if (sealed) onSealedMutation(); if (threshold < 0) throw new IllegalArgumentException(); instructionThreshold = threshold; setGenerateObserverCount(threshold > 0); } /** * Turn on or off generation of code with callbacks to * track the count of executed instructions. * Currently only affects JVM byte code generation: this slows down the * generated code, but code generated without the callbacks will not * be counted toward instruction thresholds. Rhino's interpretive * mode does instruction counting without inserting callbacks, so * there is no requirement to compile code differently. * @param generateObserverCount if true, generated code will contain * calls to accumulate an estimate of the instructions executed. */ public void setGenerateObserverCount(boolean generateObserverCount) { this.generateObserverCount = generateObserverCount; } /** * Allow application to monitor counter of executed script instructions * in Context subclasses. * Run-time calls this when instruction counting is enabled and the counter * reaches limit set by setInstructionObserverThreshold(). * The method is useful to observe long running scripts and if necessary * to terminate them. *

* The default implementation calls * {@link ContextFactory#observeInstructionCount(Context cx, * int instructionCount)} * that allows to customize Context behavior without introducing * Context subclasses. * * @param instructionCount amount of script instruction executed since * last call to observeInstructionCount * @throws Error to terminate the script * @see #setOptimizationLevel(int) */ protected void observeInstructionCount(int instructionCount) { ContextFactory f = getFactory(); f.observeInstructionCount(this, instructionCount); } /** * Create class loader for generated classes. * The method calls {@link ContextFactory#createClassLoader(ClassLoader)} * using the result of {@link #getFactory()}. */ public GeneratedClassLoader createClassLoader(ClassLoader parent) { ContextFactory f = getFactory(); return f.createClassLoader(parent); } public final ClassLoader getApplicationClassLoader() { if (applicationClassLoader == null) { ContextFactory f = getFactory(); ClassLoader loader = f.getApplicationClassLoader(); if (loader == null) { ClassLoader threadLoader = VMBridge.instance.getCurrentThreadClassLoader(); if (threadLoader != null && Kit.testIfCanLoadRhinoClasses(threadLoader)) { // Thread.getContextClassLoader is not cached since // its caching prevents it from GC which may lead to // a memory leak and hides updates to // Thread.getContextClassLoader return threadLoader; } // Thread.getContextClassLoader can not load Rhino classes, // try to use the loader of ContextFactory or Context // subclasses. Class fClass = f.getClass(); if (fClass != ScriptRuntime.ContextFactoryClass) { loader = fClass.getClassLoader(); } else { loader = getClass().getClassLoader(); } } applicationClassLoader = loader; } return applicationClassLoader; } public final void setApplicationClassLoader(ClassLoader loader) { if (sealed) onSealedMutation(); if (loader == null) { // restore default behaviour applicationClassLoader = null; return; } if (!Kit.testIfCanLoadRhinoClasses(loader)) { throw new IllegalArgumentException( "Loader can not resolve Rhino classes"); } applicationClassLoader = loader; } /********** end of API **********/ /** * Internal method that reports an error for missing calls to * enter(). */ static Context getContext() { Context cx = getCurrentContext(); if (cx == null) { throw new RuntimeException( "No Context associated with current Thread"); } return cx; } private Object compileImpl(Scriptable scope, Reader sourceReader, String sourceString, String sourceName, int lineno, Object securityDomain, boolean returnFunction, Evaluator compiler, ErrorReporter compilationErrorReporter) throws IOException { if(sourceName == null) { sourceName = "unnamed script"; } if (securityDomain != null && getSecurityController() == null) { throw new IllegalArgumentException( "securityDomain should be null if setSecurityController() was never called"); } // One of sourceReader or sourceString has to be null if (!(sourceReader == null ^ sourceString == null)) Kit.codeBug(); // scope should be given if and only if compiling function if (!(scope == null ^ returnFunction)) Kit.codeBug(); CompilerEnvirons compilerEnv = new CompilerEnvirons(); compilerEnv.initFromContext(this); if (compilationErrorReporter == null) { compilationErrorReporter = compilerEnv.getErrorReporter(); } if (debugger != null) { if (sourceReader != null) { sourceString = Kit.readReader(sourceReader); sourceReader = null; } } Parser p = new Parser(compilerEnv, compilationErrorReporter); if (returnFunction) { p.calledByCompileFunction = true; } AstRoot ast; if (sourceString != null) { ast = p.parse(sourceString, sourceName, lineno); } else { ast = p.parse(sourceReader, sourceName, lineno); } if (returnFunction) { // parser no longer adds function to script node if (!(ast.getFirstChild() != null && ast.getFirstChild().getType() == Token.FUNCTION)) { // XXX: the check just looks for the first child // and allows for more nodes after it for compatibility // with sources like function() {};;; throw new IllegalArgumentException( "compileFunction only accepts source with single JS function: "+sourceString); } } IRFactory irf = new IRFactory(compilerEnv, compilationErrorReporter); ScriptNode tree = irf.transformTree(ast); // discard everything but the IR tree p = null; ast = null; irf = null; if (compiler == null) { compiler = createCompiler(); } Object bytecode = compiler.compile(compilerEnv, tree, tree.getEncodedSource(), returnFunction); if (debugger != null) { if (sourceString == null) Kit.codeBug(); if (bytecode instanceof DebuggableScript) { DebuggableScript dscript = (DebuggableScript)bytecode; notifyDebugger_r(this, dscript, sourceString); } else { throw new RuntimeException("NOT SUPPORTED"); } } Object result; if (returnFunction) { result = compiler.createFunctionObject(this, scope, bytecode, securityDomain); } else { result = compiler.createScriptObject(bytecode, securityDomain); } return result; } private static void notifyDebugger_r(Context cx, DebuggableScript dscript, String debugSource) { cx.debugger.handleCompilationDone(cx, dscript, debugSource); for (int i = 0; i != dscript.getFunctionCount(); ++i) { notifyDebugger_r(cx, dscript.getFunction(i), debugSource); } } private static Class codegenClass = Kit.classOrNull( "org.mozilla.javascript.optimizer.Codegen"); private static Class interpreterClass = Kit.classOrNull( "org.mozilla.javascript.Interpreter"); private Evaluator createCompiler() { Evaluator result = null; if (optimizationLevel >= 0 && codegenClass != null) { result = (Evaluator)Kit.newInstanceOrNull(codegenClass); } if (result == null) { result = createInterpreter(); } return result; } static Evaluator createInterpreter() { return (Evaluator)Kit.newInstanceOrNull(interpreterClass); } static String getSourcePositionFromStack(int[] linep) { Context cx = getCurrentContext(); if (cx == null) return null; if (cx.lastInterpreterFrame != null) { Evaluator evaluator = createInterpreter(); if (evaluator != null) return evaluator.getSourcePositionFromStack(cx, linep); } /** * A bit of a hack, but the only way to get filename and line * number from an enclosing frame. */ CharArrayWriter writer = new CharArrayWriter(); RuntimeException re = new RuntimeException(); re.printStackTrace(new PrintWriter(writer)); String s = writer.toString(); int open = -1; int close = -1; int colon = -1; for (int i=0; i < s.length(); i++) { char c = s.charAt(i); if (c == ':') colon = i; else if (c == '(') open = i; else if (c == ')') close = i; else if (c == '\n' && open != -1 && close != -1 && colon != -1 && open < colon && colon < close) { String fileStr = s.substring(open + 1, colon); if (!fileStr.endsWith(".java")) { String lineStr = s.substring(colon + 1, close); try { linep[0] = Integer.parseInt(lineStr); if (linep[0] < 0) { linep[0] = 0; } return fileStr; } catch (NumberFormatException e) { // fall through } } open = close = colon = -1; } } return null; } RegExpProxy getRegExpProxy() { if (regExpProxy == null) { Class cl = Kit.classOrNull( "org.mozilla.javascript.regexp.RegExpImpl"); if (cl != null) { regExpProxy = (RegExpProxy)Kit.newInstanceOrNull(cl); } } return regExpProxy; } final boolean isVersionECMA1() { return version == VERSION_DEFAULT || version >= VERSION_1_3; } // The method must NOT be public or protected SecurityController getSecurityController() { SecurityController global = SecurityController.global(); if (global != null) { return global; } return securityController; } public final boolean isGeneratingDebugChanged() { return generatingDebugChanged; } /** * Add a name to the list of names forcing the creation of real * activation objects for functions. * * @param name the name of the object to add to the list */ public void addActivationName(String name) { if (sealed) onSealedMutation(); if (activationNames == null) activationNames = new HashSet(); activationNames.add(name); } /** * Check whether the name is in the list of names of objects * forcing the creation of activation objects. * * @param name the name of the object to test * * @return true if an function activation object is needed. */ public final boolean isActivationNeeded(String name) { return activationNames != null && activationNames.contains(name); } /** * Remove a name from the list of names forcing the creation of real * activation objects for functions. * * @param name the name of the object to remove from the list */ public void removeActivationName(String name) { if (sealed) onSealedMutation(); if (activationNames != null) activationNames.remove(name); } private static String implementationVersion; private final ContextFactory factory; private boolean sealed; private Object sealKey; Scriptable topCallScope; boolean isContinuationsTopCall; NativeCall currentActivationCall; XMLLib cachedXMLLib; // for Objects, Arrays to tag themselves as being printed out, // so they don't print themselves out recursively. // Use ObjToIntMap instead of java.util.HashSet for JDK 1.1 compatibility ObjToIntMap iterating; Object interpreterSecurityDomain; int version; private SecurityController securityController; private boolean hasClassShutter; private ClassShutter classShutter; private ErrorReporter errorReporter; RegExpProxy regExpProxy; private Locale locale; private boolean generatingDebug; private boolean generatingDebugChanged; private boolean generatingSource=true; boolean useDynamicScope; private int optimizationLevel; private int maximumInterpreterStackDepth; private WrapFactory wrapFactory; Debugger debugger; private Object debuggerData; private int enterCount; private Object propertyListeners; private Map threadLocalMap; private ClassLoader applicationClassLoader; /** * This is the list of names of objects forcing the creation of * function activation records. */ Set activationNames; // For the interpreter to store the last frame for error reports etc. Object lastInterpreterFrame; // For the interpreter to store information about previous invocations // interpreter invocations ObjArray previousInterpreterInvocations; // For instruction counting (interpreter only) int instructionCount; int instructionThreshold; // It can be used to return the second index-like result from function int scratchIndex; // It can be used to return the second uint32 result from function long scratchUint32; // It can be used to return the second Scriptable result from function Scriptable scratchScriptable; // Generate an observer count on compiled code public boolean generateObserverCount = false; } rhino-1.7R4/src/org/mozilla/javascript/ContextAction.java000066400000000000000000000014441176760007500235420ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * Interface to represent arbitrary action that requires to have Context * object associated with the current thread for its execution. */ public interface ContextAction { /** * Execute action using the supplied Context instance. * When Rhino runtime calls the method, cx will be associated * with the current thread as active context. * * @see ContextFactory#call(ContextAction) */ public Object run(Context cx); } rhino-1.7R4/src/org/mozilla/javascript/ContextFactory.java000066400000000000000000000464751176760007500237510ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; import java.security.AccessController; import java.security.PrivilegedAction; /** * Factory class that Rhino runtime uses to create new {@link Context} * instances. A ContextFactory can also notify listeners * about context creation and release. *

* When the Rhino runtime needs to create new {@link Context} instance during * execution of {@link Context#enter()} or {@link Context}, it will call * {@link #makeContext()} of the current global ContextFactory. * See {@link #getGlobal()} and {@link #initGlobal(ContextFactory)}. *

* It is also possible to use explicit ContextFactory instances for Context * creation. This is useful to have a set of independent Rhino runtime * instances under single JVM. See {@link #call(ContextAction)}. *

* The following example demonstrates Context customization to terminate * scripts running more then 10 seconds and to provide better compatibility * with JavaScript code using MSIE-specific features. *

 * import org.mozilla.javascript.*;
 *
 * class MyFactory extends ContextFactory
 * {
 *
 *     // Custom {@link Context} to store execution time.
 *     private static class MyContext extends Context
 *     {
 *         long startTime;
 *     }
 *
 *     static {
 *         // Initialize GlobalFactory with custom factory
 *         ContextFactory.initGlobal(new MyFactory());
 *     }
 *
 *     // Override {@link #makeContext()}
 *     protected Context makeContext()
 *     {
 *         MyContext cx = new MyContext();
 *         // Make Rhino runtime to call observeInstructionCount
 *         // each 10000 bytecode instructions
 *         cx.setInstructionObserverThreshold(10000);
 *         return cx;
 *     }
 *
 *     // Override {@link #hasFeature(Context, int)}
 *     public boolean hasFeature(Context cx, int featureIndex)
 *     {
 *         // Turn on maximum compatibility with MSIE scripts
 *         switch (featureIndex) {
 *             case {@link Context#FEATURE_NON_ECMA_GET_YEAR}:
 *                 return true;
 *
 *             case {@link Context#FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME}:
 *                 return true;
 *
 *             case {@link Context#FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER}:
 *                 return true;
 *
 *             case {@link Context#FEATURE_PARENT_PROTO_PROPERTIES}:
 *                 return false;
 *         }
 *         return super.hasFeature(cx, featureIndex);
 *     }
 *
 *     // Override {@link #observeInstructionCount(Context, int)}
 *     protected void observeInstructionCount(Context cx, int instructionCount)
 *     {
 *         MyContext mcx = (MyContext)cx;
 *         long currentTime = System.currentTimeMillis();
 *         if (currentTime - mcx.startTime > 10*1000) {
 *             // More then 10 seconds from Context creation time:
 *             // it is time to stop the script.
 *             // Throw Error instance to ensure that script will never
 *             // get control back through catch or finally.
 *             throw new Error();
 *         }
 *     }
 *
 *     // Override {@link #doTopCall(Callable,
                               Context, Scriptable,
                               Scriptable, Object[])}
 *     protected Object doTopCall(Callable callable,
 *                                Context cx, Scriptable scope,
 *                                Scriptable thisObj, Object[] args)
 *     {
 *         MyContext mcx = (MyContext)cx;
 *         mcx.startTime = System.currentTimeMillis();
 *
 *         return super.doTopCall(callable, cx, scope, thisObj, args);
 *     }
 *
 * }
 *
 * 
*/ public class ContextFactory { private static volatile boolean hasCustomGlobal; private static ContextFactory global = new ContextFactory(); private volatile boolean sealed; private final Object listenersLock = new Object(); private volatile Object listeners; private boolean disabledListening; private ClassLoader applicationClassLoader; /** * Listener of {@link Context} creation and release events. */ public interface Listener { /** * Notify about newly created {@link Context} object. */ public void contextCreated(Context cx); /** * Notify that the specified {@link Context} instance is no longer * associated with the current thread. */ public void contextReleased(Context cx); } /** * Get global ContextFactory. * * @see #hasExplicitGlobal() * @see #initGlobal(ContextFactory) */ public static ContextFactory getGlobal() { return global; } /** * Check if global factory was set. * Return true to indicate that {@link #initGlobal(ContextFactory)} was * already called and false to indicate that the global factory was not * explicitly set. * * @see #getGlobal() * @see #initGlobal(ContextFactory) */ public static boolean hasExplicitGlobal() { return hasCustomGlobal; } /** * Set global ContextFactory. * The method can only be called once. * * @see #getGlobal() * @see #hasExplicitGlobal() */ public synchronized static void initGlobal(ContextFactory factory) { if (factory == null) { throw new IllegalArgumentException(); } if (hasCustomGlobal) { throw new IllegalStateException(); } hasCustomGlobal = true; global = factory; } public interface GlobalSetter { public void setContextFactoryGlobal(ContextFactory factory); public ContextFactory getContextFactoryGlobal(); } public synchronized static GlobalSetter getGlobalSetter() { if (hasCustomGlobal) { throw new IllegalStateException(); } hasCustomGlobal = true; class GlobalSetterImpl implements GlobalSetter { public void setContextFactoryGlobal(ContextFactory factory) { global = factory == null ? new ContextFactory() : factory; } public ContextFactory getContextFactoryGlobal() { return global; } } return new GlobalSetterImpl(); } /** * Create new {@link Context} instance to be associated with the current * thread. * This is a callback method used by Rhino to create {@link Context} * instance when it is necessary to associate one with the current * execution thread. makeContext() is allowed to call * {@link Context#seal(Object)} on the result to prevent * {@link Context} changes by hostile scripts or applets. */ protected Context makeContext() { return new Context(this); } /** * Implementation of {@link Context#hasFeature(int featureIndex)}. * This can be used to customize {@link Context} without introducing * additional subclasses. */ protected boolean hasFeature(Context cx, int featureIndex) { int version; switch (featureIndex) { case Context.FEATURE_NON_ECMA_GET_YEAR: /* * During the great date rewrite of 1.3, we tried to track the * evolving ECMA standard, which then had a definition of * getYear which always subtracted 1900. Which we * implemented, not realizing that it was incompatible with * the old behavior... now, rather than thrash the behavior * yet again, we've decided to leave it with the - 1900 * behavior and point people to the getFullYear method. But * we try to protect existing scripts that have specified a * version... */ version = cx.getLanguageVersion(); return (version == Context.VERSION_1_0 || version == Context.VERSION_1_1 || version == Context.VERSION_1_2); case Context.FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME: return false; case Context.FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER: return true; case Context.FEATURE_TO_STRING_AS_SOURCE: version = cx.getLanguageVersion(); return version == Context.VERSION_1_2; case Context.FEATURE_PARENT_PROTO_PROPERTIES: return true; case Context.FEATURE_E4X: version = cx.getLanguageVersion(); return (version == Context.VERSION_DEFAULT || version >= Context.VERSION_1_6); case Context.FEATURE_DYNAMIC_SCOPE: return false; case Context.FEATURE_STRICT_VARS: return false; case Context.FEATURE_STRICT_EVAL: return false; case Context.FEATURE_LOCATION_INFORMATION_IN_ERROR: return false; case Context.FEATURE_STRICT_MODE: return false; case Context.FEATURE_WARNING_AS_ERROR: return false; case Context.FEATURE_ENHANCED_JAVA_ACCESS: return false; } // It is a bug to call the method with unknown featureIndex throw new IllegalArgumentException(String.valueOf(featureIndex)); } private boolean isDom3Present() { Class nodeClass = Kit.classOrNull("org.w3c.dom.Node"); if (nodeClass == null) return false; // Check to see whether DOM3 is present; use a new method defined in // DOM3 that is vital to our implementation try { nodeClass.getMethod("getUserData", new Class[] { String.class }); return true; } catch (NoSuchMethodException e) { return false; } } /** * Provides a default * {@link org.mozilla.javascript.xml.XMLLib.Factory XMLLib.Factory} * to be used by the Context instances produced by this * factory. See {@link Context#getE4xImplementationFactory} for details. * * May return null, in which case E4X functionality is not supported in * Rhino. * * The default implementation now prefers the DOM3 E4X implementation. */ protected org.mozilla.javascript.xml.XMLLib.Factory getE4xImplementationFactory() { // Must provide default implementation, rather than abstract method, // so that past implementors of ContextFactory do not fail at runtime // upon invocation of this method. // Note that the default implementation returns null if we // neither have XMLBeans nor a DOM3 implementation present. if (isDom3Present()) { return org.mozilla.javascript.xml.XMLLib.Factory.create( "org.mozilla.javascript.xmlimpl.XMLLibImpl" ); } else if (Kit.classOrNull("org.apache.xmlbeans.XmlCursor") != null) { return org.mozilla.javascript.xml.XMLLib.Factory.create( "org.mozilla.javascript.xml.impl.xmlbeans.XMLLibImpl" ); } else { return null; } } /** * Create class loader for generated classes. * This method creates an instance of the default implementation * of {@link GeneratedClassLoader}. Rhino uses this interface to load * generated JVM classes when no {@link SecurityController} * is installed. * Application can override the method to provide custom class loading. */ protected GeneratedClassLoader createClassLoader(final ClassLoader parent) { return AccessController.doPrivileged(new PrivilegedAction() { public DefiningClassLoader run(){ return new DefiningClassLoader(parent); } }); } /** * Get ClassLoader to use when searching for Java classes. * Unless it was explicitly initialized with * {@link #initApplicationClassLoader(ClassLoader)} the method returns * null to indicate that Thread.getContextClassLoader() should be used. */ public final ClassLoader getApplicationClassLoader() { return applicationClassLoader; } /** * Set explicit class loader to use when searching for Java classes. * * @see #getApplicationClassLoader() */ public final void initApplicationClassLoader(ClassLoader loader) { if (loader == null) throw new IllegalArgumentException("loader is null"); if (!Kit.testIfCanLoadRhinoClasses(loader)) throw new IllegalArgumentException( "Loader can not resolve Rhino classes"); if (this.applicationClassLoader != null) throw new IllegalStateException( "applicationClassLoader can only be set once"); checkNotSealed(); this.applicationClassLoader = loader; } /** * Execute top call to script or function. * When the runtime is about to execute a script or function that will * create the first stack frame with scriptable code, it calls this method * to perform the real call. In this way execution of any script * happens inside this function. */ protected Object doTopCall(Callable callable, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { Object result = callable.call(cx, scope, thisObj, args); return result instanceof ConsString ? result.toString() : result; } /** * Implementation of * {@link Context#observeInstructionCount(int instructionCount)}. * This can be used to customize {@link Context} without introducing * additional subclasses. */ protected void observeInstructionCount(Context cx, int instructionCount) { } protected void onContextCreated(Context cx) { Object listeners = this.listeners; for (int i = 0; ; ++i) { Listener l = (Listener)Kit.getListener(listeners, i); if (l == null) break; l.contextCreated(cx); } } protected void onContextReleased(Context cx) { Object listeners = this.listeners; for (int i = 0; ; ++i) { Listener l = (Listener)Kit.getListener(listeners, i); if (l == null) break; l.contextReleased(cx); } } public final void addListener(Listener listener) { checkNotSealed(); synchronized (listenersLock) { if (disabledListening) { throw new IllegalStateException(); } listeners = Kit.addListener(listeners, listener); } } public final void removeListener(Listener listener) { checkNotSealed(); synchronized (listenersLock) { if (disabledListening) { throw new IllegalStateException(); } listeners = Kit.removeListener(listeners, listener); } } /** * The method is used only to implement * Context.disableStaticContextListening() */ final void disableContextListening() { checkNotSealed(); synchronized (listenersLock) { disabledListening = true; listeners = null; } } /** * Checks if this is a sealed ContextFactory. * @see #seal() */ public final boolean isSealed() { return sealed; } /** * Seal this ContextFactory so any attempt to modify it like to add or * remove its listeners will throw an exception. * @see #isSealed() */ public final void seal() { checkNotSealed(); sealed = true; } protected final void checkNotSealed() { if (sealed) throw new IllegalStateException(); } /** * Call {@link ContextAction#run(Context cx)} * using the {@link Context} instance associated with the current thread. * If no Context is associated with the thread, then * {@link #makeContext()} will be called to construct * new Context instance. The instance will be temporary associated * with the thread during call to {@link ContextAction#run(Context)}. * * @see ContextFactory#call(ContextAction) * @see Context#call(ContextFactory factory, Callable callable, * Scriptable scope, Scriptable thisObj, * Object[] args) */ public final Object call(ContextAction action) { return Context.call(this, action); } /** * Get a context associated with the current thread, creating one if need * be. The Context stores the execution state of the JavaScript engine, so * it is required that the context be entered before execution may begin. * Once a thread has entered a Context, then getCurrentContext() may be * called to find the context that is associated with the current thread. *

* Calling enterContext() will return either the Context * currently associated with the thread, or will create a new context and * associate it with the current thread. Each call to * enterContext() must have a matching call to * {@link Context#exit()}. *

     *      Context cx = contextFactory.enterContext();
     *      try {
     *          ...
     *          cx.evaluateString(...);
     *      } finally {
     *          Context.exit();
     *      }
     * 
* Instead of using enterContext(), exit() pair consider * using {@link #call(ContextAction)} which guarantees proper association * of Context instances with the current thread. * With this method the above example becomes: *
     *      ContextFactory.call(new ContextAction() {
     *          public Object run(Context cx) {
     *              ...
     *              cx.evaluateString(...);
     *              return null;
     *          }
     *      });
     * 
* @return a Context associated with the current thread * @see Context#getCurrentContext() * @see Context#exit() * @see #call(ContextAction) */ public Context enterContext() { return enterContext(null); } /** * @deprecated use {@link #enterContext()} instead * @return a Context associated with the current thread */ public final Context enter() { return enterContext(null); } /** * @deprecated Use {@link Context#exit()} instead. */ public final void exit() { Context.exit(); } /** * Get a Context associated with the current thread, using the given * Context if need be. *

* The same as enterContext() except that cx * is associated with the current thread and returned if the current thread * has no associated context and cx is not associated with any * other thread. * @param cx a Context to associate with the thread if possible * @return a Context associated with the current thread * @see #enterContext() * @see #call(ContextAction) * @throws IllegalStateException if cx is already associated * with a different thread */ public final Context enterContext(Context cx) { return Context.enter(cx, this); } }rhino-1.7R4/src/org/mozilla/javascript/ContextListener.java000066400000000000000000000014271176760007500241130ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * @deprecated Embeddings that wish to customize newly created * {@link Context} instances should implement * {@link ContextFactory.Listener}. */ public interface ContextListener extends ContextFactory.Listener { /** * @deprecated Rhino runtime never calls the method. */ public void contextEntered(Context cx); /** * @deprecated Rhino runtime never calls the method. */ public void contextExited(Context cx); } rhino-1.7R4/src/org/mozilla/javascript/ContinuationPending.java000066400000000000000000000050031176760007500247320ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * Exception thrown by * {@link org.mozilla.javascript.Context#executeScriptWithContinuations(Script, Scriptable)} * and {@link org.mozilla.javascript.Context#callFunctionWithContinuations(Callable, Scriptable, Object[])} * when execution encounters a continuation captured by * {@link org.mozilla.javascript.Context#captureContinuation()}. * Exception will contain the captured state needed to restart the continuation * with {@link org.mozilla.javascript.Context#resumeContinuation(Object, Scriptable, Object)}. * @author Norris Boyd */ public class ContinuationPending extends RuntimeException { private static final long serialVersionUID = 4956008116771118856L; private NativeContinuation continuationState; private Object applicationState; /** * Construct a ContinuationPending exception. Internal call only; * users of the API should get continuations created on their behalf by * calling {@link org.mozilla.javascript.Context#executeScriptWithContinuations(Script, Scriptable)} * and {@link org.mozilla.javascript.Context#callFunctionWithContinuations(Callable, Scriptable, Object[])} * @param continuationState Internal Continuation object */ ContinuationPending(NativeContinuation continuationState) { this.continuationState = continuationState; } /** * Get continuation object. The only * use for this object is to be passed to * {@link org.mozilla.javascript.Context#resumeContinuation(Object, Scriptable, Object)}. * @return continuation object */ public Object getContinuation() { return continuationState; } /** * @return internal continuation state */ NativeContinuation getContinuationState() { return continuationState; } /** * Store an arbitrary object that applications can use to associate * their state with the continuation. * @param applicationState arbitrary application state */ public void setApplicationState(Object applicationState) { this.applicationState = applicationState; } /** * @return arbitrary application state */ public Object getApplicationState() { return applicationState; } } rhino-1.7R4/src/org/mozilla/javascript/DToA.java000066400000000000000000001277041176760007500215570ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /**************************************************************** * * The author of this software is David M. Gay. * * Copyright (c) 1991, 2000, 2001 by Lucent Technologies. * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. * ***************************************************************/ package org.mozilla.javascript; import java.math.BigInteger; class DToA { private static char BASEDIGIT(int digit) { return (char)((digit >= 10) ? 'a' - 10 + digit : '0' + digit); } static final int DTOSTR_STANDARD = 0, /* Either fixed or exponential format; round-trip */ DTOSTR_STANDARD_EXPONENTIAL = 1, /* Always exponential format; round-trip */ DTOSTR_FIXED = 2, /* Round to digits after the decimal point; exponential if number is large */ DTOSTR_EXPONENTIAL = 3, /* Always exponential format; significant digits */ DTOSTR_PRECISION = 4; /* Either fixed or exponential format; significant digits */ private static final int Frac_mask = 0xfffff; private static final int Exp_shift = 20; private static final int Exp_msk1 = 0x100000; private static final long Frac_maskL = 0xfffffffffffffL; private static final int Exp_shiftL = 52; private static final long Exp_msk1L = 0x10000000000000L; private static final int Bias = 1023; private static final int P = 53; private static final int Exp_shift1 = 20; private static final int Exp_mask = 0x7ff00000; private static final int Exp_mask_shifted = 0x7ff; private static final int Bndry_mask = 0xfffff; private static final int Log2P = 1; private static final int Sign_bit = 0x80000000; private static final int Exp_11 = 0x3ff00000; private static final int Ten_pmax = 22; private static final int Quick_max = 14; private static final int Bletch = 0x10; private static final int Frac_mask1 = 0xfffff; private static final int Int_max = 14; private static final int n_bigtens = 5; private static final double tens[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 }; private static final double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; private static int lo0bits(int y) { int k; int x = y; if ((x & 7) != 0) { if ((x & 1) != 0) return 0; if ((x & 2) != 0) { return 1; } return 2; } k = 0; if ((x & 0xffff) == 0) { k = 16; x >>>= 16; } if ((x & 0xff) == 0) { k += 8; x >>>= 8; } if ((x & 0xf) == 0) { k += 4; x >>>= 4; } if ((x & 0x3) == 0) { k += 2; x >>>= 2; } if ((x & 1) == 0) { k++; x >>>= 1; if ((x & 1) == 0) return 32; } return k; } /* Return the number (0 through 32) of most significant zero bits in x. */ private static int hi0bits(int x) { int k = 0; if ((x & 0xffff0000) == 0) { k = 16; x <<= 16; } if ((x & 0xff000000) == 0) { k += 8; x <<= 8; } if ((x & 0xf0000000) == 0) { k += 4; x <<= 4; } if ((x & 0xc0000000) == 0) { k += 2; x <<= 2; } if ((x & 0x80000000) == 0) { k++; if ((x & 0x40000000) == 0) return 32; } return k; } private static void stuffBits(byte bits[], int offset, int val) { bits[offset] = (byte)(val >> 24); bits[offset + 1] = (byte)(val >> 16); bits[offset + 2] = (byte)(val >> 8); bits[offset + 3] = (byte)(val); } /* Convert d into the form b*2^e, where b is an odd integer. b is the returned * Bigint and e is the returned binary exponent. Return the number of significant * bits in b in bits. d must be finite and nonzero. */ private static BigInteger d2b(double d, int[] e, int[] bits) { byte dbl_bits[]; int i, k, y, z, de; long dBits = Double.doubleToLongBits(d); int d0 = (int)(dBits >>> 32); int d1 = (int)(dBits); z = d0 & Frac_mask; d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ if ((de = (d0 >>> Exp_shift)) != 0) z |= Exp_msk1; if ((y = d1) != 0) { dbl_bits = new byte[8]; k = lo0bits(y); y >>>= k; if (k != 0) { stuffBits(dbl_bits, 4, y | z << (32 - k)); z >>= k; } else stuffBits(dbl_bits, 4, y); stuffBits(dbl_bits, 0, z); i = (z != 0) ? 2 : 1; } else { // JS_ASSERT(z); dbl_bits = new byte[4]; k = lo0bits(z); z >>>= k; stuffBits(dbl_bits, 0, z); k += 32; i = 1; } if (de != 0) { e[0] = de - Bias - (P-1) + k; bits[0] = P - k; } else { e[0] = de - Bias - (P-1) + 1 + k; bits[0] = 32*i - hi0bits(z); } return new BigInteger(dbl_bits); } static String JS_dtobasestr(int base, double d) { if (!(2 <= base && base <= 36)) throw new IllegalArgumentException("Bad base: "+base); /* Check for Infinity and NaN */ if (Double.isNaN(d)) { return "NaN"; } else if (Double.isInfinite(d)) { return (d > 0.0) ? "Infinity" : "-Infinity"; } else if (d == 0) { // ALERT: should it distinguish -0.0 from +0.0 ? return "0"; } boolean negative; if (d >= 0.0) { negative = false; } else { negative = true; d = -d; } /* Get the integer part of d including '-' sign. */ String intDigits; double dfloor = Math.floor(d); long lfloor = (long)dfloor; if (lfloor == dfloor) { // int part fits long intDigits = Long.toString((negative) ? -lfloor : lfloor, base); } else { // BigInteger should be used long floorBits = Double.doubleToLongBits(dfloor); int exp = (int)(floorBits >> Exp_shiftL) & Exp_mask_shifted; long mantissa; if (exp == 0) { mantissa = (floorBits & Frac_maskL) << 1; } else { mantissa = (floorBits & Frac_maskL) | Exp_msk1L; } if (negative) { mantissa = -mantissa; } exp -= 1075; BigInteger x = BigInteger.valueOf(mantissa); if (exp > 0) { x = x.shiftLeft(exp); } else if (exp < 0) { x = x.shiftRight(-exp); } intDigits = x.toString(base); } if (d == dfloor) { // No fraction part return intDigits; } else { /* We have a fraction. */ StringBuilder buffer; /* The output string */ int digit; double df; /* The fractional part of d */ BigInteger b; buffer = new StringBuilder(); buffer.append(intDigits).append('.'); df = d - dfloor; long dBits = Double.doubleToLongBits(d); int word0 = (int)(dBits >> 32); int word1 = (int)(dBits); int[] e = new int[1]; int[] bbits = new int[1]; b = d2b(df, e, bbits); // JS_ASSERT(e < 0); /* At this point df = b * 2^e. e must be less than zero because 0 < df < 1. */ int s2 = -(word0 >>> Exp_shift1 & Exp_mask >> Exp_shift1); if (s2 == 0) s2 = -1; s2 += Bias + P; /* 1/2^s2 = (nextDouble(d) - d)/2 */ // JS_ASSERT(-s2 < e); BigInteger mlo = BigInteger.valueOf(1); BigInteger mhi = mlo; if ((word1 == 0) && ((word0 & Bndry_mask) == 0) && ((word0 & (Exp_mask & Exp_mask << 1)) != 0)) { /* The special case. Here we want to be within a quarter of the last input significant digit instead of one half of it when the output string's value is less than d. */ s2 += Log2P; mhi = BigInteger.valueOf(1< df = b/2^s2 > 0; * (d - prevDouble(d))/2 = mlo/2^s2; * (nextDouble(d) - d)/2 = mhi/2^s2. */ BigInteger bigBase = BigInteger.valueOf(base); boolean done = false; do { b = b.multiply(bigBase); BigInteger[] divResult = b.divideAndRemainder(s); b = divResult[1]; digit = (char)(divResult[0].intValue()); if (mlo == mhi) mlo = mhi = mlo.multiply(bigBase); else { mlo = mlo.multiply(bigBase); mhi = mhi.multiply(bigBase); } /* Do we yet have the shortest string that will round to d? */ int j = b.compareTo(mlo); /* j is b/2^s2 compared with mlo/2^s2. */ BigInteger delta = s.subtract(mhi); int j1 = (delta.signum() <= 0) ? 1 : b.compareTo(delta); /* j1 is b/2^s2 compared with 1 - mhi/2^s2. */ if (j1 == 0 && ((word1 & 1) == 0)) { if (j > 0) digit++; done = true; } else if (j < 0 || (j == 0 && ((word1 & 1) == 0))) { if (j1 > 0) { /* Either dig or dig+1 would work here as the least significant digit. Use whichever would produce an output value closer to d. */ b = b.shiftLeft(1); j1 = b.compareTo(s); if (j1 > 0) /* The even test (|| (j1 == 0 && (digit & 1))) is not here because it messes up odd base output * such as 3.5 in base 3. */ digit++; } done = true; } else if (j1 > 0) { digit++; done = true; } // JS_ASSERT(digit < (uint32)base); buffer.append(BASEDIGIT(digit)); } while (!done); return buffer.toString(); } } /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. * * Inspired by "How to Print Floating-Point Numbers Accurately" by * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. * * Modifications: * 1. Rather than iterating, we use a simple numeric overestimate * to determine k = floor(log10(d)). We scale relevant * quantities using O(log2(k)) rather than O(k) multiplications. * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't * try to generate digits strictly left to right. Instead, we * compute with fewer bits and propagate the carry if necessary * when rounding the final digit up. This is often faster. * 3. Under the assumption that input will be rounded nearest, * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. * That is, we allow equality in stopping tests when the * round-nearest rule will give the same floating-point value * as would satisfaction of the stopping test with strict * inequality. * 4. We remove common factors of powers of 2 from relevant * quantities. * 5. When converting floating-point integers less than 1e16, * we use floating-point arithmetic rather than resorting * to multiple-precision integers. * 6. When asked to produce fewer than 15 digits, we first try * to get by with floating-point arithmetic; we resort to * multiple-precision integer arithmetic only if we cannot * guarantee that the floating-point calculation has given * the correctly rounded result. For k requested digits and * "uniformly" distributed input, the probability is * something like 10^(k-15) that we must resort to the Long * calculation. */ static int word0(double d) { long dBits = Double.doubleToLongBits(d); return (int)(dBits >> 32); } static double setWord0(double d, int i) { long dBits = Double.doubleToLongBits(d); dBits = ((long)i << 32) | (dBits & 0x0FFFFFFFFL); return Double.longBitsToDouble(dBits); } static int word1(double d) { long dBits = Double.doubleToLongBits(d); return (int)(dBits); } /* Return b * 5^k. k must be nonnegative. */ // XXXX the C version built a cache of these static BigInteger pow5mult(BigInteger b, int k) { return b.multiply(BigInteger.valueOf(5).pow(k)); } static boolean roundOff(StringBuilder buf) { int i = buf.length(); while (i != 0) { --i; char c = buf.charAt(i); if (c != '9') { buf.setCharAt(i, (char)(c + 1)); buf.setLength(i + 1); return false; } } buf.setLength(0); return true; } /* Always emits at least one digit. */ /* If biasUp is set, then rounding in modes 2 and 3 will round away from zero * when the number is exactly halfway between two representable values. For example, * rounding 2.5 to zero digits after the decimal point will return 3 and not 2. * 2.49 will still round to 2, and 2.51 will still round to 3. */ /* bufsize should be at least 20 for modes 0 and 1. For the other modes, * bufsize should be two greater than the maximum number of output characters expected. */ static int JS_dtoa(double d, int mode, boolean biasUp, int ndigits, boolean[] sign, StringBuilder buf) { /* Arguments ndigits, decpt, sign are similar to those of ecvt and fcvt; trailing zeros are suppressed from the returned string. If not null, *rve is set to point to the end of the return value. If d is +-Infinity or NaN, then *decpt is set to 9999. mode: 0 ==> shortest string that yields d when read in and rounded to nearest. 1 ==> like 0, but with Steele & White stopping rule; e.g. with IEEE P754 arithmetic , mode 0 gives 1e23 whereas mode 1 gives 9.999999999999999e22. 2 ==> max(1,ndigits) significant digits. This gives a return value similar to that of ecvt, except that trailing zeros are suppressed. 3 ==> through ndigits past the decimal point. This gives a return value similar to that from fcvt, except that trailing zeros are suppressed, and ndigits can be negative. 4-9 should give the same return values as 2-3, i.e., 4 <= mode <= 9 ==> same return as mode 2 + (mode & 1). These modes are mainly for debugging; often they run slower but sometimes faster than modes 2-3. 4,5,8,9 ==> left-to-right digit generation. 6-9 ==> don't try fast floating-point estimate (if applicable). Values of mode other than 0-9 are treated as mode 0. Sufficient space is allocated to the return value to hold the suppressed trailing zeros. */ int b2, b5, i, ieps, ilim, ilim0, ilim1, j, j1, k, k0, m2, m5, s2, s5; char dig; long L; long x; BigInteger b, b1, delta, mlo, mhi, S; int[] be = new int[1]; int[] bbits = new int[1]; double d2, ds, eps; boolean spec_case, denorm, k_check, try_quick, leftright; if ((word0(d) & Sign_bit) != 0) { /* set sign for everything, including 0's and NaNs */ sign[0] = true; // word0(d) &= ~Sign_bit; /* clear sign bit */ d = setWord0(d, word0(d) & ~Sign_bit); } else sign[0] = false; if ((word0(d) & Exp_mask) == Exp_mask) { /* Infinity or NaN */ buf.append(((word1(d) == 0) && ((word0(d) & Frac_mask) == 0)) ? "Infinity" : "NaN"); return 9999; } if (d == 0) { // no_digits: buf.setLength(0); buf.append('0'); /* copy "0" to buffer */ return 1; } b = d2b(d, be, bbits); if ((i = (word0(d) >>> Exp_shift1 & (Exp_mask>>Exp_shift1))) != 0) { d2 = setWord0(d, (word0(d) & Frac_mask1) | Exp_11); /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 * log10(x) = log(x) / log(10) * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) * * This suggests computing an approximation k to log10(d) by * * k = (i - Bias)*0.301029995663981 * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); * * We want k to be too large rather than too small. * The error in the first-order Taylor series approximation * is in our favor, so we just round up the constant enough * to compensate for any error in the multiplication of * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, * adding 1e-13 to the constant term more than suffices. * Hence we adjust the constant term to 0.1760912590558. * (We could get a more accurate k by invoking log10, * but this is probably not worthwhile.) */ i -= Bias; denorm = false; } else { /* d is denormalized */ i = bbits[0] + be[0] + (Bias + (P-1) - 1); x = (i > 32) ? ((long) word0(d)) << (64 - i) | word1(d) >>> (i - 32) : ((long) word1(d)) << (32 - i); // d2 = x; // word0(d2) -= 31*Exp_msk1; /* adjust exponent */ d2 = setWord0(x, word0(x) - 31*Exp_msk1); i -= (Bias + (P-1) - 1) + 1; denorm = true; } /* At this point d = f*2^i, where 1 <= f < 2. d2 is an approximation of f. */ ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; k = (int)ds; if (ds < 0.0 && ds != k) k--; /* want k = floor(ds) */ k_check = true; if (k >= 0 && k <= Ten_pmax) { if (d < tens[k]) k--; k_check = false; } /* At this point floor(log10(d)) <= k <= floor(log10(d))+1. If k_check is zero, we're guaranteed that k = floor(log10(d)). */ j = bbits[0] - i - 1; /* At this point d = b/2^j, where b is an odd integer. */ if (j >= 0) { b2 = 0; s2 = j; } else { b2 = -j; s2 = 0; } if (k >= 0) { b5 = 0; s5 = k; s2 += k; } else { b2 -= k; b5 = -k; s5 = 0; } /* At this point d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5), where b is an odd integer, b2 >= 0, b5 >= 0, s2 >= 0, and s5 >= 0. */ if (mode < 0 || mode > 9) mode = 0; try_quick = true; if (mode > 5) { mode -= 4; try_quick = false; } leftright = true; ilim = ilim1 = 0; switch(mode) { case 0: case 1: ilim = ilim1 = -1; i = 18; ndigits = 0; break; case 2: leftright = false; /* no break */ case 4: if (ndigits <= 0) ndigits = 1; ilim = ilim1 = i = ndigits; break; case 3: leftright = false; /* no break */ case 5: i = ndigits + k + 1; ilim = i; ilim1 = i - 1; if (i <= 0) i = 1; } /* ilim is the maximum number of significant digits we want, based on k and ndigits. */ /* ilim1 is the maximum number of significant digits we want, based on k and ndigits, when it turns out that k was computed too high by one. */ boolean fast_failed = false; if (ilim >= 0 && ilim <= Quick_max && try_quick) { /* Try to get by with floating-point arithmetic. */ i = 0; d2 = d; k0 = k; ilim0 = ilim; ieps = 2; /* conservative */ /* Divide d by 10^k, keeping track of the roundoff error and avoiding overflows. */ if (k > 0) { ds = tens[k&0xf]; j = k >> 4; if ((j & Bletch) != 0) { /* prevent overflows */ j &= Bletch - 1; d /= bigtens[n_bigtens-1]; ieps++; } for(; (j != 0); j >>= 1, i++) if ((j & 1) != 0) { ieps++; ds *= bigtens[i]; } d /= ds; } else if ((j1 = -k) != 0) { d *= tens[j1 & 0xf]; for(j = j1 >> 4; (j != 0); j >>= 1, i++) if ((j & 1) != 0) { ieps++; d *= bigtens[i]; } } /* Check that k was computed correctly. */ if (k_check && d < 1.0 && ilim > 0) { if (ilim1 <= 0) fast_failed = true; else { ilim = ilim1; k--; d *= 10.; ieps++; } } /* eps bounds the cumulative error. */ // eps = ieps*d + 7.0; // word0(eps) -= (P-1)*Exp_msk1; eps = ieps*d + 7.0; eps = setWord0(eps, word0(eps) - (P-1)*Exp_msk1); if (ilim == 0) { S = mhi = null; d -= 5.0; if (d > eps) { buf.append('1'); k++; return k + 1; } if (d < -eps) { buf.setLength(0); buf.append('0'); /* copy "0" to buffer */ return 1; } fast_failed = true; } if (!fast_failed) { fast_failed = true; if (leftright) { /* Use Steele & White method of only * generating digits needed. */ eps = 0.5/tens[ilim-1] - eps; for(i = 0;;) { L = (long)d; d -= L; buf.append((char)('0' + L)); if (d < eps) { return k + 1; } if (1.0 - d < eps) { // goto bump_up; char lastCh; while (true) { lastCh = buf.charAt(buf.length() - 1); buf.setLength(buf.length() - 1); if (lastCh != '9') break; if (buf.length() == 0) { k++; lastCh = '0'; break; } } buf.append((char)(lastCh + 1)); return k + 1; } if (++i >= ilim) break; eps *= 10.0; d *= 10.0; } } else { /* Generate ilim digits, then fix them up. */ eps *= tens[ilim-1]; for(i = 1;; i++, d *= 10.0) { L = (long)d; d -= L; buf.append((char)('0' + L)); if (i == ilim) { if (d > 0.5 + eps) { // goto bump_up; char lastCh; while (true) { lastCh = buf.charAt(buf.length() - 1); buf.setLength(buf.length() - 1); if (lastCh != '9') break; if (buf.length() == 0) { k++; lastCh = '0'; break; } } buf.append((char)(lastCh + 1)); return k + 1; } else if (d < 0.5 - eps) { stripTrailingZeroes(buf); // while(*--s == '0') ; // s++; return k + 1; } break; } } } } if (fast_failed) { buf.setLength(0); d = d2; k = k0; ilim = ilim0; } } /* Do we have a "small" integer? */ if (be[0] >= 0 && k <= Int_max) { /* Yes. */ ds = tens[k]; if (ndigits < 0 && ilim <= 0) { S = mhi = null; if (ilim < 0 || d < 5*ds || (!biasUp && d == 5*ds)) { buf.setLength(0); buf.append('0'); /* copy "0" to buffer */ return 1; } buf.append('1'); k++; return k + 1; } for(i = 1;; i++) { L = (long) (d / ds); d -= L*ds; buf.append((char)('0' + L)); if (i == ilim) { d += d; if ((d > ds) || (d == ds && (((L & 1) != 0) || biasUp))) { // bump_up: // while(*--s == '9') // if (s == buf) { // k++; // *s = '0'; // break; // } // ++*s++; char lastCh; while (true) { lastCh = buf.charAt(buf.length() - 1); buf.setLength(buf.length() - 1); if (lastCh != '9') break; if (buf.length() == 0) { k++; lastCh = '0'; break; } } buf.append((char)(lastCh + 1)); } break; } d *= 10.0; if (d == 0) break; } return k + 1; } m2 = b2; m5 = b5; mhi = mlo = null; if (leftright) { if (mode < 2) { i = (denorm) ? be[0] + (Bias + (P-1) - 1 + 1) : 1 + P - bbits[0]; /* i is 1 plus the number of trailing zero bits in d's significand. Thus, (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 lsb of d)/10^k. */ } else { j = ilim - 1; if (m5 >= j) m5 -= j; else { s5 += j -= m5; b5 += j; m5 = 0; } if ((i = ilim) < 0) { m2 -= i; i = 0; } /* (2^m2 * 5^m5) / (2^(s2+i) * 5^s5) = (1/2 * 10^(1-ilim))/10^k. */ } b2 += i; s2 += i; mhi = BigInteger.valueOf(1); /* (mhi * 2^m2 * 5^m5) / (2^s2 * 5^s5) = one-half of last printed (when mode >= 2) or input (when mode < 2) significant digit, divided by 10^k. */ } /* We still have d/10^k = (b * 2^b2 * 5^b5) / (2^s2 * 5^s5). Reduce common factors in b2, m2, and s2 without changing the equalities. */ if (m2 > 0 && s2 > 0) { i = (m2 < s2) ? m2 : s2; b2 -= i; m2 -= i; s2 -= i; } /* Fold b5 into b and m5 into mhi. */ if (b5 > 0) { if (leftright) { if (m5 > 0) { mhi = pow5mult(mhi, m5); b1 = mhi.multiply(b); b = b1; } if ((j = b5 - m5) != 0) b = pow5mult(b, j); } else b = pow5mult(b, b5); } /* Now we have d/10^k = (b * 2^b2) / (2^s2 * 5^s5) and (mhi * 2^m2) / (2^s2 * 5^s5) = one-half of last printed or input significant digit, divided by 10^k. */ S = BigInteger.valueOf(1); if (s5 > 0) S = pow5mult(S, s5); /* Now we have d/10^k = (b * 2^b2) / (S * 2^s2) and (mhi * 2^m2) / (S * 2^s2) = one-half of last printed or input significant digit, divided by 10^k. */ /* Check for special case that d is a normalized power of 2. */ spec_case = false; if (mode < 2) { if ( (word1(d) == 0) && ((word0(d) & Bndry_mask) == 0) && ((word0(d) & (Exp_mask & Exp_mask << 1)) != 0) ) { /* The special case. Here we want to be within a quarter of the last input significant digit instead of one half of it when the decimal output string's value is less than d. */ b2 += Log2P; s2 += Log2P; spec_case = true; } } /* Arrange for convenient computation of quotients: * shift left if necessary so divisor has 4 leading 0 bits. * * Perhaps we should just compute leading 28 bits of S once * and for all and pass them and a shift to quorem, so it * can do shifts and ors to compute the numerator for q. */ byte [] S_bytes = S.toByteArray(); int S_hiWord = 0; for (int idx = 0; idx < 4; idx++) { S_hiWord = (S_hiWord << 8); if (idx < S_bytes.length) S_hiWord |= (S_bytes[idx] & 0xFF); } if ((i = (((s5 != 0) ? 32 - hi0bits(S_hiWord) : 1) + s2) & 0x1f) != 0) i = 32 - i; /* i is the number of leading zero bits in the most significant word of S*2^s2. */ if (i > 4) { i -= 4; b2 += i; m2 += i; s2 += i; } else if (i < 4) { i += 28; b2 += i; m2 += i; s2 += i; } /* Now S*2^s2 has exactly four leading zero bits in its most significant word. */ if (b2 > 0) b = b.shiftLeft(b2); if (s2 > 0) S = S.shiftLeft(s2); /* Now we have d/10^k = b/S and (mhi * 2^m2) / S = maximum acceptable error, divided by 10^k. */ if (k_check) { if (b.compareTo(S) < 0) { k--; b = b.multiply(BigInteger.valueOf(10)); /* we botched the k estimate */ if (leftright) mhi = mhi.multiply(BigInteger.valueOf(10)); ilim = ilim1; } } /* At this point 1 <= d/10^k = b/S < 10. */ if (ilim <= 0 && mode > 2) { /* We're doing fixed-mode output and d is less than the minimum nonzero output in this mode. Output either zero or the minimum nonzero output depending on which is closer to d. */ if ((ilim < 0 ) || ((i = b.compareTo(S = S.multiply(BigInteger.valueOf(5)))) < 0) || ((i == 0 && !biasUp))) { /* Always emit at least one digit. If the number appears to be zero using the current mode, then emit one '0' digit and set decpt to 1. */ /*no_digits: k = -1 - ndigits; goto ret; */ buf.setLength(0); buf.append('0'); /* copy "0" to buffer */ return 1; // goto no_digits; } // one_digit: buf.append('1'); k++; return k + 1; } if (leftright) { if (m2 > 0) mhi = mhi.shiftLeft(m2); /* Compute mlo -- check for special case * that d is a normalized power of 2. */ mlo = mhi; if (spec_case) { mhi = mlo; mhi = mhi.shiftLeft(Log2P); } /* mlo/S = maximum acceptable error, divided by 10^k, if the output is less than d. */ /* mhi/S = maximum acceptable error, divided by 10^k, if the output is greater than d. */ for(i = 1;;i++) { BigInteger[] divResult = b.divideAndRemainder(S); b = divResult[1]; dig = (char)(divResult[0].intValue() + '0'); /* Do we yet have the shortest decimal string * that will round to d? */ j = b.compareTo(mlo); /* j is b/S compared with mlo/S. */ delta = S.subtract(mhi); j1 = (delta.signum() <= 0) ? 1 : b.compareTo(delta); /* j1 is b/S compared with 1 - mhi/S. */ if ((j1 == 0) && (mode == 0) && ((word1(d) & 1) == 0)) { if (dig == '9') { buf.append('9'); if (roundOff(buf)) { k++; buf.append('1'); } return k + 1; // goto round_9_up; } if (j > 0) dig++; buf.append(dig); return k + 1; } if ((j < 0) || ((j == 0) && (mode == 0) && ((word1(d) & 1) == 0) )) { if (j1 > 0) { /* Either dig or dig+1 would work here as the least significant decimal digit. Use whichever would produce a decimal value closer to d. */ b = b.shiftLeft(1); j1 = b.compareTo(S); if (((j1 > 0) || (j1 == 0 && (((dig & 1) == 1) || biasUp))) && (dig++ == '9')) { buf.append('9'); if (roundOff(buf)) { k++; buf.append('1'); } return k + 1; // goto round_9_up; } } buf.append(dig); return k + 1; } if (j1 > 0) { if (dig == '9') { /* possible if i == 1 */ // round_9_up: // *s++ = '9'; // goto roundoff; buf.append('9'); if (roundOff(buf)) { k++; buf.append('1'); } return k + 1; } buf.append((char)(dig + 1)); return k + 1; } buf.append(dig); if (i == ilim) break; b = b.multiply(BigInteger.valueOf(10)); if (mlo == mhi) mlo = mhi = mhi.multiply(BigInteger.valueOf(10)); else { mlo = mlo.multiply(BigInteger.valueOf(10)); mhi = mhi.multiply(BigInteger.valueOf(10)); } } } else for(i = 1;; i++) { // (char)(dig = quorem(b,S) + '0'); BigInteger[] divResult = b.divideAndRemainder(S); b = divResult[1]; dig = (char)(divResult[0].intValue() + '0'); buf.append(dig); if (i >= ilim) break; b = b.multiply(BigInteger.valueOf(10)); } /* Round off last digit */ b = b.shiftLeft(1); j = b.compareTo(S); if ((j > 0) || (j == 0 && (((dig & 1) == 1) || biasUp))) { // roundoff: // while(*--s == '9') // if (s == buf) { // k++; // *s++ = '1'; // goto ret; // } // ++*s++; if (roundOff(buf)) { k++; buf.append('1'); return k + 1; } } else { stripTrailingZeroes(buf); // while(*--s == '0') ; // s++; } // ret: // Bfree(S); // if (mhi) { // if (mlo && mlo != mhi) // Bfree(mlo); // Bfree(mhi); // } // ret1: // Bfree(b); // JS_ASSERT(s < buf + bufsize); return k + 1; } private static void stripTrailingZeroes(StringBuilder buf) { // while(*--s == '0') ; // s++; int bl = buf.length(); while(bl-->0 && buf.charAt(bl) == '0') { // empty } buf.setLength(bl + 1); } /* Mapping of JSDToStrMode -> JS_dtoa mode */ private static final int dtoaModes[] = { 0, /* DTOSTR_STANDARD */ 0, /* DTOSTR_STANDARD_EXPONENTIAL, */ 3, /* DTOSTR_FIXED, */ 2, /* DTOSTR_EXPONENTIAL, */ 2}; /* DTOSTR_PRECISION */ static void JS_dtostr(StringBuilder buffer, int mode, int precision, double d) { int decPt; /* Position of decimal point relative to first digit returned by JS_dtoa */ boolean[] sign = new boolean[1]; /* true if the sign bit was set in d */ int nDigits; /* Number of significand digits returned by JS_dtoa */ // JS_ASSERT(bufferSize >= (size_t)(mode <= DTOSTR_STANDARD_EXPONENTIAL ? DTOSTR_STANDARD_BUFFER_SIZE : // DTOSTR_VARIABLE_BUFFER_SIZE(precision))); if (mode == DTOSTR_FIXED && (d >= 1e21 || d <= -1e21)) mode = DTOSTR_STANDARD; /* Change mode here rather than below because the buffer may not be large enough to hold a large integer. */ decPt = JS_dtoa(d, dtoaModes[mode], mode >= DTOSTR_FIXED, precision, sign, buffer); nDigits = buffer.length(); /* If Infinity, -Infinity, or NaN, return the string regardless of the mode. */ if (decPt != 9999) { boolean exponentialNotation = false; int minNDigits = 0; /* Minimum number of significand digits required by mode and precision */ int p; switch (mode) { case DTOSTR_STANDARD: if (decPt < -5 || decPt > 21) exponentialNotation = true; else minNDigits = decPt; break; case DTOSTR_FIXED: if (precision >= 0) minNDigits = decPt + precision; else minNDigits = decPt; break; case DTOSTR_EXPONENTIAL: // JS_ASSERT(precision > 0); minNDigits = precision; /* Fall through */ case DTOSTR_STANDARD_EXPONENTIAL: exponentialNotation = true; break; case DTOSTR_PRECISION: // JS_ASSERT(precision > 0); minNDigits = precision; if (decPt < -5 || decPt > precision) exponentialNotation = true; break; } /* If the number has fewer than minNDigits, pad it with zeros at the end */ if (nDigits < minNDigits) { p = minNDigits; nDigits = minNDigits; do { buffer.append('0'); } while (buffer.length() != p); } if (exponentialNotation) { /* Insert a decimal point if more than one significand digit */ if (nDigits != 1) { buffer.insert(1, '.'); } buffer.append('e'); if ((decPt - 1) >= 0) buffer.append('+'); buffer.append(decPt - 1); // JS_snprintf(numEnd, bufferSize - (numEnd - buffer), "e%+d", decPt-1); } else if (decPt != nDigits) { /* Some kind of a fraction in fixed notation */ // JS_ASSERT(decPt <= nDigits); if (decPt > 0) { /* dd...dd . dd...dd */ buffer.insert(decPt, '.'); } else { /* 0 . 00...00dd...dd */ for (int i = 0; i < 1 - decPt; i++) buffer.insert(0, '0'); buffer.insert(1, '.'); } } } /* If negative and neither -0.0 nor NaN, output a leading '-'. */ if (sign[0] && !(word0(d) == Sign_bit && word1(d) == 0) && !((word0(d) & Exp_mask) == Exp_mask && ((word1(d) != 0) || ((word0(d) & Frac_mask) != 0)))) { buffer.insert(0, '-'); } } } rhino-1.7R4/src/org/mozilla/javascript/Decompiler.java000066400000000000000000000651051176760007500230470ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import org.mozilla.javascript.ast.FunctionNode; /** * The following class save decompilation information about the source. * Source information is returned from the parser as a String * associated with function nodes and with the toplevel script. When * saved in the constant pool of a class, this string will be UTF-8 * encoded, and token values will occupy a single byte. * Source is saved (mostly) as token numbers. The tokens saved pretty * much correspond to the token stream of a 'canonical' representation * of the input program, as directed by the parser. (There were a few * cases where tokens could have been left out where decompiler could * easily reconstruct them, but I left them in for clarity). (I also * looked adding source collection to TokenStream instead, where I * could have limited the changes to a few lines in getToken... but * this wouldn't have saved any space in the resulting source * representation, and would have meant that I'd have to duplicate * parser logic in the decompiler to disambiguate situations where * newlines are important.) The function decompile expands the * tokens back into their string representations, using simple * lookahead to correct spacing and indentation. * * Assignments are saved as two-token pairs (Token.ASSIGN, op). Number tokens * are stored inline, as a NUMBER token, a character representing the type, and * either 1 or 4 characters representing the bit-encoding of the number. String * types NAME, STRING and OBJECT are currently stored as a token type, * followed by a character giving the length of the string (assumed to * be less than 2^16), followed by the characters of the string * inlined into the source string. Changing this to some reference to * to the string in the compiled class' constant pool would probably * save a lot of space... but would require some method of deriving * the final constant pool entry from information available at parse * time. */ public class Decompiler { /** * Flag to indicate that the decompilation should omit the * function header and trailing brace. */ public static final int ONLY_BODY_FLAG = 1 << 0; /** * Flag to indicate that the decompilation generates toSource result. */ public static final int TO_SOURCE_FLAG = 1 << 1; /** * Decompilation property to specify initial ident value. */ public static final int INITIAL_INDENT_PROP = 1; /** * Decompilation property to specify default identation offset. */ public static final int INDENT_GAP_PROP = 2; /** * Decompilation property to specify identation offset for case labels. */ public static final int CASE_GAP_PROP = 3; // Marker to denote the last RC of function so it can be distinguished from // the last RC of object literals in case of function expressions private static final int FUNCTION_END = Token.LAST_TOKEN + 1; String getEncodedSource() { return sourceToString(0); } int getCurrentOffset() { return sourceTop; } int markFunctionStart(int functionType) { int savedOffset = getCurrentOffset(); addToken(Token.FUNCTION); append((char)functionType); return savedOffset; } int markFunctionEnd(int functionStart) { int offset = getCurrentOffset(); append((char)FUNCTION_END); return offset; } void addToken(int token) { if (!(0 <= token && token <= Token.LAST_TOKEN)) throw new IllegalArgumentException(); append((char)token); } void addEOL(int token) { if (!(0 <= token && token <= Token.LAST_TOKEN)) throw new IllegalArgumentException(); append((char)token); append((char)Token.EOL); } void addName(String str) { addToken(Token.NAME); appendString(str); } void addString(String str) { addToken(Token.STRING); appendString(str); } void addRegexp(String regexp, String flags) { addToken(Token.REGEXP); appendString('/' + regexp + '/' + flags); } void addNumber(double n) { addToken(Token.NUMBER); /* encode the number in the source stream. * Save as NUMBER type (char | char char char char) * where type is * 'D' - double, 'S' - short, 'J' - long. * We need to retain float vs. integer type info to keep the * behavior of liveconnect type-guessing the same after * decompilation. (Liveconnect tries to present 1.0 to Java * as a float/double) * OPT: This is no longer true. We could compress the format. * This may not be the most space-efficient encoding; * the chars created below may take up to 3 bytes in * constant pool UTF-8 encoding, so a Double could take * up to 12 bytes. */ long lbits = (long)n; if (lbits != n) { // if it's floating point, save as a Double bit pattern. // (12/15/97 our scanner only returns Double for f.p.) lbits = Double.doubleToLongBits(n); append('D'); append((char)(lbits >> 48)); append((char)(lbits >> 32)); append((char)(lbits >> 16)); append((char)lbits); } else { // we can ignore negative values, bc they're already prefixed // by NEG if (lbits < 0) Kit.codeBug(); // will it fit in a char? // this gives a short encoding for integer values up to 2^16. if (lbits <= Character.MAX_VALUE) { append('S'); append((char)lbits); } else { // Integral, but won't fit in a char. Store as a long. append('J'); append((char)(lbits >> 48)); append((char)(lbits >> 32)); append((char)(lbits >> 16)); append((char)lbits); } } } private void appendString(String str) { int L = str.length(); int lengthEncodingSize = 1; if (L >= 0x8000) { lengthEncodingSize = 2; } int nextTop = sourceTop + lengthEncodingSize + L; if (nextTop > sourceBuffer.length) { increaseSourceCapacity(nextTop); } if (L >= 0x8000) { // Use 2 chars to encode strings exceeding 32K, were the highest // bit in the first char indicates presence of the next byte sourceBuffer[sourceTop] = (char)(0x8000 | (L >>> 16)); ++sourceTop; } sourceBuffer[sourceTop] = (char)L; ++sourceTop; str.getChars(0, L, sourceBuffer, sourceTop); sourceTop = nextTop; } private void append(char c) { if (sourceTop == sourceBuffer.length) { increaseSourceCapacity(sourceTop + 1); } sourceBuffer[sourceTop] = c; ++sourceTop; } private void increaseSourceCapacity(int minimalCapacity) { // Call this only when capacity increase is must if (minimalCapacity <= sourceBuffer.length) Kit.codeBug(); int newCapacity = sourceBuffer.length * 2; if (newCapacity < minimalCapacity) { newCapacity = minimalCapacity; } char[] tmp = new char[newCapacity]; System.arraycopy(sourceBuffer, 0, tmp, 0, sourceTop); sourceBuffer = tmp; } private String sourceToString(int offset) { if (offset < 0 || sourceTop < offset) Kit.codeBug(); return new String(sourceBuffer, offset, sourceTop - offset); } /** * Decompile the source information associated with this js * function/script back into a string. For the most part, this * just means translating tokens back to their string * representations; there's a little bit of lookahead logic to * decide the proper spacing/indentation. Most of the work in * mapping the original source to the prettyprinted decompiled * version is done by the parser. * * @param source encoded source tree presentation * * @param flags flags to select output format * * @param properties indentation properties * */ public static String decompile(String source, int flags, UintMap properties) { int length = source.length(); if (length == 0) { return ""; } int indent = properties.getInt(INITIAL_INDENT_PROP, 0); if (indent < 0) throw new IllegalArgumentException(); int indentGap = properties.getInt(INDENT_GAP_PROP, 4); if (indentGap < 0) throw new IllegalArgumentException(); int caseGap = properties.getInt(CASE_GAP_PROP, 2); if (caseGap < 0) throw new IllegalArgumentException(); StringBuffer result = new StringBuffer(); boolean justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); boolean toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG)); // Spew tokens in source, for debugging. // as TYPE number char if (printSource) { System.err.println("length:" + length); for (int i = 0; i < length; ++i) { // Note that tokenToName will fail unless Context.printTrees // is true. String tokenname = null; if (Token.printNames) { tokenname = Token.name(source.charAt(i)); } if (tokenname == null) { tokenname = "---"; } String pad = tokenname.length() > 7 ? "\t" : "\t\t"; System.err.println (tokenname + pad + (int)source.charAt(i) + "\t'" + ScriptRuntime.escapeString (source.substring(i, i+1)) + "'"); } System.err.println(); } int braceNesting = 0; boolean afterFirstEOL = false; int i = 0; int topFunctionType; if (source.charAt(i) == Token.SCRIPT) { ++i; topFunctionType = -1; } else { topFunctionType = source.charAt(i + 1); } if (!toSource) { // add an initial newline to exactly match js. result.append('\n'); for (int j = 0; j < indent; j++) result.append(' '); } else { if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) { result.append('('); } } while (i < length) { switch(source.charAt(i)) { case Token.GET: case Token.SET: result.append(source.charAt(i) == Token.GET ? "get " : "set "); ++i; i = printSourceString(source, i + 1, false, result); // Now increment one more to get past the FUNCTION token ++i; break; case Token.NAME: case Token.REGEXP: // re-wrapped in '/'s in parser... i = printSourceString(source, i + 1, false, result); continue; case Token.STRING: i = printSourceString(source, i + 1, true, result); continue; case Token.NUMBER: i = printSourceNumber(source, i + 1, result); continue; case Token.TRUE: result.append("true"); break; case Token.FALSE: result.append("false"); break; case Token.NULL: result.append("null"); break; case Token.THIS: result.append("this"); break; case Token.FUNCTION: ++i; // skip function type result.append("function "); break; case FUNCTION_END: // Do nothing break; case Token.COMMA: result.append(", "); break; case Token.LC: ++braceNesting; if (Token.EOL == getNext(source, length, i)) indent += indentGap; result.append('{'); break; case Token.RC: { --braceNesting; /* don't print the closing RC if it closes the * toplevel function and we're called from * decompileFunctionBody. */ if (justFunctionBody && braceNesting == 0) break; result.append('}'); switch (getNext(source, length, i)) { case Token.EOL: case FUNCTION_END: indent -= indentGap; break; case Token.WHILE: case Token.ELSE: indent -= indentGap; result.append(' '); break; } break; } case Token.LP: result.append('('); break; case Token.RP: result.append(')'); if (Token.LC == getNext(source, length, i)) result.append(' '); break; case Token.LB: result.append('['); break; case Token.RB: result.append(']'); break; case Token.EOL: { if (toSource) break; boolean newLine = true; if (!afterFirstEOL) { afterFirstEOL = true; if (justFunctionBody) { /* throw away just added 'function name(...) {' * and restore the original indent */ result.setLength(0); indent -= indentGap; newLine = false; } } if (newLine) { result.append('\n'); } /* add indent if any tokens remain, * less setback if next token is * a label, case or default. */ if (i + 1 < length) { int less = 0; int nextToken = source.charAt(i + 1); if (nextToken == Token.CASE || nextToken == Token.DEFAULT) { less = indentGap - caseGap; } else if (nextToken == Token.RC) { less = indentGap; } /* elaborate check against label... skip past a * following inlined NAME and look for a COLON. */ else if (nextToken == Token.NAME) { int afterName = getSourceStringEnd(source, i + 2); if (source.charAt(afterName) == Token.COLON) less = indentGap; } for (; less < indent; less++) result.append(' '); } break; } case Token.DOT: result.append('.'); break; case Token.NEW: result.append("new "); break; case Token.DELPROP: result.append("delete "); break; case Token.IF: result.append("if "); break; case Token.ELSE: result.append("else "); break; case Token.FOR: result.append("for "); break; case Token.IN: result.append(" in "); break; case Token.WITH: result.append("with "); break; case Token.WHILE: result.append("while "); break; case Token.DO: result.append("do "); break; case Token.TRY: result.append("try "); break; case Token.CATCH: result.append("catch "); break; case Token.FINALLY: result.append("finally "); break; case Token.THROW: result.append("throw "); break; case Token.SWITCH: result.append("switch "); break; case Token.BREAK: result.append("break"); if (Token.NAME == getNext(source, length, i)) result.append(' '); break; case Token.CONTINUE: result.append("continue"); if (Token.NAME == getNext(source, length, i)) result.append(' '); break; case Token.CASE: result.append("case "); break; case Token.DEFAULT: result.append("default"); break; case Token.RETURN: result.append("return"); if (Token.SEMI != getNext(source, length, i)) result.append(' '); break; case Token.VAR: result.append("var "); break; case Token.LET: result.append("let "); break; case Token.SEMI: result.append(';'); if (Token.EOL != getNext(source, length, i)) { // separators in FOR result.append(' '); } break; case Token.ASSIGN: result.append(" = "); break; case Token.ASSIGN_ADD: result.append(" += "); break; case Token.ASSIGN_SUB: result.append(" -= "); break; case Token.ASSIGN_MUL: result.append(" *= "); break; case Token.ASSIGN_DIV: result.append(" /= "); break; case Token.ASSIGN_MOD: result.append(" %= "); break; case Token.ASSIGN_BITOR: result.append(" |= "); break; case Token.ASSIGN_BITXOR: result.append(" ^= "); break; case Token.ASSIGN_BITAND: result.append(" &= "); break; case Token.ASSIGN_LSH: result.append(" <<= "); break; case Token.ASSIGN_RSH: result.append(" >>= "); break; case Token.ASSIGN_URSH: result.append(" >>>= "); break; case Token.HOOK: result.append(" ? "); break; case Token.OBJECTLIT: // pun OBJECTLIT to mean colon in objlit property // initialization. // This needs to be distinct from COLON in the general case // to distinguish from the colon in a ternary... which needs // different spacing. result.append(':'); break; case Token.COLON: if (Token.EOL == getNext(source, length, i)) // it's the end of a label result.append(':'); else // it's the middle part of a ternary result.append(" : "); break; case Token.OR: result.append(" || "); break; case Token.AND: result.append(" && "); break; case Token.BITOR: result.append(" | "); break; case Token.BITXOR: result.append(" ^ "); break; case Token.BITAND: result.append(" & "); break; case Token.SHEQ: result.append(" === "); break; case Token.SHNE: result.append(" !== "); break; case Token.EQ: result.append(" == "); break; case Token.NE: result.append(" != "); break; case Token.LE: result.append(" <= "); break; case Token.LT: result.append(" < "); break; case Token.GE: result.append(" >= "); break; case Token.GT: result.append(" > "); break; case Token.INSTANCEOF: result.append(" instanceof "); break; case Token.LSH: result.append(" << "); break; case Token.RSH: result.append(" >> "); break; case Token.URSH: result.append(" >>> "); break; case Token.TYPEOF: result.append("typeof "); break; case Token.VOID: result.append("void "); break; case Token.CONST: result.append("const "); break; case Token.YIELD: result.append("yield "); break; case Token.NOT: result.append('!'); break; case Token.BITNOT: result.append('~'); break; case Token.POS: result.append('+'); break; case Token.NEG: result.append('-'); break; case Token.INC: result.append("++"); break; case Token.DEC: result.append("--"); break; case Token.ADD: result.append(" + "); break; case Token.SUB: result.append(" - "); break; case Token.MUL: result.append(" * "); break; case Token.DIV: result.append(" / "); break; case Token.MOD: result.append(" % "); break; case Token.COLONCOLON: result.append("::"); break; case Token.DOTDOT: result.append(".."); break; case Token.DOTQUERY: result.append(".("); break; case Token.XMLATTR: result.append('@'); break; case Token.DEBUGGER: result.append("debugger;\n"); break; default: // If we don't know how to decompile it, raise an exception. throw new RuntimeException("Token: " + Token.name(source.charAt(i))); } ++i; } if (!toSource) { // add that trailing newline if it's an outermost function. if (!justFunctionBody) result.append('\n'); } else { if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) { result.append(')'); } } return result.toString(); } private static int getNext(String source, int length, int i) { return (i + 1 < length) ? source.charAt(i + 1) : Token.EOF; } private static int getSourceStringEnd(String source, int offset) { return printSourceString(source, offset, false, null); } private static int printSourceString(String source, int offset, boolean asQuotedString, StringBuffer sb) { int length = source.charAt(offset); ++offset; if ((0x8000 & length) != 0) { length = ((0x7FFF & length) << 16) | source.charAt(offset); ++offset; } if (sb != null) { String str = source.substring(offset, offset + length); if (!asQuotedString) { sb.append(str); } else { sb.append('"'); sb.append(ScriptRuntime.escapeString(str)); sb.append('"'); } } return offset + length; } private static int printSourceNumber(String source, int offset, StringBuffer sb) { double number = 0.0; char type = source.charAt(offset); ++offset; if (type == 'S') { if (sb != null) { int ival = source.charAt(offset); number = ival; } ++offset; } else if (type == 'J' || type == 'D') { if (sb != null) { long lbits; lbits = (long)source.charAt(offset) << 48; lbits |= (long)source.charAt(offset + 1) << 32; lbits |= (long)source.charAt(offset + 2) << 16; lbits |= source.charAt(offset + 3); if (type == 'J') { number = lbits; } else { number = Double.longBitsToDouble(lbits); } } offset += 4; } else { // Bad source throw new RuntimeException(); } if (sb != null) { sb.append(ScriptRuntime.numberToString(number, 10)); } return offset; } private char[] sourceBuffer = new char[128]; // Per script/function source buffer top: parent source does not include a // nested functions source and uses function index as a reference instead. private int sourceTop; // whether to do a debug print of the source information, when decompiling. private static final boolean printSource = false; } rhino-1.7R4/src/org/mozilla/javascript/DefaultErrorReporter.java000066400000000000000000000054631176760007500251060ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * This is the default error reporter for JavaScript. * * @author Norris Boyd */ class DefaultErrorReporter implements ErrorReporter { static final DefaultErrorReporter instance = new DefaultErrorReporter(); private boolean forEval; private ErrorReporter chainedReporter; private DefaultErrorReporter() { } static ErrorReporter forEval(ErrorReporter reporter) { DefaultErrorReporter r = new DefaultErrorReporter(); r.forEval = true; r.chainedReporter = reporter; return r; } public void warning(String message, String sourceURI, int line, String lineText, int lineOffset) { if (chainedReporter != null) { chainedReporter.warning( message, sourceURI, line, lineText, lineOffset); } else { // Do nothing } } public void error(String message, String sourceURI, int line, String lineText, int lineOffset) { if (forEval) { // Assume error message strings that start with "TypeError: " // should become TypeError exceptions. A bit of a hack, but we // don't want to change the ErrorReporter interface. String error = "SyntaxError"; final String TYPE_ERROR_NAME = "TypeError"; final String DELIMETER = ": "; final String prefix = TYPE_ERROR_NAME + DELIMETER; if (message.startsWith(prefix)) { error = TYPE_ERROR_NAME; message = message.substring(prefix.length()); } throw ScriptRuntime.constructError(error, message, sourceURI, line, lineText, lineOffset); } if (chainedReporter != null) { chainedReporter.error( message, sourceURI, line, lineText, lineOffset); } else { throw runtimeError( message, sourceURI, line, lineText, lineOffset); } } public EvaluatorException runtimeError(String message, String sourceURI, int line, String lineText, int lineOffset) { if (chainedReporter != null) { return chainedReporter.runtimeError( message, sourceURI, line, lineText, lineOffset); } else { return new EvaluatorException( message, sourceURI, line, lineText, lineOffset); } } } rhino-1.7R4/src/org/mozilla/javascript/DefiningClassLoader.java000066400000000000000000000030741176760007500246210ustar00rootroot00000000000000/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * Load generated classes. * * @author Norris Boyd */ public class DefiningClassLoader extends ClassLoader implements GeneratedClassLoader { public DefiningClassLoader() { this.parentLoader = getClass().getClassLoader(); } public DefiningClassLoader(ClassLoader parentLoader) { this.parentLoader = parentLoader; } public Class defineClass(String name, byte[] data) { // Use our own protection domain for the generated classes. // TODO: we might want to use a separate protection domain for classes // compiled from scripts, based on where the script was loaded from. return super.defineClass(name, data, 0, data.length, SecurityUtilities.getProtectionDomain(getClass())); } public void linkClass(Class cl) { resolveClass(cl); } @Override public Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class cl = findLoadedClass(name); if (cl == null) { if (parentLoader != null) { cl = parentLoader.loadClass(name); } else { cl = findSystemClass(name); } } if (resolve) { resolveClass(cl); } return cl; } private final ClassLoader parentLoader; } rhino-1.7R4/src/org/mozilla/javascript/Delegator.java000066400000000000000000000153131176760007500226660ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * This is a helper class for implementing wrappers around Scriptable * objects. It implements the Function interface and delegates all * invocations to a delegee Scriptable object. The normal use of this * class involves creating a sub-class and overriding one or more of * the methods. * * A useful application is the implementation of interceptors, * pre/post conditions, debugging. * * @see Function * @see Scriptable * @author Matthias Radestock */ public class Delegator implements Function { protected Scriptable obj = null; /** * Create a Delegator prototype. * * This constructor should only be used for creating prototype * objects of Delegator. * * @see org.mozilla.javascript.Delegator#construct */ public Delegator() { } /** * Create a new Delegator that forwards requests to a delegee * Scriptable object. * * @param obj the delegee * @see org.mozilla.javascript.Scriptable */ public Delegator(Scriptable obj) { this.obj = obj; } /** * Crete new Delegator instance. * The default implementation calls this.getClass().newInstance(). * * @see #construct(Context cx, Scriptable scope, Object[] args) */ protected Delegator newInstance() { try { return this.getClass().newInstance(); } catch (Exception ex) { throw Context.throwAsScriptRuntimeEx(ex); } } /** * Retrieve the delegee. * * @return the delegee */ public Scriptable getDelegee() { return obj; } /** * Set the delegee. * * @param obj the delegee * @see org.mozilla.javascript.Scriptable */ public void setDelegee(Scriptable obj) { this.obj = obj; } /** * @see org.mozilla.javascript.Scriptable#getClassName */ public String getClassName() { return obj.getClassName(); } /** * @see org.mozilla.javascript.Scriptable#get(String, Scriptable) */ public Object get(String name, Scriptable start) { return obj.get(name,start); } /** * @see org.mozilla.javascript.Scriptable#get(int, Scriptable) */ public Object get(int index, Scriptable start) { return obj.get(index,start); } /** * @see org.mozilla.javascript.Scriptable#has(String, Scriptable) */ public boolean has(String name, Scriptable start) { return obj.has(name,start); } /** * @see org.mozilla.javascript.Scriptable#has(int, Scriptable) */ public boolean has(int index, Scriptable start) { return obj.has(index,start); } /** * @see org.mozilla.javascript.Scriptable#put(String, Scriptable, Object) */ public void put(String name, Scriptable start, Object value) { obj.put(name,start,value); } /** * @see org.mozilla.javascript.Scriptable#put(int, Scriptable, Object) */ public void put(int index, Scriptable start, Object value) { obj.put(index,start,value); } /** * @see org.mozilla.javascript.Scriptable#delete(String) */ public void delete(String name) { obj.delete(name); } /** * @see org.mozilla.javascript.Scriptable#delete(int) */ public void delete(int index) { obj.delete(index); } /** * @see org.mozilla.javascript.Scriptable#getPrototype */ public Scriptable getPrototype() { return obj.getPrototype(); } /** * @see org.mozilla.javascript.Scriptable#setPrototype */ public void setPrototype(Scriptable prototype) { obj.setPrototype(prototype); } /** * @see org.mozilla.javascript.Scriptable#getParentScope */ public Scriptable getParentScope() { return obj.getParentScope(); } /** * @see org.mozilla.javascript.Scriptable#setParentScope */ public void setParentScope(Scriptable parent) { obj.setParentScope(parent); } /** * @see org.mozilla.javascript.Scriptable#getIds */ public Object[] getIds() { return obj.getIds(); } /** * Note that this method does not get forwarded to the delegee if * the hint parameter is null, * ScriptRuntime.ScriptableClass or * ScriptRuntime.FunctionClass. Instead the object * itself is returned. * * @param hint the type hint * @return the default value * * @see org.mozilla.javascript.Scriptable#getDefaultValue */ public Object getDefaultValue(Class hint) { return (hint == null || hint == ScriptRuntime.ScriptableClass || hint == ScriptRuntime.FunctionClass) ? this : obj.getDefaultValue(hint); } /** * @see org.mozilla.javascript.Scriptable#hasInstance */ public boolean hasInstance(Scriptable instance) { return obj.hasInstance(instance); } /** * @see org.mozilla.javascript.Function#call */ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { return ((Function)obj).call(cx,scope,thisObj,args); } /** * Note that if the delegee is null, * this method creates a new instance of the Delegator itself * rathert than forwarding the call to the * delegee. This permits the use of Delegator * prototypes. * * @param cx the current Context for this thread * @param scope an enclosing scope of the caller except * when the function is called from a closure. * @param args the array of arguments * @return the allocated object * * @see Function#construct(Context, Scriptable, Object[]) */ public Scriptable construct(Context cx, Scriptable scope, Object[] args) { if (obj == null) { //this little trick allows us to declare prototype objects for //Delegators Delegator n = newInstance(); Scriptable delegee; if (args.length == 0) { delegee = new NativeObject(); } else { delegee = ScriptRuntime.toObject(cx, scope, args[0]); } n.setDelegee(delegee); return n; } else { return ((Function)obj).construct(cx,scope,args); } } } rhino-1.7R4/src/org/mozilla/javascript/EcmaError.java000066400000000000000000000067471176760007500226520ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * The class of exceptions raised by the engine as described in * ECMA edition 3. See section 15.11.6 in particular. */ public class EcmaError extends RhinoException { static final long serialVersionUID = -6261226256957286699L; private String errorName; private String errorMessage; /** * Create an exception with the specified detail message. * * Errors internal to the JavaScript engine will simply throw a * RuntimeException. * * @param sourceName the name of the source responsible for the error * @param lineNumber the line number of the source * @param columnNumber the columnNumber of the source (may be zero if * unknown) * @param lineSource the source of the line containing the error (may be * null if unknown) */ EcmaError(String errorName, String errorMessage, String sourceName, int lineNumber, String lineSource, int columnNumber) { recordErrorOrigin(sourceName, lineNumber, lineSource, columnNumber); this.errorName = errorName; this.errorMessage = errorMessage; } /** * @deprecated EcmaError error instances should not be constructed * explicitly since they are generated by the engine. */ public EcmaError(Scriptable nativeError, String sourceName, int lineNumber, int columnNumber, String lineSource) { this("InternalError", ScriptRuntime.toString(nativeError), sourceName, lineNumber, lineSource, columnNumber); } @Override public String details() { return errorName+": "+errorMessage; } /** * Gets the name of the error. * * ECMA edition 3 defines the following * errors: EvalError, RangeError, ReferenceError, * SyntaxError, TypeError, and URIError. Additional error names * may be added in the future. * * See ECMA edition 3, 15.11.7.9. * * @return the name of the error. */ public String getName() { return errorName; } /** * Gets the message corresponding to the error. * * See ECMA edition 3, 15.11.7.10. * * @return an implementation-defined string describing the error. */ public String getErrorMessage() { return errorMessage; } /** * @deprecated Use {@link RhinoException#sourceName()} from the super class. */ public String getSourceName() { return sourceName(); } /** * @deprecated Use {@link RhinoException#lineNumber()} from the super class. */ public int getLineNumber() { return lineNumber(); } /** * @deprecated * Use {@link RhinoException#columnNumber()} from the super class. */ public int getColumnNumber() { return columnNumber(); } /** * @deprecated Use {@link RhinoException#lineSource()} from the super class. */ public String getLineSource() { return lineSource(); } /** * @deprecated * Always returns null. */ public Scriptable getErrorObject() { return null; } } rhino-1.7R4/src/org/mozilla/javascript/ErrorReporter.java000066400000000000000000000053661176760007500236030ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * This is interface defines a protocol for the reporting of * errors during JavaScript translation or execution. * * @author Norris Boyd */ public interface ErrorReporter { /** * Report a warning. * * The implementing class may choose to ignore the warning * if it desires. * * @param message a String describing the warning * @param sourceName a String describing the JavaScript source * where the warning occured; typically a filename or URL * @param line the line number associated with the warning * @param lineSource the text of the line (may be null) * @param lineOffset the offset into lineSource where problem was detected */ void warning(String message, String sourceName, int line, String lineSource, int lineOffset); /** * Report an error. * * The implementing class is free to throw an exception if * it desires. * * If execution has not yet begun, the JavaScript engine is * free to find additional errors rather than terminating * the translation. It will not execute a script that had * errors, however. * * @param message a String describing the error * @param sourceName a String describing the JavaScript source * where the error occured; typically a filename or URL * @param line the line number associated with the error * @param lineSource the text of the line (may be null) * @param lineOffset the offset into lineSource where problem was detected */ void error(String message, String sourceName, int line, String lineSource, int lineOffset); /** * Creates an EvaluatorException that may be thrown. * * runtimeErrors, unlike errors, will always terminate the * current script. * * @param message a String describing the error * @param sourceName a String describing the JavaScript source * where the error occured; typically a filename or URL * @param line the line number associated with the error * @param lineSource the text of the line (may be null) * @param lineOffset the offset into lineSource where problem was detected * @return an EvaluatorException that will be thrown. */ EvaluatorException runtimeError(String message, String sourceName, int line, String lineSource, int lineOffset); } rhino-1.7R4/src/org/mozilla/javascript/Evaluator.java000066400000000000000000000064331176760007500227250ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import org.mozilla.javascript.ast.ScriptNode; import java.util.List; /** * Abstraction of evaluation, which can be implemented either by an * interpreter or compiler. */ public interface Evaluator { /** * Compile the script or function from intermediate representation * tree into an executable form. * * @param compilerEnv Compiler environment * @param tree parse tree * @param encodedSource encoding of the source code for decompilation * @param returnFunction if true, compiling a function * @return an opaque object that can be passed to either * createFunctionObject or createScriptObject, depending on the * value of returnFunction */ public Object compile(CompilerEnvirons compilerEnv, ScriptNode tree, String encodedSource, boolean returnFunction); /** * Create a function object. * * @param cx Current context * @param scope scope of the function * @param bytecode opaque object returned by compile * @param staticSecurityDomain security domain * @return Function object that can be called */ public Function createFunctionObject(Context cx, Scriptable scope, Object bytecode, Object staticSecurityDomain); /** * Create a script object. * * @param bytecode opaque object returned by compile * @param staticSecurityDomain security domain * @return Script object that can be evaluated */ public Script createScriptObject(Object bytecode, Object staticSecurityDomain); /** * Capture stack information from the given exception. * @param ex an exception thrown during execution */ public void captureStackInfo(RhinoException ex); /** * Get the source position information by examining the stack. * @param cx Context * @param linep Array object of length >= 1; getSourcePositionFromStack * will assign the line number to linep[0]. * @return the name of the file or other source container */ public String getSourcePositionFromStack(Context cx, int[] linep); /** * Given a native stack trace, patch it with script-specific source * and line information * @param ex exception * @param nativeStackTrace the native stack trace * @return patched stack trace */ public String getPatchedStack(RhinoException ex, String nativeStackTrace); /** * Get the script stack for the given exception * @param ex exception from execution * @return list of strings for the stack trace */ public List getScriptStack(RhinoException ex); /** * Mark the given script to indicate it was created by a call to * eval() or to a Function constructor. * @param script script to mark as from eval */ public void setEvalScriptFlag(Script script); } rhino-1.7R4/src/org/mozilla/javascript/EvaluatorException.java000066400000000000000000000051421176760007500246000ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * The class of exceptions thrown by the JavaScript engine. */ public class EvaluatorException extends RhinoException { static final long serialVersionUID = -8743165779676009808L; public EvaluatorException(String detail) { super(detail); } /** * Create an exception with the specified detail message. * * Errors internal to the JavaScript engine will simply throw a * RuntimeException. * * @param detail the error message * @param sourceName the name of the source reponsible for the error * @param lineNumber the line number of the source */ public EvaluatorException(String detail, String sourceName, int lineNumber) { this(detail, sourceName, lineNumber, null, 0); } /** * Create an exception with the specified detail message. * * Errors internal to the JavaScript engine will simply throw a * RuntimeException. * * @param detail the error message * @param sourceName the name of the source responsible for the error * @param lineNumber the line number of the source * @param columnNumber the columnNumber of the source (may be zero if * unknown) * @param lineSource the source of the line containing the error (may be * null if unknown) */ public EvaluatorException(String detail, String sourceName, int lineNumber, String lineSource, int columnNumber) { super(detail); recordErrorOrigin(sourceName, lineNumber, lineSource, columnNumber); } /** * @deprecated Use {@link RhinoException#sourceName()} from the super class. */ public String getSourceName() { return sourceName(); } /** * @deprecated Use {@link RhinoException#lineNumber()} from the super class. */ public int getLineNumber() { return lineNumber(); } /** * @deprecated Use {@link RhinoException#columnNumber()} from the super class. */ public int getColumnNumber() { return columnNumber(); } /** * @deprecated Use {@link RhinoException#lineSource()} from the super class. */ public String getLineSource() { return lineSource(); } } rhino-1.7R4/src/org/mozilla/javascript/Function.java000066400000000000000000000035251176760007500225470ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * This is interface that all functions in JavaScript must implement. * The interface provides for calling functions and constructors. * * @see org.mozilla.javascript.Scriptable * @author Norris Boyd */ public interface Function extends Scriptable, Callable { /** * Call the function. * * Note that the array of arguments is not guaranteed to have * length greater than 0. * * @param cx the current Context for this thread * @param scope the scope to execute the function relative to. This is * set to the value returned by getParentScope() except * when the function is called from a closure. * @param thisObj the JavaScript this object * @param args the array of arguments * @return the result of the call */ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args); /** * Call the function as a constructor. * * This method is invoked by the runtime in order to satisfy a use * of the JavaScript new operator. This method is * expected to create a new object and return it. * * @param cx the current Context for this thread * @param scope an enclosing scope of the caller except * when the function is called from a closure. * @param args the array of arguments * @return the allocated object */ public Scriptable construct(Context cx, Scriptable scope, Object[] args); } rhino-1.7R4/src/org/mozilla/javascript/FunctionObject.java000066400000000000000000000501661176760007500237010ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; import java.lang.reflect.*; import java.io.*; public class FunctionObject extends BaseFunction { static final long serialVersionUID = -5332312783643935019L; /** * Create a JavaScript function object from a Java method. * *

The member argument must be either a java.lang.reflect.Method * or a java.lang.reflect.Constructor and must match one of two forms.

* * The first form is a member with zero or more parameters * of the following types: Object, String, boolean, Scriptable, * int, or double. The Long type is not supported * because the double representation of a long (which is the * EMCA-mandated storage type for Numbers) may lose precision. * If the member is a Method, the return value must be void or one * of the types allowed for parameters.

* * The runtime will perform appropriate conversions based * upon the type of the parameter. A parameter type of * Object specifies that no conversions are to be done. A parameter * of type String will use Context.toString to convert arguments. * Similarly, parameters of type double, boolean, and Scriptable * will cause Context.toNumber, Context.toBoolean, and * Context.toObject, respectively, to be called.

* * If the method is not static, the Java 'this' value will * correspond to the JavaScript 'this' value. Any attempt * to call the function with a 'this' value that is not * of the right Java type will result in an error.

* * The second form is the variable arguments (or "varargs") * form. If the FunctionObject will be used as a constructor, * the member must have the following parameters *

     *      (Context cx, Object[] args, Function ctorObj,
     *       boolean inNewExpr)
* and if it is a Method, be static and return an Object result.

* * Otherwise, if the FunctionObject will not be used to define a * constructor, the member must be a static Method with parameters *

     *      (Context cx, Scriptable thisObj, Object[] args,
     *       Function funObj) 
* and an Object result.

* * When the function varargs form is called as part of a function call, * the args parameter contains the * arguments, with thisObj * set to the JavaScript 'this' value. funObj * is the function object for the invoked function.

* * When the constructor varargs form is called or invoked while evaluating * a new expression, args contains the * arguments, ctorObj refers to this FunctionObject, and * inNewExpr is true if and only if a new * expression caused the call. This supports defining a function that * has different behavior when called as a constructor than when * invoked as a normal function call. (For example, the Boolean * constructor, when called as a function, * will convert to boolean rather than creating a new object.)

* * @param name the name of the function * @param methodOrConstructor a java.lang.reflect.Method or a java.lang.reflect.Constructor * that defines the object * @param scope enclosing scope of function * @see org.mozilla.javascript.Scriptable */ public FunctionObject(String name, Member methodOrConstructor, Scriptable scope) { if (methodOrConstructor instanceof Constructor) { member = new MemberBox((Constructor) methodOrConstructor); isStatic = true; // well, doesn't take a 'this' } else { member = new MemberBox((Method) methodOrConstructor); isStatic = member.isStatic(); } String methodName = member.getName(); this.functionName = name; Class[] types = member.argTypes; int arity = types.length; if (arity == 4 && (types[1].isArray() || types[2].isArray())) { // Either variable args or an error. if (types[1].isArray()) { if (!isStatic || types[0] != ScriptRuntime.ContextClass || types[1].getComponentType() != ScriptRuntime.ObjectClass || types[2] != ScriptRuntime.FunctionClass || types[3] != Boolean.TYPE) { throw Context.reportRuntimeError1( "msg.varargs.ctor", methodName); } parmsLength = VARARGS_CTOR; } else { if (!isStatic || types[0] != ScriptRuntime.ContextClass || types[1] != ScriptRuntime.ScriptableClass || types[2].getComponentType() != ScriptRuntime.ObjectClass || types[3] != ScriptRuntime.FunctionClass) { throw Context.reportRuntimeError1( "msg.varargs.fun", methodName); } parmsLength = VARARGS_METHOD; } } else { parmsLength = arity; if (arity > 0) { typeTags = new byte[arity]; for (int i = 0; i != arity; ++i) { int tag = getTypeTag(types[i]); if (tag == JAVA_UNSUPPORTED_TYPE) { throw Context.reportRuntimeError2( "msg.bad.parms", types[i].getName(), methodName); } typeTags[i] = (byte)tag; } } } if (member.isMethod()) { Method method = member.method(); Class returnType = method.getReturnType(); if (returnType == Void.TYPE) { hasVoidReturn = true; } else { returnTypeTag = getTypeTag(returnType); } } else { Class ctorType = member.getDeclaringClass(); if (!ScriptRuntime.ScriptableClass.isAssignableFrom(ctorType)) { throw Context.reportRuntimeError1( "msg.bad.ctor.return", ctorType.getName()); } } ScriptRuntime.setFunctionProtoAndParent(this, scope); } /** * @return One of JAVA_*_TYPE constants to indicate desired type * or {@link #JAVA_UNSUPPORTED_TYPE} if the convertion is not * possible */ public static int getTypeTag(Class type) { if (type == ScriptRuntime.StringClass) return JAVA_STRING_TYPE; if (type == ScriptRuntime.IntegerClass || type == Integer.TYPE) return JAVA_INT_TYPE; if (type == ScriptRuntime.BooleanClass || type == Boolean.TYPE) return JAVA_BOOLEAN_TYPE; if (type == ScriptRuntime.DoubleClass || type == Double.TYPE) return JAVA_DOUBLE_TYPE; if (ScriptRuntime.ScriptableClass.isAssignableFrom(type)) return JAVA_SCRIPTABLE_TYPE; if (type == ScriptRuntime.ObjectClass) return JAVA_OBJECT_TYPE; // Note that the long type is not supported; see the javadoc for // the constructor for this class return JAVA_UNSUPPORTED_TYPE; } public static Object convertArg(Context cx, Scriptable scope, Object arg, int typeTag) { switch (typeTag) { case JAVA_STRING_TYPE: if (arg instanceof String) return arg; return ScriptRuntime.toString(arg); case JAVA_INT_TYPE: if (arg instanceof Integer) return arg; return Integer.valueOf(ScriptRuntime.toInt32(arg)); case JAVA_BOOLEAN_TYPE: if (arg instanceof Boolean) return arg; return ScriptRuntime.toBoolean(arg) ? Boolean.TRUE : Boolean.FALSE; case JAVA_DOUBLE_TYPE: if (arg instanceof Double) return arg; return new Double(ScriptRuntime.toNumber(arg)); case JAVA_SCRIPTABLE_TYPE: return ScriptRuntime.toObjectOrNull(cx, arg, scope); case JAVA_OBJECT_TYPE: return arg; default: throw new IllegalArgumentException(); } } /** * Return the value defined by the method used to construct the object * (number of parameters of the method, or 1 if the method is a "varargs" * form). */ @Override public int getArity() { return parmsLength < 0 ? 1 : parmsLength; } /** * Return the same value as {@link #getArity()}. */ @Override public int getLength() { return getArity(); } @Override public String getFunctionName() { return (functionName == null) ? "" : functionName; } /** * Get Java method or constructor this function represent. */ public Member getMethodOrConstructor() { if (member.isMethod()) { return member.method(); } else { return member.ctor(); } } static Method findSingleMethod(Method[] methods, String name) { Method found = null; for (int i = 0, N = methods.length; i != N; ++i) { Method method = methods[i]; if (method != null && name.equals(method.getName())) { if (found != null) { throw Context.reportRuntimeError2( "msg.no.overload", name, method.getDeclaringClass().getName()); } found = method; } } return found; } /** * Returns all public methods declared by the specified class. This excludes * inherited methods. * * @param clazz the class from which to pull public declared methods * @return the public methods declared in the specified class * @see Class#getDeclaredMethods() */ static Method[] getMethodList(Class clazz) { Method[] methods = null; try { // getDeclaredMethods may be rejected by the security manager // but getMethods is more expensive if (!sawSecurityException) methods = clazz.getDeclaredMethods(); } catch (SecurityException e) { // If we get an exception once, give up on getDeclaredMethods sawSecurityException = true; } if (methods == null) { methods = clazz.getMethods(); } int count = 0; for (int i=0; i < methods.length; i++) { if (sawSecurityException ? methods[i].getDeclaringClass() != clazz : !Modifier.isPublic(methods[i].getModifiers())) { methods[i] = null; } else { count++; } } Method[] result = new Method[count]; int j=0; for (int i=0; i < methods.length; i++) { if (methods[i] != null) result[j++] = methods[i]; } return result; } /** * Define this function as a JavaScript constructor. *

* Sets up the "prototype" and "constructor" properties. Also * calls setParent and setPrototype with appropriate values. * Then adds the function object as a property of the given scope, using * prototype.getClassName() * as the name of the property. * * @param scope the scope in which to define the constructor (typically * the global object) * @param prototype the prototype object * @see org.mozilla.javascript.Scriptable#setParentScope * @see org.mozilla.javascript.Scriptable#setPrototype * @see org.mozilla.javascript.Scriptable#getClassName */ public void addAsConstructor(Scriptable scope, Scriptable prototype) { initAsConstructor(scope, prototype); defineProperty(scope, prototype.getClassName(), this, ScriptableObject.DONTENUM); } void initAsConstructor(Scriptable scope, Scriptable prototype) { ScriptRuntime.setFunctionProtoAndParent(this, scope); setImmunePrototypeProperty(prototype); prototype.setParentScope(this); defineProperty(prototype, "constructor", this, ScriptableObject.DONTENUM | ScriptableObject.PERMANENT | ScriptableObject.READONLY); setParentScope(scope); } /** * @deprecated Use {@link #getTypeTag(Class)} * and {@link #convertArg(Context, Scriptable, Object, int)} * for type conversion. */ public static Object convertArg(Context cx, Scriptable scope, Object arg, Class desired) { int tag = getTypeTag(desired); if (tag == JAVA_UNSUPPORTED_TYPE) { throw Context.reportRuntimeError1 ("msg.cant.convert", desired.getName()); } return convertArg(cx, scope, arg, tag); } /** * Performs conversions on argument types if needed and * invokes the underlying Java method or constructor. *

* Implements Function.call. * * @see org.mozilla.javascript.Function#call( * Context, Scriptable, Scriptable, Object[]) */ @Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { Object result; boolean checkMethodResult = false; int argsLength = args.length; for (int i = 0; i < argsLength; i++) { // flatten cons-strings before passing them as arguments if (args[i] instanceof ConsString) { args[i] = args[i].toString(); } } if (parmsLength < 0) { if (parmsLength == VARARGS_METHOD) { Object[] invokeArgs = { cx, thisObj, args, this }; result = member.invoke(null, invokeArgs); checkMethodResult = true; } else { boolean inNewExpr = (thisObj == null); Boolean b = inNewExpr ? Boolean.TRUE : Boolean.FALSE; Object[] invokeArgs = { cx, args, this, b }; result = (member.isCtor()) ? member.newInstance(invokeArgs) : member.invoke(null, invokeArgs); } } else { if (!isStatic) { Class clazz = member.getDeclaringClass(); if (!clazz.isInstance(thisObj)) { boolean compatible = false; if (thisObj == scope) { Scriptable parentScope = getParentScope(); if (scope != parentScope) { // Call with dynamic scope for standalone function, // use parentScope as thisObj compatible = clazz.isInstance(parentScope); if (compatible) { thisObj = parentScope; } } } if (!compatible) { // Couldn't find an object to call this on. throw ScriptRuntime.typeError1("msg.incompat.call", functionName); } } } Object[] invokeArgs; if (parmsLength == argsLength) { // Do not allocate new argument array if java arguments are // the same as the original js ones. invokeArgs = args; for (int i = 0; i != parmsLength; ++i) { Object arg = args[i]; Object converted = convertArg(cx, scope, arg, typeTags[i]); if (arg != converted) { if (invokeArgs == args) { invokeArgs = args.clone(); } invokeArgs[i] = converted; } } } else if (parmsLength == 0) { invokeArgs = ScriptRuntime.emptyArgs; } else { invokeArgs = new Object[parmsLength]; for (int i = 0; i != parmsLength; ++i) { Object arg = (i < argsLength) ? args[i] : Undefined.instance; invokeArgs[i] = convertArg(cx, scope, arg, typeTags[i]); } } if (member.isMethod()) { result = member.invoke(thisObj, invokeArgs); checkMethodResult = true; } else { result = member.newInstance(invokeArgs); } } if (checkMethodResult) { if (hasVoidReturn) { result = Undefined.instance; } else if (returnTypeTag == JAVA_UNSUPPORTED_TYPE) { result = cx.getWrapFactory().wrap(cx, scope, result, null); } // XXX: the code assumes that if returnTypeTag == JAVA_OBJECT_TYPE // then the Java method did a proper job of converting the // result to JS primitive or Scriptable to avoid // potentially costly Context.javaToJS call. } return result; } /** * Return new {@link Scriptable} instance using the default * constructor for the class of the underlying Java method. * Return null to indicate that the call method should be used to create * new objects. */ @Override public Scriptable createObject(Context cx, Scriptable scope) { if (member.isCtor() || parmsLength == VARARGS_CTOR) { return null; } Scriptable result; try { result = (Scriptable) member.getDeclaringClass().newInstance(); } catch (Exception ex) { throw Context.throwAsScriptRuntimeEx(ex); } result.setPrototype(getClassPrototype()); result.setParentScope(getParentScope()); return result; } boolean isVarArgsMethod() { return parmsLength == VARARGS_METHOD; } boolean isVarArgsConstructor() { return parmsLength == VARARGS_CTOR; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); if (parmsLength > 0) { Class[] types = member.argTypes; typeTags = new byte[parmsLength]; for (int i = 0; i != parmsLength; ++i) { typeTags[i] = (byte)getTypeTag(types[i]); } } if (member.isMethod()) { Method method = member.method(); Class returnType = method.getReturnType(); if (returnType == Void.TYPE) { hasVoidReturn = true; } else { returnTypeTag = getTypeTag(returnType); } } } private static final short VARARGS_METHOD = -1; private static final short VARARGS_CTOR = -2; private static boolean sawSecurityException; public static final int JAVA_UNSUPPORTED_TYPE = 0; public static final int JAVA_STRING_TYPE = 1; public static final int JAVA_INT_TYPE = 2; public static final int JAVA_BOOLEAN_TYPE = 3; public static final int JAVA_DOUBLE_TYPE = 4; public static final int JAVA_SCRIPTABLE_TYPE = 5; public static final int JAVA_OBJECT_TYPE = 6; MemberBox member; private String functionName; private transient byte[] typeTags; private int parmsLength; private transient boolean hasVoidReturn; private transient int returnTypeTag; private boolean isStatic; } rhino-1.7R4/src/org/mozilla/javascript/GeneratedClassLoader.java000066400000000000000000000017341176760007500247750ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * Interface to define classes from generated byte code. */ public interface GeneratedClassLoader { /** * Define a new Java class. * Classes created via this method should have the same class loader. * * @param name fully qualified class name * @param data class byte code * @return new class object */ public Class defineClass(String name, byte[] data); /** * Link the given class. * * @param cl Class instance returned from the previous call to * {@link #defineClass(String, byte[])} * @see java.lang.ClassLoader */ public void linkClass(Class cl); } rhino-1.7R4/src/org/mozilla/javascript/IRFactory.java000066400000000000000000002516351176760007500226330ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import org.mozilla.javascript.ast.*; import java.util.List; import java.util.ArrayList; /** * This class rewrites the parse tree into an IR suitable for codegen. * * @see Node * @author Mike McCabe * @author Norris Boyd */ public final class IRFactory extends Parser { private static final int LOOP_DO_WHILE = 0; private static final int LOOP_WHILE = 1; private static final int LOOP_FOR = 2; private static final int ALWAYS_TRUE_BOOLEAN = 1; private static final int ALWAYS_FALSE_BOOLEAN = -1; private Decompiler decompiler = new Decompiler(); public IRFactory() { super(); } public IRFactory(CompilerEnvirons env) { this(env, env.getErrorReporter()); } public IRFactory(CompilerEnvirons env, ErrorReporter errorReporter) { super(env, errorReporter); } /** * Transforms the tree into a lower-level IR suitable for codegen. * Optionally generates the encoded source. */ public ScriptNode transformTree(AstRoot root) { currentScriptOrFn = root; this.inUseStrictDirective = root.isInStrictMode(); int sourceStartOffset = decompiler.getCurrentOffset(); if (Token.printTrees) { System.out.println("IRFactory.transformTree"); System.out.println(root.debugPrint()); } ScriptNode script = (ScriptNode)transform(root); int sourceEndOffset = decompiler.getCurrentOffset(); script.setEncodedSourceBounds(sourceStartOffset, sourceEndOffset); if (compilerEnv.isGeneratingSource()) { script.setEncodedSource(decompiler.getEncodedSource()); } decompiler = null; return script; } // Might want to convert this to polymorphism - move transform* // functions into the AstNode subclasses. OTOH that would make // IR transformation part of the public AST API - desirable? // Another possibility: create AstTransformer interface and adapter. public Node transform(AstNode node) { switch (node.getType()) { case Token.ARRAYCOMP: return transformArrayComp((ArrayComprehension)node); case Token.ARRAYLIT: return transformArrayLiteral((ArrayLiteral)node); case Token.BLOCK: return transformBlock(node); case Token.BREAK: return transformBreak((BreakStatement)node); case Token.CALL: return transformFunctionCall((FunctionCall)node); case Token.CONTINUE: return transformContinue((ContinueStatement)node); case Token.DO: return transformDoLoop((DoLoop)node); case Token.EMPTY: return node; case Token.FOR: if (node instanceof ForInLoop) { return transformForInLoop((ForInLoop)node); } else { return transformForLoop((ForLoop)node); } case Token.FUNCTION: return transformFunction((FunctionNode)node); case Token.GENEXPR: return transformGenExpr((GeneratorExpression)node); case Token.GETELEM: return transformElementGet((ElementGet)node); case Token.GETPROP: return transformPropertyGet((PropertyGet)node); case Token.HOOK: return transformCondExpr((ConditionalExpression)node); case Token.IF: return transformIf((IfStatement)node); case Token.TRUE: case Token.FALSE: case Token.THIS: case Token.NULL: case Token.DEBUGGER: return transformLiteral(node); case Token.NAME: return transformName((Name)node); case Token.NUMBER: return transformNumber((NumberLiteral)node); case Token.NEW: return transformNewExpr((NewExpression)node); case Token.OBJECTLIT: return transformObjectLiteral((ObjectLiteral)node); case Token.REGEXP: return transformRegExp((RegExpLiteral)node); case Token.RETURN: return transformReturn((ReturnStatement)node); case Token.SCRIPT: return transformScript((ScriptNode)node); case Token.STRING: return transformString((StringLiteral)node); case Token.SWITCH: return transformSwitch((SwitchStatement)node); case Token.THROW: return transformThrow((ThrowStatement)node); case Token.TRY: return transformTry((TryStatement)node); case Token.WHILE: return transformWhileLoop((WhileLoop)node); case Token.WITH: return transformWith((WithStatement)node); case Token.YIELD: return transformYield((Yield)node); default: if (node instanceof ExpressionStatement) { return transformExprStmt((ExpressionStatement)node); } if (node instanceof Assignment) { return transformAssignment((Assignment)node); } if (node instanceof UnaryExpression) { return transformUnary((UnaryExpression)node); } if (node instanceof XmlMemberGet) { return transformXmlMemberGet((XmlMemberGet)node); } if (node instanceof InfixExpression) { return transformInfix((InfixExpression)node); } if (node instanceof VariableDeclaration) { return transformVariables((VariableDeclaration)node); } if (node instanceof ParenthesizedExpression) { return transformParenExpr((ParenthesizedExpression)node); } if (node instanceof LabeledStatement) { return transformLabeledStatement((LabeledStatement)node); } if (node instanceof LetNode) { return transformLetNode((LetNode)node); } if (node instanceof XmlRef) { return transformXmlRef((XmlRef)node); } if (node instanceof XmlLiteral) { return transformXmlLiteral((XmlLiteral)node); } throw new IllegalArgumentException("Can't transform: " + node); } } private Node transformArrayComp(ArrayComprehension node) { // An array comprehension expression such as // // [expr for (x in foo) for each ([y, z] in bar) if (cond)] // // is rewritten approximately as // // new Scope(ARRAYCOMP) { // new Node(BLOCK) { // let tmp1 = new Array; // for (let x in foo) { // for each (let tmp2 in bar) { // if (cond) { // tmp1.push([y, z] = tmp2, expr); // } // } // } // } // createName(tmp1) // } int lineno = node.getLineno(); Scope scopeNode = createScopeNode(Token.ARRAYCOMP, lineno); String arrayName = currentScriptOrFn.getNextTempName(); pushScope(scopeNode); try { defineSymbol(Token.LET, arrayName, false); Node block = new Node(Token.BLOCK, lineno); Node newArray = createCallOrNew(Token.NEW, createName("Array")); Node init = new Node(Token.EXPR_VOID, createAssignment(Token.ASSIGN, createName(arrayName), newArray), lineno); block.addChildToBack(init); block.addChildToBack(arrayCompTransformHelper(node, arrayName)); scopeNode.addChildToBack(block); scopeNode.addChildToBack(createName(arrayName)); return scopeNode; } finally { popScope(); } } private Node arrayCompTransformHelper(ArrayComprehension node, String arrayName) { decompiler.addToken(Token.LB); int lineno = node.getLineno(); Node expr = transform(node.getResult()); List loops = node.getLoops(); int numLoops = loops.size(); // Walk through loops, collecting and defining their iterator symbols. Node[] iterators = new Node[numLoops]; Node[] iteratedObjs = new Node[numLoops]; for (int i = 0; i < numLoops; i++) { ArrayComprehensionLoop acl = loops.get(i); decompiler.addName(" "); decompiler.addToken(Token.FOR); if (acl.isForEach()) { decompiler.addName("each "); } decompiler.addToken(Token.LP); AstNode iter = acl.getIterator(); String name = null; if (iter.getType() == Token.NAME) { name = iter.getString(); decompiler.addName(name); } else { // destructuring assignment decompile(iter); name = currentScriptOrFn.getNextTempName(); defineSymbol(Token.LP, name, false); expr = createBinary(Token.COMMA, createAssignment(Token.ASSIGN, iter, createName(name)), expr); } Node init = createName(name); // Define as a let since we want the scope of the variable to // be restricted to the array comprehension defineSymbol(Token.LET, name, false); iterators[i] = init; decompiler.addToken(Token.IN); iteratedObjs[i] = transform(acl.getIteratedObject()); decompiler.addToken(Token.RP); } // generate code for tmpArray.push(body) Node call = createCallOrNew(Token.CALL, createPropertyGet(createName(arrayName), null, "push", 0)); Node body = new Node(Token.EXPR_VOID, call, lineno); if (node.getFilter() != null) { decompiler.addName(" "); decompiler.addToken(Token.IF); decompiler.addToken(Token.LP); body = createIf(transform(node.getFilter()), body, null, lineno); decompiler.addToken(Token.RP); } // Now walk loops in reverse to build up the body statement. int pushed = 0; try { for (int i = numLoops-1; i >= 0; i--) { ArrayComprehensionLoop acl = loops.get(i); Scope loop = createLoopNode(null, // no label acl.getLineno()); pushScope(loop); pushed++; body = createForIn(Token.LET, loop, iterators[i], iteratedObjs[i], body, acl.isForEach()); } } finally { for (int i = 0; i < pushed; i++) { popScope(); } } decompiler.addToken(Token.RB); // Now that we've accumulated any destructuring forms, // add expr to the call node; it's pushed on each iteration. call.addChildToBack(expr); return body; } private Node transformArrayLiteral(ArrayLiteral node) { if (node.isDestructuring()) { return node; } decompiler.addToken(Token.LB); List elems = node.getElements(); Node array = new Node(Token.ARRAYLIT); List skipIndexes = null; for (int i = 0; i < elems.size(); ++i) { AstNode elem = elems.get(i); if (elem.getType() != Token.EMPTY) { array.addChildToBack(transform(elem)); } else { if (skipIndexes == null) { skipIndexes = new ArrayList(); } skipIndexes.add(i); } if (i < elems.size() - 1) decompiler.addToken(Token.COMMA); } decompiler.addToken(Token.RB); array.putIntProp(Node.DESTRUCTURING_ARRAY_LENGTH, node.getDestructuringLength()); if (skipIndexes != null) { int[] skips = new int[skipIndexes.size()]; for (int i = 0; i < skipIndexes.size(); i++) skips[i] = skipIndexes.get(i); array.putProp(Node.SKIP_INDEXES_PROP, skips); } return array; } private Node transformAssignment(Assignment node) { AstNode left = removeParens(node.getLeft()); Node target = null; if (isDestructuring(left)) { decompile(left); target = left; } else { target = transform(left); } decompiler.addToken(node.getType()); return createAssignment(node.getType(), target, transform(node.getRight())); } private Node transformBlock(AstNode node) { if (node instanceof Scope) { pushScope((Scope)node); } try { List kids = new ArrayList(); for (Node kid : node) { kids.add(transform((AstNode)kid)); } node.removeChildren(); for (Node kid : kids) { node.addChildToBack(kid); } return node; } finally { if (node instanceof Scope) { popScope(); } } } private Node transformBreak(BreakStatement node) { decompiler.addToken(Token.BREAK); if (node.getBreakLabel() != null) { decompiler.addName(node.getBreakLabel().getIdentifier()); } decompiler.addEOL(Token.SEMI); return node; } private Node transformCondExpr(ConditionalExpression node) { Node test = transform(node.getTestExpression()); decompiler.addToken(Token.HOOK); Node ifTrue = transform(node.getTrueExpression()); decompiler.addToken(Token.COLON); Node ifFalse = transform(node.getFalseExpression()); return createCondExpr(test, ifTrue, ifFalse); } private Node transformContinue(ContinueStatement node) { decompiler.addToken(Token.CONTINUE); if (node.getLabel() != null) { decompiler.addName(node.getLabel().getIdentifier()); } decompiler.addEOL(Token.SEMI); return node; } private Node transformDoLoop(DoLoop loop) { loop.setType(Token.LOOP); pushScope(loop); try { decompiler.addToken(Token.DO); decompiler.addEOL(Token.LC); Node body = transform(loop.getBody()); decompiler.addToken(Token.RC); decompiler.addToken(Token.WHILE); decompiler.addToken(Token.LP); Node cond = transform(loop.getCondition()); decompiler.addToken(Token.RP); decompiler.addEOL(Token.SEMI); return createLoop(loop, LOOP_DO_WHILE, body, cond, null, null); } finally { popScope(); } } private Node transformElementGet(ElementGet node) { // OPT: could optimize to createPropertyGet // iff elem is string that can not be number Node target = transform(node.getTarget()); decompiler.addToken(Token.LB); Node element = transform(node.getElement()); decompiler.addToken(Token.RB); return new Node(Token.GETELEM, target, element); } private Node transformExprStmt(ExpressionStatement node) { Node expr = transform(node.getExpression()); decompiler.addEOL(Token.SEMI); return new Node(node.getType(), expr, node.getLineno()); } private Node transformForInLoop(ForInLoop loop) { decompiler.addToken(Token.FOR); if (loop.isForEach()) decompiler.addName("each "); decompiler.addToken(Token.LP); loop.setType(Token.LOOP); pushScope(loop); try { int declType = -1; AstNode iter = loop.getIterator(); if (iter instanceof VariableDeclaration) { declType = ((VariableDeclaration)iter).getType(); } Node lhs = transform(iter); decompiler.addToken(Token.IN); Node obj = transform(loop.getIteratedObject()); decompiler.addToken(Token.RP); decompiler.addEOL(Token.LC); Node body = transform(loop.getBody()); decompiler.addEOL(Token.RC); return createForIn(declType, loop, lhs, obj, body, loop.isForEach()); } finally { popScope(); } } private Node transformForLoop(ForLoop loop) { decompiler.addToken(Token.FOR); decompiler.addToken(Token.LP); loop.setType(Token.LOOP); // XXX: Can't use pushScope/popScope here since 'createFor' may split // the scope Scope savedScope = currentScope; currentScope = loop; try { Node init = transform(loop.getInitializer()); decompiler.addToken(Token.SEMI); Node test = transform(loop.getCondition()); decompiler.addToken(Token.SEMI); Node incr = transform(loop.getIncrement()); decompiler.addToken(Token.RP); decompiler.addEOL(Token.LC); Node body = transform(loop.getBody()); decompiler.addEOL(Token.RC); return createFor(loop, init, test, incr, body); } finally { currentScope = savedScope; } } private Node transformFunction(FunctionNode fn) { int functionType = fn.getFunctionType(); int start = decompiler.markFunctionStart(functionType); Node mexpr = decompileFunctionHeader(fn); int index = currentScriptOrFn.addFunction(fn); PerFunctionVariables savedVars = new PerFunctionVariables(fn); try { // If we start needing to record much more codegen metadata during // function parsing, we should lump it all into a helper class. Node destructuring = (Node)fn.getProp(Node.DESTRUCTURING_PARAMS); fn.removeProp(Node.DESTRUCTURING_PARAMS); int lineno = fn.getBody().getLineno(); ++nestingOfFunction; // only for body, not params Node body = transform(fn.getBody()); if (!fn.isExpressionClosure()) { decompiler.addToken(Token.RC); } fn.setEncodedSourceBounds(start, decompiler.markFunctionEnd(start)); if (functionType != FunctionNode.FUNCTION_EXPRESSION && !fn.isExpressionClosure()) { // Add EOL only if function is not part of expression // since it gets SEMI + EOL from Statement in that case decompiler.addToken(Token.EOL); } if (destructuring != null) { body.addChildToFront(new Node(Token.EXPR_VOID, destructuring, lineno)); } int syntheticType = fn.getFunctionType(); Node pn = initFunction(fn, index, body, syntheticType); if (mexpr != null) { pn = createAssignment(Token.ASSIGN, mexpr, pn); if (syntheticType != FunctionNode.FUNCTION_EXPRESSION) { pn = createExprStatementNoReturn(pn, fn.getLineno()); } } return pn; } finally { --nestingOfFunction; savedVars.restore(); } } private Node transformFunctionCall(FunctionCall node) { Node call = createCallOrNew(Token.CALL, transform(node.getTarget())); call.setLineno(node.getLineno()); decompiler.addToken(Token.LP); List args = node.getArguments(); for (int i = 0; i < args.size(); i++) { AstNode arg = args.get(i); call.addChildToBack(transform(arg)); if (i < args.size() - 1) { decompiler.addToken(Token.COMMA); } } decompiler.addToken(Token.RP); return call; } private Node transformGenExpr(GeneratorExpression node) { Node pn; FunctionNode fn = new FunctionNode(); fn.setSourceName(currentScriptOrFn.getNextTempName()); fn.setIsGenerator(); fn.setFunctionType(FunctionNode.FUNCTION_EXPRESSION); fn.setRequiresActivation(); int functionType = fn.getFunctionType(); int start = decompiler.markFunctionStart(functionType); Node mexpr = decompileFunctionHeader(fn); int index = currentScriptOrFn.addFunction(fn); PerFunctionVariables savedVars = new PerFunctionVariables(fn); try { // If we start needing to record much more codegen metadata during // function parsing, we should lump it all into a helper class. Node destructuring = (Node)fn.getProp(Node.DESTRUCTURING_PARAMS); fn.removeProp(Node.DESTRUCTURING_PARAMS); int lineno = node.lineno; ++nestingOfFunction; // only for body, not params Node body = genExprTransformHelper(node); if (!fn.isExpressionClosure()) { decompiler.addToken(Token.RC); } fn.setEncodedSourceBounds(start, decompiler.markFunctionEnd(start)); if (functionType != FunctionNode.FUNCTION_EXPRESSION && !fn.isExpressionClosure()) { // Add EOL only if function is not part of expression // since it gets SEMI + EOL from Statement in that case decompiler.addToken(Token.EOL); } if (destructuring != null) { body.addChildToFront(new Node(Token.EXPR_VOID, destructuring, lineno)); } int syntheticType = fn.getFunctionType(); pn = initFunction(fn, index, body, syntheticType); if (mexpr != null) { pn = createAssignment(Token.ASSIGN, mexpr, pn); if (syntheticType != FunctionNode.FUNCTION_EXPRESSION) { pn = createExprStatementNoReturn(pn, fn.getLineno()); } } } finally { --nestingOfFunction; savedVars.restore(); } Node call = createCallOrNew(Token.CALL, pn); call.setLineno(node.getLineno()); decompiler.addToken(Token.LP); decompiler.addToken(Token.RP); return call; } private Node genExprTransformHelper(GeneratorExpression node) { decompiler.addToken(Token.LP); int lineno = node.getLineno(); Node expr = transform(node.getResult()); List loops = node.getLoops(); int numLoops = loops.size(); // Walk through loops, collecting and defining their iterator symbols. Node[] iterators = new Node[numLoops]; Node[] iteratedObjs = new Node[numLoops]; for (int i = 0; i < numLoops; i++) { GeneratorExpressionLoop acl = loops.get(i); decompiler.addName(" "); decompiler.addToken(Token.FOR); decompiler.addToken(Token.LP); AstNode iter = acl.getIterator(); String name = null; if (iter.getType() == Token.NAME) { name = iter.getString(); decompiler.addName(name); } else { // destructuring assignment decompile(iter); name = currentScriptOrFn.getNextTempName(); defineSymbol(Token.LP, name, false); expr = createBinary(Token.COMMA, createAssignment(Token.ASSIGN, iter, createName(name)), expr); } Node init = createName(name); // Define as a let since we want the scope of the variable to // be restricted to the array comprehension defineSymbol(Token.LET, name, false); iterators[i] = init; decompiler.addToken(Token.IN); iteratedObjs[i] = transform(acl.getIteratedObject()); decompiler.addToken(Token.RP); } // generate code for tmpArray.push(body) Node yield = new Node(Token.YIELD, expr, node.getLineno()); Node body = new Node(Token.EXPR_VOID, yield, lineno); if (node.getFilter() != null) { decompiler.addName(" "); decompiler.addToken(Token.IF); decompiler.addToken(Token.LP); body = createIf(transform(node.getFilter()), body, null, lineno); decompiler.addToken(Token.RP); } // Now walk loops in reverse to build up the body statement. int pushed = 0; try { for (int i = numLoops-1; i >= 0; i--) { GeneratorExpressionLoop acl = loops.get(i); Scope loop = createLoopNode(null, // no label acl.getLineno()); pushScope(loop); pushed++; body = createForIn(Token.LET, loop, iterators[i], iteratedObjs[i], body, acl.isForEach()); } } finally { for (int i = 0; i < pushed; i++) { popScope(); } } decompiler.addToken(Token.RP); return body; } private Node transformIf(IfStatement n) { decompiler.addToken(Token.IF); decompiler.addToken(Token.LP); Node cond = transform(n.getCondition()); decompiler.addToken(Token.RP); decompiler.addEOL(Token.LC); Node ifTrue = transform(n.getThenPart()); Node ifFalse = null; if (n.getElsePart() != null) { decompiler.addToken(Token.RC); decompiler.addToken(Token.ELSE); decompiler.addEOL(Token.LC); ifFalse = transform(n.getElsePart()); } decompiler.addEOL(Token.RC); return createIf(cond, ifTrue, ifFalse, n.getLineno()); } private Node transformInfix(InfixExpression node) { Node left = transform(node.getLeft()); decompiler.addToken(node.getType()); Node right = transform(node.getRight()); if (node instanceof XmlDotQuery) { decompiler.addToken(Token.RP); } return createBinary(node.getType(), left, right); } private Node transformLabeledStatement(LabeledStatement ls) { for (Label lb : ls.getLabels()) { decompiler.addName(lb.getName()); decompiler.addEOL(Token.COLON); } Label label = ls.getFirstLabel(); Node statement = transform(ls.getStatement()); // Make a target and put it _after_ the statement node. Add in the // LABEL node, so breaks get the right target. Node breakTarget = Node.newTarget(); Node block = new Node(Token.BLOCK, label, statement, breakTarget); label.target = breakTarget; return block; } private Node transformLetNode(LetNode node) { pushScope(node); try { decompiler.addToken(Token.LET); decompiler.addToken(Token.LP); Node vars = transformVariableInitializers(node.getVariables()); decompiler.addToken(Token.RP); node.addChildToBack(vars); boolean letExpr = node.getType() == Token.LETEXPR; if (node.getBody() != null) { if (letExpr) { decompiler.addName(" "); } else { decompiler.addEOL(Token.LC); } node.addChildToBack(transform(node.getBody())); if (!letExpr) { decompiler.addEOL(Token.RC); } } return node; } finally { popScope(); } } private Node transformLiteral(AstNode node) { decompiler.addToken(node.getType()); return node; } private Node transformName(Name node) { decompiler.addName(node.getIdentifier()); return node; } private Node transformNewExpr(NewExpression node) { decompiler.addToken(Token.NEW); Node nx = createCallOrNew(Token.NEW, transform(node.getTarget())); nx.setLineno(node.getLineno()); List args = node.getArguments(); decompiler.addToken(Token.LP); for (int i = 0; i < args.size(); i++) { AstNode arg = args.get(i); nx.addChildToBack(transform(arg)); if (i < args.size() - 1) { decompiler.addToken(Token.COMMA); } } decompiler.addToken(Token.RP); if (node.getInitializer() != null) { nx.addChildToBack(transformObjectLiteral(node.getInitializer())); } return nx; } private Node transformNumber(NumberLiteral node) { decompiler.addNumber(node.getNumber()); return node; } private Node transformObjectLiteral(ObjectLiteral node) { if (node.isDestructuring()) { return node; } // createObjectLiteral rewrites its argument as object // creation plus object property entries, so later compiler // stages don't need to know about object literals. decompiler.addToken(Token.LC); List elems = node.getElements(); Node object = new Node(Token.OBJECTLIT); Object[] properties; if (elems.isEmpty()) { properties = ScriptRuntime.emptyArgs; } else { int size = elems.size(), i = 0; properties = new Object[size]; for (ObjectProperty prop : elems) { if (prop.isGetter()) { decompiler.addToken(Token.GET); } else if (prop.isSetter()) { decompiler.addToken(Token.SET); } properties[i++] = getPropKey(prop.getLeft()); // OBJECTLIT is used as ':' in object literal for // decompilation to solve spacing ambiguity. if (!(prop.isGetter() || prop.isSetter())) { decompiler.addToken(Token.OBJECTLIT); } Node right = transform(prop.getRight()); if (prop.isGetter()) { right = createUnary(Token.GET, right); } else if (prop.isSetter()) { right = createUnary(Token.SET, right); } object.addChildToBack(right); if (i < size) { decompiler.addToken(Token.COMMA); } } } decompiler.addToken(Token.RC); object.putProp(Node.OBJECT_IDS_PROP, properties); return object; } private Object getPropKey(Node id) { Object key; if (id instanceof Name) { String s = ((Name)id).getIdentifier(); decompiler.addName(s); key = ScriptRuntime.getIndexObject(s); } else if (id instanceof StringLiteral) { String s = ((StringLiteral)id).getValue(); decompiler.addString(s); key = ScriptRuntime.getIndexObject(s); } else if (id instanceof NumberLiteral) { double n = ((NumberLiteral)id).getNumber(); decompiler.addNumber(n); key = ScriptRuntime.getIndexObject(n); } else { throw Kit.codeBug(); } return key; } private Node transformParenExpr(ParenthesizedExpression node) { AstNode expr = node.getExpression(); decompiler.addToken(Token.LP); int count = 1; while (expr instanceof ParenthesizedExpression) { decompiler.addToken(Token.LP); count++; expr = ((ParenthesizedExpression)expr).getExpression(); } Node result = transform(expr); for (int i = 0; i < count; i++) { decompiler.addToken(Token.RP); } result.putProp(Node.PARENTHESIZED_PROP, Boolean.TRUE); return result; } private Node transformPropertyGet(PropertyGet node) { Node target = transform(node.getTarget()); String name = node.getProperty().getIdentifier(); decompiler.addToken(Token.DOT); decompiler.addName(name); return createPropertyGet(target, null, name, 0); } private Node transformRegExp(RegExpLiteral node) { decompiler.addRegexp(node.getValue(), node.getFlags()); currentScriptOrFn.addRegExp(node); return node; } private Node transformReturn(ReturnStatement node) { boolean expClosure = Boolean.TRUE.equals(node.getProp(Node.EXPRESSION_CLOSURE_PROP)); if (expClosure) { decompiler.addName(" "); } else { decompiler.addToken(Token.RETURN); } AstNode rv = node.getReturnValue(); Node value = rv == null ? null : transform(rv); if (!expClosure) decompiler.addEOL(Token.SEMI); return rv == null ? new Node(Token.RETURN, node.getLineno()) : new Node(Token.RETURN, value, node.getLineno()); } private Node transformScript(ScriptNode node) { decompiler.addToken(Token.SCRIPT); if (currentScope != null) Kit.codeBug(); currentScope = node; Node body = new Node(Token.BLOCK); for (Node kid : node) { body.addChildToBack(transform((AstNode)kid)); } node.removeChildren(); Node children = body.getFirstChild(); if (children != null) { node.addChildrenToBack(children); } return node; } private Node transformString(StringLiteral node) { decompiler.addString(node.getValue()); return Node.newString(node.getValue()); } private Node transformSwitch(SwitchStatement node) { // The switch will be rewritten from: // // switch (expr) { // case test1: statements1; // ... // default: statementsDefault; // ... // case testN: statementsN; // } // // to: // // { // switch (expr) { // case test1: goto label1; // ... // case testN: goto labelN; // } // goto labelDefault; // label1: // statements1; // ... // labelDefault: // statementsDefault; // ... // labelN: // statementsN; // breakLabel: // } // // where inside switch each "break;" without label will be replaced // by "goto breakLabel". // // If the original switch does not have the default label, then // after the switch he transformed code would contain this goto: // goto breakLabel; // instead of: // goto labelDefault; decompiler.addToken(Token.SWITCH); decompiler.addToken(Token.LP); Node switchExpr = transform(node.getExpression()); decompiler.addToken(Token.RP); node.addChildToBack(switchExpr); Node block = new Node(Token.BLOCK, node, node.getLineno()); decompiler.addEOL(Token.LC); for (SwitchCase sc : node.getCases()) { AstNode expr = sc.getExpression(); Node caseExpr = null; if (expr != null) { decompiler.addToken(Token.CASE); caseExpr = transform(expr); } else { decompiler.addToken(Token.DEFAULT); } decompiler.addEOL(Token.COLON); List stmts = sc.getStatements(); Node body = new Block(); if (stmts != null) { for (AstNode kid : stmts) { body.addChildToBack(transform(kid)); } } addSwitchCase(block, caseExpr, body); } decompiler.addEOL(Token.RC); closeSwitch(block); return block; } private Node transformThrow(ThrowStatement node) { decompiler.addToken(Token.THROW); Node value = transform(node.getExpression()); decompiler.addEOL(Token.SEMI); return new Node(Token.THROW, value, node.getLineno()); } private Node transformTry(TryStatement node) { decompiler.addToken(Token.TRY); decompiler.addEOL(Token.LC); Node tryBlock = transform(node.getTryBlock()); decompiler.addEOL(Token.RC); Node catchBlocks = new Block(); for (CatchClause cc : node.getCatchClauses()) { decompiler.addToken(Token.CATCH); decompiler.addToken(Token.LP); String varName = cc.getVarName().getIdentifier(); decompiler.addName(varName); Node catchCond = null; AstNode ccc = cc.getCatchCondition(); if (ccc != null) { decompiler.addName(" "); decompiler.addToken(Token.IF); catchCond = transform(ccc); } else { catchCond = new EmptyExpression(); } decompiler.addToken(Token.RP); decompiler.addEOL(Token.LC); Node body = transform(cc.getBody()); decompiler.addEOL(Token.RC); catchBlocks.addChildToBack(createCatch(varName, catchCond, body, cc.getLineno())); } Node finallyBlock = null; if (node.getFinallyBlock() != null) { decompiler.addToken(Token.FINALLY); decompiler.addEOL(Token.LC); finallyBlock = transform(node.getFinallyBlock()); decompiler.addEOL(Token.RC); } return createTryCatchFinally(tryBlock, catchBlocks, finallyBlock, node.getLineno()); } private Node transformUnary(UnaryExpression node) { int type = node.getType(); if (type == Token.DEFAULTNAMESPACE) { return transformDefaultXmlNamepace(node); } if (node.isPrefix()) { decompiler.addToken(type); } Node child = transform(node.getOperand()); if (node.isPostfix()) { decompiler.addToken(type); } if (type == Token.INC || type == Token.DEC) { return createIncDec(type, node.isPostfix(), child); } return createUnary(type, child); } private Node transformVariables(VariableDeclaration node) { decompiler.addToken(node.getType()); transformVariableInitializers(node); // Might be most robust to have parser record whether it was // a variable declaration statement, possibly as a node property. AstNode parent = node.getParent(); if (!(parent instanceof Loop) && !(parent instanceof LetNode)) { decompiler.addEOL(Token.SEMI); } return node; } private Node transformVariableInitializers(VariableDeclaration node) { List vars = node.getVariables(); int size = vars.size(), i = 0; for (VariableInitializer var : vars) { AstNode target = var.getTarget(); AstNode init = var.getInitializer(); Node left = null; if (var.isDestructuring()) { decompile(target); // decompile but don't transform left = target; } else { left = transform(target); } Node right = null; if (init != null) { decompiler.addToken(Token.ASSIGN); right = transform(init); } if (var.isDestructuring()) { if (right == null) { // TODO: should this ever happen? node.addChildToBack(left); } else { Node d = createDestructuringAssignment(node.getType(), left, right); node.addChildToBack(d); } } else { if (right != null) { left.addChildToBack(right); } node.addChildToBack(left); } if (i++ < size-1) { decompiler.addToken(Token.COMMA); } } return node; } private Node transformWhileLoop(WhileLoop loop) { decompiler.addToken(Token.WHILE); loop.setType(Token.LOOP); pushScope(loop); try { decompiler.addToken(Token.LP); Node cond = transform(loop.getCondition()); decompiler.addToken(Token.RP); decompiler.addEOL(Token.LC); Node body = transform(loop.getBody()); decompiler.addEOL(Token.RC); return createLoop(loop, LOOP_WHILE, body, cond, null, null); } finally { popScope(); } } private Node transformWith(WithStatement node) { decompiler.addToken(Token.WITH); decompiler.addToken(Token.LP); Node expr = transform(node.getExpression()); decompiler.addToken(Token.RP); decompiler.addEOL(Token.LC); Node stmt = transform(node.getStatement()); decompiler.addEOL(Token.RC); return createWith(expr, stmt, node.getLineno()); } private Node transformYield(Yield node) { decompiler.addToken(Token.YIELD); Node kid = node.getValue() == null ? null : transform(node.getValue()); if (kid != null) return new Node(Token.YIELD, kid, node.getLineno()); else return new Node(Token.YIELD, node.getLineno()); } private Node transformXmlLiteral(XmlLiteral node) { // a literal like {bar} is rewritten as // new XML("" + bar + ""); Node pnXML = new Node(Token.NEW, node.getLineno()); List frags = node.getFragments(); XmlString first = (XmlString)frags.get(0); boolean anon = first.getXml().trim().startsWith("<>"); pnXML.addChildToBack(createName(anon ? "XMLList" : "XML")); Node pn = null; for (XmlFragment frag : frags) { if (frag instanceof XmlString) { String xml = ((XmlString)frag).getXml(); decompiler.addName(xml); if (pn == null) { pn = createString(xml); } else { pn = createBinary(Token.ADD, pn, createString(xml)); } } else { XmlExpression xexpr = (XmlExpression)frag; boolean isXmlAttr = xexpr.isXmlAttribute(); Node expr; decompiler.addToken(Token.LC); if (xexpr.getExpression() instanceof EmptyExpression) { expr = createString(""); } else { expr = transform(xexpr.getExpression()); } decompiler.addToken(Token.RC); if (isXmlAttr) { // Need to put the result in double quotes expr = createUnary(Token.ESCXMLATTR, expr); Node prepend = createBinary(Token.ADD, createString("\""), expr); expr = createBinary(Token.ADD, prepend, createString("\"")); } else { expr = createUnary(Token.ESCXMLTEXT, expr); } pn = createBinary(Token.ADD, pn, expr); } } pnXML.addChildToBack(pn); return pnXML; } private Node transformXmlMemberGet(XmlMemberGet node) { XmlRef ref = node.getMemberRef(); Node pn = transform(node.getLeft()); int flags = ref.isAttributeAccess() ? Node.ATTRIBUTE_FLAG : 0; if (node.getType() == Token.DOTDOT) { flags |= Node.DESCENDANTS_FLAG; decompiler.addToken(Token.DOTDOT); } else { decompiler.addToken(Token.DOT); } return transformXmlRef(pn, ref, flags); } // We get here if we weren't a child of a . or .. infix node private Node transformXmlRef(XmlRef node) { int memberTypeFlags = node.isAttributeAccess() ? Node.ATTRIBUTE_FLAG : 0; return transformXmlRef(null, node, memberTypeFlags); } private Node transformXmlRef(Node pn, XmlRef node, int memberTypeFlags) { if ((memberTypeFlags & Node.ATTRIBUTE_FLAG) != 0) decompiler.addToken(Token.XMLATTR); Name namespace = node.getNamespace(); String ns = namespace != null ? namespace.getIdentifier() : null; if (ns != null) { decompiler.addName(ns); decompiler.addToken(Token.COLONCOLON); } if (node instanceof XmlPropRef) { String name = ((XmlPropRef)node).getPropName().getIdentifier(); decompiler.addName(name); return createPropertyGet(pn, ns, name, memberTypeFlags); } else { decompiler.addToken(Token.LB); Node expr = transform(((XmlElemRef)node).getExpression()); decompiler.addToken(Token.RB); return createElementGet(pn, ns, expr, memberTypeFlags); } } private Node transformDefaultXmlNamepace(UnaryExpression node) { decompiler.addToken(Token.DEFAULT); decompiler.addName(" xml"); decompiler.addName(" namespace"); decompiler.addToken(Token.ASSIGN); Node child = transform(node.getOperand()); return createUnary(Token.DEFAULTNAMESPACE, child); } /** * If caseExpression argument is null it indicates a default label. */ private void addSwitchCase(Node switchBlock, Node caseExpression, Node statements) { if (switchBlock.getType() != Token.BLOCK) throw Kit.codeBug(); Jump switchNode = (Jump)switchBlock.getFirstChild(); if (switchNode.getType() != Token.SWITCH) throw Kit.codeBug(); Node gotoTarget = Node.newTarget(); if (caseExpression != null) { Jump caseNode = new Jump(Token.CASE, caseExpression); caseNode.target = gotoTarget; switchNode.addChildToBack(caseNode); } else { switchNode.setDefault(gotoTarget); } switchBlock.addChildToBack(gotoTarget); switchBlock.addChildToBack(statements); } private void closeSwitch(Node switchBlock) { if (switchBlock.getType() != Token.BLOCK) throw Kit.codeBug(); Jump switchNode = (Jump)switchBlock.getFirstChild(); if (switchNode.getType() != Token.SWITCH) throw Kit.codeBug(); Node switchBreakTarget = Node.newTarget(); // switchNode.target is only used by NodeTransformer // to detect switch end switchNode.target = switchBreakTarget; Node defaultTarget = switchNode.getDefault(); if (defaultTarget == null) { defaultTarget = switchBreakTarget; } switchBlock.addChildAfter(makeJump(Token.GOTO, defaultTarget), switchNode); switchBlock.addChildToBack(switchBreakTarget); } private Node createExprStatementNoReturn(Node expr, int lineno) { return new Node(Token.EXPR_VOID, expr, lineno); } private Node createString(String string) { return Node.newString(string); } /** * Catch clause of try/catch/finally * @param varName the name of the variable to bind to the exception * @param catchCond the condition under which to catch the exception. * May be null if no condition is given. * @param stmts the statements in the catch clause * @param lineno the starting line number of the catch clause */ private Node createCatch(String varName, Node catchCond, Node stmts, int lineno) { if (catchCond == null) { catchCond = new Node(Token.EMPTY); } return new Node(Token.CATCH, createName(varName), catchCond, stmts, lineno); } private Node initFunction(FunctionNode fnNode, int functionIndex, Node statements, int functionType) { fnNode.setFunctionType(functionType); fnNode.addChildToBack(statements); int functionCount = fnNode.getFunctionCount(); if (functionCount != 0) { // Functions containing other functions require activation objects fnNode.setRequiresActivation(); } if (functionType == FunctionNode.FUNCTION_EXPRESSION) { Name name = fnNode.getFunctionName(); if (name != null && name.length() != 0 && fnNode.getSymbol(name.getIdentifier()) == null) { // A function expression needs to have its name as a // variable (if it isn't already allocated as a variable). // See ECMA Ch. 13. We add code to the beginning of the // function to initialize a local variable of the // function's name to the function value, but only if the // function doesn't already define a formal parameter, var, // or nested function with the same name. fnNode.putSymbol(new Symbol(Token.FUNCTION, name.getIdentifier())); Node setFn = new Node(Token.EXPR_VOID, new Node(Token.SETNAME, Node.newString(Token.BINDNAME, name.getIdentifier()), new Node(Token.THISFN))); statements.addChildrenToFront(setFn); } } // Add return to end if needed. Node lastStmt = statements.getLastChild(); if (lastStmt == null || lastStmt.getType() != Token.RETURN) { statements.addChildToBack(new Node(Token.RETURN)); } Node result = Node.newString(Token.FUNCTION, fnNode.getName()); result.putIntProp(Node.FUNCTION_PROP, functionIndex); return result; } /** * Create loop node. The code generator will later call * createWhile|createDoWhile|createFor|createForIn * to finish loop generation. */ private Scope createLoopNode(Node loopLabel, int lineno) { Scope result = createScopeNode(Token.LOOP, lineno); if (loopLabel != null) { ((Jump)loopLabel).setLoop(result); } return result; } private Node createFor(Scope loop, Node init, Node test, Node incr, Node body) { if (init.getType() == Token.LET) { // rewrite "for (let i=s; i < N; i++)..." as // "let (i=s) { for (; i < N; i++)..." so that "s" is evaluated // outside the scope of the for. Scope let = Scope.splitScope(loop); let.setType(Token.LET); let.addChildrenToBack(init); let.addChildToBack(createLoop(loop, LOOP_FOR, body, test, new Node(Token.EMPTY), incr)); return let; } return createLoop(loop, LOOP_FOR, body, test, init, incr); } private Node createLoop(Jump loop, int loopType, Node body, Node cond, Node init, Node incr) { Node bodyTarget = Node.newTarget(); Node condTarget = Node.newTarget(); if (loopType == LOOP_FOR && cond.getType() == Token.EMPTY) { cond = new Node(Token.TRUE); } Jump IFEQ = new Jump(Token.IFEQ, cond); IFEQ.target = bodyTarget; Node breakTarget = Node.newTarget(); loop.addChildToBack(bodyTarget); loop.addChildrenToBack(body); if (loopType == LOOP_WHILE || loopType == LOOP_FOR) { // propagate lineno to condition loop.addChildrenToBack(new Node(Token.EMPTY, loop.getLineno())); } loop.addChildToBack(condTarget); loop.addChildToBack(IFEQ); loop.addChildToBack(breakTarget); loop.target = breakTarget; Node continueTarget = condTarget; if (loopType == LOOP_WHILE || loopType == LOOP_FOR) { // Just add a GOTO to the condition in the do..while loop.addChildToFront(makeJump(Token.GOTO, condTarget)); if (loopType == LOOP_FOR) { int initType = init.getType(); if (initType != Token.EMPTY) { if (initType != Token.VAR && initType != Token.LET) { init = new Node(Token.EXPR_VOID, init); } loop.addChildToFront(init); } Node incrTarget = Node.newTarget(); loop.addChildAfter(incrTarget, body); if (incr.getType() != Token.EMPTY) { incr = new Node(Token.EXPR_VOID, incr); loop.addChildAfter(incr, incrTarget); } continueTarget = incrTarget; } } loop.setContinue(continueTarget); return loop; } /** * Generate IR for a for..in loop. */ private Node createForIn(int declType, Node loop, Node lhs, Node obj, Node body, boolean isForEach) { int destructuring = -1; int destructuringLen = 0; Node lvalue; int type = lhs.getType(); if (type == Token.VAR || type == Token.LET) { Node kid = lhs.getLastChild(); int kidType = kid.getType(); if (kidType == Token.ARRAYLIT || kidType == Token.OBJECTLIT) { type = destructuring = kidType; lvalue = kid; destructuringLen = 0; if (kid instanceof ArrayLiteral) destructuringLen = ((ArrayLiteral) kid).getDestructuringLength(); } else if (kidType == Token.NAME) { lvalue = Node.newString(Token.NAME, kid.getString()); } else { reportError("msg.bad.for.in.lhs"); return null; } } else if (type == Token.ARRAYLIT || type == Token.OBJECTLIT) { destructuring = type; lvalue = lhs; destructuringLen = 0; if (lhs instanceof ArrayLiteral) destructuringLen = ((ArrayLiteral) lhs).getDestructuringLength(); } else { lvalue = makeReference(lhs); if (lvalue == null) { reportError("msg.bad.for.in.lhs"); return null; } } Node localBlock = new Node(Token.LOCAL_BLOCK); int initType = isForEach ? Token.ENUM_INIT_VALUES : (destructuring != -1 ? Token.ENUM_INIT_ARRAY : Token.ENUM_INIT_KEYS); Node init = new Node(initType, obj); init.putProp(Node.LOCAL_BLOCK_PROP, localBlock); Node cond = new Node(Token.ENUM_NEXT); cond.putProp(Node.LOCAL_BLOCK_PROP, localBlock); Node id = new Node(Token.ENUM_ID); id.putProp(Node.LOCAL_BLOCK_PROP, localBlock); Node newBody = new Node(Token.BLOCK); Node assign; if (destructuring != -1) { assign = createDestructuringAssignment(declType, lvalue, id); if (!isForEach && (destructuring == Token.OBJECTLIT || destructuringLen != 2)) { // destructuring assignment is only allowed in for..each or // with an array type of length 2 (to hold key and value) reportError("msg.bad.for.in.destruct"); } } else { assign = simpleAssignment(lvalue, id); } newBody.addChildToBack(new Node(Token.EXPR_VOID, assign)); newBody.addChildToBack(body); loop = createLoop((Jump)loop, LOOP_WHILE, newBody, cond, null, null); loop.addChildToFront(init); if (type == Token.VAR || type == Token.LET) loop.addChildToFront(lhs); localBlock.addChildToBack(loop); return localBlock; } /** * Try/Catch/Finally * * The IRFactory tries to express as much as possible in the tree; * the responsibilities remaining for Codegen are to add the Java * handlers: (Either (but not both) of TARGET and FINALLY might not * be defined) * * - a catch handler for javascript exceptions that unwraps the * exception onto the stack and GOTOes to the catch target * * - a finally handler * * ... and a goto to GOTO around these handlers. */ private Node createTryCatchFinally(Node tryBlock, Node catchBlocks, Node finallyBlock, int lineno) { boolean hasFinally = (finallyBlock != null) && (finallyBlock.getType() != Token.BLOCK || finallyBlock.hasChildren()); // short circuit if (tryBlock.getType() == Token.BLOCK && !tryBlock.hasChildren() && !hasFinally) { return tryBlock; } boolean hasCatch = catchBlocks.hasChildren(); // short circuit if (!hasFinally && !hasCatch) { // bc finally might be an empty block... return tryBlock; } Node handlerBlock = new Node(Token.LOCAL_BLOCK); Jump pn = new Jump(Token.TRY, tryBlock, lineno); pn.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock); if (hasCatch) { // jump around catch code Node endCatch = Node.newTarget(); pn.addChildToBack(makeJump(Token.GOTO, endCatch)); // make a TARGET for the catch that the tcf node knows about Node catchTarget = Node.newTarget(); pn.target = catchTarget; // mark it pn.addChildToBack(catchTarget); // // Given // // try { // tryBlock; // } catch (e if condition1) { // something1; // ... // // } catch (e if conditionN) { // somethingN; // } catch (e) { // somethingDefault; // } // // rewrite as // // try { // tryBlock; // goto after_catch: // } catch (x) { // with (newCatchScope(e, x)) { // if (condition1) { // something1; // goto after_catch; // } // } // ... // with (newCatchScope(e, x)) { // if (conditionN) { // somethingN; // goto after_catch; // } // } // with (newCatchScope(e, x)) { // somethingDefault; // goto after_catch; // } // } // after_catch: // // If there is no default catch, then the last with block // arround "somethingDefault;" is replaced by "rethrow;" // It is assumed that catch handler generation will store // exeception object in handlerBlock register // Block with local for exception scope objects Node catchScopeBlock = new Node(Token.LOCAL_BLOCK); // expects catchblocks children to be (cond block) pairs. Node cb = catchBlocks.getFirstChild(); boolean hasDefault = false; int scopeIndex = 0; while (cb != null) { int catchLineNo = cb.getLineno(); Node name = cb.getFirstChild(); Node cond = name.getNext(); Node catchStatement = cond.getNext(); cb.removeChild(name); cb.removeChild(cond); cb.removeChild(catchStatement); // Add goto to the catch statement to jump out of catch // but prefix it with LEAVEWITH since try..catch produces // "with"code in order to limit the scope of the exception // object. catchStatement.addChildToBack(new Node(Token.LEAVEWITH)); catchStatement.addChildToBack(makeJump(Token.GOTO, endCatch)); // Create condition "if" when present Node condStmt; if (cond.getType() == Token.EMPTY) { condStmt = catchStatement; hasDefault = true; } else { condStmt = createIf(cond, catchStatement, null, catchLineNo); } // Generate code to create the scope object and store // it in catchScopeBlock register Node catchScope = new Node(Token.CATCH_SCOPE, name, createUseLocal(handlerBlock)); catchScope.putProp(Node.LOCAL_BLOCK_PROP, catchScopeBlock); catchScope.putIntProp(Node.CATCH_SCOPE_PROP, scopeIndex); catchScopeBlock.addChildToBack(catchScope); // Add with statement based on catch scope object catchScopeBlock.addChildToBack( createWith(createUseLocal(catchScopeBlock), condStmt, catchLineNo)); // move to next cb cb = cb.getNext(); ++scopeIndex; } pn.addChildToBack(catchScopeBlock); if (!hasDefault) { // Generate code to rethrow if no catch clause was executed Node rethrow = new Node(Token.RETHROW); rethrow.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock); pn.addChildToBack(rethrow); } pn.addChildToBack(endCatch); } if (hasFinally) { Node finallyTarget = Node.newTarget(); pn.setFinally(finallyTarget); // add jsr finally to the try block pn.addChildToBack(makeJump(Token.JSR, finallyTarget)); // jump around finally code Node finallyEnd = Node.newTarget(); pn.addChildToBack(makeJump(Token.GOTO, finallyEnd)); pn.addChildToBack(finallyTarget); Node fBlock = new Node(Token.FINALLY, finallyBlock); fBlock.putProp(Node.LOCAL_BLOCK_PROP, handlerBlock); pn.addChildToBack(fBlock); pn.addChildToBack(finallyEnd); } handlerBlock.addChildToBack(pn); return handlerBlock; } private Node createWith(Node obj, Node body, int lineno) { setRequiresActivation(); Node result = new Node(Token.BLOCK, lineno); result.addChildToBack(new Node(Token.ENTERWITH, obj)); Node bodyNode = new Node(Token.WITH, body, lineno); result.addChildrenToBack(bodyNode); result.addChildToBack(new Node(Token.LEAVEWITH)); return result; } private Node createIf(Node cond, Node ifTrue, Node ifFalse, int lineno) { int condStatus = isAlwaysDefinedBoolean(cond); if (condStatus == ALWAYS_TRUE_BOOLEAN) { return ifTrue; } else if (condStatus == ALWAYS_FALSE_BOOLEAN) { if (ifFalse != null) { return ifFalse; } // Replace if (false) xxx by empty block return new Node(Token.BLOCK, lineno); } Node result = new Node(Token.BLOCK, lineno); Node ifNotTarget = Node.newTarget(); Jump IFNE = new Jump(Token.IFNE, cond); IFNE.target = ifNotTarget; result.addChildToBack(IFNE); result.addChildrenToBack(ifTrue); if (ifFalse != null) { Node endTarget = Node.newTarget(); result.addChildToBack(makeJump(Token.GOTO, endTarget)); result.addChildToBack(ifNotTarget); result.addChildrenToBack(ifFalse); result.addChildToBack(endTarget); } else { result.addChildToBack(ifNotTarget); } return result; } private Node createCondExpr(Node cond, Node ifTrue, Node ifFalse) { int condStatus = isAlwaysDefinedBoolean(cond); if (condStatus == ALWAYS_TRUE_BOOLEAN) { return ifTrue; } else if (condStatus == ALWAYS_FALSE_BOOLEAN) { return ifFalse; } return new Node(Token.HOOK, cond, ifTrue, ifFalse); } private Node createUnary(int nodeType, Node child) { int childType = child.getType(); switch (nodeType) { case Token.DELPROP: { Node n; if (childType == Token.NAME) { // Transform Delete(Name "a") // to Delete(Bind("a"), String("a")) child.setType(Token.BINDNAME); Node left = child; Node right = Node.newString(child.getString()); n = new Node(nodeType, left, right); } else if (childType == Token.GETPROP || childType == Token.GETELEM) { Node left = child.getFirstChild(); Node right = child.getLastChild(); child.removeChild(left); child.removeChild(right); n = new Node(nodeType, left, right); } else if (childType == Token.GET_REF) { Node ref = child.getFirstChild(); child.removeChild(ref); n = new Node(Token.DEL_REF, ref); } else { // Always evaluate delete operand, see ES5 11.4.1 & bug #726121 n = new Node(nodeType, new Node(Token.TRUE), child); } return n; } case Token.TYPEOF: if (childType == Token.NAME) { child.setType(Token.TYPEOFNAME); return child; } break; case Token.BITNOT: if (childType == Token.NUMBER) { int value = ScriptRuntime.toInt32(child.getDouble()); child.setDouble(~value); return child; } break; case Token.NEG: if (childType == Token.NUMBER) { child.setDouble(-child.getDouble()); return child; } break; case Token.NOT: { int status = isAlwaysDefinedBoolean(child); if (status != 0) { int type; if (status == ALWAYS_TRUE_BOOLEAN) { type = Token.FALSE; } else { type = Token.TRUE; } if (childType == Token.TRUE || childType == Token.FALSE) { child.setType(type); return child; } return new Node(type); } break; } } return new Node(nodeType, child); } private Node createCallOrNew(int nodeType, Node child) { int type = Node.NON_SPECIALCALL; if (child.getType() == Token.NAME) { String name = child.getString(); if (name.equals("eval")) { type = Node.SPECIALCALL_EVAL; } else if (name.equals("With")) { type = Node.SPECIALCALL_WITH; } } else if (child.getType() == Token.GETPROP) { String name = child.getLastChild().getString(); if (name.equals("eval")) { type = Node.SPECIALCALL_EVAL; } } Node node = new Node(nodeType, child); if (type != Node.NON_SPECIALCALL) { // Calls to these functions require activation objects. setRequiresActivation(); node.putIntProp(Node.SPECIALCALL_PROP, type); } return node; } private Node createIncDec(int nodeType, boolean post, Node child) { child = makeReference(child); int childType = child.getType(); switch (childType) { case Token.NAME: case Token.GETPROP: case Token.GETELEM: case Token.GET_REF: { Node n = new Node(nodeType, child); int incrDecrMask = 0; if (nodeType == Token.DEC) { incrDecrMask |= Node.DECR_FLAG; } if (post) { incrDecrMask |= Node.POST_FLAG; } n.putIntProp(Node.INCRDECR_PROP, incrDecrMask); return n; } } throw Kit.codeBug(); } private Node createPropertyGet(Node target, String namespace, String name, int memberTypeFlags) { if (namespace == null && memberTypeFlags == 0) { if (target == null) { return createName(name); } checkActivationName(name, Token.GETPROP); if (ScriptRuntime.isSpecialProperty(name)) { Node ref = new Node(Token.REF_SPECIAL, target); ref.putProp(Node.NAME_PROP, name); return new Node(Token.GET_REF, ref); } return new Node(Token.GETPROP, target, Node.newString(name)); } Node elem = Node.newString(name); memberTypeFlags |= Node.PROPERTY_FLAG; return createMemberRefGet(target, namespace, elem, memberTypeFlags); } /** * @param target the node before the LB * @param namespace optional namespace * @param elem the node in the brackets * @param memberTypeFlags E4X flags */ private Node createElementGet(Node target, String namespace, Node elem, int memberTypeFlags) { // OPT: could optimize to createPropertyGet // iff elem is string that can not be number if (namespace == null && memberTypeFlags == 0) { // stand-alone [aaa] as primary expression is array literal // declaration and should not come here! if (target == null) throw Kit.codeBug(); return new Node(Token.GETELEM, target, elem); } return createMemberRefGet(target, namespace, elem, memberTypeFlags); } private Node createMemberRefGet(Node target, String namespace, Node elem, int memberTypeFlags) { Node nsNode = null; if (namespace != null) { // See 11.1.2 in ECMA 357 if (namespace.equals("*")) { nsNode = new Node(Token.NULL); } else { nsNode = createName(namespace); } } Node ref; if (target == null) { if (namespace == null) { ref = new Node(Token.REF_NAME, elem); } else { ref = new Node(Token.REF_NS_NAME, nsNode, elem); } } else { if (namespace == null) { ref = new Node(Token.REF_MEMBER, target, elem); } else { ref = new Node(Token.REF_NS_MEMBER, target, nsNode, elem); } } if (memberTypeFlags != 0) { ref.putIntProp(Node.MEMBER_TYPE_PROP, memberTypeFlags); } return new Node(Token.GET_REF, ref); } private Node createBinary(int nodeType, Node left, Node right) { switch (nodeType) { case Token.ADD: // numerical addition and string concatenation if (left.type == Token.STRING) { String s2; if (right.type == Token.STRING) { s2 = right.getString(); } else if (right.type == Token.NUMBER) { s2 = ScriptRuntime.numberToString(right.getDouble(), 10); } else { break; } String s1 = left.getString(); left.setString(s1.concat(s2)); return left; } else if (left.type == Token.NUMBER) { if (right.type == Token.NUMBER) { left.setDouble(left.getDouble() + right.getDouble()); return left; } else if (right.type == Token.STRING) { String s1, s2; s1 = ScriptRuntime.numberToString(left.getDouble(), 10); s2 = right.getString(); right.setString(s1.concat(s2)); return right; } } // can't do anything if we don't know both types - since // 0 + object is supposed to call toString on the object and do // string concantenation rather than addition break; case Token.SUB: // numerical subtraction if (left.type == Token.NUMBER) { double ld = left.getDouble(); if (right.type == Token.NUMBER) { //both numbers left.setDouble(ld - right.getDouble()); return left; } else if (ld == 0.0) { // first 0: 0-x -> -x return new Node(Token.NEG, right); } } else if (right.type == Token.NUMBER) { if (right.getDouble() == 0.0) { //second 0: x - 0 -> +x // can not make simply x because x - 0 must be number return new Node(Token.POS, left); } } break; case Token.MUL: // numerical multiplication if (left.type == Token.NUMBER) { double ld = left.getDouble(); if (right.type == Token.NUMBER) { //both numbers left.setDouble(ld * right.getDouble()); return left; } else if (ld == 1.0) { // first 1: 1 * x -> +x return new Node(Token.POS, right); } } else if (right.type == Token.NUMBER) { if (right.getDouble() == 1.0) { //second 1: x * 1 -> +x // can not make simply x because x - 0 must be number return new Node(Token.POS, left); } } // can't do x*0: Infinity * 0 gives NaN, not 0 break; case Token.DIV: // number division if (right.type == Token.NUMBER) { double rd = right.getDouble(); if (left.type == Token.NUMBER) { // both constants -- just divide, trust Java to handle x/0 left.setDouble(left.getDouble() / rd); return left; } else if (rd == 1.0) { // second 1: x/1 -> +x // not simply x to force number convertion return new Node(Token.POS, left); } } break; case Token.AND: { // Since x && y gives x, not false, when Boolean(x) is false, // and y, not Boolean(y), when Boolean(x) is true, x && y // can only be simplified if x is defined. See bug 309957. int leftStatus = isAlwaysDefinedBoolean(left); if (leftStatus == ALWAYS_FALSE_BOOLEAN) { // if the first one is false, just return it return left; } else if (leftStatus == ALWAYS_TRUE_BOOLEAN) { // if first is true, set to second return right; } break; } case Token.OR: { // Since x || y gives x, not true, when Boolean(x) is true, // and y, not Boolean(y), when Boolean(x) is false, x || y // can only be simplified if x is defined. See bug 309957. int leftStatus = isAlwaysDefinedBoolean(left); if (leftStatus == ALWAYS_TRUE_BOOLEAN) { // if the first one is true, just return it return left; } else if (leftStatus == ALWAYS_FALSE_BOOLEAN) { // if first is false, set to second return right; } break; } } return new Node(nodeType, left, right); } private Node createAssignment(int assignType, Node left, Node right) { Node ref = makeReference(left); if (ref == null) { if (left.getType() == Token.ARRAYLIT || left.getType() == Token.OBJECTLIT) { if (assignType != Token.ASSIGN) { reportError("msg.bad.destruct.op"); return right; } return createDestructuringAssignment(-1, left, right); } reportError("msg.bad.assign.left"); return right; } left = ref; int assignOp; switch (assignType) { case Token.ASSIGN: return simpleAssignment(left, right); case Token.ASSIGN_BITOR: assignOp = Token.BITOR; break; case Token.ASSIGN_BITXOR: assignOp = Token.BITXOR; break; case Token.ASSIGN_BITAND: assignOp = Token.BITAND; break; case Token.ASSIGN_LSH: assignOp = Token.LSH; break; case Token.ASSIGN_RSH: assignOp = Token.RSH; break; case Token.ASSIGN_URSH: assignOp = Token.URSH; break; case Token.ASSIGN_ADD: assignOp = Token.ADD; break; case Token.ASSIGN_SUB: assignOp = Token.SUB; break; case Token.ASSIGN_MUL: assignOp = Token.MUL; break; case Token.ASSIGN_DIV: assignOp = Token.DIV; break; case Token.ASSIGN_MOD: assignOp = Token.MOD; break; default: throw Kit.codeBug(); } int nodeType = left.getType(); switch (nodeType) { case Token.NAME: { Node op = new Node(assignOp, left, right); Node lvalueLeft = Node.newString(Token.BINDNAME, left.getString()); return new Node(Token.SETNAME, lvalueLeft, op); } case Token.GETPROP: case Token.GETELEM: { Node obj = left.getFirstChild(); Node id = left.getLastChild(); int type = nodeType == Token.GETPROP ? Token.SETPROP_OP : Token.SETELEM_OP; Node opLeft = new Node(Token.USE_STACK); Node op = new Node(assignOp, opLeft, right); return new Node(type, obj, id, op); } case Token.GET_REF: { ref = left.getFirstChild(); checkMutableReference(ref); Node opLeft = new Node(Token.USE_STACK); Node op = new Node(assignOp, opLeft, right); return new Node(Token.SET_REF_OP, ref, op); } } throw Kit.codeBug(); } private Node createUseLocal(Node localBlock) { if (Token.LOCAL_BLOCK != localBlock.getType()) throw Kit.codeBug(); Node result = new Node(Token.LOCAL_LOAD); result.putProp(Node.LOCAL_BLOCK_PROP, localBlock); return result; } private Jump makeJump(int type, Node target) { Jump n = new Jump(type); n.target = target; return n; } private Node makeReference(Node node) { int type = node.getType(); switch (type) { case Token.NAME: case Token.GETPROP: case Token.GETELEM: case Token.GET_REF: return node; case Token.CALL: node.setType(Token.REF_CALL); return new Node(Token.GET_REF, node); } // Signal caller to report error return null; } // Check if Node always mean true or false in boolean context private static int isAlwaysDefinedBoolean(Node node) { switch (node.getType()) { case Token.FALSE: case Token.NULL: return ALWAYS_FALSE_BOOLEAN; case Token.TRUE: return ALWAYS_TRUE_BOOLEAN; case Token.NUMBER: { double num = node.getDouble(); if (num == num && num != 0.0) { return ALWAYS_TRUE_BOOLEAN; } else { return ALWAYS_FALSE_BOOLEAN; } } } return 0; } // Check if node is the target of a destructuring bind. boolean isDestructuring(Node n) { return n instanceof DestructuringForm && ((DestructuringForm)n).isDestructuring(); } Node decompileFunctionHeader(FunctionNode fn) { Node mexpr = null; if (fn.getFunctionName() != null) { decompiler.addName(fn.getName()); } else if (fn.getMemberExprNode() != null) { mexpr = transform(fn.getMemberExprNode()); } decompiler.addToken(Token.LP); List params = fn.getParams(); for (int i = 0; i < params.size(); i++) { decompile(params.get(i)); if (i < params.size() - 1) { decompiler.addToken(Token.COMMA); } } decompiler.addToken(Token.RP); if (!fn.isExpressionClosure()) { decompiler.addEOL(Token.LC); } return mexpr; } void decompile(AstNode node) { switch (node.getType()) { case Token.ARRAYLIT: decompileArrayLiteral((ArrayLiteral)node); break; case Token.OBJECTLIT: decompileObjectLiteral((ObjectLiteral)node); break; case Token.STRING: decompiler.addString(((StringLiteral)node).getValue()); break; case Token.NAME: decompiler.addName(((Name)node).getIdentifier()); break; case Token.NUMBER: decompiler.addNumber(((NumberLiteral)node).getNumber()); break; case Token.GETPROP: decompilePropertyGet((PropertyGet)node); break; case Token.EMPTY: break; case Token.GETELEM: decompileElementGet((ElementGet) node); break; case Token.THIS: decompiler.addToken(node.getType()); break; default: Kit.codeBug("unexpected token: " + Token.typeToName(node.getType())); } } // used for destructuring forms, since we don't transform() them void decompileArrayLiteral(ArrayLiteral node) { decompiler.addToken(Token.LB); List elems = node.getElements(); int size = elems.size(); for (int i = 0; i < size; i++) { AstNode elem = elems.get(i); decompile(elem); if (i < size - 1) { decompiler.addToken(Token.COMMA); } } decompiler.addToken(Token.RB); } // only used for destructuring forms void decompileObjectLiteral(ObjectLiteral node) { decompiler.addToken(Token.LC); List props = node.getElements(); int size = props.size(); for (int i = 0; i < size; i++) { ObjectProperty prop = props.get(i); boolean destructuringShorthand = Boolean.TRUE.equals(prop.getProp(Node.DESTRUCTURING_SHORTHAND)); decompile(prop.getLeft()); if (!destructuringShorthand) { decompiler.addToken(Token.COLON); decompile(prop.getRight()); } if (i < size - 1) { decompiler.addToken(Token.COMMA); } } decompiler.addToken(Token.RC); } // only used for destructuring forms void decompilePropertyGet(PropertyGet node) { decompile(node.getTarget()); decompiler.addToken(Token.DOT); decompile(node.getProperty()); } // only used for destructuring forms void decompileElementGet(ElementGet node) { decompile(node.getTarget()); decompiler.addToken(Token.LB); decompile(node.getElement()); decompiler.addToken(Token.RB); } } rhino-1.7R4/src/org/mozilla/javascript/Icode.java000066400000000000000000000224021176760007500220000ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * Additional interpreter-specific codes */ abstract class Icode { static final int // delete operator used on a name Icode_DELNAME = 0, // Stack: ... value1 -> ... value1 value1 Icode_DUP = -1, // Stack: ... value2 value1 -> ... value2 value1 value2 value1 Icode_DUP2 = -2, // Stack: ... value2 value1 -> ... value1 value2 Icode_SWAP = -3, // Stack: ... value1 -> ... Icode_POP = -4, // Store stack top into return register and then pop it Icode_POP_RESULT = -5, // To jump conditionally and pop additional stack value Icode_IFEQ_POP = -6, // various types of ++/-- Icode_VAR_INC_DEC = -7, Icode_NAME_INC_DEC = -8, Icode_PROP_INC_DEC = -9, Icode_ELEM_INC_DEC = -10, Icode_REF_INC_DEC = -11, // load/save scope from/to local Icode_SCOPE_LOAD = -12, Icode_SCOPE_SAVE = -13, Icode_TYPEOFNAME = -14, // helper for function calls Icode_NAME_AND_THIS = -15, Icode_PROP_AND_THIS = -16, Icode_ELEM_AND_THIS = -17, Icode_VALUE_AND_THIS = -18, // Create closure object for nested functions Icode_CLOSURE_EXPR = -19, Icode_CLOSURE_STMT = -20, // Special calls Icode_CALLSPECIAL = -21, // To return undefined value Icode_RETUNDEF = -22, // Exception handling implementation Icode_GOSUB = -23, Icode_STARTSUB = -24, Icode_RETSUB = -25, // To indicating a line number change in icodes. Icode_LINE = -26, // To store shorts and ints inline Icode_SHORTNUMBER = -27, Icode_INTNUMBER = -28, // To create and populate array to hold values for [] and {} literals Icode_LITERAL_NEW = -29, Icode_LITERAL_SET = -30, // Array literal with skipped index like [1,,2] Icode_SPARE_ARRAYLIT = -31, // Load index register to prepare for the following index operation Icode_REG_IND_C0 = -32, Icode_REG_IND_C1 = -33, Icode_REG_IND_C2 = -34, Icode_REG_IND_C3 = -35, Icode_REG_IND_C4 = -36, Icode_REG_IND_C5 = -37, Icode_REG_IND1 = -38, Icode_REG_IND2 = -39, Icode_REG_IND4 = -40, // Load string register to prepare for the following string operation Icode_REG_STR_C0 = -41, Icode_REG_STR_C1 = -42, Icode_REG_STR_C2 = -43, Icode_REG_STR_C3 = -44, Icode_REG_STR1 = -45, Icode_REG_STR2 = -46, Icode_REG_STR4 = -47, // Version of getvar/setvar that read var index directly from bytecode Icode_GETVAR1 = -48, Icode_SETVAR1 = -49, // Load undefined Icode_UNDEF = -50, Icode_ZERO = -51, Icode_ONE = -52, // entrance and exit from .() Icode_ENTERDQ = -53, Icode_LEAVEDQ = -54, Icode_TAIL_CALL = -55, // Clear local to allow GC its context Icode_LOCAL_CLEAR = -56, // Literal get/set Icode_LITERAL_GETTER = -57, Icode_LITERAL_SETTER = -58, // const Icode_SETCONST = -59, Icode_SETCONSTVAR = -60, Icode_SETCONSTVAR1 = -61, // Generator opcodes (along with Token.YIELD) Icode_GENERATOR = -62, Icode_GENERATOR_END = -63, Icode_DEBUGGER = -64, // Last icode MIN_ICODE = -64; static String bytecodeName(int bytecode) { if (!validBytecode(bytecode)) { throw new IllegalArgumentException(String.valueOf(bytecode)); } if (!Token.printICode) { return String.valueOf(bytecode); } if (validTokenCode(bytecode)) { return Token.name(bytecode); } switch (bytecode) { case Icode_DUP: return "DUP"; case Icode_DUP2: return "DUP2"; case Icode_SWAP: return "SWAP"; case Icode_POP: return "POP"; case Icode_POP_RESULT: return "POP_RESULT"; case Icode_IFEQ_POP: return "IFEQ_POP"; case Icode_VAR_INC_DEC: return "VAR_INC_DEC"; case Icode_NAME_INC_DEC: return "NAME_INC_DEC"; case Icode_PROP_INC_DEC: return "PROP_INC_DEC"; case Icode_ELEM_INC_DEC: return "ELEM_INC_DEC"; case Icode_REF_INC_DEC: return "REF_INC_DEC"; case Icode_SCOPE_LOAD: return "SCOPE_LOAD"; case Icode_SCOPE_SAVE: return "SCOPE_SAVE"; case Icode_TYPEOFNAME: return "TYPEOFNAME"; case Icode_NAME_AND_THIS: return "NAME_AND_THIS"; case Icode_PROP_AND_THIS: return "PROP_AND_THIS"; case Icode_ELEM_AND_THIS: return "ELEM_AND_THIS"; case Icode_VALUE_AND_THIS: return "VALUE_AND_THIS"; case Icode_CLOSURE_EXPR: return "CLOSURE_EXPR"; case Icode_CLOSURE_STMT: return "CLOSURE_STMT"; case Icode_CALLSPECIAL: return "CALLSPECIAL"; case Icode_RETUNDEF: return "RETUNDEF"; case Icode_GOSUB: return "GOSUB"; case Icode_STARTSUB: return "STARTSUB"; case Icode_RETSUB: return "RETSUB"; case Icode_LINE: return "LINE"; case Icode_SHORTNUMBER: return "SHORTNUMBER"; case Icode_INTNUMBER: return "INTNUMBER"; case Icode_LITERAL_NEW: return "LITERAL_NEW"; case Icode_LITERAL_SET: return "LITERAL_SET"; case Icode_SPARE_ARRAYLIT: return "SPARE_ARRAYLIT"; case Icode_REG_IND_C0: return "REG_IND_C0"; case Icode_REG_IND_C1: return "REG_IND_C1"; case Icode_REG_IND_C2: return "REG_IND_C2"; case Icode_REG_IND_C3: return "REG_IND_C3"; case Icode_REG_IND_C4: return "REG_IND_C4"; case Icode_REG_IND_C5: return "REG_IND_C5"; case Icode_REG_IND1: return "LOAD_IND1"; case Icode_REG_IND2: return "LOAD_IND2"; case Icode_REG_IND4: return "LOAD_IND4"; case Icode_REG_STR_C0: return "REG_STR_C0"; case Icode_REG_STR_C1: return "REG_STR_C1"; case Icode_REG_STR_C2: return "REG_STR_C2"; case Icode_REG_STR_C3: return "REG_STR_C3"; case Icode_REG_STR1: return "LOAD_STR1"; case Icode_REG_STR2: return "LOAD_STR2"; case Icode_REG_STR4: return "LOAD_STR4"; case Icode_GETVAR1: return "GETVAR1"; case Icode_SETVAR1: return "SETVAR1"; case Icode_UNDEF: return "UNDEF"; case Icode_ZERO: return "ZERO"; case Icode_ONE: return "ONE"; case Icode_ENTERDQ: return "ENTERDQ"; case Icode_LEAVEDQ: return "LEAVEDQ"; case Icode_TAIL_CALL: return "TAIL_CALL"; case Icode_LOCAL_CLEAR: return "LOCAL_CLEAR"; case Icode_LITERAL_GETTER: return "LITERAL_GETTER"; case Icode_LITERAL_SETTER: return "LITERAL_SETTER"; case Icode_SETCONST: return "SETCONST"; case Icode_SETCONSTVAR: return "SETCONSTVAR"; case Icode_SETCONSTVAR1: return "SETCONSTVAR1"; case Icode_GENERATOR: return "GENERATOR"; case Icode_GENERATOR_END: return "GENERATOR_END"; case Icode_DEBUGGER: return "DEBUGGER"; } // icode without name throw new IllegalStateException(String.valueOf(bytecode)); } static boolean validIcode(int icode) { return MIN_ICODE <= icode && icode <= 0; } static boolean validTokenCode(int token) { return Token.FIRST_BYTECODE_TOKEN <= token && token <= Token.LAST_BYTECODE_TOKEN; } static boolean validBytecode(int bytecode) { return validIcode(bytecode) || validTokenCode(bytecode); } } rhino-1.7R4/src/org/mozilla/javascript/IdFunctionCall.java000066400000000000000000000013371176760007500236170ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * Master for id-based functions that knows their properties and how to * execute them. */ public interface IdFunctionCall { /** * 'thisObj' will be null if invoked as constructor, in which case * instance of Scriptable should be returned */ public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args); } rhino-1.7R4/src/org/mozilla/javascript/IdFunctionObject.java000066400000000000000000000111521176760007500241460ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; public class IdFunctionObject extends BaseFunction { static final long serialVersionUID = -5332312783643935019L; public IdFunctionObject(IdFunctionCall idcall, Object tag, int id, int arity) { if (arity < 0) throw new IllegalArgumentException(); this.idcall = idcall; this.tag = tag; this.methodId = id; this.arity = arity; if (arity < 0) throw new IllegalArgumentException(); } public IdFunctionObject(IdFunctionCall idcall, Object tag, int id, String name, int arity, Scriptable scope) { super(scope, null); if (arity < 0) throw new IllegalArgumentException(); if (name == null) throw new IllegalArgumentException(); this.idcall = idcall; this.tag = tag; this.methodId = id; this.arity = arity; this.functionName = name; } public void initFunction(String name, Scriptable scope) { if (name == null) throw new IllegalArgumentException(); if (scope == null) throw new IllegalArgumentException(); this.functionName = name; setParentScope(scope); } public final boolean hasTag(Object tag) { return tag == null ? this.tag == null : tag.equals(this.tag); } public final int methodId() { return methodId; } public final void markAsConstructor(Scriptable prototypeProperty) { useCallAsConstructor = true; setImmunePrototypeProperty(prototypeProperty); } public final void addAsProperty(Scriptable target) { ScriptableObject.defineProperty(target, functionName, this, ScriptableObject.DONTENUM); } public void exportAsScopeProperty() { addAsProperty(getParentScope()); } @Override public Scriptable getPrototype() { // Lazy initialization of prototype: for native functions this // may not be called at all Scriptable proto = super.getPrototype(); if (proto == null) { proto = getFunctionPrototype(getParentScope()); setPrototype(proto); } return proto; } @Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { return idcall.execIdCall(this, cx, scope, thisObj, args); } @Override public Scriptable createObject(Context cx, Scriptable scope) { if (useCallAsConstructor) { return null; } // Throw error if not explicitly coded to be used as constructor, // to satisfy ECMAScript standard (see bugzilla 202019). // To follow current (2003-05-01) SpiderMonkey behavior, change it to: // return super.createObject(cx, scope); throw ScriptRuntime.typeError1("msg.not.ctor", functionName); } @Override String decompile(int indent, int flags) { StringBuffer sb = new StringBuffer(); boolean justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); if (!justbody) { sb.append("function "); sb.append(getFunctionName()); sb.append("() { "); } sb.append("[native code for "); if (idcall instanceof Scriptable) { Scriptable sobj = (Scriptable)idcall; sb.append(sobj.getClassName()); sb.append('.'); } sb.append(getFunctionName()); sb.append(", arity="); sb.append(getArity()); sb.append(justbody ? "]\n" : "] }\n"); return sb.toString(); } @Override public int getArity() { return arity; } @Override public int getLength() { return getArity(); } @Override public String getFunctionName() { return (functionName == null) ? "" : functionName; } public final RuntimeException unknown() { // It is program error to call id-like methods for unknown function return new IllegalArgumentException( "BAD FUNCTION ID="+methodId+" MASTER="+idcall); } private final IdFunctionCall idcall; private final Object tag; private final int methodId; private int arity; private boolean useCallAsConstructor; private String functionName; } rhino-1.7R4/src/org/mozilla/javascript/IdScriptableObject.java000066400000000000000000000644531176760007500244650ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.io.*; /** Base class for native object implementation that uses IdFunctionObject to export its methods to script via .prototype object. Any descendant should implement at least the following methods: findInstanceIdInfo getInstanceIdName execIdCall methodArity To define non-function properties, the descendant should override getInstanceIdValue setInstanceIdValue to get/set property value and provide its default attributes. To customize initialization of constructor and prototype objects, descendant may override scopeInit or fillConstructorProperties methods. */ public abstract class IdScriptableObject extends ScriptableObject implements IdFunctionCall { private transient PrototypeValues prototypeValues; private static final class PrototypeValues implements Serializable { static final long serialVersionUID = 3038645279153854371L; private static final int NAME_SLOT = 1; private static final int SLOT_SPAN = 2; private IdScriptableObject obj; private int maxId; private Object[] valueArray; private short[] attributeArray; // The following helps to avoid creation of valueArray during runtime // initialization for common case of "constructor" property int constructorId; private IdFunctionObject constructor; private short constructorAttrs; PrototypeValues(IdScriptableObject obj, int maxId) { if (obj == null) throw new IllegalArgumentException(); if (maxId < 1) throw new IllegalArgumentException(); this.obj = obj; this.maxId = maxId; } final int getMaxId() { return maxId; } final void initValue(int id, String name, Object value, int attributes) { if (!(1 <= id && id <= maxId)) throw new IllegalArgumentException(); if (name == null) throw new IllegalArgumentException(); if (value == NOT_FOUND) throw new IllegalArgumentException(); ScriptableObject.checkValidAttributes(attributes); if (obj.findPrototypeId(name) != id) throw new IllegalArgumentException(name); if (id == constructorId) { if (!(value instanceof IdFunctionObject)) { throw new IllegalArgumentException("consructor should be initialized with IdFunctionObject"); } constructor = (IdFunctionObject)value; constructorAttrs = (short)attributes; return; } initSlot(id, name, value, attributes); } private void initSlot(int id, String name, Object value, int attributes) { Object[] array = valueArray; if (array == null) throw new IllegalStateException(); if (value == null) { value = UniqueTag.NULL_VALUE; } int index = (id - 1) * SLOT_SPAN; synchronized (this) { Object value2 = array[index]; if (value2 == null) { array[index] = value; array[index + NAME_SLOT] = name; attributeArray[id - 1] = (short)attributes; } else { if (!name.equals(array[index + NAME_SLOT])) throw new IllegalStateException(); } } } final IdFunctionObject createPrecachedConstructor() { if (constructorId != 0) throw new IllegalStateException(); constructorId = obj.findPrototypeId("constructor"); if (constructorId == 0) { throw new IllegalStateException( "No id for constructor property"); } obj.initPrototypeId(constructorId); if (constructor == null) { throw new IllegalStateException( obj.getClass().getName()+".initPrototypeId() did not " +"initialize id="+constructorId); } constructor.initFunction(obj.getClassName(), ScriptableObject.getTopLevelScope(obj)); constructor.markAsConstructor(obj); return constructor; } final int findId(String name) { return obj.findPrototypeId(name); } final boolean has(int id) { Object[] array = valueArray; if (array == null) { // Not yet initialized, assume all exists return true; } int valueSlot = (id - 1) * SLOT_SPAN; Object value = array[valueSlot]; if (value == null) { // The particular entry has not been yet initialized return true; } return value != NOT_FOUND; } final Object get(int id) { Object value = ensureId(id); if (value == UniqueTag.NULL_VALUE) { value = null; } return value; } final void set(int id, Scriptable start, Object value) { if (value == NOT_FOUND) throw new IllegalArgumentException(); ensureId(id); int attr = attributeArray[id - 1]; if ((attr & READONLY) == 0) { if (start == obj) { if (value == null) { value = UniqueTag.NULL_VALUE; } int valueSlot = (id - 1) * SLOT_SPAN; synchronized (this) { valueArray[valueSlot] = value; } } else { int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT; String name = (String)valueArray[nameSlot]; start.put(name, start, value); } } } final void delete(int id) { ensureId(id); int attr = attributeArray[id - 1]; if ((attr & PERMANENT) == 0) { int valueSlot = (id - 1) * SLOT_SPAN; synchronized (this) { valueArray[valueSlot] = NOT_FOUND; attributeArray[id - 1] = EMPTY; } } } final int getAttributes(int id) { ensureId(id); return attributeArray[id - 1]; } final void setAttributes(int id, int attributes) { ScriptableObject.checkValidAttributes(attributes); ensureId(id); synchronized (this) { attributeArray[id - 1] = (short)attributes; } } final Object[] getNames(boolean getAll, Object[] extraEntries) { Object[] names = null; int count = 0; for (int id = 1; id <= maxId; ++id) { Object value = ensureId(id); if (getAll || (attributeArray[id - 1] & DONTENUM) == 0) { if (value != NOT_FOUND) { int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT; String name = (String)valueArray[nameSlot]; if (names == null) { names = new Object[maxId]; } names[count++] = name; } } } if (count == 0) { return extraEntries; } else if (extraEntries == null || extraEntries.length == 0) { if (count != names.length) { Object[] tmp = new Object[count]; System.arraycopy(names, 0, tmp, 0, count); names = tmp; } return names; } else { int extra = extraEntries.length; Object[] tmp = new Object[extra + count]; System.arraycopy(extraEntries, 0, tmp, 0, extra); System.arraycopy(names, 0, tmp, extra, count); return tmp; } } private Object ensureId(int id) { Object[] array = valueArray; if (array == null) { synchronized (this) { array = valueArray; if (array == null) { array = new Object[maxId * SLOT_SPAN]; valueArray = array; attributeArray = new short[maxId]; } } } int valueSlot = (id - 1) * SLOT_SPAN; Object value = array[valueSlot]; if (value == null) { if (id == constructorId) { initSlot(constructorId, "constructor", constructor, constructorAttrs); constructor = null; // no need to refer it any longer } else { obj.initPrototypeId(id); } value = array[valueSlot]; if (value == null) { throw new IllegalStateException( obj.getClass().getName()+".initPrototypeId(int id) " +"did not initialize id="+id); } } return value; } } public IdScriptableObject() { } public IdScriptableObject(Scriptable scope, Scriptable prototype) { super(scope, prototype); } protected final Object defaultGet(String name) { return super.get(name, this); } protected final void defaultPut(String name, Object value) { super.put(name, this, value); } @Override public boolean has(String name, Scriptable start) { int info = findInstanceIdInfo(name); if (info != 0) { int attr = (info >>> 16); if ((attr & PERMANENT) != 0) { return true; } int id = (info & 0xFFFF); return NOT_FOUND != getInstanceIdValue(id); } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { return prototypeValues.has(id); } } return super.has(name, start); } @Override public Object get(String name, Scriptable start) { // Check for slot first for performance. This is a very hot code // path that should be further optimized. Object value = super.get(name, start); if (value != NOT_FOUND) { return value; } int info = findInstanceIdInfo(name); if (info != 0) { int id = (info & 0xFFFF); value = getInstanceIdValue(id); if (value != NOT_FOUND) return value; } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { value = prototypeValues.get(id); if (value != NOT_FOUND) return value; } } return NOT_FOUND; } @Override public void put(String name, Scriptable start, Object value) { int info = findInstanceIdInfo(name); if (info != 0) { if (start == this && isSealed()) { throw Context.reportRuntimeError1("msg.modify.sealed", name); } int attr = (info >>> 16); if ((attr & READONLY) == 0) { if (start == this) { int id = (info & 0xFFFF); setInstanceIdValue(id, value); } else { start.put(name, start, value); } } return; } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { if (start == this && isSealed()) { throw Context.reportRuntimeError1("msg.modify.sealed", name); } prototypeValues.set(id, start, value); return; } } super.put(name, start, value); } @Override public void delete(String name) { int info = findInstanceIdInfo(name); if (info != 0) { // Let the super class to throw exceptions for sealed objects if (!isSealed()) { int attr = (info >>> 16); if ((attr & PERMANENT) == 0) { int id = (info & 0xFFFF); setInstanceIdValue(id, NOT_FOUND); } return; } } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { if (!isSealed()) { prototypeValues.delete(id); } return; } } super.delete(name); } @Override public int getAttributes(String name) { int info = findInstanceIdInfo(name); if (info != 0) { int attr = (info >>> 16); return attr; } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { return prototypeValues.getAttributes(id); } } return super.getAttributes(name); } @Override public void setAttributes(String name, int attributes) { ScriptableObject.checkValidAttributes(attributes); int info = findInstanceIdInfo(name); if (info != 0) { int id = (info & 0xFFFF); int currentAttributes = (info >>> 16); if (attributes != currentAttributes) { setInstanceIdAttributes(id, attributes); } return; } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { prototypeValues.setAttributes(id, attributes); return; } } super.setAttributes(name, attributes); } @Override Object[] getIds(boolean getAll) { Object[] result = super.getIds(getAll); if (prototypeValues != null) { result = prototypeValues.getNames(getAll, result); } int maxInstanceId = getMaxInstanceId(); if (maxInstanceId != 0) { Object[] ids = null; int count = 0; for (int id = maxInstanceId; id != 0; --id) { String name = getInstanceIdName(id); int info = findInstanceIdInfo(name); if (info != 0) { int attr = (info >>> 16); if ((attr & PERMANENT) == 0) { if (NOT_FOUND == getInstanceIdValue(id)) { continue; } } if (getAll || (attr & DONTENUM) == 0) { if (count == 0) { // Need extra room for no more then [1..id] names ids = new Object[id]; } ids[count++] = name; } } } if (count != 0) { if (result.length == 0 && ids.length == count) { result = ids; } else { Object[] tmp = new Object[result.length + count]; System.arraycopy(result, 0, tmp, 0, result.length); System.arraycopy(ids, 0, tmp, result.length, count); result = tmp; } } } return result; } /** * Get maximum id findInstanceIdInfo can generate. */ protected int getMaxInstanceId() { return 0; } protected static int instanceIdInfo(int attributes, int id) { return (attributes << 16) | id; } /** * Map name to id of instance property. * Should return 0 if not found or the result of * {@link #instanceIdInfo(int, int)}. */ protected int findInstanceIdInfo(String name) { return 0; } /** Map id back to property name it defines. */ protected String getInstanceIdName(int id) { throw new IllegalArgumentException(String.valueOf(id)); } /** Get id value. ** If id value is constant, descendant can call cacheIdValue to store ** value in the permanent cache. ** Default implementation creates IdFunctionObject instance for given id ** and cache its value */ protected Object getInstanceIdValue(int id) { throw new IllegalStateException(String.valueOf(id)); } /** * Set or delete id value. If value == NOT_FOUND , the implementation * should make sure that the following getInstanceIdValue return NOT_FOUND. */ protected void setInstanceIdValue(int id, Object value) { throw new IllegalStateException(String.valueOf(id)); } /** * Update the attributes of the given instance property. Classes which * want to support changing property attributes via Object.defineProperty * must override this method. The default implementation throws * InternalError. * @param id the instance property id * @param attr the new attribute bitset */ protected void setInstanceIdAttributes(int id, int attr) { throw ScriptRuntime.constructError("InternalError", "Changing attributes not supported for " + getClassName() + " " + getInstanceIdName(id) + " property"); } /** 'thisObj' will be null if invoked as constructor, in which case ** instance of Scriptable should be returned. */ public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { throw f.unknown(); } public final IdFunctionObject exportAsJSClass(int maxPrototypeId, Scriptable scope, boolean sealed) { // Set scope and prototype unless this is top level scope itself if (scope != this && scope != null) { setParentScope(scope); setPrototype(getObjectPrototype(scope)); } activatePrototypeMap(maxPrototypeId); IdFunctionObject ctor = prototypeValues.createPrecachedConstructor(); if (sealed) { sealObject(); } fillConstructorProperties(ctor); if (sealed) { ctor.sealObject(); } ctor.exportAsScopeProperty(); return ctor; } public final boolean hasPrototypeMap() { return prototypeValues != null; } public final void activatePrototypeMap(int maxPrototypeId) { PrototypeValues values = new PrototypeValues(this, maxPrototypeId); synchronized (this) { if (prototypeValues != null) throw new IllegalStateException(); prototypeValues = values; } } public final void initPrototypeMethod(Object tag, int id, String name, int arity) { Scriptable scope = ScriptableObject.getTopLevelScope(this); IdFunctionObject f = newIdFunction(tag, id, name, arity, scope); prototypeValues.initValue(id, name, f, DONTENUM); } public final void initPrototypeConstructor(IdFunctionObject f) { int id = prototypeValues.constructorId; if (id == 0) throw new IllegalStateException(); if (f.methodId() != id) throw new IllegalArgumentException(); if (isSealed()) { f.sealObject(); } prototypeValues.initValue(id, "constructor", f, DONTENUM); } public final void initPrototypeValue(int id, String name, Object value, int attributes) { prototypeValues.initValue(id, name, value, attributes); } protected void initPrototypeId(int id) { throw new IllegalStateException(String.valueOf(id)); } protected int findPrototypeId(String name) { throw new IllegalStateException(name); } protected void fillConstructorProperties(IdFunctionObject ctor) { } protected void addIdFunctionProperty(Scriptable obj, Object tag, int id, String name, int arity) { Scriptable scope = ScriptableObject.getTopLevelScope(obj); IdFunctionObject f = newIdFunction(tag, id, name, arity, scope); f.addAsProperty(obj); } /** * Utility method to construct type error to indicate incompatible call * when converting script thisObj to a particular type is not possible. * Possible usage would be to have a private function like realThis: *

     *  private static NativeSomething realThis(Scriptable thisObj,
     *                                          IdFunctionObject f)
     *  {
     *      if (!(thisObj instanceof NativeSomething))
     *          throw incompatibleCallError(f);
     *      return (NativeSomething)thisObj;
     * }
     * 
* Note that although such function can be implemented universally via * java.lang.Class.isInstance(), it would be much more slower. * @param f function that is attempting to convert 'this' * object. * @return Scriptable object suitable for a check by the instanceof * operator. * @throws RuntimeException if no more instanceof target can be found */ protected static EcmaError incompatibleCallError(IdFunctionObject f) { throw ScriptRuntime.typeError1("msg.incompat.call", f.getFunctionName()); } private IdFunctionObject newIdFunction(Object tag, int id, String name, int arity, Scriptable scope) { IdFunctionObject f = new IdFunctionObject(this, tag, id, name, arity, scope); if (isSealed()) { f.sealObject(); } return f; } @Override public void defineOwnProperty(Context cx, Object key, ScriptableObject desc) { if (key instanceof String) { String name = (String) key; int info = findInstanceIdInfo(name); if (info != 0) { int id = (info & 0xFFFF); if (isAccessorDescriptor(desc)) { delete(id); // it will be replaced with a slot } else { checkPropertyDefinition(desc); ScriptableObject current = getOwnPropertyDescriptor(cx, key); checkPropertyChange(name, current, desc); int attr = (info >>> 16); Object value = getProperty(desc, "value"); if (value != NOT_FOUND && (attr & READONLY) == 0) { Object currentValue = getInstanceIdValue(id); if (!sameValue(value, currentValue)) { setInstanceIdValue(id, value); } } setAttributes(name, applyDescriptorToAttributeBitset(attr, desc)); return; } } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { if (isAccessorDescriptor(desc)) { prototypeValues.delete(id); // it will be replaced with a slot } else { checkPropertyDefinition(desc); ScriptableObject current = getOwnPropertyDescriptor(cx, key); checkPropertyChange(name, current, desc); int attr = prototypeValues.getAttributes(id); Object value = getProperty(desc, "value"); if (value != NOT_FOUND && (attr & READONLY) == 0) { Object currentValue = prototypeValues.get(id); if (!sameValue(value, currentValue)) { prototypeValues.set(id, this, value); } } prototypeValues.setAttributes(id, applyDescriptorToAttributeBitset(attr, desc)); return; } } } } super.defineOwnProperty(cx, key, desc); } @Override protected ScriptableObject getOwnPropertyDescriptor(Context cx, Object id) { ScriptableObject desc = super.getOwnPropertyDescriptor(cx, id); if (desc == null && id instanceof String) { desc = getBuiltInDescriptor((String) id); } return desc; } private ScriptableObject getBuiltInDescriptor(String name) { Object value = null; int attr = EMPTY; Scriptable scope = getParentScope(); if (scope == null) { scope = this; } int info = findInstanceIdInfo(name); if (info != 0) { int id = (info & 0xFFFF); value = getInstanceIdValue(id); attr = (info >>> 16); return buildDataDescriptor(scope, value, attr); } if (prototypeValues != null) { int id = prototypeValues.findId(name); if (id != 0) { value = prototypeValues.get(id); attr = prototypeValues.getAttributes(id); return buildDataDescriptor(scope, value, attr); } } return null; } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); int maxPrototypeId = stream.readInt(); if (maxPrototypeId != 0) { activatePrototypeMap(maxPrototypeId); } } private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); int maxPrototypeId = 0; if (prototypeValues != null) { maxPrototypeId = prototypeValues.getMaxId(); } stream.writeInt(maxPrototypeId); } } rhino-1.7R4/src/org/mozilla/javascript/ImporterTopLevel.java000066400000000000000000000223651176760007500242410ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // API class package org.mozilla.javascript; /** * Class ImporterTopLevel * * This class defines a ScriptableObject that can be instantiated * as a top-level ("global") object to provide functionality similar * to Java's "import" statement. *

* This class can be used to create a top-level scope using the following code: *

 *  Scriptable scope = new ImporterTopLevel(cx);
 * 
* Then JavaScript code will have access to the following methods: *
    *
  • importClass - will "import" a class by making its unqualified name * available as a property of the top-level scope *
  • importPackage - will "import" all the classes of the package by * searching for unqualified names as classes qualified * by the given package. *
* The following code from the shell illustrates this use: *
 * js> importClass(java.io.File)
 * js> f = new File('help.txt')
 * help.txt
 * js> importPackage(java.util)
 * js> v = new Vector()
 * []
 *
 * @author Norris Boyd
 */
public class ImporterTopLevel extends TopLevel {
    static final long serialVersionUID = -9095380847465315412L;

    private static final Object IMPORTER_TAG = "Importer";

    public ImporterTopLevel() { }

    public ImporterTopLevel(Context cx) {
        this(cx, false);
    }

    public ImporterTopLevel(Context cx, boolean sealed)
    {
        initStandardObjects(cx, sealed);
    }

    @Override
    public String getClassName()
    {
        return (topScopeFlag) ? "global" : "JavaImporter";
    }

    public static void init(Context cx, Scriptable scope, boolean sealed)
    {
        ImporterTopLevel obj = new ImporterTopLevel();
        obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);
    }

    public void initStandardObjects(Context cx, boolean sealed)
    {
        // Assume that Context.initStandardObjects initialize JavaImporter
        // property lazily so the above init call is not yet called
        cx.initStandardObjects(this, sealed);
        topScopeFlag = true;
        // If seal is true then exportAsJSClass(cx, seal) would seal
        // this obj. Since this is scope as well, it would not allow
        // to add variables.
        IdFunctionObject ctor = exportAsJSClass(MAX_PROTOTYPE_ID, this, false);
        if (sealed) {
            ctor.sealObject();
        }
        // delete "constructor" defined by exportAsJSClass so "constructor"
        // name would refer to Object.constructor
        // and not to JavaImporter.prototype.constructor.
        delete("constructor");
    }

    @Override
    public boolean has(String name, Scriptable start) {
        return super.has(name, start)
               || getPackageProperty(name, start) != NOT_FOUND;
    }

    @Override
    public Object get(String name, Scriptable start) {
        Object result = super.get(name, start);
        if (result != NOT_FOUND)
            return result;
        result = getPackageProperty(name, start);
        return result;
    }

    private Object getPackageProperty(String name, Scriptable start) {
        Object result = NOT_FOUND;
        Object[] elements;
        synchronized (importedPackages) {
            elements = importedPackages.toArray();
        }
        for (int i=0; i < elements.length; i++) {
            NativeJavaPackage p = (NativeJavaPackage) elements[i];
            Object v = p.getPkgProperty(name, start, false);
            if (v != null && !(v instanceof NativeJavaPackage)) {
                if (result == NOT_FOUND) {
                    result = v;
                } else {
                    throw Context.reportRuntimeError2(
                        "msg.ambig.import", result.toString(), v.toString());
                }
            }
        }
        return result;
    }

    /**
     * @deprecated Kept only for compatibility.
     */
    public void importPackage(Context cx, Scriptable thisObj, Object[] args,
                              Function funObj)
    {
        js_importPackage(args);
    }

    private Object js_construct(Scriptable scope, Object[] args)
    {
        ImporterTopLevel result = new ImporterTopLevel();
        for (int i = 0; i != args.length; ++i) {
            Object arg = args[i];
            if (arg instanceof NativeJavaClass) {
                result.importClass((NativeJavaClass)arg);
            } else if (arg instanceof NativeJavaPackage) {
                result.importPackage((NativeJavaPackage)arg);
            } else {
                throw Context.reportRuntimeError1(
                    "msg.not.class.not.pkg", Context.toString(arg));
            }
        }
        // set explicitly prototype and scope
        // as otherwise in top scope mode BaseFunction.construct
        // would keep them set to null. It also allow to use
        // JavaImporter without new and still get properly
        // initialized object.
        result.setParentScope(scope);
        result.setPrototype(this);
        return result;
    }

    private Object js_importClass(Object[] args)
    {
        for (int i = 0; i != args.length; i++) {
            Object arg = args[i];
            if (!(arg instanceof NativeJavaClass)) {
                throw Context.reportRuntimeError1(
                    "msg.not.class", Context.toString(arg));
            }
            importClass((NativeJavaClass)arg);
        }
        return Undefined.instance;
    }

    private Object js_importPackage(Object[] args)
    {
        for (int i = 0; i != args.length; i++) {
            Object arg = args[i];
            if (!(arg instanceof NativeJavaPackage)) {
                throw Context.reportRuntimeError1(
                    "msg.not.pkg", Context.toString(arg));
            }
            importPackage((NativeJavaPackage)arg);
        }
        return Undefined.instance;
    }

    private void importPackage(NativeJavaPackage pkg)
    {
        if(pkg == null) {
            return;
        }
        synchronized (importedPackages) {
            for (int j = 0; j != importedPackages.size(); j++) {
                if (pkg.equals(importedPackages.get(j))) {
                    return;
                }
            }
            importedPackages.add(pkg);
        }
    }

    private void importClass(NativeJavaClass cl)
    {
        String s = cl.getClassObject().getName();
        String n = s.substring(s.lastIndexOf('.')+1);
        Object val = get(n, this);
        if (val != NOT_FOUND && val != cl) {
            throw Context.reportRuntimeError1("msg.prop.defined", n);
        }
        //defineProperty(n, cl, DONTENUM);
        put(n, this, cl);
    }

    @Override
    protected void initPrototypeId(int id)
    {
        String s;
        int arity;
        switch (id) {
          case Id_constructor:   arity=0; s="constructor";   break;
          case Id_importClass:   arity=1; s="importClass";   break;
          case Id_importPackage: arity=1; s="importPackage"; break;
          default: throw new IllegalArgumentException(String.valueOf(id));
        }
        initPrototypeMethod(IMPORTER_TAG, id, s, arity);
    }

    @Override
    public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
                             Scriptable thisObj, Object[] args)
    {
        if (!f.hasTag(IMPORTER_TAG)) {
            return super.execIdCall(f, cx, scope, thisObj, args);
        }
        int id = f.methodId();
        switch (id) {
          case Id_constructor:
            return js_construct(scope, args);

          case Id_importClass:
            return realThis(thisObj, f).js_importClass(args);

          case Id_importPackage:
            return realThis(thisObj, f).js_importPackage(args);
        }
        throw new IllegalArgumentException(String.valueOf(id));
    }

    private ImporterTopLevel realThis(Scriptable thisObj, IdFunctionObject f)
    {
        if (topScopeFlag) {
            // when used as top scope importPackage and importClass are global
            // function that ignore thisObj
            return this;
        }
        if (!(thisObj instanceof ImporterTopLevel))
            throw incompatibleCallError(f);
        return (ImporterTopLevel)thisObj;
    }

// #string_id_map#

    @Override
    protected int findPrototypeId(String s)
    {
        int id;
// #generated# Last update: 2007-05-09 08:15:24 EDT
        L0: { id = 0; String X = null; int c;
            int s_length = s.length();
            if (s_length==11) {
                c=s.charAt(0);
                if (c=='c') { X="constructor";id=Id_constructor; }
                else if (c=='i') { X="importClass";id=Id_importClass; }
            }
            else if (s_length==13) { X="importPackage";id=Id_importPackage; }
            if (X!=null && X!=s && !X.equals(s)) id = 0;
            break L0;
        }
// #/generated#
        return id;
    }

    private static final int
        Id_constructor          = 1,
        Id_importClass          = 2,
        Id_importPackage        = 3,
        MAX_PROTOTYPE_ID        = 3;

// #/string_id_map#

    private ObjArray importedPackages = new ObjArray();
    private boolean topScopeFlag;
}
rhino-1.7R4/src/org/mozilla/javascript/InterfaceAdapter.java000066400000000000000000000132561176760007500241650ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import java.lang.reflect.Method;

/**
 * Adapter to use JS function as implementation of Java interfaces with
 * single method or multiple methods with the same signature.
 */
public class InterfaceAdapter
{
    private final Object proxyHelper;

    /**
     * Make glue object implementing interface cl that will
     * call the supplied JS function when called.
     * Only interfaces were all methods have the same signature is supported.
     *
     * @return The glue object or null if cl is not interface or
     *         has methods with different signatures.
     */
    static Object create(Context cx, Class cl, ScriptableObject object)
    {
        if (!cl.isInterface()) throw new IllegalArgumentException();

        Scriptable topScope = ScriptRuntime.getTopCallScope(cx);
        ClassCache cache = ClassCache.get(topScope);
        InterfaceAdapter adapter;
        adapter = (InterfaceAdapter)cache.getInterfaceAdapter(cl);
        ContextFactory cf = cx.getFactory();
        if (adapter == null) {
            Method[] methods = cl.getMethods();
            if ( object instanceof Callable) {
                // Check if interface can be implemented by a single function.
                // We allow this if the interface has only one method or multiple 
                // methods with the same name (in which case they'd result in 
                // the same function to be invoked anyway).
                int length = methods.length;
                if (length == 0) {
                    throw Context.reportRuntimeError1(
                        "msg.no.empty.interface.conversion", cl.getName());
                }
                if (length > 1) {
                    String methodName = methods[0].getName();
                    for (int i = 1; i < length; i++) {
                        if (!methodName.equals(methods[i].getName())) {
                            throw Context.reportRuntimeError1(
                                    "msg.no.function.interface.conversion",
                                    cl.getName());
                        }
                    }
                }
            }
            adapter = new InterfaceAdapter(cf, cl);
            cache.cacheInterfaceAdapter(cl, adapter);
        }
        return VMBridge.instance.newInterfaceProxy(
            adapter.proxyHelper, cf, adapter, object, topScope);
    }

    private InterfaceAdapter(ContextFactory cf, Class cl)
    {
        this.proxyHelper
            = VMBridge.instance.getInterfaceProxyHelper(
                cf, new Class[] { cl });
    }

    public Object invoke(ContextFactory cf,
                         final Object target,
                         final Scriptable topScope,
                         final Object thisObject,
                         final Method method,
                         final Object[] args)
    {
        ContextAction action = new ContextAction() {
                public Object run(Context cx)
                {
                    return invokeImpl(cx, target, topScope, thisObject, method, args);
                }
            };
        return cf.call(action);
    }

    Object invokeImpl(Context cx,
                      Object target,
                      Scriptable topScope,
                      Object thisObject,
                      Method method,
                      Object[] args)
    {
        Callable function;
        if (target instanceof Callable) {
            function = (Callable)target;
        } else {
            Scriptable s = (Scriptable)target;
            String methodName = method.getName();
            Object value = ScriptableObject.getProperty(s, methodName);
            if (value == ScriptableObject.NOT_FOUND) {
                // We really should throw an error here, but for the sake of
                // compatibility with JavaAdapter we silently ignore undefined
                // methods.
                Context.reportWarning(ScriptRuntime.getMessage1(
                        "msg.undefined.function.interface", methodName));
                Class resultType = method.getReturnType();
                if (resultType == Void.TYPE) {
                    return null;
                } else {
                    return Context.jsToJava(null, resultType);
                }
            }
            if (!(value instanceof Callable)) {
                throw Context.reportRuntimeError1(
                        "msg.not.function.interface",methodName);
            }
            function = (Callable)value;
        }
        WrapFactory wf = cx.getWrapFactory();
        if (args == null) {
            args = ScriptRuntime.emptyArgs;
        } else {
            for (int i = 0, N = args.length; i != N; ++i) {
                Object arg = args[i];
                // neutralize wrap factory java primitive wrap feature
                if (!(arg instanceof String || arg instanceof Number
                        || arg instanceof Boolean)) {
                    args[i] = wf.wrap(cx, topScope, arg, null);
                }
            }
        }
        Scriptable thisObj = wf.wrapAsJavaObject(cx, topScope, thisObject, null);

        Object result = function.call(cx, topScope, thisObj, args);
        Class javaResultType = method.getReturnType();
        if (javaResultType == Void.TYPE) {
            result = null;
        } else {
            result = Context.jsToJava(result, javaResultType);
        }
        return result;
    }
}
rhino-1.7R4/src/org/mozilla/javascript/InterpretedFunction.java000066400000000000000000000123511176760007500247520ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import org.mozilla.javascript.debug.DebuggableScript;

final class InterpretedFunction extends NativeFunction implements Script
{
    static final long serialVersionUID = 541475680333911468L;

    InterpreterData idata;
    SecurityController securityController;
    Object securityDomain;

    private InterpretedFunction(InterpreterData idata,
                                Object staticSecurityDomain)
    {
        this.idata = idata;

        // Always get Context from the current thread to
        // avoid security breaches via passing mangled Context instances
        // with bogus SecurityController
        Context cx = Context.getContext();
        SecurityController sc = cx.getSecurityController();
        Object dynamicDomain;
        if (sc != null) {
            dynamicDomain = sc.getDynamicSecurityDomain(staticSecurityDomain);
        } else {
            if (staticSecurityDomain != null) {
                throw new IllegalArgumentException();
            }
            dynamicDomain = null;
        }

        this.securityController = sc;
        this.securityDomain = dynamicDomain;
    }

    private InterpretedFunction(InterpretedFunction parent, int index)
    {
        this.idata = parent.idata.itsNestedFunctions[index];
        this.securityController = parent.securityController;
        this.securityDomain = parent.securityDomain;
    }

    /**
     * Create script from compiled bytecode.
     */
    static InterpretedFunction createScript(InterpreterData idata,
                                            Object staticSecurityDomain)
    {
        InterpretedFunction f;
        f = new InterpretedFunction(idata, staticSecurityDomain);
        return f;
    }

    /**
     * Create function compiled from Function(...) constructor.
     */
    static InterpretedFunction createFunction(Context cx,Scriptable scope,
                                              InterpreterData idata,
                                              Object staticSecurityDomain)
    {
        InterpretedFunction f;
        f = new InterpretedFunction(idata, staticSecurityDomain);
        f.initScriptFunction(cx, scope);
        return f;
    }

    /**
     * Create function embedded in script or another function.
     */
    static InterpretedFunction createFunction(Context cx, Scriptable scope,
                                              InterpretedFunction  parent,
                                              int index)
    {
        InterpretedFunction f = new InterpretedFunction(parent, index);
        f.initScriptFunction(cx, scope);
        return f;
    }


    @Override
    public String getFunctionName()
    {
        return (idata.itsName == null) ? "" : idata.itsName;
    }

    /**
     * Calls the function.
     * @param cx the current context
     * @param scope the scope used for the call
     * @param thisObj the value of "this"
     * @param args function arguments. Must not be null. You can use
     * {@link ScriptRuntime#emptyArgs} to pass empty arguments.
     * @return the result of the function call.
     */
    @Override
    public Object call(Context cx, Scriptable scope, Scriptable thisObj,
                       Object[] args)
    {
        if (!ScriptRuntime.hasTopCall(cx)) {
            return ScriptRuntime.doTopCall(this, cx, scope, thisObj, args);
        }
        return Interpreter.interpret(this, cx, scope, thisObj, args);
    }

    public Object exec(Context cx, Scriptable scope)
    {
        if (!isScript()) {
            // Can only be applied to scripts
            throw new IllegalStateException();
        }
        if (!ScriptRuntime.hasTopCall(cx)) {
            // It will go through "call" path. but they are equivalent
            return ScriptRuntime.doTopCall(
                this, cx, scope, scope, ScriptRuntime.emptyArgs);
        }
        return Interpreter.interpret(
            this, cx, scope, scope, ScriptRuntime.emptyArgs);
    }

    public boolean isScript() {
        return idata.itsFunctionType == 0;
    }

    @Override
    public String getEncodedSource()
    {
        return Interpreter.getEncodedSource(idata);
    }

    @Override
    public DebuggableScript getDebuggableView()
    {
        return idata;
    }

    @Override
    public Object resumeGenerator(Context cx, Scriptable scope, int operation,
                                  Object state, Object value)
    {
        return Interpreter.resumeGenerator(cx, scope, operation, state, value);
    }

    @Override
    protected int getLanguageVersion()
    {
        return idata.languageVersion;
    }

    @Override
    protected int getParamCount()
    {
        return idata.argCount;
    }

    @Override
    protected int getParamAndVarCount()
    {
        return idata.argNames.length;
    }

    @Override
    protected String getParamOrVarName(int index)
    {
        return idata.argNames[index];
    }

    @Override
    protected boolean getParamOrVarConst(int index)
    {
        return idata.argIsConst[index];
    }
}

rhino-1.7R4/src/org/mozilla/javascript/Interpreter.java000066400000000000000000003465671176760007500233050ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import java.io.PrintStream;
import java.io.Serializable;
import java.util.List;
import java.util.ArrayList;

import org.mozilla.javascript.ast.FunctionNode;
import org.mozilla.javascript.ast.ScriptNode;
import org.mozilla.javascript.ScriptRuntime.NoSuchMethodShim;
import org.mozilla.javascript.debug.DebugFrame;

import static org.mozilla.javascript.UniqueTag.DOUBLE_MARK;

public final class Interpreter extends Icode implements Evaluator
{
    // data for parsing
    InterpreterData itsData;

    static final int EXCEPTION_TRY_START_SLOT  = 0;
    static final int EXCEPTION_TRY_END_SLOT    = 1;
    static final int EXCEPTION_HANDLER_SLOT    = 2;
    static final int EXCEPTION_TYPE_SLOT       = 3;
    static final int EXCEPTION_LOCAL_SLOT      = 4;
    static final int EXCEPTION_SCOPE_SLOT      = 5;
    // SLOT_SIZE: space for try start/end, handler, start, handler type,
    //            exception local and scope local
    static final int EXCEPTION_SLOT_SIZE       = 6;

    /**
     * Class to hold data corresponding to one interpreted call stack frame.
     */
    private static class CallFrame implements Cloneable, Serializable
    {
        static final long serialVersionUID = -2843792508994958978L;

        CallFrame parentFrame;
        // amount of stack frames before this one on the interpretation stack
        int frameIndex;
        // If true indicates read-only frame that is a part of continuation
        boolean frozen;

        InterpretedFunction fnOrScript;
        InterpreterData idata;

// Stack structure
// stack[0 <= i < localShift]: arguments and local variables
// stack[localShift <= i <= emptyStackTop]: used for local temporaries
// stack[emptyStackTop < i < stack.length]: stack data
// sDbl[i]: if stack[i] is UniqueTag.DOUBLE_MARK, sDbl[i] holds the number value

        Object[] stack;
        int[] stackAttributes;
        double[] sDbl;
        CallFrame varSource; // defaults to this unless continuation frame
        int localShift;
        int emptyStackTop;

        DebugFrame debuggerFrame;
        boolean useActivation;
        boolean isContinuationsTopFrame;

        Scriptable thisObj;

// The values that change during interpretation

        Object result;
        double resultDbl;
        int pc;
        int pcPrevBranch;
        int pcSourceLineStart;
        Scriptable scope;

        int savedStackTop;
        int savedCallOp;
        Object throwable;

        CallFrame cloneFrozen()
        {
            if (!frozen) Kit.codeBug();

            CallFrame copy;
            try {
                copy = (CallFrame)clone();
            } catch (CloneNotSupportedException ex) {
                throw new IllegalStateException();
            }

            // clone stack but keep varSource to point to values
            // from this frame to share variables.

            copy.stack = stack.clone();
            copy.stackAttributes = stackAttributes.clone();
            copy.sDbl = sDbl.clone();

            copy.frozen = false;
            return copy;
        }
    }

    private static final class ContinuationJump implements Serializable
    {
        static final long serialVersionUID = 7687739156004308247L;

        CallFrame capturedFrame;
        CallFrame branchFrame;
        Object result;
        double resultDbl;

        ContinuationJump(NativeContinuation c, CallFrame current)
        {
            this.capturedFrame = (CallFrame)c.getImplementation();
            if (this.capturedFrame == null || current == null) {
                // Continuation and current execution does not share
                // any frames if there is nothing to capture or
                // if there is no currently executed frames
                this.branchFrame = null;
            } else {
                // Search for branch frame where parent frame chains starting
                // from captured and current meet.
                CallFrame chain1 = this.capturedFrame;
                CallFrame chain2 = current;

                // First work parents of chain1 or chain2 until the same
                // frame depth.
                int diff = chain1.frameIndex - chain2.frameIndex;
                if (diff != 0) {
                    if (diff < 0) {
                        // swap to make sure that
                        // chain1.frameIndex > chain2.frameIndex and diff > 0
                        chain1 = current;
                        chain2 = this.capturedFrame;
                        diff = -diff;
                    }
                    do {
                        chain1 = chain1.parentFrame;
                    } while (--diff != 0);
                    if (chain1.frameIndex != chain2.frameIndex) Kit.codeBug();
                }

                // Now walk parents in parallel until a shared frame is found
                // or until the root is reached.
                while (chain1 != chain2 && chain1 != null) {
                    chain1 = chain1.parentFrame;
                    chain2 = chain2.parentFrame;
                }

                this.branchFrame = chain1;
                if (this.branchFrame != null && !this.branchFrame.frozen)
                    Kit.codeBug();
            }
        }
    }

    private static CallFrame captureFrameForGenerator(CallFrame frame) {
      frame.frozen = true;
      CallFrame result = frame.cloneFrozen();
      frame.frozen = false;

      // now isolate this frame from its previous context
      result.parentFrame = null;
      result.frameIndex = 0;

      return result;
    }

    static {
        // Checks for byte code consistencies, good compiler can eliminate them

        if (Token.LAST_BYTECODE_TOKEN > 127) {
            String str = "Violation of Token.LAST_BYTECODE_TOKEN <= 127";
            System.err.println(str);
            throw new IllegalStateException(str);
        }
        if (MIN_ICODE < -128) {
            String str = "Violation of Interpreter.MIN_ICODE >= -128";
            System.err.println(str);
            throw new IllegalStateException(str);
        }
    }

    public Object compile(CompilerEnvirons compilerEnv,
                          ScriptNode tree,
                          String encodedSource,
                          boolean returnFunction)
    {
        CodeGenerator cgen = new CodeGenerator();
        itsData = cgen.compile(compilerEnv, tree, encodedSource, returnFunction);
        return itsData;
    }

    public Script createScriptObject(Object bytecode, Object staticSecurityDomain)
    {
        if(bytecode != itsData)
        {
            Kit.codeBug();
        }
        return InterpretedFunction.createScript(itsData,
                                                staticSecurityDomain);
    }

    public void setEvalScriptFlag(Script script) {
        ((InterpretedFunction)script).idata.evalScriptFlag = true;
    }


    public Function createFunctionObject(Context cx, Scriptable scope,
            Object bytecode, Object staticSecurityDomain)
    {
        if(bytecode != itsData)
        {
            Kit.codeBug();
        }
        return InterpretedFunction.createFunction(cx, scope, itsData,
                                                  staticSecurityDomain);
    }

    private static int getShort(byte[] iCode, int pc) {
        return (iCode[pc] << 8) | (iCode[pc + 1] & 0xFF);
    }

    private static int getIndex(byte[] iCode, int pc) {
        return ((iCode[pc] & 0xFF) << 8) | (iCode[pc + 1] & 0xFF);
    }

    private static int getInt(byte[] iCode, int pc) {
        return (iCode[pc] << 24) | ((iCode[pc + 1] & 0xFF) << 16)
               | ((iCode[pc + 2] & 0xFF) << 8) | (iCode[pc + 3] & 0xFF);
    }

    private static int getExceptionHandler(CallFrame frame,
                                           boolean onlyFinally)
    {
        int[] exceptionTable = frame.idata.itsExceptionTable;
        if (exceptionTable == null) {
            // No exception handlers
            return -1;
        }

        // Icode switch in the interpreter increments PC immediately
        // and it is necessary to subtract 1 from the saved PC
        // to point it before the start of the next instruction.
        int pc = frame.pc - 1;

        // OPT: use binary search
        int best = -1, bestStart = 0, bestEnd = 0;
        for (int i = 0; i != exceptionTable.length; i += EXCEPTION_SLOT_SIZE) {
            int start = exceptionTable[i + EXCEPTION_TRY_START_SLOT];
            int end = exceptionTable[i + EXCEPTION_TRY_END_SLOT];
            if (!(start <= pc && pc < end)) {
                continue;
            }
            if (onlyFinally && exceptionTable[i + EXCEPTION_TYPE_SLOT] != 1) {
                continue;
            }
            if (best >= 0) {
                // Since handlers always nest and they never have shared end
                // although they can share start  it is sufficient to compare
                // handlers ends
                if (bestEnd < end) {
                    continue;
                }
                // Check the above assumption
                if (bestStart > start) Kit.codeBug(); // should be nested
                if (bestEnd == end) Kit.codeBug();  // no ens sharing
            }
            best = i;
            bestStart = start;
            bestEnd = end;
        }
        return best;
    }

    static void dumpICode(InterpreterData idata)
    {
        if (!Token.printICode) {
            return;
        }

        byte iCode[] = idata.itsICode;
        int iCodeLength = iCode.length;
        String[] strings = idata.itsStringTable;
        PrintStream out = System.out;
        out.println("ICode dump, for " + idata.itsName
                    + ", length = " + iCodeLength);
        out.println("MaxStack = " + idata.itsMaxStack);

        int indexReg = 0;
        for (int pc = 0; pc < iCodeLength; ) {
            out.flush();
            out.print(" [" + pc + "] ");
            int token = iCode[pc];
            int icodeLength = bytecodeSpan(token);
            String tname = Icode.bytecodeName(token);
            int old_pc = pc;
            ++pc;
            switch (token) {
              default:
                if (icodeLength != 1) Kit.codeBug();
                out.println(tname);
                break;

              case Icode_GOSUB :
              case Token.GOTO :
              case Token.IFEQ :
              case Token.IFNE :
              case Icode_IFEQ_POP :
              case Icode_LEAVEDQ : {
                int newPC = pc + getShort(iCode, pc) - 1;
                out.println(tname + " " + newPC);
                pc += 2;
                break;
              }
              case Icode_VAR_INC_DEC :
              case Icode_NAME_INC_DEC :
              case Icode_PROP_INC_DEC :
              case Icode_ELEM_INC_DEC :
              case Icode_REF_INC_DEC: {
                int incrDecrType = iCode[pc];
                out.println(tname + " " + incrDecrType);
                ++pc;
                break;
              }

              case Icode_CALLSPECIAL : {
                int callType = iCode[pc] & 0xFF;
                boolean isNew =  (iCode[pc + 1] != 0);
                int line = getIndex(iCode, pc+2);
                out.println(tname+" "+callType+" "+isNew+" "+indexReg+" "+line);
                pc += 4;
                break;
              }

              case Token.CATCH_SCOPE:
                {
                    boolean afterFisrtFlag =  (iCode[pc] != 0);
                    out.println(tname+" "+afterFisrtFlag);
                    ++pc;
                }
                break;
              case Token.REGEXP :
                out.println(tname+" "+idata.itsRegExpLiterals[indexReg]);
                break;
              case Token.OBJECTLIT :
              case Icode_SPARE_ARRAYLIT :
                out.println(tname+" "+idata.literalIds[indexReg]);
                break;
              case Icode_CLOSURE_EXPR :
              case Icode_CLOSURE_STMT :
                out.println(tname+" "+idata.itsNestedFunctions[indexReg]);
                break;
              case Token.CALL :
              case Icode_TAIL_CALL :
              case Token.REF_CALL :
              case Token.NEW :
                out.println(tname+' '+indexReg);
                break;
              case Token.THROW :
              case Token.YIELD :
              case Icode_GENERATOR :
              case Icode_GENERATOR_END :
              {
                int line = getIndex(iCode, pc);
                out.println(tname + " : " + line);
                pc += 2;
                break;
              }
              case Icode_SHORTNUMBER : {
                int value = getShort(iCode, pc);
                out.println(tname + " " + value);
                pc += 2;
                break;
              }
              case Icode_INTNUMBER : {
                int value = getInt(iCode, pc);
                out.println(tname + " " + value);
                pc += 4;
                break;
              }
              case Token.NUMBER : {
                double value = idata.itsDoubleTable[indexReg];
                out.println(tname + " " + value);
                break;
              }
              case Icode_LINE : {
                int line = getIndex(iCode, pc);
                out.println(tname + " : " + line);
                pc += 2;
                break;
              }
              case Icode_REG_STR1: {
                String str = strings[0xFF & iCode[pc]];
                out.println(tname + " \"" + str + '"');
                ++pc;
                break;
              }
              case Icode_REG_STR2: {
                String str = strings[getIndex(iCode, pc)];
                out.println(tname + " \"" + str + '"');
                pc += 2;
                break;
              }
              case Icode_REG_STR4: {
                String str = strings[getInt(iCode, pc)];
                out.println(tname + " \"" + str + '"');
                pc += 4;
                break;
              }
              case Icode_REG_IND_C0:
                  indexReg = 0;
                  out.println(tname);
                  break;
              case Icode_REG_IND_C1:
                  indexReg = 1;
                  out.println(tname);
                  break;
              case Icode_REG_IND_C2:
                  indexReg = 2;
                  out.println(tname);
                  break;
              case Icode_REG_IND_C3:
                  indexReg = 3;
                  out.println(tname);
                  break;
              case Icode_REG_IND_C4:
                  indexReg = 4;
                  out.println(tname);
                  break;
              case Icode_REG_IND_C5:
                  indexReg = 5;
                  out.println(tname);
                  break;
              case Icode_REG_IND1: {
                indexReg = 0xFF & iCode[pc];
                out.println(tname+" "+indexReg);
                ++pc;
                break;
              }
              case Icode_REG_IND2: {
                indexReg = getIndex(iCode, pc);
                out.println(tname+" "+indexReg);
                pc += 2;
                break;
              }
              case Icode_REG_IND4: {
                indexReg = getInt(iCode, pc);
                out.println(tname+" "+indexReg);
                pc += 4;
                break;
              }
              case Icode_GETVAR1:
              case Icode_SETVAR1:
              case Icode_SETCONSTVAR1:
                indexReg = iCode[pc];
                out.println(tname+" "+indexReg);
                ++pc;
                break;
            }
            if (old_pc + icodeLength != pc) Kit.codeBug();
        }

        int[] table = idata.itsExceptionTable;
        if (table != null) {
            out.println("Exception handlers: "
                         +table.length / EXCEPTION_SLOT_SIZE);
            for (int i = 0; i != table.length;
                 i += EXCEPTION_SLOT_SIZE)
            {
                int tryStart       = table[i + EXCEPTION_TRY_START_SLOT];
                int tryEnd         = table[i + EXCEPTION_TRY_END_SLOT];
                int handlerStart   = table[i + EXCEPTION_HANDLER_SLOT];
                int type           = table[i + EXCEPTION_TYPE_SLOT];
                int exceptionLocal = table[i + EXCEPTION_LOCAL_SLOT];
                int scopeLocal     = table[i + EXCEPTION_SCOPE_SLOT];

                out.println(" tryStart="+tryStart+" tryEnd="+tryEnd
                            +" handlerStart="+handlerStart
                            +" type="+(type == 0 ? "catch" : "finally")
                            +" exceptionLocal="+exceptionLocal);
            }
        }
        out.flush();
    }

    private static int bytecodeSpan(int bytecode)
    {
        switch (bytecode) {
            case Token.THROW :
            case Token.YIELD:
            case Icode_GENERATOR:
            case Icode_GENERATOR_END:
                // source line
                return 1 + 2;

            case Icode_GOSUB :
            case Token.GOTO :
            case Token.IFEQ :
            case Token.IFNE :
            case Icode_IFEQ_POP :
            case Icode_LEAVEDQ :
                // target pc offset
                return 1 + 2;

            case Icode_CALLSPECIAL :
                // call type
                // is new
                // line number
                return 1 + 1 + 1 + 2;

            case Token.CATCH_SCOPE:
                // scope flag
                return 1 + 1;

            case Icode_VAR_INC_DEC:
            case Icode_NAME_INC_DEC:
            case Icode_PROP_INC_DEC:
            case Icode_ELEM_INC_DEC:
            case Icode_REF_INC_DEC:
                // type of ++/--
                return 1 + 1;

            case Icode_SHORTNUMBER :
                // short number
                return 1 + 2;

            case Icode_INTNUMBER :
                // int number
                return 1 + 4;

            case Icode_REG_IND1:
                // ubyte index
                return 1 + 1;

            case Icode_REG_IND2:
                // ushort index
                return 1 + 2;

            case Icode_REG_IND4:
                // int index
                return 1 + 4;

            case Icode_REG_STR1:
                // ubyte string index
                return 1 + 1;

            case Icode_REG_STR2:
                // ushort string index
                return 1 + 2;

            case Icode_REG_STR4:
                // int string index
                return 1 + 4;

            case Icode_GETVAR1:
            case Icode_SETVAR1:
            case Icode_SETCONSTVAR1:
                // byte var index
                return 1 + 1;

            case Icode_LINE :
                // line number
                return 1 + 2;
        }
        if (!validBytecode(bytecode)) throw Kit.codeBug();
        return 1;
    }

    static int[] getLineNumbers(InterpreterData data)
    {
        UintMap presentLines = new UintMap();

        byte[] iCode = data.itsICode;
        int iCodeLength = iCode.length;
        for (int pc = 0; pc != iCodeLength;) {
            int bytecode = iCode[pc];
            int span = bytecodeSpan(bytecode);
            if (bytecode == Icode_LINE) {
                if (span != 3) Kit.codeBug();
                int line = getIndex(iCode, pc + 1);
                presentLines.put(line, 0);
            }
            pc += span;
        }

        return presentLines.getKeys();
    }

    public void captureStackInfo(RhinoException ex)
    {
        Context cx = Context.getCurrentContext();
        if (cx == null || cx.lastInterpreterFrame == null) {
            // No interpreter invocations
            ex.interpreterStackInfo = null;
            ex.interpreterLineData = null;
            return;
        }
        // has interpreter frame on the stack
        CallFrame[] array;
        if (cx.previousInterpreterInvocations == null
            || cx.previousInterpreterInvocations.size() == 0)
        {
            array = new CallFrame[1];
        } else {
            int previousCount = cx.previousInterpreterInvocations.size();
            if (cx.previousInterpreterInvocations.peek()
                == cx.lastInterpreterFrame)
            {
                // It can happen if exception was generated after
                // frame was pushed to cx.previousInterpreterInvocations
                // but before assignment to cx.lastInterpreterFrame.
                // In this case frames has to be ignored.
                --previousCount;
            }
            array = new CallFrame[previousCount + 1];
            cx.previousInterpreterInvocations.toArray(array);
        }
        array[array.length - 1]  = (CallFrame)cx.lastInterpreterFrame;

        int interpreterFrameCount = 0;
        for (int i = 0; i != array.length; ++i) {
            interpreterFrameCount += 1 + array[i].frameIndex;
        }

        int[] linePC = new int[interpreterFrameCount];
        // Fill linePC with pc positions from all interpreter frames.
        // Start from the most nested frame
        int linePCIndex = interpreterFrameCount;
        for (int i = array.length; i != 0;) {
            --i;
            CallFrame frame = array[i];
            while (frame != null) {
                --linePCIndex;
                linePC[linePCIndex] = frame.pcSourceLineStart;
                frame = frame.parentFrame;
            }
        }
        if (linePCIndex != 0) Kit.codeBug();

        ex.interpreterStackInfo = array;
        ex.interpreterLineData = linePC;
    }

    public String getSourcePositionFromStack(Context cx, int[] linep)
    {
        CallFrame frame = (CallFrame)cx.lastInterpreterFrame;
        InterpreterData idata = frame.idata;
        if (frame.pcSourceLineStart >= 0) {
            linep[0] = getIndex(idata.itsICode, frame.pcSourceLineStart);
        } else {
            linep[0] = 0;
        }
        return idata.itsSourceFile;
    }

    public String getPatchedStack(RhinoException ex,
                                  String nativeStackTrace)
    {
        String tag = "org.mozilla.javascript.Interpreter.interpretLoop";
        StringBuffer sb = new StringBuffer(nativeStackTrace.length() + 1000);
        String lineSeparator = SecurityUtilities.getSystemProperty("line.separator");

        CallFrame[] array = (CallFrame[])ex.interpreterStackInfo;
        int[] linePC = ex.interpreterLineData;
        int arrayIndex = array.length;
        int linePCIndex = linePC.length;
        int offset = 0;
        while (arrayIndex != 0) {
            --arrayIndex;
            int pos = nativeStackTrace.indexOf(tag, offset);
            if (pos < 0) {
                break;
            }

            // Skip tag length
            pos += tag.length();
            // Skip until the end of line
            for (; pos != nativeStackTrace.length(); ++pos) {
                char c = nativeStackTrace.charAt(pos);
                if (c == '\n' || c == '\r') {
                    break;
                }
            }
            sb.append(nativeStackTrace.substring(offset, pos));
            offset = pos;

            CallFrame frame = array[arrayIndex];
            while (frame != null) {
                if (linePCIndex == 0) Kit.codeBug();
                --linePCIndex;
                InterpreterData idata = frame.idata;
                sb.append(lineSeparator);
                sb.append("\tat script");
                if (idata.itsName != null && idata.itsName.length() != 0) {
                    sb.append('.');
                    sb.append(idata.itsName);
                }
                sb.append('(');
                sb.append(idata.itsSourceFile);
                int pc = linePC[linePCIndex];
                if (pc >= 0) {
                    // Include line info only if available
                    sb.append(':');
                    sb.append(getIndex(idata.itsICode, pc));
                }
                sb.append(')');
                frame = frame.parentFrame;
            }
        }
        sb.append(nativeStackTrace.substring(offset));

        return sb.toString();
    }

    public List getScriptStack(RhinoException ex) {
        ScriptStackElement[][] stack = getScriptStackElements(ex);
        List list = new ArrayList(stack.length);
        String lineSeparator =
                SecurityUtilities.getSystemProperty("line.separator");
        for (ScriptStackElement[] group : stack) {
            StringBuilder sb = new StringBuilder();
            for (ScriptStackElement elem : group) {
                elem.renderJavaStyle(sb);
                sb.append(lineSeparator);
            }
            list.add(sb.toString());
        }
        return list;
    }

    public ScriptStackElement[][] getScriptStackElements(RhinoException ex)
    {
        if (ex.interpreterStackInfo == null) {
            return null;
        }

        List list = new ArrayList();

        CallFrame[] array = (CallFrame[])ex.interpreterStackInfo;
        int[] linePC = ex.interpreterLineData;
        int arrayIndex = array.length;
        int linePCIndex = linePC.length;
        while (arrayIndex != 0) {
            --arrayIndex;
            CallFrame frame = array[arrayIndex];
            List group = new ArrayList();
            while (frame != null) {
                if (linePCIndex == 0) Kit.codeBug();
                --linePCIndex;
                InterpreterData idata = frame.idata;
                String fileName = idata.itsSourceFile;
                String functionName = null;
                int lineNumber = -1;
                int pc = linePC[linePCIndex];
                if (pc >= 0) {
                    lineNumber = getIndex(idata.itsICode, pc);
                }
                if (idata.itsName != null && idata.itsName.length() != 0) {
                    functionName = idata.itsName;
                }
                frame = frame.parentFrame;
                group.add(new ScriptStackElement(fileName, functionName, lineNumber));
            }
            list.add(group.toArray(new ScriptStackElement[group.size()]));
        }
        return list.toArray(new ScriptStackElement[list.size()][]);
    }

    static String getEncodedSource(InterpreterData idata)
    {
        if (idata.encodedSource == null) {
            return null;
        }
        return idata.encodedSource.substring(idata.encodedSourceStart,
                                             idata.encodedSourceEnd);
    }

    private static void initFunction(Context cx, Scriptable scope,
                                     InterpretedFunction parent, int index)
    {
        InterpretedFunction fn;
        fn = InterpretedFunction.createFunction(cx, scope, parent, index);
        ScriptRuntime.initFunction(cx, scope, fn, fn.idata.itsFunctionType,
                                   parent.idata.evalScriptFlag);
    }

    static Object interpret(InterpretedFunction ifun,
                            Context cx, Scriptable scope,
                            Scriptable thisObj, Object[] args)
    {
        if (!ScriptRuntime.hasTopCall(cx)) Kit.codeBug();

        if (cx.interpreterSecurityDomain != ifun.securityDomain) {
            Object savedDomain = cx.interpreterSecurityDomain;
            cx.interpreterSecurityDomain = ifun.securityDomain;
            try {
                return ifun.securityController.callWithDomain(
                    ifun.securityDomain, cx, ifun, scope, thisObj, args);
            } finally {
                cx.interpreterSecurityDomain = savedDomain;
            }
        }

        CallFrame frame = new CallFrame();
        initFrame(cx, scope, thisObj, args, null, 0, args.length,
                  ifun, null, frame);
        frame.isContinuationsTopFrame = cx.isContinuationsTopCall;
        cx.isContinuationsTopCall = false;

        return interpretLoop(cx, frame, null);
    }

    static class GeneratorState {
        GeneratorState(int operation, Object value) {
            this.operation = operation;
            this.value = value;
        }
        int operation;
        Object value;
        RuntimeException returnedException;
    }

    public static Object resumeGenerator(Context cx,
                                         Scriptable scope,
                                         int operation,
                                         Object savedState,
                                         Object value)
    {
      CallFrame frame = (CallFrame) savedState;
      GeneratorState generatorState = new GeneratorState(operation, value);
      if (operation == NativeGenerator.GENERATOR_CLOSE) {
          try {
              return interpretLoop(cx, frame, generatorState);
          } catch (RuntimeException e) {
              // Only propagate exceptions other than closingException
              if (e != value)
                  throw e;
          }
          return Undefined.instance;
      }
      Object result = interpretLoop(cx, frame, generatorState);
      if (generatorState.returnedException != null)
          throw generatorState.returnedException;
      return result;
    }

    public static Object restartContinuation(NativeContinuation c, Context cx,
                                             Scriptable scope, Object[] args)
    {
        if (!ScriptRuntime.hasTopCall(cx)) {
            return ScriptRuntime.doTopCall(c, cx, scope, null, args);
        }

        Object arg;
        if (args.length == 0) {
            arg = Undefined.instance;
        } else {
            arg = args[0];
        }

        CallFrame capturedFrame = (CallFrame)c.getImplementation();
        if (capturedFrame == null) {
            // No frames to restart
            return arg;
        }

        ContinuationJump cjump = new ContinuationJump(c, null);

        cjump.result = arg;
        return interpretLoop(cx, null, cjump);
    }

    private static Object interpretLoop(Context cx, CallFrame frame,
                                        Object throwable)
    {
        // throwable holds exception object to rethrow or catch
        // It is also used for continuation restart in which case
        // it holds ContinuationJump

        final Object DBL_MRK = DOUBLE_MARK;
        final Object undefined = Undefined.instance;

        final boolean instructionCounting = (cx.instructionThreshold != 0);
        // arbitrary number to add to instructionCount when calling
        // other functions
        final int INVOCATION_COST = 100;
        // arbitrary exception cost for instruction counting
        final int EXCEPTION_COST = 100;

        String stringReg = null;
        int indexReg = -1;

        if (cx.lastInterpreterFrame != null) {
            // save the top frame from the previous interpretLoop
            // invocation on the stack
            if (cx.previousInterpreterInvocations == null) {
                cx.previousInterpreterInvocations = new ObjArray();
            }
            cx.previousInterpreterInvocations.push(cx.lastInterpreterFrame);
        }

        // When restarting continuation throwable is not null and to jump
        // to the code that rewind continuation state indexReg should be set
        // to -1.
        // With the normal call throwable == null and indexReg == -1 allows to
        // catch bugs with using indeReg to access array elements before
        // initializing indexReg.

        GeneratorState generatorState = null;
        if (throwable != null) {
            if (throwable instanceof GeneratorState) {
              generatorState = (GeneratorState) throwable;

              // reestablish this call frame
              enterFrame(cx, frame, ScriptRuntime.emptyArgs, true);
              throwable = null;
            } else if (!(throwable instanceof ContinuationJump)) {
                // It should be continuation
                Kit.codeBug();
            }
        }

        Object interpreterResult = null;
        double interpreterResultDbl = 0.0;

        StateLoop: for (;;) {
            withoutExceptions: try {

                if (throwable != null) {
                    // Need to return both 'frame' and 'throwable' from
                    // 'processThrowable', so just added a 'throwable'
                    // member in 'frame'.
                    frame = processThrowable(cx, throwable, frame, indexReg,
                                             instructionCounting);
                    throwable = frame.throwable;
                    frame.throwable = null;
                } else {
                    if (generatorState == null && frame.frozen) Kit.codeBug();
                }

                // Use local variables for constant values in frame
                // for faster access
                Object[] stack = frame.stack;
                double[] sDbl = frame.sDbl;
                Object[] vars = frame.varSource.stack;
                double[] varDbls = frame.varSource.sDbl;
                int[] varAttributes = frame.varSource.stackAttributes;
                byte[] iCode = frame.idata.itsICode;
                String[] strings = frame.idata.itsStringTable;

                // Use local for stackTop as well. Since execption handlers
                // can only exist at statement level where stack is empty,
                // it is necessary to save/restore stackTop only across
                // function calls and normal returns.
                int stackTop = frame.savedStackTop;

                // Store new frame in cx which is used for error reporting etc.
                cx.lastInterpreterFrame = frame;

                Loop: for (;;) {

                    // Exception handler assumes that PC is already incremented
                    // pass the instruction start when it searches the
                    // exception handler
                    int op = iCode[frame.pc++];
                    jumplessRun: {

    // Back indent to ease implementation reading
switch (op) {
    case Icode_GENERATOR: {
        if (!frame.frozen) {
          // First time encountering this opcode: create new generator
          // object and return
          frame.pc--; // we want to come back here when we resume
          CallFrame generatorFrame = captureFrameForGenerator(frame);
          generatorFrame.frozen = true;
          NativeGenerator generator = new NativeGenerator(frame.scope,
              generatorFrame.fnOrScript, generatorFrame);
          frame.result = generator;
          break Loop;
        } else {
          // We are now resuming execution. Fall through to YIELD case.
        }
    }
    // fall through...
    case Token.YIELD: {
        if (!frame.frozen) {
            return freezeGenerator(cx, frame, stackTop, generatorState);
        } else {
            Object obj = thawGenerator(frame, stackTop, generatorState, op);
            if (obj != Scriptable.NOT_FOUND) {
                throwable = obj;
                break withoutExceptions;
            }
            continue Loop;
        }
    }
    case Icode_GENERATOR_END: {
      // throw StopIteration
      frame.frozen = true;
      int sourceLine = getIndex(iCode, frame.pc);
      generatorState.returnedException = new JavaScriptException(
          NativeIterator.getStopIterationObject(frame.scope),
          frame.idata.itsSourceFile, sourceLine);
      break Loop;
    }
    case Token.THROW: {
        Object value = stack[stackTop];
        if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;

        int sourceLine = getIndex(iCode, frame.pc);
        throwable = new JavaScriptException(value,
                                            frame.idata.itsSourceFile,
                                            sourceLine);
        break withoutExceptions;
    }
    case Token.RETHROW: {
        indexReg += frame.localShift;
        throwable = stack[indexReg];
        break withoutExceptions;
    }
    case Token.GE :
    case Token.LE :
    case Token.GT :
    case Token.LT : {
        stackTop = doCompare(frame, op, stack, sDbl, stackTop);
        continue Loop;
    }
    case Token.IN :
    case Token.INSTANCEOF : {
        stackTop = doInOrInstanceof(cx, op, stack, sDbl, stackTop);
        continue Loop;
    }
    case Token.EQ :
    case Token.NE : {
        --stackTop;
        boolean valBln = doEquals(stack, sDbl, stackTop);
        valBln ^= (op == Token.NE);
        stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
        continue Loop;
    }
    case Token.SHEQ :
    case Token.SHNE : {
        --stackTop;
        boolean valBln = doShallowEquals(stack, sDbl, stackTop);
        valBln ^= (op == Token.SHNE);
        stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
        continue Loop;
    }
    case Token.IFNE :
        if (stack_boolean(frame, stackTop--)) {
            frame.pc += 2;
            continue Loop;
        }
        break jumplessRun;
    case Token.IFEQ :
        if (!stack_boolean(frame, stackTop--)) {
            frame.pc += 2;
            continue Loop;
        }
        break jumplessRun;
    case Icode_IFEQ_POP :
        if (!stack_boolean(frame, stackTop--)) {
            frame.pc += 2;
            continue Loop;
        }
        stack[stackTop--] = null;
        break jumplessRun;
    case Token.GOTO :
        break jumplessRun;
    case Icode_GOSUB :
        ++stackTop;
        stack[stackTop] = DBL_MRK;
        sDbl[stackTop] = frame.pc + 2;
        break jumplessRun;
    case Icode_STARTSUB :
        if (stackTop == frame.emptyStackTop + 1) {
            // Call from Icode_GOSUB: store return PC address in the local
            indexReg += frame.localShift;
            stack[indexReg] = stack[stackTop];
            sDbl[indexReg] = sDbl[stackTop];
            --stackTop;
        } else {
            // Call from exception handler: exception object is already stored
            // in the local
            if (stackTop != frame.emptyStackTop) Kit.codeBug();
        }
        continue Loop;
    case Icode_RETSUB : {
        // indexReg: local to store return address
        if (instructionCounting) {
            addInstructionCount(cx, frame, 0);
        }
        indexReg += frame.localShift;
        Object value = stack[indexReg];
        if (value != DBL_MRK) {
            // Invocation from exception handler, restore object to rethrow
            throwable = value;
            break withoutExceptions;
        }
        // Normal return from GOSUB
        frame.pc = (int)sDbl[indexReg];
        if (instructionCounting) {
            frame.pcPrevBranch = frame.pc;
        }
        continue Loop;
    }
    case Icode_POP :
        stack[stackTop] = null;
        stackTop--;
        continue Loop;
    case Icode_POP_RESULT :
        frame.result = stack[stackTop];
        frame.resultDbl = sDbl[stackTop];
        stack[stackTop] = null;
        --stackTop;
        continue Loop;
    case Icode_DUP :
        stack[stackTop + 1] = stack[stackTop];
        sDbl[stackTop + 1] = sDbl[stackTop];
        stackTop++;
        continue Loop;
    case Icode_DUP2 :
        stack[stackTop + 1] = stack[stackTop - 1];
        sDbl[stackTop + 1] = sDbl[stackTop - 1];
        stack[stackTop + 2] = stack[stackTop];
        sDbl[stackTop + 2] = sDbl[stackTop];
        stackTop += 2;
        continue Loop;
    case Icode_SWAP : {
        Object o = stack[stackTop];
        stack[stackTop] = stack[stackTop - 1];
        stack[stackTop - 1] = o;
        double d = sDbl[stackTop];
        sDbl[stackTop] = sDbl[stackTop - 1];
        sDbl[stackTop - 1] = d;
        continue Loop;
    }
    case Token.RETURN :
        frame.result = stack[stackTop];
        frame.resultDbl = sDbl[stackTop];
        --stackTop;
        break Loop;
    case Token.RETURN_RESULT :
        break Loop;
    case Icode_RETUNDEF :
        frame.result = undefined;
        break Loop;
    case Token.BITNOT : {
        int rIntValue = stack_int32(frame, stackTop);
        stack[stackTop] = DBL_MRK;
        sDbl[stackTop] = ~rIntValue;
        continue Loop;
    }
    case Token.BITAND :
    case Token.BITOR :
    case Token.BITXOR :
    case Token.LSH :
    case Token.RSH : {
        stackTop = doBitOp(frame, op, stack, sDbl, stackTop);
        continue Loop;
    }
    case Token.URSH : {
        double lDbl = stack_double(frame, stackTop - 1);
        int rIntValue = stack_int32(frame, stackTop) & 0x1F;
        stack[--stackTop] = DBL_MRK;
        sDbl[stackTop] = ScriptRuntime.toUint32(lDbl) >>> rIntValue;
        continue Loop;
    }
    case Token.NEG :
    case Token.POS : {
        double rDbl = stack_double(frame, stackTop);
        stack[stackTop] = DBL_MRK;
        if (op == Token.NEG) {
            rDbl = -rDbl;
        }
        sDbl[stackTop] = rDbl;
        continue Loop;
    }
    case Token.ADD :
        --stackTop;
        doAdd(stack, sDbl, stackTop, cx);
        continue Loop;
    case Token.SUB :
    case Token.MUL :
    case Token.DIV :
    case Token.MOD : {
        stackTop = doArithmetic(frame, op, stack, sDbl, stackTop);
        continue Loop;
    }
    case Token.NOT :
        stack[stackTop] = ScriptRuntime.wrapBoolean(
                              !stack_boolean(frame, stackTop));
        continue Loop;
    case Token.BINDNAME :
        stack[++stackTop] = ScriptRuntime.bind(cx, frame.scope, stringReg);
        continue Loop;
    case Token.STRICT_SETNAME:
    case Token.SETNAME : {
        Object rhs = stack[stackTop];
        if (rhs == DBL_MRK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Scriptable lhs = (Scriptable)stack[stackTop];
        stack[stackTop] = op == Token.SETNAME ?
                ScriptRuntime.setName(lhs, rhs, cx,
                                      frame.scope, stringReg) :
                ScriptRuntime.strictSetName(lhs, rhs, cx,
                                      frame.scope, stringReg);
        continue Loop;
    }
    case Icode_SETCONST: {
        Object rhs = stack[stackTop];
        if (rhs == DBL_MRK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Scriptable lhs = (Scriptable)stack[stackTop];
        stack[stackTop] = ScriptRuntime.setConst(lhs, rhs, cx, stringReg);
        continue Loop;
    }
    case Token.DELPROP :
    case Icode_DELNAME : {
        stackTop = doDelName(cx, op, stack, sDbl, stackTop);
        continue Loop;
    }
    case Token.GETPROPNOWARN : {
        Object lhs = stack[stackTop];
        if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.getObjectPropNoWarn(lhs, stringReg, cx);
        continue Loop;
    }
    case Token.GETPROP : {
        Object lhs = stack[stackTop];
        if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.getObjectProp(lhs, stringReg, cx, frame.scope);
        continue Loop;
    }
    case Token.SETPROP : {
        Object rhs = stack[stackTop];
        if (rhs == DBL_MRK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Object lhs = stack[stackTop];
        if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.setObjectProp(lhs, stringReg, rhs, cx);
        continue Loop;
    }
    case Icode_PROP_INC_DEC : {
        Object lhs = stack[stackTop];
        if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.propIncrDecr(lhs, stringReg,
                                                     cx, iCode[frame.pc]);
        ++frame.pc;
        continue Loop;
    }
    case Token.GETELEM : {
        stackTop = doGetElem(cx, frame, stack, sDbl, stackTop);
        continue Loop;
    }
    case Token.SETELEM : {
        stackTop = doSetElem(cx, stack, sDbl, stackTop);
        continue Loop;
    }
    case Icode_ELEM_INC_DEC: {
        stackTop = doElemIncDec(cx, frame, iCode, stack, sDbl, stackTop);
        continue Loop;
    }
    case Token.GET_REF : {
        Ref ref = (Ref)stack[stackTop];
        stack[stackTop] = ScriptRuntime.refGet(ref, cx);
        continue Loop;
    }
    case Token.SET_REF : {
        Object value = stack[stackTop];
        if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Ref ref = (Ref)stack[stackTop];
        stack[stackTop] = ScriptRuntime.refSet(ref, value, cx);
        continue Loop;
    }
    case Token.DEL_REF : {
        Ref ref = (Ref)stack[stackTop];
        stack[stackTop] = ScriptRuntime.refDel(ref, cx);
        continue Loop;
    }
    case Icode_REF_INC_DEC : {
        Ref ref = (Ref)stack[stackTop];
        stack[stackTop] = ScriptRuntime.refIncrDecr(ref, cx, iCode[frame.pc]);
        ++frame.pc;
        continue Loop;
    }
    case Token.LOCAL_LOAD :
        ++stackTop;
        indexReg += frame.localShift;
        stack[stackTop] = stack[indexReg];
        sDbl[stackTop] = sDbl[indexReg];
        continue Loop;
    case Icode_LOCAL_CLEAR :
        indexReg += frame.localShift;
        stack[indexReg] = null;
        continue Loop;
    case Icode_NAME_AND_THIS :
        // stringReg: name
        ++stackTop;
        stack[stackTop] = ScriptRuntime.getNameFunctionAndThis(stringReg,
                                                               cx, frame.scope);
        ++stackTop;
        stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
        continue Loop;
    case Icode_PROP_AND_THIS: {
        Object obj = stack[stackTop];
        if (obj == DBL_MRK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        // stringReg: property
        stack[stackTop] = ScriptRuntime.getPropFunctionAndThis(obj, stringReg,
                                                               cx, frame.scope);
        ++stackTop;
        stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
        continue Loop;
    }
    case Icode_ELEM_AND_THIS: {
        Object obj = stack[stackTop - 1];
        if (obj == DBL_MRK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop - 1]);
        Object id = stack[stackTop];
        if (id == DBL_MRK) id = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop - 1] = ScriptRuntime.getElemFunctionAndThis(obj, id, cx);
        stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
        continue Loop;
    }
    case Icode_VALUE_AND_THIS : {
        Object value = stack[stackTop];
        if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.getValueFunctionAndThis(value, cx);
        ++stackTop;
        stack[stackTop] = ScriptRuntime.lastStoredScriptable(cx);
        continue Loop;
    }
    case Icode_CALLSPECIAL : {
        if (instructionCounting) {
            cx.instructionCount += INVOCATION_COST;
        }
        stackTop = doCallSpecial(cx, frame, stack, sDbl, stackTop, iCode, indexReg);
        continue Loop;
    }
    case Token.CALL :
    case Icode_TAIL_CALL :
    case Token.REF_CALL : {
        if (instructionCounting) {
            cx.instructionCount += INVOCATION_COST;
        }
        // stack change: function thisObj arg0 .. argN -> result
        // indexReg: number of arguments
        stackTop -= 1 + indexReg;

        // CALL generation ensures that fun and funThisObj
        // are already Scriptable and Callable objects respectively
        Callable fun = (Callable)stack[stackTop];
        Scriptable funThisObj = (Scriptable)stack[stackTop + 1];
        if (op == Token.REF_CALL) {
            Object[] outArgs = getArgsArray(stack, sDbl, stackTop + 2,
                                            indexReg);
            stack[stackTop] = ScriptRuntime.callRef(fun, funThisObj,
                                                    outArgs, cx);
            continue Loop;
        }
        Scriptable calleeScope = frame.scope;
        if (frame.useActivation) {
            calleeScope = ScriptableObject.getTopLevelScope(frame.scope);
        }
        if (fun instanceof InterpretedFunction) {
            InterpretedFunction ifun = (InterpretedFunction)fun;
            if (frame.fnOrScript.securityDomain == ifun.securityDomain) {
                CallFrame callParentFrame = frame;
                CallFrame calleeFrame = new CallFrame();
                if (op == Icode_TAIL_CALL) {
                    // In principle tail call can re-use the current
                    // frame and its stack arrays but it is hard to
                    // do properly. Any exceptions that can legally
                    // happen during frame re-initialization including
                    // StackOverflowException during innocent looking
                    // System.arraycopy may leave the current frame
                    // data corrupted leading to undefined behaviour
                    // in the catch code bellow that unwinds JS stack
                    // on exceptions. Then there is issue about frame release
                    // end exceptions there.
                    // To avoid frame allocation a released frame
                    // can be cached for re-use which would also benefit
                    // non-tail calls but it is not clear that this caching
                    // would gain in performance due to potentially
                    // bad interaction with GC.
                    callParentFrame = frame.parentFrame;
                    // Release the current frame. See Bug #344501 to see why
                    // it is being done here.
                    exitFrame(cx, frame, null);
                }
                initFrame(cx, calleeScope, funThisObj, stack, sDbl,
                          stackTop + 2, indexReg, ifun, callParentFrame,
                          calleeFrame);
                if (op != Icode_TAIL_CALL) {
                    frame.savedStackTop = stackTop;
                    frame.savedCallOp = op;
                }
                frame = calleeFrame;
                continue StateLoop;
            }
        }

        if (fun instanceof NativeContinuation) {
            // Jump to the captured continuation
            ContinuationJump cjump;
            cjump = new ContinuationJump((NativeContinuation)fun, frame);

            // continuation result is the first argument if any
            // of continuation call
            if (indexReg == 0) {
                cjump.result = undefined;
            } else {
                cjump.result = stack[stackTop + 2];
                cjump.resultDbl = sDbl[stackTop + 2];
            }

            // Start the real unwind job
            throwable = cjump;
            break withoutExceptions;
        }

        if (fun instanceof IdFunctionObject) {
            IdFunctionObject ifun = (IdFunctionObject)fun;
            if (NativeContinuation.isContinuationConstructor(ifun)) {
                frame.stack[stackTop] = captureContinuation(cx,
                        frame.parentFrame, false);
                continue Loop;
            }
            // Bug 405654 -- make best effort to keep Function.apply and
            // Function.call within this interpreter loop invocation
            if (BaseFunction.isApplyOrCall(ifun)) {
                Callable applyCallable = ScriptRuntime.getCallable(funThisObj);
                if (applyCallable instanceof InterpretedFunction) {
                    InterpretedFunction iApplyCallable = (InterpretedFunction)applyCallable;
                    if (frame.fnOrScript.securityDomain == iApplyCallable.securityDomain) {
                        frame = initFrameForApplyOrCall(cx, frame, indexReg,
                                stack, sDbl, stackTop, op, calleeScope, ifun,
                                iApplyCallable);
                        continue StateLoop;
                    }
                }
            }
        }

        // Bug 447697 -- make best effort to keep __noSuchMethod__ within this
        // interpreter loop invocation
        if (fun instanceof NoSuchMethodShim) {
            // get the shim and the actual method
            NoSuchMethodShim noSuchMethodShim = (NoSuchMethodShim) fun;
            Callable noSuchMethodMethod = noSuchMethodShim.noSuchMethodMethod;
            // if the method is in fact an InterpretedFunction
            if (noSuchMethodMethod instanceof InterpretedFunction) {
                InterpretedFunction ifun = (InterpretedFunction) noSuchMethodMethod;
                if (frame.fnOrScript.securityDomain == ifun.securityDomain) {
                    frame = initFrameForNoSuchMethod(cx, frame, indexReg, stack, sDbl,
                                             stackTop, op, funThisObj, calleeScope,
                                             noSuchMethodShim, ifun);
                    continue StateLoop;
                }
            }
        }

        cx.lastInterpreterFrame = frame;
        frame.savedCallOp = op;
        frame.savedStackTop = stackTop;
        stack[stackTop] = fun.call(cx, calleeScope, funThisObj,
                getArgsArray(stack, sDbl, stackTop + 2, indexReg));

        continue Loop;
    }
    case Token.NEW : {
        if (instructionCounting) {
            cx.instructionCount += INVOCATION_COST;
        }
        // stack change: function arg0 .. argN -> newResult
        // indexReg: number of arguments
        stackTop -= indexReg;

        Object lhs = stack[stackTop];
        if (lhs instanceof InterpretedFunction) {
            InterpretedFunction f = (InterpretedFunction)lhs;
            if (frame.fnOrScript.securityDomain == f.securityDomain) {
                Scriptable newInstance = f.createObject(cx, frame.scope);
                CallFrame calleeFrame = new CallFrame();
                initFrame(cx, frame.scope, newInstance, stack, sDbl,
                          stackTop + 1, indexReg, f, frame,
                          calleeFrame);

                stack[stackTop] = newInstance;
                frame.savedStackTop = stackTop;
                frame.savedCallOp = op;
                frame = calleeFrame;
                continue StateLoop;
            }
        }
        if (!(lhs instanceof Function)) {
            if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
            throw ScriptRuntime.notFunctionError(lhs);
        }
        Function fun = (Function)lhs;

        if (fun instanceof IdFunctionObject) {
            IdFunctionObject ifun = (IdFunctionObject)fun;
            if (NativeContinuation.isContinuationConstructor(ifun)) {
                frame.stack[stackTop] =
                    captureContinuation(cx, frame.parentFrame, false);
                continue Loop;
            }
        }

        Object[] outArgs = getArgsArray(stack, sDbl, stackTop + 1, indexReg);
        stack[stackTop] = fun.construct(cx, frame.scope, outArgs);
        continue Loop;
    }
    case Token.TYPEOF : {
        Object lhs = stack[stackTop];
        if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.typeof(lhs);
        continue Loop;
    }
    case Icode_TYPEOFNAME :
        stack[++stackTop] = ScriptRuntime.typeofName(frame.scope, stringReg);
        continue Loop;
    case Token.STRING :
        stack[++stackTop] = stringReg;
        continue Loop;
    case Icode_SHORTNUMBER :
        ++stackTop;
        stack[stackTop] = DBL_MRK;
        sDbl[stackTop] = getShort(iCode, frame.pc);
        frame.pc += 2;
        continue Loop;
    case Icode_INTNUMBER :
        ++stackTop;
        stack[stackTop] = DBL_MRK;
        sDbl[stackTop] = getInt(iCode, frame.pc);
        frame.pc += 4;
        continue Loop;
    case Token.NUMBER :
        ++stackTop;
        stack[stackTop] = DBL_MRK;
        sDbl[stackTop] = frame.idata.itsDoubleTable[indexReg];
        continue Loop;
    case Token.NAME :
        stack[++stackTop] = ScriptRuntime.name(cx, frame.scope, stringReg);
        continue Loop;
    case Icode_NAME_INC_DEC :
        stack[++stackTop] = ScriptRuntime.nameIncrDecr(frame.scope, stringReg,
                                                       cx, iCode[frame.pc]);
        ++frame.pc;
        continue Loop;
    case Icode_SETCONSTVAR1:
        indexReg = iCode[frame.pc++];
        // fallthrough
    case Token.SETCONSTVAR :
        stackTop = doSetConstVar(frame, stack, sDbl, stackTop, vars, varDbls,
                                 varAttributes, indexReg);
        continue Loop;
    case Icode_SETVAR1:
        indexReg = iCode[frame.pc++];
        // fallthrough
    case Token.SETVAR :
        stackTop = doSetVar(frame, stack, sDbl, stackTop, vars, varDbls,
                            varAttributes, indexReg);
        continue Loop;
    case Icode_GETVAR1:
        indexReg = iCode[frame.pc++];
        // fallthrough
    case Token.GETVAR :
        stackTop = doGetVar(frame, stack, sDbl, stackTop, vars, varDbls, indexReg);
        continue Loop;
    case Icode_VAR_INC_DEC : {
        stackTop = doVarIncDec(cx, frame, stack, sDbl, stackTop,
                               vars, varDbls, indexReg);
        continue Loop;
    }
    case Icode_ZERO :
        ++stackTop;
        stack[stackTop] = DBL_MRK;
        sDbl[stackTop] = 0;
        continue Loop;
    case Icode_ONE :
        ++stackTop;
        stack[stackTop] = DBL_MRK;
        sDbl[stackTop] = 1;
        continue Loop;
    case Token.NULL :
        stack[++stackTop] = null;
        continue Loop;
    case Token.THIS :
        stack[++stackTop] = frame.thisObj;
        continue Loop;
    case Token.THISFN :
        stack[++stackTop] = frame.fnOrScript;
        continue Loop;
    case Token.FALSE :
        stack[++stackTop] = Boolean.FALSE;
        continue Loop;
    case Token.TRUE :
        stack[++stackTop] = Boolean.TRUE;
        continue Loop;
    case Icode_UNDEF :
        stack[++stackTop] = undefined;
        continue Loop;
    case Token.ENTERWITH : {
        Object lhs = stack[stackTop];
        if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        frame.scope = ScriptRuntime.enterWith(lhs, cx, frame.scope);
        continue Loop;
    }
    case Token.LEAVEWITH :
        frame.scope = ScriptRuntime.leaveWith(frame.scope);
        continue Loop;
    case Token.CATCH_SCOPE : {
        // stack top: exception object
        // stringReg: name of exception variable
        // indexReg: local for exception scope
        --stackTop;
        indexReg += frame.localShift;

        boolean afterFirstScope =  (frame.idata.itsICode[frame.pc] != 0);
        Throwable caughtException = (Throwable)stack[stackTop + 1];
        Scriptable lastCatchScope;
        if (!afterFirstScope) {
            lastCatchScope = null;
        } else {
            lastCatchScope = (Scriptable)stack[indexReg];
        }
        stack[indexReg] = ScriptRuntime.newCatchScope(caughtException,
                                                      lastCatchScope, stringReg,
                                                      cx, frame.scope);
        ++frame.pc;
        continue Loop;
    }
    case Token.ENUM_INIT_KEYS :
    case Token.ENUM_INIT_VALUES :
    case Token.ENUM_INIT_ARRAY : {
        Object lhs = stack[stackTop];
        if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        indexReg += frame.localShift;
        int enumType = op == Token.ENUM_INIT_KEYS
                         ? ScriptRuntime.ENUMERATE_KEYS :
                       op == Token.ENUM_INIT_VALUES
                         ? ScriptRuntime.ENUMERATE_VALUES :
                       ScriptRuntime.ENUMERATE_ARRAY;
        stack[indexReg] = ScriptRuntime.enumInit(lhs, cx, enumType);
        continue Loop;
    }
    case Token.ENUM_NEXT :
    case Token.ENUM_ID : {
        indexReg += frame.localShift;
        Object val = stack[indexReg];
        ++stackTop;
        stack[stackTop] = (op == Token.ENUM_NEXT)
                          ? (Object)ScriptRuntime.enumNext(val)
                          : (Object)ScriptRuntime.enumId(val, cx);
        continue Loop;
    }
    case Token.REF_SPECIAL : {
        //stringReg: name of special property
        Object obj = stack[stackTop];
        if (obj == DBL_MRK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.specialRef(obj, stringReg, cx);
        continue Loop;
    }
    case Token.REF_MEMBER: {
        //indexReg: flags
        stackTop = doRefMember(cx, stack, sDbl, stackTop, indexReg);
        continue Loop;
    }
    case Token.REF_NS_MEMBER: {
        //indexReg: flags
        stackTop = doRefNsMember(cx, stack, sDbl, stackTop, indexReg);
        continue Loop;
    }
    case Token.REF_NAME: {
        //indexReg: flags
        Object name = stack[stackTop];
        if (name == DBL_MRK) name = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.nameRef(name, cx, frame.scope,
                                                indexReg);
        continue Loop;
    }
    case Token.REF_NS_NAME: {
        //indexReg: flags
        stackTop = doRefNsName(cx, frame, stack, sDbl, stackTop, indexReg);
        continue Loop;
    }
    case Icode_SCOPE_LOAD :
        indexReg += frame.localShift;
        frame.scope = (Scriptable)stack[indexReg];
        continue Loop;
    case Icode_SCOPE_SAVE :
        indexReg += frame.localShift;
        stack[indexReg] = frame.scope;
        continue Loop;
    case Icode_CLOSURE_EXPR :
        stack[++stackTop] = InterpretedFunction.createFunction(cx, frame.scope,
                                                               frame.fnOrScript,
                                                               indexReg);
        continue Loop;
    case Icode_CLOSURE_STMT :
        initFunction(cx, frame.scope, frame.fnOrScript, indexReg);
        continue Loop;
    case Token.REGEXP :
        Object re = frame.idata.itsRegExpLiterals[indexReg];
        stack[++stackTop] = ScriptRuntime.wrapRegExp(cx, frame.scope, re);
        continue Loop;
    case Icode_LITERAL_NEW :
        // indexReg: number of values in the literal
        ++stackTop;
        stack[stackTop] = new int[indexReg];
        ++stackTop;
        stack[stackTop] = new Object[indexReg];
        sDbl[stackTop] = 0;
        continue Loop;
    case Icode_LITERAL_SET : {
        Object value = stack[stackTop];
        if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        int i = (int)sDbl[stackTop];
        ((Object[])stack[stackTop])[i] = value;
        sDbl[stackTop] = i + 1;
        continue Loop;
    }
    case Icode_LITERAL_GETTER : {
        Object value = stack[stackTop];
        --stackTop;
        int i = (int)sDbl[stackTop];
        ((Object[])stack[stackTop])[i] = value;
        ((int[])stack[stackTop - 1])[i] = -1;
        sDbl[stackTop] = i + 1;
        continue Loop;
    }
    case Icode_LITERAL_SETTER : {
        Object value = stack[stackTop];
        --stackTop;
        int i = (int)sDbl[stackTop];
        ((Object[])stack[stackTop])[i] = value;
        ((int[])stack[stackTop - 1])[i] = +1;
        sDbl[stackTop] = i + 1;
        continue Loop;
    }
    case Token.ARRAYLIT :
    case Icode_SPARE_ARRAYLIT :
    case Token.OBJECTLIT : {
        Object[] data = (Object[])stack[stackTop];
        --stackTop;
        int[] getterSetters = (int[])stack[stackTop];
        Object val;
        if (op == Token.OBJECTLIT) {
            Object[] ids = (Object[])frame.idata.literalIds[indexReg];
            val = ScriptRuntime.newObjectLiteral(ids, data, getterSetters, cx,
                    frame.scope);
        } else {
            int[] skipIndexces = null;
            if (op == Icode_SPARE_ARRAYLIT) {
                skipIndexces = (int[])frame.idata.literalIds[indexReg];
            }
            val = ScriptRuntime.newArrayLiteral(data, skipIndexces, cx,
                                                frame.scope);
        }
        stack[stackTop] = val;
        continue Loop;
    }
    case Icode_ENTERDQ : {
        Object lhs = stack[stackTop];
        if (lhs == DBL_MRK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        frame.scope = ScriptRuntime.enterDotQuery(lhs, frame.scope);
        continue Loop;
    }
    case Icode_LEAVEDQ : {
        boolean valBln = stack_boolean(frame, stackTop);
        Object x = ScriptRuntime.updateDotQuery(valBln, frame.scope);
        if (x != null) {
            stack[stackTop] = x;
            frame.scope = ScriptRuntime.leaveDotQuery(frame.scope);
            frame.pc += 2;
            continue Loop;
        }
        // reset stack and PC to code after ENTERDQ
        --stackTop;
        break jumplessRun;
    }
    case Token.DEFAULTNAMESPACE : {
        Object value = stack[stackTop];
        if (value == DBL_MRK) value = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.setDefaultNamespace(value, cx);
        continue Loop;
    }
    case Token.ESCXMLATTR : {
        Object value = stack[stackTop];
        if (value != DBL_MRK) {
            stack[stackTop] = ScriptRuntime.escapeAttributeValue(value, cx);
        }
        continue Loop;
    }
    case Token.ESCXMLTEXT : {
        Object value = stack[stackTop];
        if (value != DBL_MRK) {
            stack[stackTop] = ScriptRuntime.escapeTextValue(value, cx);
        }
        continue Loop;
    }
    case Icode_DEBUGGER:
        if (frame.debuggerFrame != null) {
            frame.debuggerFrame.onDebuggerStatement(cx);
        }
        continue Loop;
    case Icode_LINE :
        frame.pcSourceLineStart = frame.pc;
        if (frame.debuggerFrame != null) {
            int line = getIndex(iCode, frame.pc);
            frame.debuggerFrame.onLineChange(cx, line);
        }
        frame.pc += 2;
        continue Loop;
    case Icode_REG_IND_C0:
        indexReg = 0;
        continue Loop;
    case Icode_REG_IND_C1:
        indexReg = 1;
        continue Loop;
    case Icode_REG_IND_C2:
        indexReg = 2;
        continue Loop;
    case Icode_REG_IND_C3:
        indexReg = 3;
        continue Loop;
    case Icode_REG_IND_C4:
        indexReg = 4;
        continue Loop;
    case Icode_REG_IND_C5:
        indexReg = 5;
        continue Loop;
    case Icode_REG_IND1:
        indexReg = 0xFF & iCode[frame.pc];
        ++frame.pc;
        continue Loop;
    case Icode_REG_IND2:
        indexReg = getIndex(iCode, frame.pc);
        frame.pc += 2;
        continue Loop;
    case Icode_REG_IND4:
        indexReg = getInt(iCode, frame.pc);
        frame.pc += 4;
        continue Loop;
    case Icode_REG_STR_C0:
        stringReg = strings[0];
        continue Loop;
    case Icode_REG_STR_C1:
        stringReg = strings[1];
        continue Loop;
    case Icode_REG_STR_C2:
        stringReg = strings[2];
        continue Loop;
    case Icode_REG_STR_C3:
        stringReg = strings[3];
        continue Loop;
    case Icode_REG_STR1:
        stringReg = strings[0xFF & iCode[frame.pc]];
        ++frame.pc;
        continue Loop;
    case Icode_REG_STR2:
        stringReg = strings[getIndex(iCode, frame.pc)];
        frame.pc += 2;
        continue Loop;
    case Icode_REG_STR4:
        stringReg = strings[getInt(iCode, frame.pc)];
        frame.pc += 4;
        continue Loop;
    default :
        dumpICode(frame.idata);
        throw new RuntimeException("Unknown icode : " + op
                                 + " @ pc : " + (frame.pc-1));
}  // end of interpreter switch

                    } // end of jumplessRun label block

                    // This should be reachable only for jump implementation
                    // when pc points to encoded target offset
                    if (instructionCounting) {
                        addInstructionCount(cx, frame, 2);
                    }
                    int offset = getShort(iCode, frame.pc);
                    if (offset != 0) {
                        // -1 accounts for pc pointing to jump opcode + 1
                        frame.pc += offset - 1;
                    } else {
                        frame.pc = frame.idata.longJumps.
                                       getExistingInt(frame.pc);
                    }
                    if (instructionCounting) {
                        frame.pcPrevBranch = frame.pc;
                    }
                    continue Loop;

                } // end of Loop: for

                exitFrame(cx, frame, null);
                interpreterResult = frame.result;
                interpreterResultDbl = frame.resultDbl;
                if (frame.parentFrame != null) {
                    frame = frame.parentFrame;
                    if (frame.frozen) {
                        frame = frame.cloneFrozen();
                    }
                    setCallResult(
                        frame, interpreterResult, interpreterResultDbl);
                    interpreterResult = null; // Help GC
                    continue StateLoop;
                }
                break StateLoop;

            }  // end of interpreter withoutExceptions: try
            catch (Throwable ex) {
                if (throwable != null) {
                    // This is serious bug and it is better to track it ASAP
                    ex.printStackTrace(System.err);
                    throw new IllegalStateException();
                }
                throwable = ex;
            }

            // This should be reachable only after above catch or from
            // finally when it needs to propagate exception or from
            // explicit throw
            if (throwable == null) Kit.codeBug();

            // Exception type
            final int EX_CATCH_STATE = 2; // Can execute JS catch
            final int EX_FINALLY_STATE = 1; // Can execute JS finally
            final int EX_NO_JS_STATE = 0; // Terminate JS execution

            int exState;
            ContinuationJump cjump = null;

            if (generatorState != null &&
                generatorState.operation == NativeGenerator.GENERATOR_CLOSE &&
                throwable == generatorState.value)
            {
                exState = EX_FINALLY_STATE;
            } else if (throwable instanceof JavaScriptException) {
                exState = EX_CATCH_STATE;
            } else if (throwable instanceof EcmaError) {
                // an offical ECMA error object,
                exState = EX_CATCH_STATE;
            } else if (throwable instanceof EvaluatorException) {
                exState = EX_CATCH_STATE;
            } else if (throwable instanceof RuntimeException) {
                exState = cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)
                          ? EX_CATCH_STATE
                          : EX_FINALLY_STATE;
            } else if (throwable instanceof Error) {
                exState = cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)
                          ? EX_CATCH_STATE
                          : EX_NO_JS_STATE;
            } else if (throwable instanceof ContinuationJump) {
                // It must be ContinuationJump
                exState = EX_FINALLY_STATE;
                cjump = (ContinuationJump)throwable;
            } else {
                exState = cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)
                          ? EX_CATCH_STATE
                          : EX_FINALLY_STATE;
            }

            if (instructionCounting) {
                try {
                    addInstructionCount(cx, frame, EXCEPTION_COST);
                } catch (RuntimeException ex) {
                    throwable = ex;
                    exState = EX_FINALLY_STATE;
                } catch (Error ex) {
                    // Error from instruction counting
                    //     => unconditionally terminate JS
                    throwable = ex;
                    cjump = null;
                    exState = EX_NO_JS_STATE;
                }
            }
            if (frame.debuggerFrame != null
                && throwable instanceof RuntimeException)
            {
                // Call debugger only for RuntimeException
                RuntimeException rex = (RuntimeException)throwable;
                try {
                    frame.debuggerFrame.onExceptionThrown(cx, rex);
                } catch (Throwable ex) {
                    // Any exception from debugger
                    //     => unconditionally terminate JS
                    throwable = ex;
                    cjump = null;
                    exState = EX_NO_JS_STATE;
                }
            }

            for (;;) {
                if (exState != EX_NO_JS_STATE) {
                    boolean onlyFinally = (exState != EX_CATCH_STATE);
                    indexReg = getExceptionHandler(frame, onlyFinally);
                    if (indexReg >= 0) {
                        // We caught an exception, restart the loop
                        // with exception pending the processing at the loop
                        // start
                        continue StateLoop;
                    }
                }
                // No allowed exception handlers in this frame, unwind
                // to parent and try to look there

                exitFrame(cx, frame, throwable);

                frame = frame.parentFrame;
                if (frame == null) { break; }
                if (cjump != null && cjump.branchFrame == frame) {
                    // Continuation branch point was hit,
                    // restart the state loop to reenter continuation
                    indexReg = -1;
                    continue StateLoop;
                }
            }

            // No more frames, rethrow the exception or deal with continuation
            if (cjump != null) {
                if (cjump.branchFrame != null) {
                    // The above loop should locate the top frame
                    Kit.codeBug();
                }
                if (cjump.capturedFrame != null) {
                    // Restarting detached continuation
                    indexReg = -1;
                    continue StateLoop;
                }
                // Return continuation result to the caller
                interpreterResult = cjump.result;
                interpreterResultDbl = cjump.resultDbl;
                throwable = null;
            }
            break StateLoop;

        } // end of StateLoop: for(;;)

        // Do cleanups/restorations before the final return or throw

        if (cx.previousInterpreterInvocations != null
            && cx.previousInterpreterInvocations.size() != 0)
        {
            cx.lastInterpreterFrame
                = cx.previousInterpreterInvocations.pop();
        } else {
            // It was the last interpreter frame on the stack
            cx.lastInterpreterFrame = null;
            // Force GC of the value cx.previousInterpreterInvocations
            cx.previousInterpreterInvocations = null;
        }

        if (throwable != null) {
            if (throwable instanceof RuntimeException) {
                throw (RuntimeException)throwable;
            } else {
                // Must be instance of Error or code bug
                throw (Error)throwable;
            }
        }

        return (interpreterResult != DBL_MRK)
               ? interpreterResult
               : ScriptRuntime.wrapNumber(interpreterResultDbl);
    }

    private static int doInOrInstanceof(Context cx, int op, Object[] stack,
                                        double[] sDbl, int stackTop) {
        Object rhs = stack[stackTop];
        if (rhs == DOUBLE_MARK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Object lhs = stack[stackTop];
        if (lhs == DOUBLE_MARK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        boolean valBln;
        if (op == Token.IN) {
            valBln = ScriptRuntime.in(lhs, rhs, cx);
        } else {
            valBln = ScriptRuntime.instanceOf(lhs, rhs, cx);
        }
        stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
        return stackTop;
    }

    private static int doCompare(CallFrame frame, int op, Object[] stack,
                                 double[] sDbl, int stackTop) {
        --stackTop;
        Object rhs = stack[stackTop + 1];
        Object lhs = stack[stackTop];
        boolean valBln;
        object_compare:
        {
            number_compare:
            {
                double rDbl, lDbl;
                if (rhs == DOUBLE_MARK) {
                    rDbl = sDbl[stackTop + 1];
                    lDbl = stack_double(frame, stackTop);
                } else if (lhs == DOUBLE_MARK) {
                    rDbl = ScriptRuntime.toNumber(rhs);
                    lDbl = sDbl[stackTop];
                } else {
                    break number_compare;
                }
                switch (op) {
                    case Token.GE:
                        valBln = (lDbl >= rDbl);
                        break object_compare;
                    case Token.LE:
                        valBln = (lDbl <= rDbl);
                        break object_compare;
                    case Token.GT:
                        valBln = (lDbl > rDbl);
                        break object_compare;
                    case Token.LT:
                        valBln = (lDbl < rDbl);
                        break object_compare;
                    default:
                        throw Kit.codeBug();
                }
            }
            switch (op) {
                case Token.GE:
                    valBln = ScriptRuntime.cmp_LE(rhs, lhs);
                    break;
                case Token.LE:
                    valBln = ScriptRuntime.cmp_LE(lhs, rhs);
                    break;
                case Token.GT:
                    valBln = ScriptRuntime.cmp_LT(rhs, lhs);
                    break;
                case Token.LT:
                    valBln = ScriptRuntime.cmp_LT(lhs, rhs);
                    break;
                default:
                    throw Kit.codeBug();
            }
        }
        stack[stackTop] = ScriptRuntime.wrapBoolean(valBln);
        return stackTop;
    }

    private static int doBitOp(CallFrame frame, int op, Object[] stack,
                               double[] sDbl, int stackTop) {
        int lIntValue = stack_int32(frame, stackTop - 1);
        int rIntValue = stack_int32(frame, stackTop);
        stack[--stackTop] = DOUBLE_MARK;
        switch (op) {
          case Token.BITAND:
            lIntValue &= rIntValue;
            break;
          case Token.BITOR:
            lIntValue |= rIntValue;
            break;
          case Token.BITXOR:
            lIntValue ^= rIntValue;
            break;
          case Token.LSH:
            lIntValue <<= rIntValue;
            break;
          case Token.RSH:
            lIntValue >>= rIntValue;
            break;
        }
        sDbl[stackTop] = lIntValue;
        return stackTop;
    }

    private static int doDelName(Context cx, int op, Object[] stack,
                                 double[] sDbl, int stackTop) {
        Object rhs = stack[stackTop];
        if (rhs == DOUBLE_MARK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Object lhs = stack[stackTop];
        if (lhs == DOUBLE_MARK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.delete(lhs, rhs, cx, op == Icode_DELNAME);
        return stackTop;
    }

    private static int doGetElem(Context cx, CallFrame frame, Object[] stack,
                                 double[] sDbl, int stackTop) {
        --stackTop;
        Object lhs = stack[stackTop];
        if (lhs == DOUBLE_MARK) {
            lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        }
        Object value;
        Object id = stack[stackTop + 1];
        if (id != DOUBLE_MARK) {
            value = ScriptRuntime.getObjectElem(lhs, id, cx, frame.scope);
        } else {
            double d = sDbl[stackTop + 1];
            value = ScriptRuntime.getObjectIndex(lhs, d, cx);
        }
        stack[stackTop] = value;
        return stackTop;
    }

    private static int doSetElem(Context cx, Object[] stack, double[] sDbl,
                                 int stackTop) {
        stackTop -= 2;
        Object rhs = stack[stackTop + 2];
        if (rhs == DOUBLE_MARK) {
            rhs = ScriptRuntime.wrapNumber(sDbl[stackTop + 2]);
        }
        Object lhs = stack[stackTop];
        if (lhs == DOUBLE_MARK) {
            lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        }
        Object value;
        Object id = stack[stackTop + 1];
        if (id != DOUBLE_MARK) {
            value = ScriptRuntime.setObjectElem(lhs, id, rhs, cx);
        } else {
            double d = sDbl[stackTop + 1];
            value = ScriptRuntime.setObjectIndex(lhs, d, rhs, cx);
        }
        stack[stackTop] = value;
        return stackTop;
    }

    private static int doElemIncDec(Context cx, CallFrame frame, byte[] iCode,
                                    Object[] stack, double[] sDbl, int stackTop) {
        Object rhs = stack[stackTop];
        if (rhs == DOUBLE_MARK) rhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Object lhs = stack[stackTop];
        if (lhs == DOUBLE_MARK) lhs = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.elemIncrDecr(lhs, rhs, cx,
                                                     iCode[frame.pc]);
        ++frame.pc;
        return stackTop;
    }

    private static int doCallSpecial(Context cx, CallFrame frame,
                                     Object[] stack, double[] sDbl,
                                     int stackTop, byte[] iCode,
                                     int indexReg) {
        int callType = iCode[frame.pc] & 0xFF;
        boolean isNew =  (iCode[frame.pc + 1] != 0);
        int sourceLine = getIndex(iCode, frame.pc + 2);

        // indexReg: number of arguments
        if (isNew) {
            // stack change: function arg0 .. argN -> newResult
            stackTop -= indexReg;

            Object function = stack[stackTop];
            if (function == DOUBLE_MARK)
                function = ScriptRuntime.wrapNumber(sDbl[stackTop]);
            Object[] outArgs = getArgsArray(
                                   stack, sDbl, stackTop + 1, indexReg);
            stack[stackTop] = ScriptRuntime.newSpecial(
                                  cx, function, outArgs, frame.scope, callType);
        } else {
            // stack change: function thisObj arg0 .. argN -> result
            stackTop -= 1 + indexReg;

            // Call code generation ensure that stack here
            // is ... Callable Scriptable
            Scriptable functionThis = (Scriptable)stack[stackTop + 1];
            Callable function = (Callable)stack[stackTop];
            Object[] outArgs = getArgsArray(
                                   stack, sDbl, stackTop + 2, indexReg);
            stack[stackTop] = ScriptRuntime.callSpecial(
                                  cx, function, functionThis, outArgs,
                                  frame.scope, frame.thisObj, callType,
                                  frame.idata.itsSourceFile, sourceLine);
        }
        frame.pc += 4;
        return stackTop;
    }

    private static int doSetConstVar(CallFrame frame, Object[] stack,
                                     double[] sDbl, int stackTop,
                                     Object[] vars, double[] varDbls,
                                     int[] varAttributes, int indexReg) {
        if (!frame.useActivation) {
            if ((varAttributes[indexReg] & ScriptableObject.READONLY) == 0) {
                throw Context.reportRuntimeError1("msg.var.redecl",
                                                  frame.idata.argNames[indexReg]);
            }
            if ((varAttributes[indexReg] & ScriptableObject.UNINITIALIZED_CONST)
                != 0)
            {
                vars[indexReg] = stack[stackTop];
                varAttributes[indexReg] &= ~ScriptableObject.UNINITIALIZED_CONST;
                varDbls[indexReg] = sDbl[stackTop];
            }
        } else {
            Object val = stack[stackTop];
            if (val == DOUBLE_MARK) val = ScriptRuntime.wrapNumber(sDbl[stackTop]);
            String stringReg = frame.idata.argNames[indexReg];
            if (frame.scope instanceof ConstProperties) {
                ConstProperties cp = (ConstProperties)frame.scope;
                cp.putConst(stringReg, frame.scope, val);
            } else
                throw Kit.codeBug();
        }
        return stackTop;
    }

    private static int doSetVar(CallFrame frame, Object[] stack,
                                double[] sDbl, int stackTop,
                                Object[] vars, double[] varDbls,
                                int[] varAttributes, int indexReg) {
        if (!frame.useActivation) {
            if ((varAttributes[indexReg] & ScriptableObject.READONLY) == 0) {
                vars[indexReg] = stack[stackTop];
                varDbls[indexReg] = sDbl[stackTop];
            }
        } else {
            Object val = stack[stackTop];
            if (val == DOUBLE_MARK) val = ScriptRuntime.wrapNumber(sDbl[stackTop]);
            String stringReg = frame.idata.argNames[indexReg];
            frame.scope.put(stringReg, frame.scope, val);
        }
        return stackTop;
    }

    private static int doGetVar(CallFrame frame, Object[] stack,
                                double[] sDbl, int stackTop,
                                Object[] vars, double[] varDbls,
                                int indexReg) {
        ++stackTop;
        if (!frame.useActivation) {
            stack[stackTop] = vars[indexReg];
            sDbl[stackTop] = varDbls[indexReg];
        } else {
            String stringReg = frame.idata.argNames[indexReg];
            stack[stackTop] = frame.scope.get(stringReg, frame.scope);
        }
        return stackTop;
    }

    private static int doVarIncDec(Context cx, CallFrame frame,
                                   Object[] stack, double[] sDbl,
                                   int stackTop, Object[] vars,
                                   double[] varDbls, int indexReg) {
        // indexReg : varindex
        ++stackTop;
        int incrDecrMask = frame.idata.itsICode[frame.pc];
        if (!frame.useActivation) {
            stack[stackTop] = DOUBLE_MARK;
            Object varValue = vars[indexReg];
            double d;
            if (varValue == DOUBLE_MARK) {
                d = varDbls[indexReg];
            } else {
                d = ScriptRuntime.toNumber(varValue);
                vars[indexReg] = DOUBLE_MARK;
            }
            double d2 = ((incrDecrMask & Node.DECR_FLAG) == 0)
                        ? d + 1.0 : d - 1.0;
            varDbls[indexReg] = d2;
            sDbl[stackTop] = ((incrDecrMask & Node.POST_FLAG) == 0) ? d2 : d;
        } else {
            String varName = frame.idata.argNames[indexReg];
            stack[stackTop] = ScriptRuntime.nameIncrDecr(frame.scope, varName,
                                                         cx, incrDecrMask);
        }
        ++frame.pc;
        return stackTop;
    }

    private static int doRefMember(Context cx, Object[] stack, double[] sDbl,
                                   int stackTop, int flags) {
        Object elem = stack[stackTop];
        if (elem == DOUBLE_MARK) elem = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Object obj = stack[stackTop];
        if (obj == DOUBLE_MARK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.memberRef(obj, elem, cx, flags);
        return stackTop;
    }

    private static int doRefNsMember(Context cx, Object[] stack, double[] sDbl,
                                     int stackTop, int flags) {
        Object elem = stack[stackTop];
        if (elem == DOUBLE_MARK) elem = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Object ns = stack[stackTop];
        if (ns == DOUBLE_MARK) ns = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Object obj = stack[stackTop];
        if (obj == DOUBLE_MARK) obj = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.memberRef(obj, ns, elem, cx, flags);
        return stackTop;
    }

    private static int doRefNsName(Context cx, CallFrame frame,
                                   Object[] stack, double[] sDbl,
                                   int stackTop, int flags) {
        Object name = stack[stackTop];
        if (name == DOUBLE_MARK) name = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        --stackTop;
        Object ns = stack[stackTop];
        if (ns == DOUBLE_MARK) ns = ScriptRuntime.wrapNumber(sDbl[stackTop]);
        stack[stackTop] = ScriptRuntime.nameRef(ns, name, cx, frame.scope, flags);
        return stackTop;
    }

    /**
     * Call __noSuchMethod__.
     */
    private static CallFrame initFrameForNoSuchMethod(Context cx,
            CallFrame frame, int indexReg, Object[] stack, double[] sDbl,
            int stackTop, int op, Scriptable funThisObj, Scriptable calleeScope,
            NoSuchMethodShim noSuchMethodShim, InterpretedFunction ifun)
    {
        // create an args array from the stack
        Object[] argsArray = null;
        // exactly like getArgsArray except that the first argument
        // is the method name from the shim
        int shift = stackTop + 2;
        Object[] elements = new Object[indexReg];
        for (int i=0; i < indexReg; ++i, ++shift) {
            Object val = stack[shift];
            if (val == DOUBLE_MARK) {
                val = ScriptRuntime.wrapNumber(sDbl[shift]);
            }
            elements[i] = val;
        }
        argsArray = new Object[2];
        argsArray[0] = noSuchMethodShim.methodName;
        argsArray[1] = cx.newArray(calleeScope, elements);

        // exactly the same as if it's a regular InterpretedFunction
        CallFrame callParentFrame = frame;
        CallFrame calleeFrame = new CallFrame();
        if (op == Icode_TAIL_CALL) {
            callParentFrame = frame.parentFrame;
            exitFrame(cx, frame, null);
        }
        // init the frame with the underlying method with the
        // adjusted args array and shim's function
        initFrame(cx, calleeScope, funThisObj, argsArray, null,
          0, 2, ifun, callParentFrame, calleeFrame);
        if (op != Icode_TAIL_CALL) {
            frame.savedStackTop = stackTop;
            frame.savedCallOp = op;
        }
        return calleeFrame;
    }

    private static boolean doEquals(Object[] stack, double[] sDbl,
                                    int stackTop) {
        Object rhs = stack[stackTop + 1];
        Object lhs = stack[stackTop];
        if (rhs == DOUBLE_MARK) {
            if (lhs == DOUBLE_MARK) {
                return (sDbl[stackTop] == sDbl[stackTop + 1]);
            } else {
                return ScriptRuntime.eqNumber(sDbl[stackTop + 1], lhs);
            }
        } else {
            if (lhs == DOUBLE_MARK) {
                return ScriptRuntime.eqNumber(sDbl[stackTop], rhs);
            } else {
                return ScriptRuntime.eq(lhs, rhs);
            }
        }
    }

    private static boolean doShallowEquals(Object[] stack, double[] sDbl,
                                           int stackTop)
    {
        Object rhs = stack[stackTop + 1];
        Object lhs = stack[stackTop];
        final Object DBL_MRK = DOUBLE_MARK;
        double rdbl, ldbl;
        if (rhs == DBL_MRK) {
            rdbl = sDbl[stackTop + 1];
            if (lhs == DBL_MRK) {
                ldbl = sDbl[stackTop];
            } else if (lhs instanceof Number) {
                ldbl = ((Number)lhs).doubleValue();
            } else {
                return false;
            }
        } else if (lhs == DBL_MRK) {
            ldbl = sDbl[stackTop];
            if (rhs instanceof Number) {
                rdbl = ((Number)rhs).doubleValue();
            } else {
                return false;
            }
        } else {
            return ScriptRuntime.shallowEq(lhs, rhs);
        }
        return (ldbl == rdbl);
    }

    private static CallFrame processThrowable(Context cx, Object throwable,
                                              CallFrame frame, int indexReg,
                                              boolean instructionCounting)
    {
        // Recovering from exception, indexReg contains
        // the index of handler

        if (indexReg >= 0) {
            // Normal exception handler, transfer
            // control appropriately

            if (frame.frozen) {
                // XXX Deal with exceptios!!!
                frame = frame.cloneFrozen();
            }

            int[] table = frame.idata.itsExceptionTable;

            frame.pc = table[indexReg + EXCEPTION_HANDLER_SLOT];
            if (instructionCounting) {
                frame.pcPrevBranch = frame.pc;
            }

            frame.savedStackTop = frame.emptyStackTop;
            int scopeLocal = frame.localShift
                             + table[indexReg
                                     + EXCEPTION_SCOPE_SLOT];
            int exLocal = frame.localShift
                             + table[indexReg
                                     + EXCEPTION_LOCAL_SLOT];
            frame.scope = (Scriptable)frame.stack[scopeLocal];
            frame.stack[exLocal] = throwable;

            throwable = null;
        } else {
            // Continuation restoration
            ContinuationJump cjump = (ContinuationJump)throwable;

            // Clear throwable to indicate that exceptions are OK
            throwable = null;

            if (cjump.branchFrame != frame) Kit.codeBug();

            // Check that we have at least one frozen frame
            // in the case of detached continuation restoration:
            // unwind code ensure that
            if (cjump.capturedFrame == null) Kit.codeBug();

            // Need to rewind branchFrame, capturedFrame
            // and all frames in between
            int rewindCount = cjump.capturedFrame.frameIndex + 1;
            if (cjump.branchFrame != null) {
                rewindCount -= cjump.branchFrame.frameIndex;
            }

            int enterCount = 0;
            CallFrame[] enterFrames = null;

            CallFrame x = cjump.capturedFrame;
            for (int i = 0; i != rewindCount; ++i) {
                if (!x.frozen) Kit.codeBug();
                if (isFrameEnterExitRequired(x)) {
                    if (enterFrames == null) {
                        // Allocate enough space to store the rest
                        // of rewind frames in case all of them
                        // would require to enter
                        enterFrames = new CallFrame[rewindCount
                                                    - i];
                    }
                    enterFrames[enterCount] = x;
                    ++enterCount;
                }
                x = x.parentFrame;
            }

            while (enterCount != 0) {
                // execute enter: walk enterFrames in the reverse
                // order since they were stored starting from
                // the capturedFrame, not branchFrame
                --enterCount;
                x = enterFrames[enterCount];
                enterFrame(cx, x, ScriptRuntime.emptyArgs, true);
            }

            // Continuation jump is almost done: capturedFrame
            // points to the call to the function that captured
            // continuation, so clone capturedFrame and
            // emulate return that function with the suplied result
            frame = cjump.capturedFrame.cloneFrozen();
            setCallResult(frame, cjump.result, cjump.resultDbl);
            // restart the execution
        }
        frame.throwable = throwable;
        return frame;
    }

    private static Object freezeGenerator(Context cx, CallFrame frame,
                                          int stackTop,
                                          GeneratorState generatorState)
    {
          if (generatorState.operation == NativeGenerator.GENERATOR_CLOSE) {
              // Error: no yields when generator is closing
              throw ScriptRuntime.typeError0("msg.yield.closing");
          }
          // return to our caller (which should be a method of NativeGenerator)
          frame.frozen = true;
          frame.result = frame.stack[stackTop];
          frame.resultDbl = frame.sDbl[stackTop];
          frame.savedStackTop = stackTop;
          frame.pc--; // we want to come back here when we resume
          ScriptRuntime.exitActivationFunction(cx);
          return (frame.result != DOUBLE_MARK)
              ? frame.result
              : ScriptRuntime.wrapNumber(frame.resultDbl);
    }

    private static Object thawGenerator(CallFrame frame, int stackTop,
                                        GeneratorState generatorState, int op)
    {
          // we are resuming execution
          frame.frozen = false;
          int sourceLine = getIndex(frame.idata.itsICode, frame.pc);
          frame.pc += 2; // skip line number data
          if (generatorState.operation == NativeGenerator.GENERATOR_THROW) {
              // processing a call to .throw(exception): must
              // act as if exception was thrown from resumption point
              return new JavaScriptException(generatorState.value,
                                                  frame.idata.itsSourceFile,
                                                  sourceLine);
          }
          if (generatorState.operation == NativeGenerator.GENERATOR_CLOSE) {
              return generatorState.value;
          }
          if (generatorState.operation != NativeGenerator.GENERATOR_SEND)
              throw Kit.codeBug();
          if (op == Token.YIELD)
              frame.stack[stackTop] = generatorState.value;
          return Scriptable.NOT_FOUND;
    }

    private static CallFrame initFrameForApplyOrCall(Context cx, CallFrame frame,
            int indexReg, Object[] stack, double[] sDbl, int stackTop, int op,
            Scriptable calleeScope, IdFunctionObject ifun,
            InterpretedFunction iApplyCallable)
    {
        Scriptable applyThis;
        if (indexReg != 0) {
            Object obj = stack[stackTop + 2];
            if (obj == DOUBLE_MARK)
                obj = ScriptRuntime.wrapNumber(sDbl[stackTop + 2]);
            applyThis = ScriptRuntime.toObjectOrNull(cx, obj);
        }
        else {
            applyThis = null;
        }
        if (applyThis == null) {
            // This covers the case of args[0] == (null|undefined) as well.
            applyThis = ScriptRuntime.getTopCallScope(cx);
        }
        if(op == Icode_TAIL_CALL) {
            exitFrame(cx, frame, null);
            frame = frame.parentFrame;
        }
        else {
            frame.savedStackTop = stackTop;
            frame.savedCallOp = op;
        }
        CallFrame calleeFrame = new CallFrame();
        if(BaseFunction.isApply(ifun)) {
            Object[] callArgs = indexReg < 2 ? ScriptRuntime.emptyArgs :
                ScriptRuntime.getApplyArguments(cx, stack[stackTop + 3]);
            initFrame(cx, calleeScope, applyThis, callArgs, null, 0,
                    callArgs.length, iApplyCallable, frame, calleeFrame);
        }
        else {
            // Shift args left
            for(int i = 1; i < indexReg; ++i) {
                stack[stackTop + 1 + i] = stack[stackTop + 2 + i];
                sDbl[stackTop + 1 + i] = sDbl[stackTop + 2 + i];
            }
            int argCount = indexReg < 2 ? 0 : indexReg - 1;
            initFrame(cx, calleeScope, applyThis, stack, sDbl, stackTop + 2,
                    argCount, iApplyCallable, frame, calleeFrame);
        }

        frame = calleeFrame;
        return frame;
    }

    private static void initFrame(Context cx, Scriptable callerScope,
                                  Scriptable thisObj,
                                  Object[] args, double[] argsDbl,
                                  int argShift, int argCount,
                                  InterpretedFunction fnOrScript,
                                  CallFrame parentFrame, CallFrame frame)
    {
        InterpreterData idata = fnOrScript.idata;

        boolean useActivation = idata.itsNeedsActivation;
        DebugFrame debuggerFrame = null;
        if (cx.debugger != null) {
            debuggerFrame = cx.debugger.getFrame(cx, idata);
            if (debuggerFrame != null) {
                useActivation = true;
            }
        }

        if (useActivation) {
            // Copy args to new array to pass to enterActivationFunction
            // or debuggerFrame.onEnter
            if (argsDbl != null) {
                args = getArgsArray(args, argsDbl, argShift, argCount);
            }
            argShift = 0;
            argsDbl = null;
        }

        Scriptable scope;
        if (idata.itsFunctionType != 0) {
            scope = fnOrScript.getParentScope();

            if (useActivation) {
                scope = ScriptRuntime.createFunctionActivation(
                            fnOrScript, scope, args);
            }
        } else {
            scope = callerScope;
            ScriptRuntime.initScript(fnOrScript, thisObj, cx, scope,
                                     fnOrScript.idata.evalScriptFlag);
        }

        if (idata.itsNestedFunctions != null) {
            if (idata.itsFunctionType != 0 && !idata.itsNeedsActivation)
                Kit.codeBug();
            for (int i = 0; i < idata.itsNestedFunctions.length; i++) {
                InterpreterData fdata = idata.itsNestedFunctions[i];
                if (fdata.itsFunctionType == FunctionNode.FUNCTION_STATEMENT) {
                    initFunction(cx, scope, fnOrScript, i);
                }
            }
        }

        // Initialize args, vars, locals and stack

        int emptyStackTop = idata.itsMaxVars + idata.itsMaxLocals - 1;
        int maxFrameArray = idata.itsMaxFrameArray;
        if (maxFrameArray != emptyStackTop + idata.itsMaxStack + 1)
            Kit.codeBug();

        Object[] stack;
        int[] stackAttributes;
        double[] sDbl;
        boolean stackReuse;
        if (frame.stack != null && maxFrameArray <= frame.stack.length) {
            // Reuse stacks from old frame
            stackReuse = true;
            stack = frame.stack;
            stackAttributes = frame.stackAttributes;
            sDbl = frame.sDbl;
        } else {
            stackReuse = false;
            stack = new Object[maxFrameArray];
            stackAttributes = new int[maxFrameArray];
            sDbl = new double[maxFrameArray];
        }

        int varCount = idata.getParamAndVarCount();
        for (int i = 0; i < varCount; i++) {
            if (idata.getParamOrVarConst(i))
                stackAttributes[i] = ScriptableObject.CONST;
        }
        int definedArgs = idata.argCount;
        if (definedArgs > argCount) { definedArgs = argCount; }

        // Fill the frame structure

        frame.parentFrame = parentFrame;
        frame.frameIndex = (parentFrame == null)
                           ? 0 : parentFrame.frameIndex + 1;
        if(frame.frameIndex > cx.getMaximumInterpreterStackDepth())
        {
            throw Context.reportRuntimeError("Exceeded maximum stack depth");
        }
        frame.frozen = false;

        frame.fnOrScript = fnOrScript;
        frame.idata = idata;

        frame.stack = stack;
        frame.stackAttributes = stackAttributes;
        frame.sDbl = sDbl;
        frame.varSource = frame;
        frame.localShift = idata.itsMaxVars;
        frame.emptyStackTop = emptyStackTop;

        frame.debuggerFrame = debuggerFrame;
        frame.useActivation = useActivation;

        frame.thisObj = thisObj;

        // Initialize initial values of variables that change during
        // interpretation.
        frame.result = Undefined.instance;
        frame.pc = 0;
        frame.pcPrevBranch = 0;
        frame.pcSourceLineStart = idata.firstLinePC;
        frame.scope = scope;

        frame.savedStackTop = emptyStackTop;
        frame.savedCallOp = 0;

        System.arraycopy(args, argShift, stack, 0, definedArgs);
        if (argsDbl != null) {
            System.arraycopy(argsDbl, argShift, sDbl, 0, definedArgs);
        }
        for (int i = definedArgs; i != idata.itsMaxVars; ++i) {
            stack[i] = Undefined.instance;
        }
        if (stackReuse) {
            // Clean the stack part and space beyond stack if any
            // of the old array to allow to GC objects there
            for (int i = emptyStackTop + 1; i != stack.length; ++i) {
                stack[i] = null;
            }
        }

        enterFrame(cx, frame, args, false);
    }

    private static boolean isFrameEnterExitRequired(CallFrame frame)
    {
        return frame.debuggerFrame != null || frame.idata.itsNeedsActivation;
    }

    private static void enterFrame(Context cx, CallFrame frame, Object[] args,
                                   boolean continuationRestart)
    {
        boolean usesActivation = frame.idata.itsNeedsActivation;
        boolean isDebugged = frame.debuggerFrame != null;
        if(usesActivation || isDebugged) {
            Scriptable scope = frame.scope;
            if(scope == null) {
                Kit.codeBug();
            } else if (continuationRestart) {
                // Walk the parent chain of frame.scope until a NativeCall is
                // found. Normally, frame.scope is a NativeCall when called
                // from initFrame() for a debugged or activatable function.
                // However, when called from interpretLoop() as part of
                // restarting a continuation, it can also be a NativeWith if
                // the continuation was captured within a "with" or "catch"
                // block ("catch" implicitly uses NativeWith to create a scope
                // to expose the exception variable).
                for(;;) {
                    if(scope instanceof NativeWith) {
                        scope = scope.getParentScope();
                        if (scope == null || (frame.parentFrame != null &&
                                              frame.parentFrame.scope == scope))
                        {
                            // If we get here, we didn't find a NativeCall in
                            // the call chain before reaching parent frame's
                            // scope. This should not be possible.
                            Kit.codeBug();
                            break; // Never reached, but keeps the static analyzer
                            // happy about "scope" not being null 5 lines above.
                        }
                    }
                    else {
                        break;
                    }
                }
            }
            if (isDebugged) {
                frame.debuggerFrame.onEnter(cx, scope, frame.thisObj, args);
            }
            // Enter activation only when itsNeedsActivation true,
            // since debugger should not interfere with activation
            // chaining
            if (usesActivation) {
                ScriptRuntime.enterActivationFunction(cx, scope);
            }
        }
    }

    private static void exitFrame(Context cx, CallFrame frame,
                                  Object throwable)
    {
        if (frame.idata.itsNeedsActivation) {
            ScriptRuntime.exitActivationFunction(cx);
        }

        if (frame.debuggerFrame != null) {
            try {
                if (throwable instanceof Throwable) {
                    frame.debuggerFrame.onExit(cx, true, throwable);
                } else {
                    Object result;
                    ContinuationJump cjump = (ContinuationJump)throwable;
                    if (cjump == null) {
                        result = frame.result;
                    } else {
                        result = cjump.result;
                    }
                    if (result == DOUBLE_MARK) {
                        double resultDbl;
                        if (cjump == null) {
                            resultDbl = frame.resultDbl;
                        } else {
                            resultDbl = cjump.resultDbl;
                        }
                        result = ScriptRuntime.wrapNumber(resultDbl);
                    }
                    frame.debuggerFrame.onExit(cx, false, result);
                }
            } catch (Throwable ex) {
                System.err.println(
"RHINO USAGE WARNING: onExit terminated with exception");
                ex.printStackTrace(System.err);
            }
        }
    }

    private static void setCallResult(CallFrame frame,
                                      Object callResult,
                                      double callResultDbl)
    {
        if (frame.savedCallOp == Token.CALL) {
            frame.stack[frame.savedStackTop] = callResult;
            frame.sDbl[frame.savedStackTop] = callResultDbl;
        } else if (frame.savedCallOp == Token.NEW) {
            // If construct returns scriptable,
            // then it replaces on stack top saved original instance
            // of the object.
            if (callResult instanceof Scriptable) {
                frame.stack[frame.savedStackTop] = callResult;
            }
        } else {
            Kit.codeBug();
        }
        frame.savedCallOp = 0;
    }

    public static NativeContinuation captureContinuation(Context cx) {
        if (cx.lastInterpreterFrame == null ||
            !(cx.lastInterpreterFrame instanceof CallFrame))
        {
            throw new IllegalStateException("Interpreter frames not found");
        }
        return captureContinuation(cx, (CallFrame)cx.lastInterpreterFrame, true);
    }

    private static NativeContinuation captureContinuation(Context cx, CallFrame frame,
        boolean requireContinuationsTopFrame)
    {
        NativeContinuation c = new NativeContinuation();
        ScriptRuntime.setObjectProtoAndParent(
            c, ScriptRuntime.getTopCallScope(cx));

        // Make sure that all frames are frozen
        CallFrame x = frame;
        CallFrame outermost = frame;
        while (x != null && !x.frozen) {
            x.frozen = true;
            // Allow to GC unused stack space
            for (int i = x.savedStackTop + 1; i != x.stack.length; ++i) {
                // Allow to GC unused stack space
                x.stack[i] = null;
                x.stackAttributes[i] = ScriptableObject.EMPTY;
            }
            if (x.savedCallOp == Token.CALL) {
                // the call will always overwrite the stack top with the result
                x.stack[x.savedStackTop] = null;
            } else {
                if (x.savedCallOp != Token.NEW) Kit.codeBug();
                // the new operator uses stack top to store the constructed
                // object so it shall not be cleared: see comments in
                // setCallResult
            }
            outermost = x;
            x = x.parentFrame;
        }

        if (requireContinuationsTopFrame) {
            while (outermost.parentFrame != null)
                outermost = outermost.parentFrame;

            if (!outermost.isContinuationsTopFrame) {
                throw new IllegalStateException("Cannot capture continuation " +
                        "from JavaScript code not called directly by " +
                        "executeScriptWithContinuations or " +
                        "callFunctionWithContinuations");
            }
        }

        c.initImplementation(frame);
        return c;
    }

    private static int stack_int32(CallFrame frame, int i)
    {
        Object x = frame.stack[i];
        if (x == UniqueTag.DOUBLE_MARK) {
            return ScriptRuntime.toInt32(frame.sDbl[i]);
        } else {
            return ScriptRuntime.toInt32(x);
        }
    }

    private static double stack_double(CallFrame frame, int i)
    {
        Object x = frame.stack[i];
        if (x != UniqueTag.DOUBLE_MARK) {
            return ScriptRuntime.toNumber(x);
        } else {
            return frame.sDbl[i];
        }
    }

    private static boolean stack_boolean(CallFrame frame, int i)
    {
        Object x = frame.stack[i];
        if (x == Boolean.TRUE) {
            return true;
        } else if (x == Boolean.FALSE) {
            return false;
        } else if (x == UniqueTag.DOUBLE_MARK) {
            double d = frame.sDbl[i];
            return d == d && d != 0.0;
        } else if (x == null || x == Undefined.instance) {
            return false;
        } else if (x instanceof Number) {
            double d = ((Number)x).doubleValue();
            return (d == d && d != 0.0);
        } else if (x instanceof Boolean) {
            return ((Boolean)x).booleanValue();
        } else {
            return ScriptRuntime.toBoolean(x);
        }
    }

    private static void doAdd(Object[] stack, double[] sDbl, int stackTop,
                              Context cx)
    {
        Object rhs = stack[stackTop + 1];
        Object lhs = stack[stackTop];
        double d;
        boolean leftRightOrder;
        if (rhs == DOUBLE_MARK) {
            d = sDbl[stackTop + 1];
            if (lhs == DOUBLE_MARK) {
                sDbl[stackTop] += d;
                return;
            }
            leftRightOrder = true;
            // fallthrough to object + number code
        } else if (lhs == DOUBLE_MARK) {
            d = sDbl[stackTop];
            lhs = rhs;
            leftRightOrder = false;
            // fallthrough to object + number code
        } else {
            if (lhs instanceof Scriptable || rhs instanceof Scriptable) {
                stack[stackTop] = ScriptRuntime.add(lhs, rhs, cx);
            } else if (lhs instanceof CharSequence || rhs instanceof CharSequence) {
                CharSequence lstr = ScriptRuntime.toCharSequence(lhs);
                CharSequence rstr = ScriptRuntime.toCharSequence(rhs);
                stack[stackTop] = new ConsString(lstr, rstr);
            } else {
                double lDbl = (lhs instanceof Number)
                    ? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);
                double rDbl = (rhs instanceof Number)
                    ? ((Number)rhs).doubleValue() : ScriptRuntime.toNumber(rhs);
                stack[stackTop] = DOUBLE_MARK;
                sDbl[stackTop] = lDbl + rDbl;
            }
            return;
        }

        // handle object(lhs) + number(d) code
        if (lhs instanceof Scriptable) {
            rhs = ScriptRuntime.wrapNumber(d);
            if (!leftRightOrder) {
                Object tmp = lhs;
                lhs = rhs;
                rhs = tmp;
            }
            stack[stackTop] = ScriptRuntime.add(lhs, rhs, cx);
        } else if (lhs instanceof CharSequence) {
            CharSequence lstr = (CharSequence)lhs;
            CharSequence rstr = ScriptRuntime.toCharSequence(d);
            if (leftRightOrder) {
                stack[stackTop] = new ConsString(lstr, rstr);
            } else {
                stack[stackTop] = new ConsString(rstr, lstr);
            }
        } else {
            double lDbl = (lhs instanceof Number)
                ? ((Number)lhs).doubleValue() : ScriptRuntime.toNumber(lhs);
            stack[stackTop] = DOUBLE_MARK;
            sDbl[stackTop] = lDbl + d;
        }
    }

    private static int doArithmetic(CallFrame frame, int op, Object[] stack,
                                    double[] sDbl, int stackTop) {
        double rDbl = stack_double(frame, stackTop);
        --stackTop;
        double lDbl = stack_double(frame, stackTop);
        stack[stackTop] = DOUBLE_MARK;
        switch (op) {
          case Token.SUB:
            lDbl -= rDbl;
            break;
          case Token.MUL:
            lDbl *= rDbl;
            break;
          case Token.DIV:
            lDbl /= rDbl;
            break;
          case Token.MOD:
            lDbl %= rDbl;
            break;
        }
        sDbl[stackTop] = lDbl;
        return stackTop;
    }

    private static Object[] getArgsArray(Object[] stack, double[] sDbl,
                                         int shift, int count)
    {
        if (count == 0) {
            return ScriptRuntime.emptyArgs;
        }
        Object[] args = new Object[count];
        for (int i = 0; i != count; ++i, ++shift) {
            Object val = stack[shift];
            if (val == UniqueTag.DOUBLE_MARK) {
                val = ScriptRuntime.wrapNumber(sDbl[shift]);
            }
            args[i] = val;
        }
        return args;
    }

    private static void addInstructionCount(Context cx, CallFrame frame,
                                            int extra)
    {
        cx.instructionCount += frame.pc - frame.pcPrevBranch + extra;
        if (cx.instructionCount > cx.instructionThreshold) {
            cx.observeInstructionCount(cx.instructionCount);
            cx.instructionCount = 0;
        }
    }
}
rhino-1.7R4/src/org/mozilla/javascript/InterpreterData.java000066400000000000000000000066761176760007500240710ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import java.io.Serializable;

import org.mozilla.javascript.debug.DebuggableScript;

final class InterpreterData implements Serializable, DebuggableScript
{
    static final long serialVersionUID = 5067677351589230234L;

    static final int INITIAL_MAX_ICODE_LENGTH = 1024;
    static final int INITIAL_STRINGTABLE_SIZE = 64;
    static final int INITIAL_NUMBERTABLE_SIZE = 64;

    InterpreterData(int languageVersion, String sourceFile,
                    String encodedSource, boolean isStrict)
    {
        this.languageVersion = languageVersion;
        this.itsSourceFile = sourceFile;
        this.encodedSource = encodedSource;
        this.isStrict = isStrict;
        init();
    }

    InterpreterData(InterpreterData parent)
    {
        this.parentData = parent;
        this.languageVersion = parent.languageVersion;
        this.itsSourceFile = parent.itsSourceFile;
        this.encodedSource = parent.encodedSource;

        init();
    }

    private void init()
    {
        itsICode = new byte[INITIAL_MAX_ICODE_LENGTH];
        itsStringTable = new String[INITIAL_STRINGTABLE_SIZE];
    }

    String itsName;
    String itsSourceFile;
    boolean itsNeedsActivation;
    int itsFunctionType;

    String[] itsStringTable;
    double[] itsDoubleTable;
    InterpreterData[] itsNestedFunctions;
    Object[] itsRegExpLiterals;

    byte[] itsICode;

    int[] itsExceptionTable;

    int itsMaxVars;
    int itsMaxLocals;
    int itsMaxStack;
    int itsMaxFrameArray;

    // see comments in NativeFuncion for definition of argNames and argCount
    String[] argNames;
    boolean[] argIsConst;
    int argCount;

    int itsMaxCalleeArgs;

    String encodedSource;
    int encodedSourceStart;
    int encodedSourceEnd;

    int languageVersion;

    boolean isStrict;
    boolean topLevel;

    Object[] literalIds;

    UintMap longJumps;

    int firstLinePC = -1; // PC for the first LINE icode

    InterpreterData parentData;

    boolean evalScriptFlag; // true if script corresponds to eval() code

    public boolean isTopLevel()
    {
        return topLevel;
    }

    public boolean isFunction()
    {
        return itsFunctionType != 0;
    }

    public String getFunctionName()
    {
        return itsName;
    }

    public int getParamCount()
    {
        return argCount;
    }

    public int getParamAndVarCount()
    {
        return argNames.length;
    }

    public String getParamOrVarName(int index)
    {
        return argNames[index];
    }

    public boolean getParamOrVarConst(int index)
    {
        return argIsConst[index];
    }

    public String getSourceName()
    {
        return itsSourceFile;
    }

    public boolean isGeneratedScript()
    {
        return ScriptRuntime.isGeneratedScript(itsSourceFile);
    }

    public int[] getLineNumbers()
    {
        return Interpreter.getLineNumbers(this);
    }

    public int getFunctionCount()
    {
        return (itsNestedFunctions == null) ? 0 : itsNestedFunctions.length;
    }

    public DebuggableScript getFunction(int index)
    {
        return itsNestedFunctions[index];
    }

    public DebuggableScript getParent()
    {
         return parentData;
    }
}
rhino-1.7R4/src/org/mozilla/javascript/JavaAdapter.java000066400000000000000000001340211176760007500231400ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import org.mozilla.classfile.*;
import java.lang.reflect.*;
import java.io.*;
import java.security.*;
import java.util.*;

public final class JavaAdapter implements IdFunctionCall
{
    /**
     * Provides a key with which to distinguish previously generated
     * adapter classes stored in a hash table.
     */
    static class JavaAdapterSignature
    {
        Class superClass;
        Class[] interfaces;
        ObjToIntMap names;

        JavaAdapterSignature(Class superClass, Class[] interfaces,
                             ObjToIntMap names)
        {
            this.superClass = superClass;
            this.interfaces = interfaces;
            this.names = names;
        }

        @Override
        public boolean equals(Object obj)
        {
            if (!(obj instanceof JavaAdapterSignature))
                return false;
            JavaAdapterSignature sig = (JavaAdapterSignature) obj;
            if (superClass != sig.superClass)
                return false;
            if (interfaces != sig.interfaces) {
                if (interfaces.length != sig.interfaces.length)
                    return false;
                for (int i=0; i < interfaces.length; i++)
                    if (interfaces[i] != sig.interfaces[i])
                        return false;
            }
            if (names.size() != sig.names.size())
                return false;
            ObjToIntMap.Iterator iter = new ObjToIntMap.Iterator(names);
            for (iter.start(); !iter.done(); iter.next()) {
                String name = (String)iter.getKey();
                int arity = iter.getValue();
                if (arity != sig.names.get(name, arity + 1))
                    return false;
            }
            return true;
        }

        @Override
        public int hashCode()
        {
            return (superClass.hashCode() + Arrays.hashCode(interfaces)) ^ names.size();
        }
    }

    public static void init(Context cx, Scriptable scope, boolean sealed)
    {
        JavaAdapter obj = new JavaAdapter();
        IdFunctionObject ctor = new IdFunctionObject(obj, FTAG, Id_JavaAdapter,
                                                     "JavaAdapter", 1, scope);
        ctor.markAsConstructor(null);
        if (sealed) {
            ctor.sealObject();
        }
        ctor.exportAsScopeProperty();
    }

    public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
                             Scriptable thisObj, Object[] args)
    {
        if (f.hasTag(FTAG)) {
            if (f.methodId() == Id_JavaAdapter) {
                return js_createAdapter(cx, scope, args);
            }
        }
        throw f.unknown();
    }

    public static Object convertResult(Object result, Class c)
    {
        if (result == Undefined.instance &&
            (c != ScriptRuntime.ObjectClass &&
             c != ScriptRuntime.StringClass))
        {
            // Avoid an error for an undefined value; return null instead.
            return null;
        }
        return Context.jsToJava(result, c);
    }

    public static Scriptable createAdapterWrapper(Scriptable obj, Object adapter)
    {
        Scriptable scope = ScriptableObject.getTopLevelScope(obj);
        NativeJavaObject res = new NativeJavaObject(scope, adapter, null, true);
        res.setPrototype(obj);
        return res;
    }

    public static Object getAdapterSelf(Class adapterClass, Object adapter)
        throws NoSuchFieldException, IllegalAccessException
    {
        Field self = adapterClass.getDeclaredField("self");
        return self.get(adapter);
    }

    static Object js_createAdapter(Context cx, Scriptable scope, Object[] args)
    {
        int N = args.length;
        if (N == 0) {
            throw ScriptRuntime.typeError0("msg.adapter.zero.args");
        }

        // Expected arguments:
        // Any number of NativeJavaClass objects representing the super-class
        // and/or interfaces to implement, followed by one NativeObject providing
        // the implementation, followed by any number of arguments to pass on
        // to the (super-class) constructor.

        int classCount;
        for (classCount = 0; classCount < N - 1; classCount++) {
            Object arg = args[classCount];
            // We explicitly test for NativeObject here since checking for
            // instanceof ScriptableObject or !(instanceof NativeJavaClass)
            // would fail for a Java class that isn't found in the class path
            // as NativeJavaPackage extends ScriptableObject.
            if (arg instanceof NativeObject) {
                break;
            }
            if (!(arg instanceof NativeJavaClass)) {
                throw ScriptRuntime.typeError2("msg.not.java.class.arg",
                                               String.valueOf(classCount),
                                               ScriptRuntime.toString(arg));
            }
        }
        Class superClass = null;
        Class[] intfs = new Class[classCount];
        int interfaceCount = 0;
        for (int i = 0; i < classCount; ++i) {
            Class c = ((NativeJavaClass) args[i]).getClassObject();
            if (!c.isInterface()) {
                if (superClass != null) {
                    throw ScriptRuntime.typeError2("msg.only.one.super",
                              superClass.getName(), c.getName());
                }
                superClass = c;
            } else {
                intfs[interfaceCount++] = c;
            }
        }

        if (superClass == null) {
            superClass = ScriptRuntime.ObjectClass;
        }
        
        Class[] interfaces = new Class[interfaceCount];
        System.arraycopy(intfs, 0, interfaces, 0, interfaceCount);
        // next argument is implementation, must be scriptable
        Scriptable obj = ScriptableObject.ensureScriptable(args[classCount]);

        Class adapterClass = getAdapterClass(scope, superClass, interfaces, obj);
        Object adapter;
        
        int argsCount = N - classCount - 1;
        try {
            if (argsCount > 0) {
                // Arguments contain parameters for super-class constructor.
                // We use the generic Java method lookup logic to find and
                // invoke the right constructor.
                Object[] ctorArgs = new Object[argsCount + 2];
                ctorArgs[0] = obj;
                ctorArgs[1] = cx.getFactory();
                System.arraycopy(args, classCount + 1, ctorArgs, 2, argsCount);
                // TODO: cache class wrapper?
                NativeJavaClass classWrapper = new NativeJavaClass(scope,
                        adapterClass, true);
                NativeJavaMethod ctors = classWrapper.members.ctors;
                int index = ctors.findCachedFunction(cx, ctorArgs);
                if (index < 0) {
                    String sig = NativeJavaMethod.scriptSignature(args);
                    throw Context.reportRuntimeError2(
                            "msg.no.java.ctor", adapterClass.getName(), sig);
                }

                // Found the constructor, so try invoking it.
                adapter = NativeJavaClass.constructInternal(ctorArgs, ctors.methods[index]);
            } else {
                Class[] ctorParms = {
                        ScriptRuntime.ScriptableClass,
                        ScriptRuntime.ContextFactoryClass
                };
                Object[] ctorArgs = { obj, cx.getFactory() };
                adapter = adapterClass.getConstructor(ctorParms).newInstance(ctorArgs);
            }

            Object self = getAdapterSelf(adapterClass, adapter);
            // Return unwrapped JavaAdapter if it implements Scriptable
            if (self instanceof Wrapper) {
                Object unwrapped = ((Wrapper) self).unwrap();
                if (unwrapped instanceof Scriptable) {
                    if (unwrapped instanceof ScriptableObject) {
                        ScriptRuntime.setObjectProtoAndParent(
                                (ScriptableObject)unwrapped, scope);
                    }
                    return unwrapped;
                }
            }
            return self;
        } catch (Exception ex) {
            throw Context.throwAsScriptRuntimeEx(ex);
        }
    }

    // Needed by NativeJavaObject serializer
    public static void writeAdapterObject(Object javaObject,
                                          ObjectOutputStream out)
        throws IOException
    {
        Class cl = javaObject.getClass();
        out.writeObject(cl.getSuperclass().getName());

        Class[] interfaces = cl.getInterfaces();
        String[] interfaceNames = new String[interfaces.length];

        for (int i=0; i < interfaces.length; i++)
            interfaceNames[i] = interfaces[i].getName();

        out.writeObject(interfaceNames);

        try {
            Object delegee = cl.getField("delegee").get(javaObject);
            out.writeObject(delegee);
            return;
        } catch (IllegalAccessException e) {
        } catch (NoSuchFieldException e) {
        }
        throw new IOException();
    }

    // Needed by NativeJavaObject de-serializer
    public static Object readAdapterObject(Scriptable self,
                                           ObjectInputStream in)
        throws IOException, ClassNotFoundException
    {
        ContextFactory factory;
        Context cx = Context.getCurrentContext();
        if (cx != null) {
            factory = cx.getFactory();
        } else {
            factory = null;
        }

        Class superClass = Class.forName((String)in.readObject());

        String[] interfaceNames = (String[])in.readObject();
        Class[] interfaces = new Class[interfaceNames.length];

        for (int i=0; i < interfaceNames.length; i++)
            interfaces[i] = Class.forName(interfaceNames[i]);

        Scriptable delegee = (Scriptable)in.readObject();

        Class adapterClass = getAdapterClass(self, superClass, interfaces,
                                             delegee);

        Class[] ctorParms = {
            ScriptRuntime.ContextFactoryClass,
            ScriptRuntime.ScriptableClass,
            ScriptRuntime.ScriptableClass
        };
        Object[] ctorArgs = { factory, delegee, self };
        try {
            return adapterClass.getConstructor(ctorParms).newInstance(ctorArgs);
        } catch(InstantiationException e) {
        } catch(IllegalAccessException e) {
        } catch(InvocationTargetException e) {
        } catch(NoSuchMethodException e) {
        }

        throw new ClassNotFoundException("adapter");
    }

    private static ObjToIntMap getObjectFunctionNames(Scriptable obj)
    {
        Object[] ids = ScriptableObject.getPropertyIds(obj);
        ObjToIntMap map = new ObjToIntMap(ids.length);
        for (int i = 0; i != ids.length; ++i) {
            if (!(ids[i] instanceof String))
                continue;
            String id = (String) ids[i];
            Object value = ScriptableObject.getProperty(obj, id);
            if (value instanceof Function) {
                Function f = (Function)value;
                int length = ScriptRuntime.toInt32(
                                 ScriptableObject.getProperty(f, "length"));
                if (length < 0) {
                    length = 0;
                }
                map.put(id, length);
            }
        }
        return map;
    }

    private static Class getAdapterClass(Scriptable scope, Class superClass,
                                            Class[] interfaces, Scriptable obj)
    {
        ClassCache cache = ClassCache.get(scope);
        Map> generated
            = cache.getInterfaceAdapterCacheMap();

        ObjToIntMap names = getObjectFunctionNames(obj);
        JavaAdapterSignature sig;
        sig = new JavaAdapterSignature(superClass, interfaces, names);
        Class adapterClass = generated.get(sig);
        if (adapterClass == null) {
            String adapterName = "adapter" + cache.newClassSerialNumber();
            byte[] code = createAdapterCode(names, adapterName,
                                            superClass, interfaces, null);

            adapterClass = loadAdapterClass(adapterName, code);
            if (cache.isCachingEnabled()) {
                generated.put(sig, adapterClass);
            }
        }
        return adapterClass;
    }

    public static byte[] createAdapterCode(ObjToIntMap functionNames,
                                           String adapterName,
                                           Class superClass,
                                           Class[] interfaces,
                                           String scriptClassName)
    {
        ClassFileWriter cfw = new ClassFileWriter(adapterName,
                                                  superClass.getName(),
                                                  "");
        cfw.addField("factory", "Lorg/mozilla/javascript/ContextFactory;",
                     (short) (ClassFileWriter.ACC_PUBLIC |
                              ClassFileWriter.ACC_FINAL));
        cfw.addField("delegee", "Lorg/mozilla/javascript/Scriptable;",
                     (short) (ClassFileWriter.ACC_PUBLIC |
                              ClassFileWriter.ACC_FINAL));
        cfw.addField("self", "Lorg/mozilla/javascript/Scriptable;",
                     (short) (ClassFileWriter.ACC_PUBLIC |
                              ClassFileWriter.ACC_FINAL));
        int interfacesCount = interfaces == null ? 0 : interfaces.length;
        for (int i=0; i < interfacesCount; i++) {
            if (interfaces[i] != null)
                cfw.addInterface(interfaces[i].getName());
        }

        String superName = superClass.getName().replace('.', '/');
        Constructor[] ctors = superClass.getConstructors();
        for (Constructor ctor : ctors) {
            generateCtor(cfw, adapterName, superName, ctor);
        }
        generateSerialCtor(cfw, adapterName, superName);
        if (scriptClassName != null) {
            generateEmptyCtor(cfw, adapterName, superName, scriptClassName);
        }

        ObjToIntMap generatedOverrides = new ObjToIntMap();
        ObjToIntMap generatedMethods = new ObjToIntMap();

        // generate methods to satisfy all specified interfaces.
        for (int i = 0; i < interfacesCount; i++) {
            Method[] methods = interfaces[i].getMethods();
            for (int j = 0; j < methods.length; j++) {
                Method method = methods[j];
                int mods = method.getModifiers();
                if (Modifier.isStatic(mods) || Modifier.isFinal(mods)) {
                    continue;
                }
                String methodName = method.getName();
                Class[] argTypes = method.getParameterTypes();
                if (!functionNames.has(methodName)) {
                    try {
                        superClass.getMethod(methodName, argTypes);
                        // The class we're extending implements this method and
                        // the JavaScript object doesn't have an override. See
                        // bug 61226.
                        continue;
                    } catch (NoSuchMethodException e) {
                        // Not implemented by superclass; fall through
                    }
                }
                // make sure to generate only one instance of a particular
                // method/signature.
                String methodSignature = getMethodSignature(method, argTypes);
                String methodKey = methodName + methodSignature;
                if (! generatedOverrides.has(methodKey)) {
                    generateMethod(cfw, adapterName, methodName, argTypes,
                                   method.getReturnType(), true);
                    generatedOverrides.put(methodKey, 0);
                    generatedMethods.put(methodName, 0);
                }
            }
        }

        // Now, go through the superclass's methods, checking for abstract
        // methods or additional methods to override.

        // generate any additional overrides that the object might contain.
        Method[] methods = getOverridableMethods(superClass);
        for (int j = 0; j < methods.length; j++) {
            Method method = methods[j];
            int mods = method.getModifiers();
            // if a method is marked abstract, must implement it or the
            // resulting class won't be instantiable. otherwise, if the object
            // has a property of the same name, then an override is intended.
            boolean isAbstractMethod = Modifier.isAbstract(mods);
            String methodName = method.getName();
            if (isAbstractMethod || functionNames.has(methodName)) {
                // make sure to generate only one instance of a particular
                // method/signature.
                Class[] argTypes = method.getParameterTypes();
                String methodSignature = getMethodSignature(method, argTypes);
                String methodKey = methodName + methodSignature;
                if (! generatedOverrides.has(methodKey)) {
                    generateMethod(cfw, adapterName, methodName, argTypes,
                                   method.getReturnType(), true);
                    generatedOverrides.put(methodKey, 0);
                    generatedMethods.put(methodName, 0);

                    // if a method was overridden, generate a "super$method"
                    // which lets the delegate call the superclass' version.
                    if (!isAbstractMethod) {
                        generateSuper(cfw, adapterName, superName,
                                      methodName, methodSignature,
                                      argTypes, method.getReturnType());
                    }
                }
            }
        }

        // Generate Java methods for remaining properties that are not
        // overrides.
        ObjToIntMap.Iterator iter = new ObjToIntMap.Iterator(functionNames);
        for (iter.start(); !iter.done(); iter.next()) {
            String functionName = (String)iter.getKey();
            if (generatedMethods.has(functionName))
                continue;
            int length = iter.getValue();
            Class[] parms = new Class[length];
            for (int k=0; k < length; k++)
                parms[k] = ScriptRuntime.ObjectClass;
            generateMethod(cfw, adapterName, functionName, parms,
                           ScriptRuntime.ObjectClass, false);
        }
        return cfw.toByteArray();
    }

    static Method[] getOverridableMethods(Class clazz)
    {
        ArrayList list = new ArrayList();
        HashSet skip = new HashSet();
        // Check superclasses before interfaces so we always choose
        // implemented methods over abstract ones, even if a subclass
        // re-implements an interface already implemented in a superclass
        // (e.g. java.util.ArrayList)
        for (Class c = clazz; c != null; c = c.getSuperclass()) {
            appendOverridableMethods(c, list, skip);
        }
        for (Class c = clazz; c != null; c = c.getSuperclass()) {
            for (Class intf: c.getInterfaces())
                appendOverridableMethods(intf, list, skip);
        }
        return list.toArray(new Method[list.size()]);
    }

    private static void appendOverridableMethods(Class c,
            ArrayList list, HashSet skip)
    {
        Method[] methods = c.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            String methodKey = methods[i].getName() +
                getMethodSignature(methods[i],
                        methods[i].getParameterTypes());
            if (skip.contains(methodKey))
                continue; // skip this method
            int mods = methods[i].getModifiers();
            if (Modifier.isStatic(mods))
                continue;
            if (Modifier.isFinal(mods)) {
                // Make sure we don't add a final method to the list
                // of overridable methods.
                skip.add(methodKey);
                continue;
            }
            if (Modifier.isPublic(mods) || Modifier.isProtected(mods)) {
                list.add(methods[i]);
                skip.add(methodKey);
            }
        }
    }

    static Class loadAdapterClass(String className, byte[] classBytes)
    {
        Object staticDomain;
        Class domainClass = SecurityController.getStaticSecurityDomainClass();
        if(domainClass == CodeSource.class || domainClass == ProtectionDomain.class) {
            // use the calling script's security domain if available
            ProtectionDomain protectionDomain = SecurityUtilities.getScriptProtectionDomain();
            if (protectionDomain == null) {
                protectionDomain = JavaAdapter.class.getProtectionDomain();
            }
            if(domainClass == CodeSource.class) {
                staticDomain = protectionDomain == null ? null : protectionDomain.getCodeSource();
            }
            else {
                staticDomain = protectionDomain;
            }
        }
        else {
            staticDomain = null;
        }
        GeneratedClassLoader loader = SecurityController.createLoader(null,
                staticDomain);
        Class result = loader.defineClass(className, classBytes);
        loader.linkClass(result);
        return result;
    }

    public static Function getFunction(Scriptable obj, String functionName)
    {
        Object x = ScriptableObject.getProperty(obj, functionName);
        if (x == Scriptable.NOT_FOUND) {
            // This method used to swallow the exception from calling
            // an undefined method. People have come to depend on this
            // somewhat dubious behavior. It allows people to avoid
            // implementing listener methods that they don't care about,
            // for instance.
            return null;
        }
        if (!(x instanceof Function))
            throw ScriptRuntime.notFunctionError(x, functionName);

        return (Function)x;
    }

    /**
     * Utility method which dynamically binds a Context to the current thread,
     * if none already exists.
     */
    public static Object callMethod(ContextFactory factory,
                                    final Scriptable thisObj,
                                    final Function f, final Object[] args,
                                    final long argsToWrap)
    {
        if (f == null) {
            // See comments in getFunction
            return Undefined.instance;
        }
        if (factory == null) {
            factory = ContextFactory.getGlobal();
        }

        final Scriptable scope = f.getParentScope();
        if (argsToWrap == 0) {
            return Context.call(factory, f, scope, thisObj, args);
        }

        Context cx = Context.getCurrentContext();
        if (cx != null) {
            return doCall(cx, scope, thisObj, f, args, argsToWrap);
        } else {
            return factory.call(new ContextAction() {
                public Object run(Context cx)
                {
                    return doCall(cx, scope, thisObj, f, args, argsToWrap);
                }
            });
        }
    }

    private static Object doCall(Context cx, Scriptable scope,
                                 Scriptable thisObj, Function f,
                                 Object[] args, long argsToWrap)
    {
        // Wrap the rest of objects
        for (int i = 0; i != args.length; ++i) {
            if (0 != (argsToWrap & (1 << i))) {
                Object arg = args[i];
                if (!(arg instanceof Scriptable)) {
                    args[i] = cx.getWrapFactory().wrap(cx, scope, arg,
                                                       null);
                }
            }
        }
        return f.call(cx, scope, thisObj, args);
    }

    public static Scriptable runScript(final Script script)
    {
        return (Scriptable)ContextFactory.getGlobal().call(
            new ContextAction() {
                public Object run(Context cx)
                {
                    ScriptableObject global = ScriptRuntime.getGlobal(cx);
                    script.exec(cx, global);
                    return global;
                }
            });
    }

    private static void generateCtor(ClassFileWriter cfw, String adapterName,
                                     String superName, Constructor superCtor)
    {
        short locals = 3; // this + factory + delegee
        Class[] parameters = superCtor.getParameterTypes();

        // Note that we swapped arguments in app-facing constructors to avoid
        // conflicting signatures with serial constructor defined below.
        if (parameters.length == 0) {
            cfw.startMethod("",
                        "(Lorg/mozilla/javascript/Scriptable;"
                        +"Lorg/mozilla/javascript/ContextFactory;)V",
                        ClassFileWriter.ACC_PUBLIC);

            // Invoke base class constructor
            cfw.add(ByteCode.ALOAD_0);  // this
            cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "", "()V");
        } else {
            StringBuilder sig = new StringBuilder(
                    "(Lorg/mozilla/javascript/Scriptable;"
                    +"Lorg/mozilla/javascript/ContextFactory;");
            int marker = sig.length(); // lets us reuse buffer for super signature
            for (Class c : parameters) {
                appendTypeString(sig, c);
            }
            sig.append(")V");
            cfw.startMethod("", sig.toString(), ClassFileWriter.ACC_PUBLIC);

            // Invoke base class constructor
            cfw.add(ByteCode.ALOAD_0);  // this
            short paramOffset = 3;
            for (Class parameter : parameters) {
                paramOffset += generatePushParam(cfw, paramOffset, parameter);
            }
            locals = paramOffset;
            sig.delete(1, marker);
            cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "", sig.toString());
        }

        // Save parameter in instance variable "delegee"
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.add(ByteCode.ALOAD_1);  // first arg: Scriptable delegee
        cfw.add(ByteCode.PUTFIELD, adapterName, "delegee",
                "Lorg/mozilla/javascript/Scriptable;");

        // Save parameter in instance variable "factory"
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.add(ByteCode.ALOAD_2);  // second arg: ContextFactory instance
        cfw.add(ByteCode.PUTFIELD, adapterName, "factory",
                "Lorg/mozilla/javascript/ContextFactory;");

        cfw.add(ByteCode.ALOAD_0);  // this for the following PUTFIELD for self
        // create a wrapper object to be used as "this" in method calls
        cfw.add(ByteCode.ALOAD_1);  // the Scriptable delegee
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.addInvoke(ByteCode.INVOKESTATIC,
                      "org/mozilla/javascript/JavaAdapter",
                      "createAdapterWrapper",
                      "(Lorg/mozilla/javascript/Scriptable;"
                      +"Ljava/lang/Object;"
                      +")Lorg/mozilla/javascript/Scriptable;");
        cfw.add(ByteCode.PUTFIELD, adapterName, "self",
                "Lorg/mozilla/javascript/Scriptable;");

        cfw.add(ByteCode.RETURN);
        cfw.stopMethod(locals);
    }

    private static void generateSerialCtor(ClassFileWriter cfw,
                                           String adapterName,
                                           String superName)
    {
        cfw.startMethod("",
                        "(Lorg/mozilla/javascript/ContextFactory;"
                        +"Lorg/mozilla/javascript/Scriptable;"
                        +"Lorg/mozilla/javascript/Scriptable;"
                        +")V",
                        ClassFileWriter.ACC_PUBLIC);

        // Invoke base class constructor
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "", "()V");

        // Save parameter in instance variable "factory"
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.add(ByteCode.ALOAD_1);  // first arg: ContextFactory instance
        cfw.add(ByteCode.PUTFIELD, adapterName, "factory",
                "Lorg/mozilla/javascript/ContextFactory;");

        // Save parameter in instance variable "delegee"
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.add(ByteCode.ALOAD_2);  // second arg: Scriptable delegee
        cfw.add(ByteCode.PUTFIELD, adapterName, "delegee",
                "Lorg/mozilla/javascript/Scriptable;");
        // save self
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.add(ByteCode.ALOAD_3);  // third arg: Scriptable self
        cfw.add(ByteCode.PUTFIELD, adapterName, "self",
                "Lorg/mozilla/javascript/Scriptable;");

        cfw.add(ByteCode.RETURN);
        cfw.stopMethod((short)4); // 4: this + factory + delegee + self
    }

    private static void generateEmptyCtor(ClassFileWriter cfw,
                                          String adapterName,
                                          String superName,
                                          String scriptClassName)
    {
        cfw.startMethod("", "()V", ClassFileWriter.ACC_PUBLIC);

        // Invoke base class constructor
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "", "()V");

        // Set factory to null to use current global when necessary
        cfw.add(ByteCode.ALOAD_0);
        cfw.add(ByteCode.ACONST_NULL);
        cfw.add(ByteCode.PUTFIELD, adapterName, "factory",
                "Lorg/mozilla/javascript/ContextFactory;");

        // Load script class
        cfw.add(ByteCode.NEW, scriptClassName);
        cfw.add(ByteCode.DUP);
        cfw.addInvoke(ByteCode.INVOKESPECIAL, scriptClassName, "", "()V");

        // Run script and save resulting scope
        cfw.addInvoke(ByteCode.INVOKESTATIC,
                      "org/mozilla/javascript/JavaAdapter",
                      "runScript",
                      "(Lorg/mozilla/javascript/Script;"
                      +")Lorg/mozilla/javascript/Scriptable;");
        cfw.add(ByteCode.ASTORE_1);

        // Save the Scriptable in instance variable "delegee"
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.add(ByteCode.ALOAD_1);  // the Scriptable
        cfw.add(ByteCode.PUTFIELD, adapterName, "delegee",
                "Lorg/mozilla/javascript/Scriptable;");

        cfw.add(ByteCode.ALOAD_0);  // this for the following PUTFIELD for self
        // create a wrapper object to be used as "this" in method calls
        cfw.add(ByteCode.ALOAD_1);  // the Scriptable
        cfw.add(ByteCode.ALOAD_0);  // this
        cfw.addInvoke(ByteCode.INVOKESTATIC,
                      "org/mozilla/javascript/JavaAdapter",
                      "createAdapterWrapper",
                      "(Lorg/mozilla/javascript/Scriptable;"
                      +"Ljava/lang/Object;"
                      +")Lorg/mozilla/javascript/Scriptable;");
        cfw.add(ByteCode.PUTFIELD, adapterName, "self",
                "Lorg/mozilla/javascript/Scriptable;");

        cfw.add(ByteCode.RETURN);
        cfw.stopMethod((short)2); // this + delegee
    }

    /**
     * Generates code to wrap Java arguments into Object[].
     * Non-primitive Java types are left as-is pending conversion
     * in the helper method. Leaves the array object on the top of the stack.
     */
    static void generatePushWrappedArgs(ClassFileWriter cfw,
                                        Class[] argTypes,
                                        int arrayLength)
    {
        // push arguments
        cfw.addPush(arrayLength);
        cfw.add(ByteCode.ANEWARRAY, "java/lang/Object");
        int paramOffset = 1;
        for (int i = 0; i != argTypes.length; ++i) {
            cfw.add(ByteCode.DUP); // duplicate array reference
            cfw.addPush(i);
            paramOffset += generateWrapArg(cfw, paramOffset, argTypes[i]);
            cfw.add(ByteCode.AASTORE);
        }
    }

    /**
     * Generates code to wrap Java argument into Object.
     * Non-primitive Java types are left unconverted pending conversion
     * in the helper method. Leaves the wrapper object on the top of the stack.
     */
    private static int generateWrapArg(ClassFileWriter cfw, int paramOffset,
                                       Class argType)
    {
        int size = 1;
        if (!argType.isPrimitive()) {
            cfw.add(ByteCode.ALOAD, paramOffset);

        } else if (argType == Boolean.TYPE) {
            // wrap boolean values with java.lang.Boolean.
            cfw.add(ByteCode.NEW, "java/lang/Boolean");
            cfw.add(ByteCode.DUP);
            cfw.add(ByteCode.ILOAD, paramOffset);
            cfw.addInvoke(ByteCode.INVOKESPECIAL, "java/lang/Boolean",
                          "", "(Z)V");

        } else if (argType == Character.TYPE) {
            // Create a string of length 1 using the character parameter.
            cfw.add(ByteCode.ILOAD, paramOffset);
            cfw.addInvoke(ByteCode.INVOKESTATIC, "java/lang/String",
                          "valueOf", "(C)Ljava/lang/String;");

        } else {
            // convert all numeric values to java.lang.Double.
            cfw.add(ByteCode.NEW, "java/lang/Double");
            cfw.add(ByteCode.DUP);
            String typeName = argType.getName();
            switch (typeName.charAt(0)) {
            case 'b':
            case 's':
            case 'i':
                // load an int value, convert to double.
                cfw.add(ByteCode.ILOAD, paramOffset);
                cfw.add(ByteCode.I2D);
                break;
            case 'l':
                // load a long, convert to double.
                cfw.add(ByteCode.LLOAD, paramOffset);
                cfw.add(ByteCode.L2D);
                size = 2;
                break;
            case 'f':
                // load a float, convert to double.
                cfw.add(ByteCode.FLOAD, paramOffset);
                cfw.add(ByteCode.F2D);
                break;
            case 'd':
                cfw.add(ByteCode.DLOAD, paramOffset);
                size = 2;
                break;
            }
            cfw.addInvoke(ByteCode.INVOKESPECIAL, "java/lang/Double",
                          "", "(D)V");
        }
        return size;
    }

    /**
     * Generates code to convert a wrapped value type to a primitive type.
     * Handles unwrapping java.lang.Boolean, and java.lang.Number types.
     * Generates the appropriate RETURN bytecode.
     */
    static void generateReturnResult(ClassFileWriter cfw, Class retType,
                                     boolean callConvertResult)
    {
        // wrap boolean values with java.lang.Boolean, convert all other
        // primitive values to java.lang.Double.
        if (retType == Void.TYPE) {
            cfw.add(ByteCode.POP);
            cfw.add(ByteCode.RETURN);

        } else if (retType == Boolean.TYPE) {
            cfw.addInvoke(ByteCode.INVOKESTATIC,
                          "org/mozilla/javascript/Context",
                          "toBoolean", "(Ljava/lang/Object;)Z");
            cfw.add(ByteCode.IRETURN);

        } else if (retType == Character.TYPE) {
            // characters are represented as strings in JavaScript.
            // return the first character.
            // first convert the value to a string if possible.
            cfw.addInvoke(ByteCode.INVOKESTATIC,
                          "org/mozilla/javascript/Context",
                          "toString",
                          "(Ljava/lang/Object;)Ljava/lang/String;");
            cfw.add(ByteCode.ICONST_0);
            cfw.addInvoke(ByteCode.INVOKEVIRTUAL, "java/lang/String",
                          "charAt", "(I)C");
            cfw.add(ByteCode.IRETURN);

        } else if (retType.isPrimitive()) {
            cfw.addInvoke(ByteCode.INVOKESTATIC,
                          "org/mozilla/javascript/Context",
                          "toNumber", "(Ljava/lang/Object;)D");
            String typeName = retType.getName();
            switch (typeName.charAt(0)) {
            case 'b':
            case 's':
            case 'i':
                cfw.add(ByteCode.D2I);
                cfw.add(ByteCode.IRETURN);
                break;
            case 'l':
                cfw.add(ByteCode.D2L);
                cfw.add(ByteCode.LRETURN);
                break;
            case 'f':
                cfw.add(ByteCode.D2F);
                cfw.add(ByteCode.FRETURN);
                break;
            case 'd':
                cfw.add(ByteCode.DRETURN);
                break;
            default:
                throw new RuntimeException("Unexpected return type " +
                                           retType.toString());
            }

        } else {
            String retTypeStr = retType.getName();
            if (callConvertResult) {
                cfw.addLoadConstant(retTypeStr);
                cfw.addInvoke(ByteCode.INVOKESTATIC,
                              "java/lang/Class",
                              "forName",
                              "(Ljava/lang/String;)Ljava/lang/Class;");

                cfw.addInvoke(ByteCode.INVOKESTATIC,
                              "org/mozilla/javascript/JavaAdapter",
                              "convertResult",
                              "(Ljava/lang/Object;"
                              +"Ljava/lang/Class;"
                              +")Ljava/lang/Object;");
            }
            // Now cast to return type
            cfw.add(ByteCode.CHECKCAST, retTypeStr);
            cfw.add(ByteCode.ARETURN);
        }
    }

    private static void generateMethod(ClassFileWriter cfw, String genName,
                                       String methodName, Class[] parms,
                                       Class returnType, boolean convertResult)
    {
        StringBuilder sb = new StringBuilder();
        int paramsEnd = appendMethodSignature(parms, returnType, sb);
        String methodSignature = sb.toString();
        cfw.startMethod(methodName, methodSignature,
                        ClassFileWriter.ACC_PUBLIC);

        // Prepare stack to call method

        // push factory
        cfw.add(ByteCode.ALOAD_0);
        cfw.add(ByteCode.GETFIELD, genName, "factory",
                "Lorg/mozilla/javascript/ContextFactory;");

        // push self
        cfw.add(ByteCode.ALOAD_0);
        cfw.add(ByteCode.GETFIELD, genName, "self",
                "Lorg/mozilla/javascript/Scriptable;");

        // push function
        cfw.add(ByteCode.ALOAD_0);
        cfw.add(ByteCode.GETFIELD, genName, "delegee",
                "Lorg/mozilla/javascript/Scriptable;");
        cfw.addPush(methodName);
        cfw.addInvoke(ByteCode.INVOKESTATIC,
                      "org/mozilla/javascript/JavaAdapter",
                      "getFunction",
                      "(Lorg/mozilla/javascript/Scriptable;"
                      +"Ljava/lang/String;"
                      +")Lorg/mozilla/javascript/Function;");

        // push arguments
        generatePushWrappedArgs(cfw, parms, parms.length);

        // push bits to indicate which parameters should be wrapped
        if (parms.length > 64) {
            // If it will be an issue, then passing a static boolean array
            // can be an option, but for now using simple bitmask
            throw Context.reportRuntimeError0(
                "JavaAdapter can not subclass methods with more then"
                +" 64 arguments.");
        }
        long convertionMask = 0;
        for (int i = 0; i != parms.length; ++i) {
            if (!parms[i].isPrimitive()) {
                convertionMask |= (1 << i);
            }
        }
        cfw.addPush(convertionMask);

        // go through utility method, which creates a Context to run the
        // method in.
        cfw.addInvoke(ByteCode.INVOKESTATIC,
                      "org/mozilla/javascript/JavaAdapter",
                      "callMethod",
                      "(Lorg/mozilla/javascript/ContextFactory;"
                      +"Lorg/mozilla/javascript/Scriptable;"
                      +"Lorg/mozilla/javascript/Function;"
                      +"[Ljava/lang/Object;"
                      +"J"
                      +")Ljava/lang/Object;");

        generateReturnResult(cfw, returnType, convertResult);

        cfw.stopMethod((short)paramsEnd);
    }

    /**
     * Generates code to push typed parameters onto the operand stack
     * prior to a direct Java method call.
     */
    private static int generatePushParam(ClassFileWriter cfw, int paramOffset,
                                         Class paramType)
    {
        if (!paramType.isPrimitive()) {
            cfw.addALoad(paramOffset);
            return 1;
        }
        String typeName = paramType.getName();
        switch (typeName.charAt(0)) {
        case 'z':
        case 'b':
        case 'c':
        case 's':
        case 'i':
            // load an int value, convert to double.
            cfw.addILoad(paramOffset);
            return 1;
        case 'l':
            // load a long, convert to double.
            cfw.addLLoad(paramOffset);
            return 2;
        case 'f':
            // load a float, convert to double.
            cfw.addFLoad(paramOffset);
            return 1;
        case 'd':
            cfw.addDLoad(paramOffset);
            return 2;
        }
        throw Kit.codeBug();
    }

    /**
     * Generates code to return a Java type, after calling a Java method
     * that returns the same type.
     * Generates the appropriate RETURN bytecode.
     */
    private static void generatePopResult(ClassFileWriter cfw,
                                          Class retType)
    {
        if (retType.isPrimitive()) {
            String typeName = retType.getName();
            switch (typeName.charAt(0)) {
            case 'b':
            case 'c':
            case 's':
            case 'i':
            case 'z':
                cfw.add(ByteCode.IRETURN);
                break;
            case 'l':
                cfw.add(ByteCode.LRETURN);
                break;
            case 'f':
                cfw.add(ByteCode.FRETURN);
                break;
            case 'd':
                cfw.add(ByteCode.DRETURN);
                break;
            }
        } else {
            cfw.add(ByteCode.ARETURN);
        }
    }

    /**
     * Generates a method called "super$methodName()" which can be called
     * from JavaScript that is equivalent to calling "super.methodName()"
     * from Java. Eventually, this may be supported directly in JavaScript.
     */
    private static void generateSuper(ClassFileWriter cfw,
                                      String genName, String superName,
                                      String methodName, String methodSignature,
                                      Class[] parms, Class returnType)
    {
        cfw.startMethod("super$" + methodName, methodSignature,
                        ClassFileWriter.ACC_PUBLIC);

        // push "this"
        cfw.add(ByteCode.ALOAD, 0);

        // push the rest of the parameters.
        int paramOffset = 1;
        for (Class parm : parms) {
            paramOffset += generatePushParam(cfw, paramOffset, parm);
        }

        // call the superclass implementation of the method.
        cfw.addInvoke(ByteCode.INVOKESPECIAL,
                      superName,
                      methodName,
                      methodSignature);

        // now, handle the return type appropriately.
        Class retType = returnType;
        if (!retType.equals(Void.TYPE)) {
            generatePopResult(cfw, retType);
        } else {
            cfw.add(ByteCode.RETURN);
        }
        cfw.stopMethod((short)(paramOffset + 1));
    }

    /**
     * Returns a fully qualified method name concatenated with its signature.
     */
    private static String getMethodSignature(Method method, Class[] argTypes)
    {
        StringBuilder sb = new StringBuilder();
        appendMethodSignature(argTypes, method.getReturnType(), sb);
        return sb.toString();
    }

    static int appendMethodSignature(Class[] argTypes,
                                     Class returnType,
                                     StringBuilder sb)
    {
        sb.append('(');
        int firstLocal = 1 + argTypes.length; // includes this.
        for (Class type : argTypes) {
            appendTypeString(sb, type);
            if (type == Long.TYPE || type == Double.TYPE) {
                // adjust for double slot
                ++firstLocal;
            }
        }
        sb.append(')');
        appendTypeString(sb, returnType);
        return firstLocal;
    }

    private static StringBuilder appendTypeString(StringBuilder sb, Class type)
    {
        while (type.isArray()) {
            sb.append('[');
            type = type.getComponentType();
        }
        if (type.isPrimitive()) {
            char typeLetter;
            if (type == Boolean.TYPE) {
                typeLetter = 'Z';
            } else if (type == Long.TYPE) {
                typeLetter = 'J';
            } else {
                String typeName = type.getName();
                typeLetter = Character.toUpperCase(typeName.charAt(0));
            }
            sb.append(typeLetter);
        } else {
            sb.append('L');
            sb.append(type.getName().replace('.', '/'));
            sb.append(';');
        }
        return sb;
    }

    static int[] getArgsToConvert(Class[] argTypes)
    {
        int count = 0;
        for (int i = 0; i != argTypes.length; ++i) {
            if (!argTypes[i].isPrimitive())
                ++count;
        }
        if (count == 0)
            return null;
        int[] array = new int[count];
        count = 0;
        for (int i = 0; i != argTypes.length; ++i) {
            if (!argTypes[i].isPrimitive())
                array[count++] = i;
        }
        return array;
    }

    private static final Object FTAG = "JavaAdapter";
    private static final int Id_JavaAdapter = 1;
}
rhino-1.7R4/src/org/mozilla/javascript/JavaMembers.java000066400000000000000000001064771176760007500231700ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import java.lang.reflect.*;
import java.util.*;

import static java.lang.reflect.Modifier.isProtected;
import static java.lang.reflect.Modifier.isPublic;

/**
 *
 * @author Mike Shaver
 * @author Norris Boyd
 * @see NativeJavaObject
 * @see NativeJavaClass
 */
class JavaMembers
{
    JavaMembers(Scriptable scope, Class cl)
    {
        this(scope, cl, false);
    }

    JavaMembers(Scriptable scope, Class cl, boolean includeProtected)
    {
        try {
            Context cx = ContextFactory.getGlobal().enterContext();
            ClassShutter shutter = cx.getClassShutter();
            if (shutter != null && !shutter.visibleToScripts(cl.getName())) {
                throw Context.reportRuntimeError1("msg.access.prohibited",
                                                  cl.getName());
            }
            this.members = new HashMap();
            this.staticMembers = new HashMap();
            this.cl = cl;
            boolean includePrivate = cx.hasFeature(
                    Context.FEATURE_ENHANCED_JAVA_ACCESS);
            reflect(scope, includeProtected, includePrivate);
        } finally {
            Context.exit();
        }
    }

    boolean has(String name, boolean isStatic)
    {
        Map ht = isStatic ? staticMembers : members;
        Object obj = ht.get(name);
        if (obj != null) {
            return true;
        }
        return findExplicitFunction(name, isStatic) != null;
    }

    Object get(Scriptable scope, String name, Object javaObject,
               boolean isStatic)
    {
        Map ht = isStatic ? staticMembers : members;
        Object member = ht.get(name);
        if (!isStatic && member == null) {
            // Try to get static member from instance (LC3)
            member = staticMembers.get(name);
        }
        if (member == null) {
            member = this.getExplicitFunction(scope, name,
                                              javaObject, isStatic);
            if (member == null)
                return Scriptable.NOT_FOUND;
        }
        if (member instanceof Scriptable) {
            return member;
        }
        Context cx = Context.getContext();
        Object rval;
        Class type;
        try {
            if (member instanceof BeanProperty) {
                BeanProperty bp = (BeanProperty) member;
                if (bp.getter == null)
                    return Scriptable.NOT_FOUND;
                rval = bp.getter.invoke(javaObject, Context.emptyArgs);
                type = bp.getter.method().getReturnType();
            } else {
                Field field = (Field) member;
                rval = field.get(isStatic ? null : javaObject);
                type = field.getType();
            }
        } catch (Exception ex) {
            throw Context.throwAsScriptRuntimeEx(ex);
        }
        // Need to wrap the object before we return it.
        scope = ScriptableObject.getTopLevelScope(scope);
        return cx.getWrapFactory().wrap(cx, scope, rval, type);
    }

    void put(Scriptable scope, String name, Object javaObject,
             Object value, boolean isStatic)
    {
        Map ht = isStatic ? staticMembers : members;
        Object member = ht.get(name);
        if (!isStatic && member == null) {
            // Try to get static member from instance (LC3)
            member = staticMembers.get(name);
        }
        if (member == null)
            throw reportMemberNotFound(name);
        if (member instanceof FieldAndMethods) {
            FieldAndMethods fam = (FieldAndMethods) ht.get(name);
            member = fam.field;
        }

        // Is this a bean property "set"?
        if (member instanceof BeanProperty) {
            BeanProperty bp = (BeanProperty)member;
            if (bp.setter == null) {
                throw reportMemberNotFound(name);
            }
            // If there's only one setter or if the value is null, use the
            // main setter. Otherwise, let the NativeJavaMethod decide which
            // setter to use:
            if (bp.setters == null || value == null) {
                Class setType = bp.setter.argTypes[0];
                Object[] args = { Context.jsToJava(value, setType) };
                try {
                    bp.setter.invoke(javaObject, args);
                } catch (Exception ex) {
                  throw Context.throwAsScriptRuntimeEx(ex);
                }
            } else {
                Object[] args = { value };
                bp.setters.call(Context.getContext(),
                                ScriptableObject.getTopLevelScope(scope),
                                scope, args);
            }
        }
        else {
            if (!(member instanceof Field)) {
                String str = (member == null) ? "msg.java.internal.private"
                                              : "msg.java.method.assign";
                throw Context.reportRuntimeError1(str, name);
            }
            Field field = (Field)member;
            Object javaValue = Context.jsToJava(value, field.getType());
            try {
                field.set(javaObject, javaValue);
            } catch (IllegalAccessException accessEx) {
                if ((field.getModifiers() & Modifier.FINAL) != 0) {
                    // treat Java final the same as JavaScript [[READONLY]]
                    return;
                }
                throw Context.throwAsScriptRuntimeEx(accessEx);
            } catch (IllegalArgumentException argEx) {
                throw Context.reportRuntimeError3(
                    "msg.java.internal.field.type",
                    value.getClass().getName(), field,
                    javaObject.getClass().getName());
            }
        }
    }

    Object[] getIds(boolean isStatic)
    {
        Map map = isStatic ? staticMembers : members;
        return map.keySet().toArray(new Object[map.size()]);
    }

    static String javaSignature(Class type)
    {
        if (!type.isArray()) {
            return type.getName();
        } else {
            int arrayDimension = 0;
            do {
                ++arrayDimension;
                type = type.getComponentType();
            } while (type.isArray());
            String name = type.getName();
            String suffix = "[]";
            if (arrayDimension == 1) {
                return name.concat(suffix);
            } else {
                int length = name.length() + arrayDimension * suffix.length();
                StringBuilder sb = new StringBuilder(length);
                sb.append(name);
                while (arrayDimension != 0) {
                    --arrayDimension;
                    sb.append(suffix);
                }
                return sb.toString();
            }
        }
    }

    static String liveConnectSignature(Class[] argTypes)
    {
        int N = argTypes.length;
        if (N == 0) { return "()"; }
        StringBuilder sb = new StringBuilder();
        sb.append('(');
        for (int i = 0; i != N; ++i) {
            if (i != 0) {
                sb.append(',');
            }
            sb.append(javaSignature(argTypes[i]));
        }
        sb.append(')');
        return sb.toString();
    }

    private MemberBox findExplicitFunction(String name, boolean isStatic)
    {
        int sigStart = name.indexOf('(');
        if (sigStart < 0) { return null; }

        Map ht = isStatic ? staticMembers : members;
        MemberBox[] methodsOrCtors = null;
        boolean isCtor = (isStatic && sigStart == 0);

        if (isCtor) {
            // Explicit request for an overloaded constructor
            methodsOrCtors = ctors.methods;
        } else {
            // Explicit request for an overloaded method
            String trueName = name.substring(0,sigStart);
            Object obj = ht.get(trueName);
            if (!isStatic && obj == null) {
                // Try to get static member from instance (LC3)
                obj = staticMembers.get(trueName);
            }
            if (obj instanceof NativeJavaMethod) {
                NativeJavaMethod njm = (NativeJavaMethod)obj;
                methodsOrCtors = njm.methods;
            }
        }

        if (methodsOrCtors != null) {
            for (MemberBox methodsOrCtor : methodsOrCtors) {
                Class[] type = methodsOrCtor.argTypes;
                String sig = liveConnectSignature(type);
                if (sigStart + sig.length() == name.length()
                        && name.regionMatches(sigStart, sig, 0, sig.length()))
                {
                    return methodsOrCtor;
                }
            }
        }

        return null;
    }

    private Object getExplicitFunction(Scriptable scope, String name,
                                       Object javaObject, boolean isStatic)
    {
        Map ht = isStatic ? staticMembers : members;
        Object member = null;
        MemberBox methodOrCtor = findExplicitFunction(name, isStatic);

        if (methodOrCtor != null) {
            Scriptable prototype =
                ScriptableObject.getFunctionPrototype(scope);

            if (methodOrCtor.isCtor()) {
                NativeJavaConstructor fun =
                    new NativeJavaConstructor(methodOrCtor);
                fun.setPrototype(prototype);
                member = fun;
                ht.put(name, fun);
            } else {
                String trueName = methodOrCtor.getName();
                member = ht.get(trueName);

                if (member instanceof NativeJavaMethod &&
                    ((NativeJavaMethod)member).methods.length > 1 ) {
                    NativeJavaMethod fun =
                        new NativeJavaMethod(methodOrCtor, name);
                    fun.setPrototype(prototype);
                    ht.put(name, fun);
                    member = fun;
                }
            }
        }

        return member;
    }

    /**
     * Retrieves mapping of methods to accessible methods for a class.
     * In case the class is not public, retrieves methods with same
     * signature as its public methods from public superclasses and
     * interfaces (if they exist). Basically upcasts every method to the
     * nearest accessible method.
     */
    private static Method[] discoverAccessibleMethods(Class clazz,
                                                      boolean includeProtected,
                                                      boolean includePrivate)
    {
        Map map = new HashMap();
        discoverAccessibleMethods(clazz, map, includeProtected, includePrivate);
        return map.values().toArray(new Method[map.size()]);
    }

    private static void discoverAccessibleMethods(Class clazz,
            Map map, boolean includeProtected,
            boolean includePrivate)
    {
        if (isPublic(clazz.getModifiers()) || includePrivate) {
            try {
                if (includeProtected || includePrivate) {
                    while (clazz != null) {
                        try {
                            Method[] methods = clazz.getDeclaredMethods();
                            for (Method method : methods) {
                                int mods = method.getModifiers();

                                if (isPublic(mods)
                                        || isProtected(mods)
                                        || includePrivate) {
                                    MethodSignature sig = new MethodSignature(method);
                                    if (!map.containsKey(sig)) {
                                        if (includePrivate && !method.isAccessible())
                                            method.setAccessible(true);
                                        map.put(sig, method);
                                    }
                                }
                            }
                            clazz = clazz.getSuperclass();
                        } catch (SecurityException e) {
                            // Some security settings (i.e., applets) disallow
                            // access to Class.getDeclaredMethods. Fall back to
                            // Class.getMethods.
                            Method[] methods = clazz.getMethods();
                            for (Method method : methods) {
                                MethodSignature sig = new MethodSignature(method);
                                if (!map.containsKey(sig))
                                    map.put(sig, method);
                            }
                            break; // getMethods gets superclass methods, no
                                   // need to loop any more
                        }
                    }
                } else {
                    Method[] methods = clazz.getMethods();
                    for (Method method : methods) {
                        MethodSignature sig = new MethodSignature(method);
                        // Array may contain methods with same signature but different return value!
                        if (!map.containsKey(sig))
                            map.put(sig, method);
                    }
                }
                return;
            } catch (SecurityException e) {
                Context.reportWarning(
                        "Could not discover accessible methods of class " +
                            clazz.getName() + " due to lack of privileges, " +
                            "attemping superclasses/interfaces.");
                // Fall through and attempt to discover superclass/interface
                // methods
            }
        }

        Class[] interfaces = clazz.getInterfaces();
        for (Class intface : interfaces) {
            discoverAccessibleMethods(intface, map, includeProtected,
                    includePrivate);
        }
        Class superclass = clazz.getSuperclass();
        if (superclass != null) {
            discoverAccessibleMethods(superclass, map, includeProtected,
                    includePrivate);
        }
    }

    private static final class MethodSignature
    {
        private final String name;
        private final Class[] args;

        private MethodSignature(String name, Class[] args)
        {
            this.name = name;
            this.args = args;
        }

        MethodSignature(Method method)
        {
            this(method.getName(), method.getParameterTypes());
        }

        @Override
        public boolean equals(Object o)
        {
            if(o instanceof MethodSignature)
            {
                MethodSignature ms = (MethodSignature)o;
                return ms.name.equals(name) && Arrays.equals(args, ms.args);
            }
            return false;
        }

        @Override
        public int hashCode()
        {
            return name.hashCode() ^ args.length;
        }
    }

    private void reflect(Scriptable scope,
                         boolean includeProtected,
                         boolean includePrivate)
    {
        // We reflect methods first, because we want overloaded field/method
        // names to be allocated to the NativeJavaMethod before the field
        // gets in the way.

        Method[] methods = discoverAccessibleMethods(cl, includeProtected,
                                                     includePrivate);
        for (Method method : methods) {
            int mods = method.getModifiers();
            boolean isStatic = Modifier.isStatic(mods);
            Map ht = isStatic ? staticMembers : members;
            String name = method.getName();
            Object value = ht.get(name);
            if (value == null) {
                ht.put(name, method);
            } else {
                ObjArray overloadedMethods;
                if (value instanceof ObjArray) {
                    overloadedMethods = (ObjArray)value;
                } else {
                    if (!(value instanceof Method)) Kit.codeBug();
                    // value should be instance of Method as at this stage
                    // staticMembers and members can only contain methods
                    overloadedMethods = new ObjArray();
                    overloadedMethods.add(value);
                    ht.put(name, overloadedMethods);
                }
                overloadedMethods.add(method);
            }
        }

        // replace Method instances by wrapped NativeJavaMethod objects
        // first in staticMembers and then in members
        for (int tableCursor = 0; tableCursor != 2; ++tableCursor) {
            boolean isStatic = (tableCursor == 0);
            Map ht = isStatic ? staticMembers : members;
            for (Map.Entry entry: ht.entrySet()) {
                MemberBox[] methodBoxes;
                Object value = entry.getValue();
                if (value instanceof Method) {
                    methodBoxes = new MemberBox[1];
                    methodBoxes[0] = new MemberBox((Method)value);
                } else {
                    ObjArray overloadedMethods = (ObjArray)value;
                    int N = overloadedMethods.size();
                    if (N < 2) Kit.codeBug();
                    methodBoxes = new MemberBox[N];
                    for (int i = 0; i != N; ++i) {
                        Method method = (Method)overloadedMethods.get(i);
                        methodBoxes[i] = new MemberBox(method);
                    }
                }
                NativeJavaMethod fun = new NativeJavaMethod(methodBoxes);
                if (scope != null) {
                    ScriptRuntime.setFunctionProtoAndParent(fun, scope);
                }
                ht.put(entry.getKey(), fun);
            }
        }

        // Reflect fields.
        Field[] fields = getAccessibleFields(includeProtected, includePrivate);
        for (Field field : fields) {
            String name = field.getName();
            int mods = field.getModifiers();
            try {
                boolean isStatic = Modifier.isStatic(mods);
                Map ht = isStatic ? staticMembers : members;
                Object member = ht.get(name);
                if (member == null) {
                    ht.put(name, field);
                } else if (member instanceof NativeJavaMethod) {
                    NativeJavaMethod method = (NativeJavaMethod) member;
                    FieldAndMethods fam
                        = new FieldAndMethods(scope, method.methods, field);
                    Map fmht = isStatic ? staticFieldAndMethods
                                              : fieldAndMethods;
                    if (fmht == null) {
                        fmht = new HashMap();
                        if (isStatic) {
                            staticFieldAndMethods = fmht;
                        } else {
                            fieldAndMethods = fmht;
                        }
                    }
                    fmht.put(name, fam);
                    ht.put(name, fam);
                } else if (member instanceof Field) {
                    Field oldField = (Field) member;
                    // If this newly reflected field shadows an inherited field,
                    // then replace it. Otherwise, since access to the field
                    // would be ambiguous from Java, no field should be
                    // reflected.
                    // For now, the first field found wins, unless another field
                    // explicitly shadows it.
                    if (oldField.getDeclaringClass().
                            isAssignableFrom(field.getDeclaringClass()))
                    {
                        ht.put(name, field);
                    }
                } else {
                    // "unknown member type"
                    Kit.codeBug();
                }
            } catch (SecurityException e) {
                // skip this field
                Context.reportWarning("Could not access field "
                        + name + " of class " + cl.getName() +
                        " due to lack of privileges.");
            }
        }

        // Create bean properties from corresponding get/set methods first for
        // static members and then for instance members
        for (int tableCursor = 0; tableCursor != 2; ++tableCursor) {
            boolean isStatic = (tableCursor == 0);
            Map ht = isStatic ? staticMembers : members;

            Map toAdd = new HashMap();

            // Now, For each member, make "bean" properties.
            for (String name: ht.keySet()) {
                // Is this a getter?
                boolean memberIsGetMethod = name.startsWith("get");
                boolean memberIsSetMethod = name.startsWith("set");
                boolean memberIsIsMethod = name.startsWith("is");
                if (memberIsGetMethod || memberIsIsMethod
                        || memberIsSetMethod) {
                    // Double check name component.
                    String nameComponent
                        = name.substring(memberIsIsMethod ? 2 : 3);
                    if (nameComponent.length() == 0)
                        continue;

                    // Make the bean property name.
                    String beanPropertyName = nameComponent;
                    char ch0 = nameComponent.charAt(0);
                    if (Character.isUpperCase(ch0)) {
                        if (nameComponent.length() == 1) {
                            beanPropertyName = nameComponent.toLowerCase();
                        } else {
                            char ch1 = nameComponent.charAt(1);
                            if (!Character.isUpperCase(ch1)) {
                                beanPropertyName = Character.toLowerCase(ch0)
                                                   +nameComponent.substring(1);
                            }
                        }
                    }

                    // If we already have a member by this name, don't do this
                    // property.
                    if (toAdd.containsKey(beanPropertyName))
                        continue;
                    Object v = ht.get(beanPropertyName);
                    if (v != null) {
                        // A private field shouldn't mask a public getter/setter
                        if (!includePrivate || !(v instanceof Member) ||
                            !Modifier.isPrivate(((Member)v).getModifiers()))

                        {
                            continue;
                        }
                    }

                    // Find the getter method, or if there is none, the is-
                    // method.
                    MemberBox getter = null;
                    getter = findGetter(isStatic, ht, "get", nameComponent);
                    // If there was no valid getter, check for an is- method.
                    if (getter == null) {
                        getter = findGetter(isStatic, ht, "is", nameComponent);
                    }

                    // setter
                    MemberBox setter = null;
                    NativeJavaMethod setters = null;
                    String setterName = "set".concat(nameComponent);

                    if (ht.containsKey(setterName)) {
                        // Is this value a method?
                        Object member = ht.get(setterName);
                        if (member instanceof NativeJavaMethod) {
                            NativeJavaMethod njmSet = (NativeJavaMethod)member;
                            if (getter != null) {
                                // We have a getter. Now, do we have a matching
                                // setter?
                                Class type = getter.method().getReturnType();
                                setter = extractSetMethod(type, njmSet.methods,
                                                            isStatic);
                            } else {
                                // No getter, find any set method
                                setter = extractSetMethod(njmSet.methods,
                                                            isStatic);
                            }
                            if (njmSet.methods.length > 1) {
                                setters = njmSet;
                            }
                        }
                    }
                    // Make the property.
                    BeanProperty bp = new BeanProperty(getter, setter,
                                                       setters);
                    toAdd.put(beanPropertyName, bp);
                }
            }

            // Add the new bean properties.
            for (String key: toAdd.keySet()) {
                Object value = toAdd.get(key);
                ht.put(key, value);
            }
        }

        // Reflect constructors
        Constructor[] constructors = getAccessibleConstructors(includePrivate);
        MemberBox[] ctorMembers = new MemberBox[constructors.length];
        for (int i = 0; i != constructors.length; ++i) {
            ctorMembers[i] = new MemberBox(constructors[i]);
        }
        ctors = new NativeJavaMethod(ctorMembers, cl.getSimpleName());
    }

    private Constructor[] getAccessibleConstructors(boolean includePrivate)
    {
      // The JVM currently doesn't allow changing access on java.lang.Class
      // constructors, so don't try
      if (includePrivate && cl != ScriptRuntime.ClassClass) {
          try {
              Constructor[] cons = cl.getDeclaredConstructors();
              AccessibleObject.setAccessible(cons, true);

              return cons;
          } catch (SecurityException e) {
              // Fall through to !includePrivate case
              Context.reportWarning("Could not access constructor " +
                    " of class " + cl.getName() +
                    " due to lack of privileges.");
          }
      }
      return cl.getConstructors();
    }

    private Field[] getAccessibleFields(boolean includeProtected,
                                        boolean includePrivate) {
        if (includePrivate || includeProtected) {
            try {
                List fieldsList = new ArrayList();
                Class currentClass = cl;

                while (currentClass != null) {
                    // get all declared fields in this class, make them
                    // accessible, and save
                    Field[] declared = currentClass.getDeclaredFields();
                    for (Field field : declared) {
                        int mod = field.getModifiers();
                        if (includePrivate || isPublic(mod) || isProtected(mod)) {
                            if (!field.isAccessible())
                                field.setAccessible(true);
                            fieldsList.add(field);
                        }
                    }
                    // walk up superclass chain.  no need to deal specially with
                    // interfaces, since they can't have fields
                    currentClass = currentClass.getSuperclass();
                }

                return fieldsList.toArray(new Field[fieldsList.size()]);
            } catch (SecurityException e) {
                // fall through to !includePrivate case
            }
        }
        return cl.getFields();
    }

    private MemberBox findGetter(boolean isStatic, Map ht, String prefix,
                                 String propertyName)
    {
        String getterName = prefix.concat(propertyName);
        if (ht.containsKey(getterName)) {
            // Check that the getter is a method.
            Object member = ht.get(getterName);
            if (member instanceof NativeJavaMethod) {
                NativeJavaMethod njmGet = (NativeJavaMethod) member;
                return extractGetMethod(njmGet.methods, isStatic);
            }
        }
        return null;
    }

    private static MemberBox extractGetMethod(MemberBox[] methods,
                                              boolean isStatic)
    {
        // Inspect the list of all MemberBox for the only one having no
        // parameters
        for (MemberBox method : methods) {
            // Does getter method have an empty parameter list with a return
            // value (eg. a getSomething() or isSomething())?
            if (method.argTypes.length == 0 && (!isStatic || method.isStatic())) {
                Class type = method.method().getReturnType();
                if (type != Void.TYPE) {
                    return method;
                }
                break;
            }
        }
        return null;
    }

    private static MemberBox extractSetMethod(Class type, MemberBox[] methods,
                                              boolean isStatic)
    {
        //
        // Note: it may be preferable to allow NativeJavaMethod.findFunction()
        //       to find the appropriate setter; unfortunately, it requires an
        //       instance of the target arg to determine that.
        //

        // Make two passes: one to find a method with direct type assignment,
        // and one to find a widening conversion.
        for (int pass = 1; pass <= 2; ++pass) {
            for (MemberBox method : methods) {
                if (!isStatic || method.isStatic()) {
                    Class[] params = method.argTypes;
                    if (params.length == 1) {
                        if (pass == 1) {
                            if (params[0] == type) {
                                return method;
                            }
                        } else {
                            if (pass != 2) Kit.codeBug();
                            if (params[0].isAssignableFrom(type)) {
                                return method;
                            }
                        }
                    }
                }
            }
        }
        return null;
    }

    private static MemberBox extractSetMethod(MemberBox[] methods,
                                              boolean isStatic)
    {

        for (MemberBox method : methods) {
            if (!isStatic || method.isStatic()) {
                if (method.method().getReturnType() == Void.TYPE) {
                    if (method.argTypes.length == 1) {
                        return method;
                    }
                }
            }
        }
        return null;
    }

    Map getFieldAndMethodsObjects(Scriptable scope,
            Object javaObject, boolean isStatic)
    {
        Map ht = isStatic ? staticFieldAndMethods : fieldAndMethods;
        if (ht == null)
            return null;
        int len = ht.size();
        Map result = new HashMap(len);
        for (FieldAndMethods fam: ht.values()) {
            FieldAndMethods famNew = new FieldAndMethods(scope, fam.methods,
                                                         fam.field);
            famNew.javaObject = javaObject;
            result.put(fam.field.getName(), famNew);
        }
        return result;
    }

    static JavaMembers lookupClass(Scriptable scope, Class dynamicType,
                                   Class staticType, boolean includeProtected)
    {
        JavaMembers members;
        ClassCache cache = ClassCache.get(scope);
        Map,JavaMembers> ct = cache.getClassCacheMap();

        Class cl = dynamicType;
        for (;;) {
            members = ct.get(cl);
            if (members != null) {
                if (cl != dynamicType) {
                    // member lookup for the original class failed because of
                    // missing privileges, cache the result so we don't try again
                    ct.put(dynamicType, members);
                }
                return members;
            }
            try {
                members = new JavaMembers(cache.getAssociatedScope(), cl,
                        includeProtected);
                break;
            } catch (SecurityException e) {
                // Reflection may fail for objects that are in a restricted
                // access package (e.g. sun.*).  If we get a security
                // exception, try again with the static type if it is interface.
                // Otherwise, try superclass
                if (staticType != null && staticType.isInterface()) {
                    cl = staticType;
                    staticType = null; // try staticType only once
                } else {
                    Class parent = cl.getSuperclass();
                    if (parent == null) {
                        if (cl.isInterface()) {
                            // last resort after failed staticType interface
                            parent = ScriptRuntime.ObjectClass;
                        } else {
                            throw e;
                        }
                    }
                    cl = parent;
                }
            }
        }

        if (cache.isCachingEnabled()) {
            ct.put(cl, members);
            if (cl != dynamicType) {
                // member lookup for the original class failed because of
                // missing privileges, cache the result so we don't try again
                ct.put(dynamicType, members);
            }
        }
        return members;
    }

    RuntimeException reportMemberNotFound(String memberName)
    {
        return Context.reportRuntimeError2(
            "msg.java.member.not.found", cl.getName(), memberName);
    }

    private Class cl;
    private Map members;
    private Map fieldAndMethods;
    private Map staticMembers;
    private Map staticFieldAndMethods;
    NativeJavaMethod ctors; // we use NativeJavaMethod for ctor overload resolution
}

class BeanProperty
{
    BeanProperty(MemberBox getter, MemberBox setter, NativeJavaMethod setters)
    {
        this.getter = getter;
        this.setter = setter;
        this.setters = setters;
    }

    MemberBox getter;
    MemberBox setter;
    NativeJavaMethod setters;
}

class FieldAndMethods extends NativeJavaMethod
{
    static final long serialVersionUID = -9222428244284796755L;

    FieldAndMethods(Scriptable scope, MemberBox[] methods, Field field)
    {
        super(methods);
        this.field = field;
        setParentScope(scope);
        setPrototype(ScriptableObject.getFunctionPrototype(scope));
    }

    @Override
    public Object getDefaultValue(Class hint)
    {
        if (hint == ScriptRuntime.FunctionClass)
            return this;
        Object rval;
        Class type;
        try {
            rval = field.get(javaObject);
            type = field.getType();
        } catch (IllegalAccessException accEx) {
            throw Context.reportRuntimeError1(
                "msg.java.internal.private", field.getName());
        }
        Context cx  = Context.getContext();
        rval = cx.getWrapFactory().wrap(cx, this, rval, type);
        if (rval instanceof Scriptable) {
            rval = ((Scriptable) rval).getDefaultValue(hint);
        }
        return rval;
    }

    Field field;
    Object javaObject;
}
rhino-1.7R4/src/org/mozilla/javascript/JavaScriptException.java000066400000000000000000000056011176760007500247040ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// API class

package org.mozilla.javascript;

/**
 * Java reflection of JavaScript exceptions.
 * Instances of this class are thrown by the JavaScript 'throw' keyword.
 *
 * @author Mike McCabe
 */
public class JavaScriptException extends RhinoException
{
    static final long serialVersionUID = -7666130513694669293L;

    /**
     * @deprecated
     * Use {@link WrappedException#WrappedException(Throwable)} to report
     * exceptions in Java code.
     */
    public JavaScriptException(Object value)
    {
        this(value, "", 0);
    }

    /**
     * Create a JavaScript exception wrapping the given JavaScript value
     *
     * @param value the JavaScript value thrown.
     */
    public JavaScriptException(Object value, String sourceName, int lineNumber)
    {
        recordErrorOrigin(sourceName, lineNumber, null, 0);
        this.value = value;
        // Fill in fileName and lineNumber automatically when not specified
        // explicitly, see Bugzilla issue #342807
        if (value instanceof NativeError && Context.getContext()
                .hasFeature(Context.FEATURE_LOCATION_INFORMATION_IN_ERROR)) {
            NativeError error = (NativeError) value;
            if (!error.has("fileName", error)) {
                error.put("fileName", error, sourceName);
            }
            if (!error.has("lineNumber", error)) {
                error.put("lineNumber", error, Integer.valueOf(lineNumber));
            }
            // set stack property, see bug #549604
            error.setStackProvider(this);
        }
    }

    @Override
    public String details()
    {
        if (value == null) {
            return "null";
        } else if (value instanceof NativeError) {
            return value.toString();
        }
        try {
            return ScriptRuntime.toString(value);
        } catch (RuntimeException rte) {
            // ScriptRuntime.toString may throw a RuntimeException
            if (value instanceof Scriptable) {
                return ScriptRuntime.defaultObjectToString((Scriptable)value);
            } else {
                return value.toString();
            }
        }
    }

    /**
     * @return the value wrapped by this exception
     */
    public Object getValue()
    {
        return value;
    }

    /**
     * @deprecated Use {@link RhinoException#sourceName()} from the super class.
     */
    public String getSourceName()
    {
        return sourceName();
    }

    /**
     * @deprecated Use {@link RhinoException#lineNumber()} from the super class.
     */
    public int getLineNumber()
    {
        return lineNumber();
    }

    private Object value;
}
rhino-1.7R4/src/org/mozilla/javascript/Kit.java000066400000000000000000000343331176760007500215120ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * Collection of utilities
 */

public class Kit
{
    /**
     * Reflection of Throwable.initCause(Throwable) from JDK 1.4
     * or nul if it is not available.
     */
    private static Method Throwable_initCause = null;

    static {
        // Are we running on a JDK 1.4 or later system?
        try {
            Class ThrowableClass = Kit.classOrNull("java.lang.Throwable");
            Class[] signature = { ThrowableClass };
            Throwable_initCause
                = ThrowableClass.getMethod("initCause", signature);
        } catch (Exception ex) {
            // Assume any exceptions means the method does not exist.
        }
    }

    public static Class classOrNull(String className)
    {
        try {
            return Class.forName(className);
        } catch  (ClassNotFoundException ex) {
        } catch  (SecurityException ex) {
        } catch  (LinkageError ex) {
        } catch (IllegalArgumentException e) {
            // Can be thrown if name has characters that a class name
            // can not contain
        }
        return null;
    }

    /**
     * Attempt to load the class of the given name. Note that the type parameter
     * isn't checked.
     */
    public static Class classOrNull(ClassLoader loader, String className)
    {
        try {
            return loader.loadClass(className);
        } catch (ClassNotFoundException ex) {
        } catch (SecurityException ex) {
        } catch (LinkageError ex) {
        } catch (IllegalArgumentException e) {
            // Can be thrown if name has characters that a class name
            // can not contain
        }
        return null;
    }

    static Object newInstanceOrNull(Class cl)
    {
        try {
            return cl.newInstance();
        } catch (SecurityException x) {
        } catch  (LinkageError ex) {
        } catch (InstantiationException x) {
        } catch (IllegalAccessException x) {
        }
        return null;
    }

    /**
     * Check that testClass is accessible from the given loader.
     */
    static boolean testIfCanLoadRhinoClasses(ClassLoader loader)
    {
        Class testClass = ScriptRuntime.ContextFactoryClass;
        Class x = Kit.classOrNull(loader, testClass.getName());
        if (x != testClass) {
            // The check covers the case when x == null =>
            // loader does not know about testClass or the case
            // when x != null && x != testClass =>
            // loader loads a class unrelated to testClass
            return false;
        }
        return true;
    }

    /**
     * If initCause methods exists in Throwable, call
     * ex.initCause(cause) or otherwise do nothing.
     * @return The ex argument.
     */
    public static RuntimeException initCause(RuntimeException ex,
                                             Throwable cause)
    {
        if (Throwable_initCause != null) {
            Object[] args = { cause };
            try {
                Throwable_initCause.invoke(ex, args);
            } catch (Exception e) {
                // Ignore any exceptions
            }
        }
        return ex;
    }

    /**
     * If character c is a hexadecimal digit, return
     * accumulator * 16 plus corresponding
     * number. Otherise return -1.
     */
    public static int xDigitToInt(int c, int accumulator)
    {
        check: {
            // Use 0..9 < A..Z < a..z
            if (c <= '9') {
                c -= '0';
                if (0 <= c) { break check; }
            } else if (c <= 'F') {
                if ('A' <= c) {
                    c -= ('A' - 10);
                    break check;
                }
            } else if (c <= 'f') {
                if ('a' <= c) {
                    c -= ('a' - 10);
                    break check;
                }
            }
            return -1;
        }
        return (accumulator << 4) | c;
    }

    /**
     * Add listener to bag of listeners.
     * The function does not modify bag and return a new collection
     * containing listener and all listeners from bag.
     * Bag without listeners always represented as the null value.
     * 

* Usage example: *

     *     private volatile Object changeListeners;
     *
     *     public void addMyListener(PropertyChangeListener l)
     *     {
     *         synchronized (this) {
     *             changeListeners = Kit.addListener(changeListeners, l);
     *         }
     *     }
     *
     *     public void removeTextListener(PropertyChangeListener l)
     *     {
     *         synchronized (this) {
     *             changeListeners = Kit.removeListener(changeListeners, l);
     *         }
     *     }
     *
     *     public void fireChangeEvent(Object oldValue, Object newValue)
     *     {
     *     // Get immune local copy
     *         Object listeners = changeListeners;
     *         if (listeners != null) {
     *             PropertyChangeEvent e = new PropertyChangeEvent(
     *                 this, "someProperty" oldValue, newValue);
     *             for (int i = 0; ; ++i) {
     *                 Object l = Kit.getListener(listeners, i);
     *                 if (l == null)
     *                     break;
     *                 ((PropertyChangeListener)l).propertyChange(e);
     *             }
     *         }
     *     }
     * 
* * @param listener Listener to add to bag * @param bag Current collection of listeners. * @return A new bag containing all listeners from bag and * listener. * @see #removeListener(Object bag, Object listener) * @see #getListener(Object bag, int index) */ public static Object addListener(Object bag, Object listener) { if (listener == null) throw new IllegalArgumentException(); if (listener instanceof Object[]) throw new IllegalArgumentException(); if (bag == null) { bag = listener; } else if (!(bag instanceof Object[])) { bag = new Object[] { bag, listener }; } else { Object[] array = (Object[])bag; int L = array.length; // bag has at least 2 elements if it is array if (L < 2) throw new IllegalArgumentException(); Object[] tmp = new Object[L + 1]; System.arraycopy(array, 0, tmp, 0, L); tmp[L] = listener; bag = tmp; } return bag; } /** * Remove listener from bag of listeners. * The function does not modify bag and return a new collection * containing all listeners from bag except listener. * If bag does not contain listener, the function returns * bag. *

* For usage example, see {@link #addListener(Object bag, Object listener)}. * * @param listener Listener to remove from bag * @param bag Current collection of listeners. * @return A new bag containing all listeners from bag except * listener. * @see #addListener(Object bag, Object listener) * @see #getListener(Object bag, int index) */ public static Object removeListener(Object bag, Object listener) { if (listener == null) throw new IllegalArgumentException(); if (listener instanceof Object[]) throw new IllegalArgumentException(); if (bag == listener) { bag = null; } else if (bag instanceof Object[]) { Object[] array = (Object[])bag; int L = array.length; // bag has at least 2 elements if it is array if (L < 2) throw new IllegalArgumentException(); if (L == 2) { if (array[1] == listener) { bag = array[0]; } else if (array[0] == listener) { bag = array[1]; } } else { int i = L; do { --i; if (array[i] == listener) { Object[] tmp = new Object[L - 1]; System.arraycopy(array, 0, tmp, 0, i); System.arraycopy(array, i + 1, tmp, i, L - (i + 1)); bag = tmp; break; } } while (i != 0); } } return bag; } /** * Get listener at index position in bag or null if * index equals to number of listeners in bag. *

* For usage example, see {@link #addListener(Object bag, Object listener)}. * * @param bag Current collection of listeners. * @param index Index of the listener to access. * @return Listener at the given index or null. * @see #addListener(Object bag, Object listener) * @see #removeListener(Object bag, Object listener) */ public static Object getListener(Object bag, int index) { if (index == 0) { if (bag == null) return null; if (!(bag instanceof Object[])) return bag; Object[] array = (Object[])bag; // bag has at least 2 elements if it is array if (array.length < 2) throw new IllegalArgumentException(); return array[0]; } else if (index == 1) { if (!(bag instanceof Object[])) { if (bag == null) throw new IllegalArgumentException(); return null; } Object[] array = (Object[])bag; // the array access will check for index on its own return array[1]; } else { // bag has to array Object[] array = (Object[])bag; int L = array.length; if (L < 2) throw new IllegalArgumentException(); if (index == L) return null; return array[index]; } } static Object initHash(Map h, Object key, Object initialValue) { synchronized (h) { Object current = h.get(key); if (current == null) { h.put(key, initialValue); } else { initialValue = current; } } return initialValue; } private final static class ComplexKey { private Object key1; private Object key2; private int hash; ComplexKey(Object key1, Object key2) { this.key1 = key1; this.key2 = key2; } @Override public boolean equals(Object anotherObj) { if (!(anotherObj instanceof ComplexKey)) return false; ComplexKey another = (ComplexKey)anotherObj; return key1.equals(another.key1) && key2.equals(another.key2); } @Override public int hashCode() { if (hash == 0) { hash = key1.hashCode() ^ key2.hashCode(); } return hash; } } public static Object makeHashKeyFromPair(Object key1, Object key2) { if (key1 == null) throw new IllegalArgumentException(); if (key2 == null) throw new IllegalArgumentException(); return new ComplexKey(key1, key2); } public static String readReader(Reader r) throws IOException { char[] buffer = new char[512]; int cursor = 0; for (;;) { int n = r.read(buffer, cursor, buffer.length - cursor); if (n < 0) { break; } cursor += n; if (cursor == buffer.length) { char[] tmp = new char[buffer.length * 2]; System.arraycopy(buffer, 0, tmp, 0, cursor); buffer = tmp; } } return new String(buffer, 0, cursor); } public static byte[] readStream(InputStream is, int initialBufferCapacity) throws IOException { if (initialBufferCapacity <= 0) { throw new IllegalArgumentException( "Bad initialBufferCapacity: "+initialBufferCapacity); } byte[] buffer = new byte[initialBufferCapacity]; int cursor = 0; for (;;) { int n = is.read(buffer, cursor, buffer.length - cursor); if (n < 0) { break; } cursor += n; if (cursor == buffer.length) { byte[] tmp = new byte[buffer.length * 2]; System.arraycopy(buffer, 0, tmp, 0, cursor); buffer = tmp; } } if (cursor != buffer.length) { byte[] tmp = new byte[cursor]; System.arraycopy(buffer, 0, tmp, 0, cursor); buffer = tmp; } return buffer; } /** * Throws RuntimeException to indicate failed assertion. * The function never returns and its return type is RuntimeException * only to be able to write throw Kit.codeBug() if plain * Kit.codeBug() triggers unreachable code error. */ public static RuntimeException codeBug() throws RuntimeException { RuntimeException ex = new IllegalStateException("FAILED ASSERTION"); // Print stack trace ASAP ex.printStackTrace(System.err); throw ex; } /** * Throws RuntimeException to indicate failed assertion. * The function never returns and its return type is RuntimeException * only to be able to write throw Kit.codeBug() if plain * Kit.codeBug() triggers unreachable code error. */ public static RuntimeException codeBug(String msg) throws RuntimeException { msg = "FAILED ASSERTION: " + msg; RuntimeException ex = new IllegalStateException(msg); // Print stack trace ASAP ex.printStackTrace(System.err); throw ex; } } rhino-1.7R4/src/org/mozilla/javascript/LazilyLoadedCtor.java000066400000000000000000000104021176760007500241570ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.lang.reflect.*; import java.security.AccessController; import java.security.PrivilegedAction; /** * Avoid loading classes unless they are used. * *

This improves startup time and average memory usage. */ public final class LazilyLoadedCtor implements java.io.Serializable { private static final long serialVersionUID = 1L; private static final int STATE_BEFORE_INIT = 0; private static final int STATE_INITIALIZING = 1; private static final int STATE_WITH_VALUE = 2; private final ScriptableObject scope; private final String propertyName; private final String className; private final boolean sealed; private final boolean privileged; private Object initializedValue; private int state; public LazilyLoadedCtor(ScriptableObject scope, String propertyName, String className, boolean sealed) { this(scope, propertyName, className, sealed, false); } LazilyLoadedCtor(ScriptableObject scope, String propertyName, String className, boolean sealed, boolean privileged) { this.scope = scope; this.propertyName = propertyName; this.className = className; this.sealed = sealed; this.privileged = privileged; this.state = STATE_BEFORE_INIT; scope.addLazilyInitializedValue(propertyName, 0, this, ScriptableObject.DONTENUM); } void init() { synchronized (this) { if (state == STATE_INITIALIZING) throw new IllegalStateException( "Recursive initialization for "+propertyName); if (state == STATE_BEFORE_INIT) { state = STATE_INITIALIZING; // Set value now to have something to set in finally block if // buildValue throws. Object value = Scriptable.NOT_FOUND; try { value = buildValue(); } finally { initializedValue = value; state = STATE_WITH_VALUE; } } } } Object getValue() { if (state != STATE_WITH_VALUE) throw new IllegalStateException(propertyName); return initializedValue; } private Object buildValue() { if(privileged) { return AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return buildValue0(); } }); } else { return buildValue0(); } } private Object buildValue0() { Class cl = cast(Kit.classOrNull(className)); if (cl != null) { try { Object value = ScriptableObject.buildClassCtor(scope, cl, sealed, false); if (value != null) { return value; } else { // cl has own static initializer which is expected // to set the property on its own. value = scope.get(propertyName, scope); if (value != Scriptable.NOT_FOUND) return value; } } catch (InvocationTargetException ex) { Throwable target = ex.getTargetException(); if (target instanceof RuntimeException) { throw (RuntimeException)target; } } catch (RhinoException ex) { } catch (InstantiationException ex) { } catch (IllegalAccessException ex) { } catch (SecurityException ex) { } } return Scriptable.NOT_FOUND; } @SuppressWarnings({"unchecked"}) private Class cast(Class cl) { return (Class)cl; } } rhino-1.7R4/src/org/mozilla/javascript/MemberBox.java000066400000000000000000000241741176760007500226450ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.lang.reflect.*; import java.io.*; /** * Wrappper class for Method and Constructor instances to cache * getParameterTypes() results, recover from IllegalAccessException * in some cases and provide serialization support. * * @author Igor Bukanov */ final class MemberBox implements Serializable { static final long serialVersionUID = 6358550398665688245L; private transient Member memberObject; transient Class[] argTypes; transient Object delegateTo; transient boolean vararg; MemberBox(Method method) { init(method); } MemberBox(Constructor constructor) { init(constructor); } private void init(Method method) { this.memberObject = method; this.argTypes = method.getParameterTypes(); this.vararg = VMBridge.instance.isVarArgs(method); } private void init(Constructor constructor) { this.memberObject = constructor; this.argTypes = constructor.getParameterTypes(); this.vararg = VMBridge.instance.isVarArgs(constructor); } Method method() { return (Method)memberObject; } Constructor ctor() { return (Constructor)memberObject; } Member member() { return memberObject; } boolean isMethod() { return memberObject instanceof Method; } boolean isCtor() { return memberObject instanceof Constructor; } boolean isStatic() { return Modifier.isStatic(memberObject.getModifiers()); } String getName() { return memberObject.getName(); } Class getDeclaringClass() { return memberObject.getDeclaringClass(); } String toJavaDeclaration() { StringBuffer sb = new StringBuffer(); if (isMethod()) { Method method = method(); sb.append(method.getReturnType()); sb.append(' '); sb.append(method.getName()); } else { Constructor ctor = ctor(); String name = ctor.getDeclaringClass().getName(); int lastDot = name.lastIndexOf('.'); if (lastDot >= 0) { name = name.substring(lastDot + 1); } sb.append(name); } sb.append(JavaMembers.liveConnectSignature(argTypes)); return sb.toString(); } @Override public String toString() { return memberObject.toString(); } Object invoke(Object target, Object[] args) { Method method = method(); try { try { return method.invoke(target, args); } catch (IllegalAccessException ex) { Method accessible = searchAccessibleMethod(method, argTypes); if (accessible != null) { memberObject = accessible; method = accessible; } else { if (!VMBridge.instance.tryToMakeAccessible(method)) { throw Context.throwAsScriptRuntimeEx(ex); } } // Retry after recovery return method.invoke(target, args); } } catch (InvocationTargetException ite) { // Must allow ContinuationPending exceptions to propagate unhindered Throwable e = ite; do { e = ((InvocationTargetException) e).getTargetException(); } while ((e instanceof InvocationTargetException)); if (e instanceof ContinuationPending) throw (ContinuationPending) e; throw Context.throwAsScriptRuntimeEx(e); } catch (Exception ex) { throw Context.throwAsScriptRuntimeEx(ex); } } Object newInstance(Object[] args) { Constructor ctor = ctor(); try { try { return ctor.newInstance(args); } catch (IllegalAccessException ex) { if (!VMBridge.instance.tryToMakeAccessible(ctor)) { throw Context.throwAsScriptRuntimeEx(ex); } } return ctor.newInstance(args); } catch (Exception ex) { throw Context.throwAsScriptRuntimeEx(ex); } } private static Method searchAccessibleMethod(Method method, Class[] params) { int modifiers = method.getModifiers(); if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) { Class c = method.getDeclaringClass(); if (!Modifier.isPublic(c.getModifiers())) { String name = method.getName(); Class[] intfs = c.getInterfaces(); for (int i = 0, N = intfs.length; i != N; ++i) { Class intf = intfs[i]; if (Modifier.isPublic(intf.getModifiers())) { try { return intf.getMethod(name, params); } catch (NoSuchMethodException ex) { } catch (SecurityException ex) { } } } for (;;) { c = c.getSuperclass(); if (c == null) { break; } if (Modifier.isPublic(c.getModifiers())) { try { Method m = c.getMethod(name, params); int mModifiers = m.getModifiers(); if (Modifier.isPublic(mModifiers) && !Modifier.isStatic(mModifiers)) { return m; } } catch (NoSuchMethodException ex) { } catch (SecurityException ex) { } } } } } return null; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); Member member = readMember(in); if (member instanceof Method) { init((Method)member); } else { init((Constructor)member); } } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); writeMember(out, memberObject); } /** * Writes a Constructor or Method object. * * Methods and Constructors are not serializable, so we must serialize * information about the class, the name, and the parameters and * recreate upon deserialization. */ private static void writeMember(ObjectOutputStream out, Member member) throws IOException { if (member == null) { out.writeBoolean(false); return; } out.writeBoolean(true); if (!(member instanceof Method || member instanceof Constructor)) throw new IllegalArgumentException("not Method or Constructor"); out.writeBoolean(member instanceof Method); out.writeObject(member.getName()); out.writeObject(member.getDeclaringClass()); if (member instanceof Method) { writeParameters(out, ((Method) member).getParameterTypes()); } else { writeParameters(out, ((Constructor) member).getParameterTypes()); } } /** * Reads a Method or a Constructor from the stream. */ private static Member readMember(ObjectInputStream in) throws IOException, ClassNotFoundException { if (!in.readBoolean()) return null; boolean isMethod = in.readBoolean(); String name = (String) in.readObject(); Class declaring = (Class) in.readObject(); Class[] parms = readParameters(in); try { if (isMethod) { return declaring.getMethod(name, parms); } else { return declaring.getConstructor(parms); } } catch (NoSuchMethodException e) { throw new IOException("Cannot find member: " + e); } } private static final Class[] primitives = { Boolean.TYPE, Byte.TYPE, Character.TYPE, Double.TYPE, Float.TYPE, Integer.TYPE, Long.TYPE, Short.TYPE, Void.TYPE }; /** * Writes an array of parameter types to the stream. * * Requires special handling because primitive types cannot be * found upon deserialization by the default Java implementation. */ private static void writeParameters(ObjectOutputStream out, Class[] parms) throws IOException { out.writeShort(parms.length); outer: for (int i=0; i < parms.length; i++) { Class parm = parms[i]; boolean primitive = parm.isPrimitive(); out.writeBoolean(primitive); if (!primitive) { out.writeObject(parm); continue; } for (int j=0; j < primitives.length; j++) { if (parm.equals(primitives[j])) { out.writeByte(j); continue outer; } } throw new IllegalArgumentException("Primitive " + parm + " not found"); } } /** * Reads an array of parameter types from the stream. */ private static Class[] readParameters(ObjectInputStream in) throws IOException, ClassNotFoundException { Class[] result = new Class[in.readShort()]; for (int i=0; i < result.length; i++) { if (!in.readBoolean()) { result[i] = (Class) in.readObject(); continue; } result[i] = primitives[in.readByte()]; } return result; } } rhino-1.7R4/src/org/mozilla/javascript/NativeArray.java000066400000000000000000002131361176760007500232100ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.Set; /** * This class implements the Array native object. * @author Norris Boyd * @author Mike McCabe */ public class NativeArray extends IdScriptableObject implements List { static final long serialVersionUID = 7331366857676127338L; /* * Optimization possibilities and open issues: * - Long vs. double schizophrenia. I suspect it might be better * to use double throughout. * * - Functions that need a new Array call "new Array" in the * current scope rather than using a hardwired constructor; * "Array" could be redefined. It turns out that js calls the * equivalent of "new Array" in the current scope, except that it * always gets at least an object back, even when Array == null. */ private static final Object ARRAY_TAG = "Array"; private static final Integer NEGATIVE_ONE = Integer.valueOf(-1); static void init(Scriptable scope, boolean sealed) { NativeArray obj = new NativeArray(0); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } static int getMaximumInitialCapacity() { return maximumInitialCapacity; } static void setMaximumInitialCapacity(int maximumInitialCapacity) { NativeArray.maximumInitialCapacity = maximumInitialCapacity; } public NativeArray(long lengthArg) { denseOnly = lengthArg <= maximumInitialCapacity; if (denseOnly) { int intLength = (int) lengthArg; if (intLength < DEFAULT_INITIAL_CAPACITY) intLength = DEFAULT_INITIAL_CAPACITY; dense = new Object[intLength]; Arrays.fill(dense, Scriptable.NOT_FOUND); } length = lengthArg; } public NativeArray(Object[] array) { denseOnly = true; dense = array; length = array.length; } @Override public String getClassName() { return "Array"; } private static final int Id_length = 1, MAX_INSTANCE_ID = 1; @Override protected int getMaxInstanceId() { return MAX_INSTANCE_ID; } @Override protected void setInstanceIdAttributes(int id, int attr) { if (id == Id_length) { lengthAttr = attr; } } @Override protected int findInstanceIdInfo(String s) { if (s.equals("length")) { return instanceIdInfo(lengthAttr, Id_length); } return super.findInstanceIdInfo(s); } @Override protected String getInstanceIdName(int id) { if (id == Id_length) { return "length"; } return super.getInstanceIdName(id); } @Override protected Object getInstanceIdValue(int id) { if (id == Id_length) { return ScriptRuntime.wrapNumber(length); } return super.getInstanceIdValue(id); } @Override protected void setInstanceIdValue(int id, Object value) { if (id == Id_length) { setLength(value); return; } super.setInstanceIdValue(id, value); } @Override protected void fillConstructorProperties(IdFunctionObject ctor) { addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_join, "join", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_reverse, "reverse", 0); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_sort, "sort", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_push, "push", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_pop, "pop", 0); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_shift, "shift", 0); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_unshift, "unshift", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_splice, "splice", 2); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_concat, "concat", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_slice, "slice", 2); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_indexOf, "indexOf", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_lastIndexOf, "lastIndexOf", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_every, "every", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_filter, "filter", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_forEach, "forEach", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_map, "map", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_some, "some", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_reduce, "reduce", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_reduceRight, "reduceRight", 1); addIdFunctionProperty(ctor, ARRAY_TAG, ConstructorId_isArray, "isArray", 1); super.fillConstructorProperties(ctor); } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=1; s="constructor"; break; case Id_toString: arity=0; s="toString"; break; case Id_toLocaleString: arity=0; s="toLocaleString"; break; case Id_toSource: arity=0; s="toSource"; break; case Id_join: arity=1; s="join"; break; case Id_reverse: arity=0; s="reverse"; break; case Id_sort: arity=1; s="sort"; break; case Id_push: arity=1; s="push"; break; case Id_pop: arity=0; s="pop"; break; case Id_shift: arity=0; s="shift"; break; case Id_unshift: arity=1; s="unshift"; break; case Id_splice: arity=2; s="splice"; break; case Id_concat: arity=1; s="concat"; break; case Id_slice: arity=2; s="slice"; break; case Id_indexOf: arity=1; s="indexOf"; break; case Id_lastIndexOf: arity=1; s="lastIndexOf"; break; case Id_every: arity=1; s="every"; break; case Id_filter: arity=1; s="filter"; break; case Id_forEach: arity=1; s="forEach"; break; case Id_map: arity=1; s="map"; break; case Id_some: arity=1; s="some"; break; case Id_reduce: arity=1; s="reduce"; break; case Id_reduceRight: arity=1; s="reduceRight"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(ARRAY_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(ARRAY_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); again: for (;;) { switch (id) { case ConstructorId_join: case ConstructorId_reverse: case ConstructorId_sort: case ConstructorId_push: case ConstructorId_pop: case ConstructorId_shift: case ConstructorId_unshift: case ConstructorId_splice: case ConstructorId_concat: case ConstructorId_slice: case ConstructorId_indexOf: case ConstructorId_lastIndexOf: case ConstructorId_every: case ConstructorId_filter: case ConstructorId_forEach: case ConstructorId_map: case ConstructorId_some: case ConstructorId_reduce: case ConstructorId_reduceRight: { if (args.length > 0) { thisObj = ScriptRuntime.toObject(scope, args[0]); Object[] newArgs = new Object[args.length-1]; for (int i=0; i < newArgs.length; i++) newArgs[i] = args[i+1]; args = newArgs; } id = -id; continue again; } case ConstructorId_isArray: return args.length > 0 && (args[0] instanceof NativeArray); case Id_constructor: { boolean inNewExpr = (thisObj == null); if (!inNewExpr) { // IdFunctionObject.construct will set up parent, proto return f.construct(cx, scope, args); } return jsConstructor(cx, scope, args); } case Id_toString: return toStringHelper(cx, scope, thisObj, cx.hasFeature(Context.FEATURE_TO_STRING_AS_SOURCE), false); case Id_toLocaleString: return toStringHelper(cx, scope, thisObj, false, true); case Id_toSource: return toStringHelper(cx, scope, thisObj, true, false); case Id_join: return js_join(cx, thisObj, args); case Id_reverse: return js_reverse(cx, thisObj, args); case Id_sort: return js_sort(cx, scope, thisObj, args); case Id_push: return js_push(cx, thisObj, args); case Id_pop: return js_pop(cx, thisObj, args); case Id_shift: return js_shift(cx, thisObj, args); case Id_unshift: return js_unshift(cx, thisObj, args); case Id_splice: return js_splice(cx, scope, thisObj, args); case Id_concat: return js_concat(cx, scope, thisObj, args); case Id_slice: return js_slice(cx, thisObj, args); case Id_indexOf: return indexOfHelper(cx, thisObj, args, false); case Id_lastIndexOf: return indexOfHelper(cx, thisObj, args, true); case Id_every: case Id_filter: case Id_forEach: case Id_map: case Id_some: return iterativeMethod(cx, id, scope, thisObj, args); case Id_reduce: case Id_reduceRight: return reduceMethod(cx, id, scope, thisObj, args); } throw new IllegalArgumentException(String.valueOf(id)); } } @Override public Object get(int index, Scriptable start) { if (!denseOnly && isGetterOrSetter(null, index, false)) return super.get(index, start); if (dense != null && 0 <= index && index < dense.length) return dense[index]; return super.get(index, start); } @Override public boolean has(int index, Scriptable start) { if (!denseOnly && isGetterOrSetter(null, index, false)) return super.has(index, start); if (dense != null && 0 <= index && index < dense.length) return dense[index] != NOT_FOUND; return super.has(index, start); } private static long toArrayIndex(Object id) { if (id instanceof String) { return toArrayIndex((String)id); } else if (id instanceof Number) { return toArrayIndex(((Number)id).doubleValue()); } return -1; } // if id is an array index (ECMA 15.4.0), return the number, // otherwise return -1L private static long toArrayIndex(String id) { long index = toArrayIndex(ScriptRuntime.toNumber(id)); // Assume that ScriptRuntime.toString(index) is the same // as java.lang.Long.toString(index) for long if (Long.toString(index).equals(id)) { return index; } return -1; } private static long toArrayIndex(double d) { if (d == d) { long index = ScriptRuntime.toUint32(d); if (index == d && index != 4294967295L) { return index; } } return -1; } private static int toDenseIndex(Object id) { long index = toArrayIndex(id); return 0 <= index && index < Integer.MAX_VALUE ? (int) index : -1; } @Override public void put(String id, Scriptable start, Object value) { super.put(id, start, value); if (start == this) { // If the object is sealed, super will throw exception long index = toArrayIndex(id); if (index >= length) { length = index + 1; denseOnly = false; } } } private boolean ensureCapacity(int capacity) { if (capacity > dense.length) { if (capacity > MAX_PRE_GROW_SIZE) { denseOnly = false; return false; } capacity = Math.max(capacity, (int)(dense.length * GROW_FACTOR)); Object[] newDense = new Object[capacity]; System.arraycopy(dense, 0, newDense, 0, dense.length); Arrays.fill(newDense, dense.length, newDense.length, Scriptable.NOT_FOUND); dense = newDense; } return true; } @Override public void put(int index, Scriptable start, Object value) { if (start == this && !isSealed() && dense != null && 0 <= index && (denseOnly || !isGetterOrSetter(null, index, true))) { if (index < dense.length) { dense[index] = value; if (this.length <= index) this.length = (long)index + 1; return; } else if (denseOnly && index < dense.length * GROW_FACTOR && ensureCapacity(index+1)) { dense[index] = value; this.length = (long)index + 1; return; } else { denseOnly = false; } } super.put(index, start, value); if (start == this && (lengthAttr & READONLY) == 0) { // only set the array length if given an array index (ECMA 15.4.0) if (this.length <= index) { // avoid overflowing index! this.length = (long)index + 1; } } } @Override public void delete(int index) { if (dense != null && 0 <= index && index < dense.length && !isSealed() && (denseOnly || !isGetterOrSetter(null, index, true))) { dense[index] = NOT_FOUND; } else { super.delete(index); } } @Override public Object[] getIds() { Object[] superIds = super.getIds(); if (dense == null) { return superIds; } int N = dense.length; long currentLength = length; if (N > currentLength) { N = (int)currentLength; } if (N == 0) { return superIds; } int superLength = superIds.length; Object[] ids = new Object[N + superLength]; int presentCount = 0; for (int i = 0; i != N; ++i) { // Replace existing elements by their indexes if (dense[i] != NOT_FOUND) { ids[presentCount] = Integer.valueOf(i); ++presentCount; } } if (presentCount != N) { // dense contains deleted elems, need to shrink the result Object[] tmp = new Object[presentCount + superLength]; System.arraycopy(ids, 0, tmp, 0, presentCount); ids = tmp; } System.arraycopy(superIds, 0, ids, presentCount, superLength); return ids; } @Override public Object[] getAllIds() { Set allIds = new LinkedHashSet( Arrays.asList(this.getIds())); allIds.addAll(Arrays.asList(super.getAllIds())); return allIds.toArray(); } public Integer[] getIndexIds() { Object[] ids = getIds(); java.util.List indices = new java.util.ArrayList(ids.length); for (Object id : ids) { int int32Id = ScriptRuntime.toInt32(id); if (int32Id >= 0 && ScriptRuntime.toString(int32Id).equals(ScriptRuntime.toString(id))) { indices.add(int32Id); } } return indices.toArray(new Integer[indices.size()]); } @Override public Object getDefaultValue(Class hint) { if (hint == ScriptRuntime.NumberClass) { Context cx = Context.getContext(); if (cx.getLanguageVersion() == Context.VERSION_1_2) return Long.valueOf(length); } return super.getDefaultValue(hint); } private ScriptableObject defaultIndexPropertyDescriptor(Object value) { Scriptable scope = getParentScope(); if (scope == null) scope = this; ScriptableObject desc = new NativeObject(); ScriptRuntime.setBuiltinProtoAndParent(desc, scope, TopLevel.Builtins.Object); desc.defineProperty("value", value, EMPTY); desc.defineProperty("writable", true, EMPTY); desc.defineProperty("enumerable", true, EMPTY); desc.defineProperty("configurable", true, EMPTY); return desc; } @Override public int getAttributes(int index) { if (dense != null && index >= 0 && index < dense.length && dense[index] != NOT_FOUND) { return EMPTY; } return super.getAttributes(index); } @Override protected ScriptableObject getOwnPropertyDescriptor(Context cx, Object id) { if (dense != null) { int index = toDenseIndex(id); if (0 <= index && index < dense.length && dense[index] != NOT_FOUND) { Object value = dense[index]; return defaultIndexPropertyDescriptor(value); } } return super.getOwnPropertyDescriptor(cx, id); } @Override protected void defineOwnProperty(Context cx, Object id, ScriptableObject desc, boolean checkValid) { if (dense != null) { Object[] values = dense; dense = null; denseOnly = false; for (int i = 0; i < values.length; i++) { if (values[i] != NOT_FOUND) { put(i, this, values[i]); } } } long index = toArrayIndex(id); if (index >= length) { length = index + 1; } super.defineOwnProperty(cx, id, desc, checkValid); } /** * See ECMA 15.4.1,2 */ private static Object jsConstructor(Context cx, Scriptable scope, Object[] args) { if (args.length == 0) return new NativeArray(0); // Only use 1 arg as first element for version 1.2; for // any other version (including 1.3) follow ECMA and use it as // a length. if (cx.getLanguageVersion() == Context.VERSION_1_2) { return new NativeArray(args); } else { Object arg0 = args[0]; if (args.length > 1 || !(arg0 instanceof Number)) { return new NativeArray(args); } else { long len = ScriptRuntime.toUint32(arg0); if (len != ((Number)arg0).doubleValue()) { String msg = ScriptRuntime.getMessage0("msg.arraylength.bad"); throw ScriptRuntime.constructError("RangeError", msg); } return new NativeArray(len); } } } public long getLength() { return length; } /** @deprecated Use {@link #getLength()} instead. */ public long jsGet_length() { return getLength(); } /** * Change the value of the internal flag that determines whether all * storage is handed by a dense backing array rather than an associative * store. * @param denseOnly new value for denseOnly flag * @throws IllegalArgumentException if an attempt is made to enable * denseOnly after it was disabled; NativeArray code is not written * to handle switching back to a dense representation */ void setDenseOnly(boolean denseOnly) { if (denseOnly && !this.denseOnly) throw new IllegalArgumentException(); this.denseOnly = denseOnly; } private void setLength(Object val) { /* XXX do we satisfy this? * 15.4.5.1 [[Put]](P, V): * 1. Call the [[CanPut]] method of A with name P. * 2. If Result(1) is false, return. * ? */ if ((lengthAttr & READONLY) != 0) { return; } double d = ScriptRuntime.toNumber(val); long longVal = ScriptRuntime.toUint32(d); if (longVal != d) { String msg = ScriptRuntime.getMessage0("msg.arraylength.bad"); throw ScriptRuntime.constructError("RangeError", msg); } if (denseOnly) { if (longVal < length) { // downcast okay because denseOnly Arrays.fill(dense, (int) longVal, dense.length, NOT_FOUND); length = longVal; return; } else if (longVal < MAX_PRE_GROW_SIZE && longVal < (length * GROW_FACTOR) && ensureCapacity((int)longVal)) { length = longVal; return; } else { denseOnly = false; } } if (longVal < length) { // remove all properties between longVal and length if (length - longVal > 0x1000) { // assume that the representation is sparse Object[] e = getIds(); // will only find in object itself for (int i=0; i < e.length; i++) { Object id = e[i]; if (id instanceof String) { // > MAXINT will appear as string String strId = (String)id; long index = toArrayIndex(strId); if (index >= longVal) delete(strId); } else { int index = ((Integer)id).intValue(); if (index >= longVal) delete(index); } } } else { // assume a dense representation for (long i = longVal; i < length; i++) { deleteElem(this, i); } } } length = longVal; } /* Support for generic Array-ish objects. Most of the Array * functions try to be generic; anything that has a length * property is assumed to be an array. * getLengthProperty returns 0 if obj does not have the length property * or its value is not convertible to a number. */ static long getLengthProperty(Context cx, Scriptable obj) { // These will both give numeric lengths within Uint32 range. if (obj instanceof NativeString) { return ((NativeString)obj).getLength(); } else if (obj instanceof NativeArray) { return ((NativeArray)obj).getLength(); } return ScriptRuntime.toUint32( ScriptRuntime.getObjectProp(obj, "length", cx)); } private static Object setLengthProperty(Context cx, Scriptable target, long length) { return ScriptRuntime.setObjectProp( target, "length", ScriptRuntime.wrapNumber(length), cx); } /* Utility functions to encapsulate index > Integer.MAX_VALUE * handling. Also avoids unnecessary object creation that would * be necessary to use the general ScriptRuntime.get/setElem * functions... though this is probably premature optimization. */ private static void deleteElem(Scriptable target, long index) { int i = (int)index; if (i == index) { target.delete(i); } else { target.delete(Long.toString(index)); } } private static Object getElem(Context cx, Scriptable target, long index) { if (index > Integer.MAX_VALUE) { String id = Long.toString(index); return ScriptRuntime.getObjectProp(target, id, cx); } else { return ScriptRuntime.getObjectIndex(target, (int)index, cx); } } // same as getElem, but without converting NOT_FOUND to undefined private static Object getRawElem(Scriptable target, long index) { if (index > Integer.MAX_VALUE) { return ScriptableObject.getProperty(target, Long.toString(index)); } else { return ScriptableObject.getProperty(target, (int)index); } } private static void setElem(Context cx, Scriptable target, long index, Object value) { if (index > Integer.MAX_VALUE) { String id = Long.toString(index); ScriptRuntime.setObjectProp(target, id, value, cx); } else { ScriptRuntime.setObjectIndex(target, (int)index, value, cx); } } // Similar as setElem(), but triggers deleteElem() if value is NOT_FOUND private static void setRawElem(Context cx, Scriptable target, long index, Object value) { if (value == NOT_FOUND) { deleteElem(target, index); } else { setElem(cx, target, index, value); } } private static String toStringHelper(Context cx, Scriptable scope, Scriptable thisObj, boolean toSource, boolean toLocale) { /* It's probably redundant to handle long lengths in this * function; StringBuilders are limited to 2^31 in java. */ long length = getLengthProperty(cx, thisObj); StringBuilder result = new StringBuilder(256); // whether to return '4,unquoted,5' or '[4, "quoted", 5]' String separator; if (toSource) { result.append('['); separator = ", "; } else { separator = ","; } boolean haslast = false; long i = 0; boolean toplevel, iterating; if (cx.iterating == null) { toplevel = true; iterating = false; cx.iterating = new ObjToIntMap(31); } else { toplevel = false; iterating = cx.iterating.has(thisObj); } // Make sure cx.iterating is set to null when done // so we don't leak memory try { if (!iterating) { cx.iterating.put(thisObj, 0); // stop recursion. // make toSource print null and undefined values in recent versions boolean skipUndefinedAndNull = !toSource || cx.getLanguageVersion() < Context.VERSION_1_5; for (i = 0; i < length; i++) { if (i > 0) result.append(separator); Object elem = getRawElem(thisObj, i); if (elem == NOT_FOUND || (skipUndefinedAndNull && (elem == null || elem == Undefined.instance))) { haslast = false; continue; } haslast = true; if (toSource) { result.append(ScriptRuntime.uneval(cx, scope, elem)); } else if (elem instanceof String) { String s = (String)elem; if (toSource) { result.append('\"'); result.append(ScriptRuntime.escapeString(s)); result.append('\"'); } else { result.append(s); } } else { if (toLocale) { Callable fun; Scriptable funThis; fun = ScriptRuntime.getPropFunctionAndThis( elem, "toLocaleString", cx); funThis = ScriptRuntime.lastStoredScriptable(cx); elem = fun.call(cx, scope, funThis, ScriptRuntime.emptyArgs); } result.append(ScriptRuntime.toString(elem)); } } } } finally { if (toplevel) { cx.iterating = null; } } if (toSource) { //for [,,].length behavior; we want toString to be symmetric. if (!haslast && i > 0) result.append(", ]"); else result.append(']'); } return result.toString(); } /** * See ECMA 15.4.4.3 */ private static String js_join(Context cx, Scriptable thisObj, Object[] args) { long llength = getLengthProperty(cx, thisObj); int length = (int)llength; if (llength != length) { throw Context.reportRuntimeError1( "msg.arraylength.too.big", String.valueOf(llength)); } // if no args, use "," as separator String separator = (args.length < 1 || args[0] == Undefined.instance) ? "," : ScriptRuntime.toString(args[0]); if (thisObj instanceof NativeArray) { NativeArray na = (NativeArray) thisObj; if (na.denseOnly) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) { if (i != 0) { sb.append(separator); } if (i < na.dense.length) { Object temp = na.dense[i]; if (temp != null && temp != Undefined.instance && temp != Scriptable.NOT_FOUND) { sb.append(ScriptRuntime.toString(temp)); } } } return sb.toString(); } } if (length == 0) { return ""; } String[] buf = new String[length]; int total_size = 0; for (int i = 0; i != length; i++) { Object temp = getElem(cx, thisObj, i); if (temp != null && temp != Undefined.instance) { String str = ScriptRuntime.toString(temp); total_size += str.length(); buf[i] = str; } } total_size += (length - 1) * separator.length(); StringBuilder sb = new StringBuilder(total_size); for (int i = 0; i != length; i++) { if (i != 0) { sb.append(separator); } String str = buf[i]; if (str != null) { // str == null for undefined or null sb.append(str); } } return sb.toString(); } /** * See ECMA 15.4.4.4 */ private static Scriptable js_reverse(Context cx, Scriptable thisObj, Object[] args) { if (thisObj instanceof NativeArray) { NativeArray na = (NativeArray) thisObj; if (na.denseOnly) { for (int i=0, j=((int)na.length)-1; i < j; i++,j--) { Object temp = na.dense[i]; na.dense[i] = na.dense[j]; na.dense[j] = temp; } return thisObj; } } long len = getLengthProperty(cx, thisObj); long half = len / 2; for(long i=0; i < half; i++) { long j = len - i - 1; Object temp1 = getRawElem(thisObj, i); Object temp2 = getRawElem(thisObj, j); setRawElem(cx, thisObj, i, temp2); setRawElem(cx, thisObj, j, temp1); } return thisObj; } /** * See ECMA 15.4.4.5 */ private static Scriptable js_sort(final Context cx, final Scriptable scope, final Scriptable thisObj, final Object[] args) { final Comparator comparator; if (args.length > 0 && Undefined.instance != args[0]) { final Callable jsCompareFunction = ScriptRuntime .getValueFunctionAndThis(args[0], cx); final Scriptable funThis = ScriptRuntime.lastStoredScriptable(cx); final Object[] cmpBuf = new Object[2]; // Buffer for cmp arguments comparator = new Comparator() { public int compare(final Object x, final Object y) { // sort undefined to end if (x == y) { return 0; } else if (y == Undefined.instance || y == Scriptable.NOT_FOUND) { return -1; } else if (x == Undefined.instance || x == Scriptable.NOT_FOUND) { return 1; } cmpBuf[0] = x; cmpBuf[1] = y; Object ret = jsCompareFunction.call(cx, scope, funThis, cmpBuf); final double d = ScriptRuntime.toNumber(ret); if (d < 0) { return -1; } else if (d > 0) { return +1; } return 0; // ??? double and 0??? } }; } else { comparator = new Comparator() { public int compare(final Object x, final Object y) { // sort undefined to end if (x == y) return 0; else if (y == Undefined.instance || y == Scriptable.NOT_FOUND) { return -1; } else if (x == Undefined.instance || x == Scriptable.NOT_FOUND) { return 1; } final String a = ScriptRuntime.toString(x); final String b = ScriptRuntime.toString(y); return a.compareTo(b); } }; } final int length = (int) getLengthProperty(cx, thisObj); // copy the JS array into a working array, so it can be // sorted cheaply. final Object[] working = new Object[length]; for (int i = 0; i != length; ++i) { working[i] = getElem(cx, thisObj, i); } Arrays.sort(working, comparator); // copy the working array back into thisObj for (int i = 0; i < length; ++i) { setElem(cx, thisObj, i, working[i]); } return thisObj; } /** * Non-ECMA methods. */ private static Object js_push(Context cx, Scriptable thisObj, Object[] args) { if (thisObj instanceof NativeArray) { NativeArray na = (NativeArray) thisObj; if (na.denseOnly && na.ensureCapacity((int) na.length + args.length)) { for (int i = 0; i < args.length; i++) { na.dense[(int)na.length++] = args[i]; } return ScriptRuntime.wrapNumber(na.length); } } long length = getLengthProperty(cx, thisObj); for (int i = 0; i < args.length; i++) { setElem(cx, thisObj, length + i, args[i]); } length += args.length; Object lengthObj = setLengthProperty(cx, thisObj, length); /* * If JS1.2, follow Perl4 by returning the last thing pushed. * Otherwise, return the new array length. */ if (cx.getLanguageVersion() == Context.VERSION_1_2) // if JS1.2 && no arguments, return undefined. return args.length == 0 ? Undefined.instance : args[args.length - 1]; else return lengthObj; } private static Object js_pop(Context cx, Scriptable thisObj, Object[] args) { Object result; if (thisObj instanceof NativeArray) { NativeArray na = (NativeArray) thisObj; if (na.denseOnly && na.length > 0) { na.length--; result = na.dense[(int)na.length]; na.dense[(int)na.length] = NOT_FOUND; return result; } } long length = getLengthProperty(cx, thisObj); if (length > 0) { length--; // Get the to-be-deleted property's value. result = getElem(cx, thisObj, length); // We don't need to delete the last property, because // setLength does that for us. } else { result = Undefined.instance; } // necessary to match js even when length < 0; js pop will give a // length property to any target it is called on. setLengthProperty(cx, thisObj, length); return result; } private static Object js_shift(Context cx, Scriptable thisObj, Object[] args) { if (thisObj instanceof NativeArray) { NativeArray na = (NativeArray) thisObj; if (na.denseOnly && na.length > 0) { na.length--; Object result = na.dense[0]; System.arraycopy(na.dense, 1, na.dense, 0, (int)na.length); na.dense[(int)na.length] = NOT_FOUND; return result == NOT_FOUND ? Undefined.instance : result; } } Object result; long length = getLengthProperty(cx, thisObj); if (length > 0) { long i = 0; length--; // Get the to-be-deleted property's value. result = getElem(cx, thisObj, i); /* * Slide down the array above the first element. Leave i * set to point to the last element. */ if (length > 0) { for (i = 1; i <= length; i++) { Object temp = getRawElem(thisObj, i); setRawElem(cx, thisObj, i - 1, temp); } } // We don't need to delete the last property, because // setLength does that for us. } else { result = Undefined.instance; } setLengthProperty(cx, thisObj, length); return result; } private static Object js_unshift(Context cx, Scriptable thisObj, Object[] args) { if (thisObj instanceof NativeArray) { NativeArray na = (NativeArray) thisObj; if (na.denseOnly && na.ensureCapacity((int)na.length + args.length)) { System.arraycopy(na.dense, 0, na.dense, args.length, (int) na.length); for (int i = 0; i < args.length; i++) { na.dense[i] = args[i]; } na.length += args.length; return ScriptRuntime.wrapNumber(na.length); } } long length = getLengthProperty(cx, thisObj); int argc = args.length; if (args.length > 0) { /* Slide up the array to make room for args at the bottom */ if (length > 0) { for (long last = length - 1; last >= 0; last--) { Object temp = getRawElem(thisObj, last); setRawElem(cx, thisObj, last + argc, temp); } } /* Copy from argv to the bottom of the array. */ for (int i = 0; i < args.length; i++) { setElem(cx, thisObj, i, args[i]); } /* Follow Perl by returning the new array length. */ length += args.length; return setLengthProperty(cx, thisObj, length); } return ScriptRuntime.wrapNumber(length); } private static Object js_splice(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { NativeArray na = null; boolean denseMode = false; if (thisObj instanceof NativeArray) { na = (NativeArray) thisObj; denseMode = na.denseOnly; } /* create an empty Array to return. */ scope = getTopLevelScope(scope); int argc = args.length; if (argc == 0) return cx.newArray(scope, 0); long length = getLengthProperty(cx, thisObj); /* Convert the first argument into a starting index. */ long begin = toSliceIndex(ScriptRuntime.toInteger(args[0]), length); argc--; /* Convert the second argument into count */ long count; if (args.length == 1) { count = length - begin; } else { double dcount = ScriptRuntime.toInteger(args[1]); if (dcount < 0) { count = 0; } else if (dcount > (length - begin)) { count = length - begin; } else { count = (long)dcount; } argc--; } long end = begin + count; /* If there are elements to remove, put them into the return value. */ Object result; if (count != 0) { if (count == 1 && (cx.getLanguageVersion() == Context.VERSION_1_2)) { /* * JS lacks "list context", whereby in Perl one turns the * single scalar that's spliced out into an array just by * assigning it to @single instead of $single, or by using it * as Perl push's first argument, for instance. * * JS1.2 emulated Perl too closely and returned a non-Array for * the single-splice-out case, requiring callers to test and * wrap in [] if necessary. So JS1.3, default, and other * versions all return an array of length 1 for uniformity. */ result = getElem(cx, thisObj, begin); } else { if (denseMode) { int intLen = (int) (end - begin); Object[] copy = new Object[intLen]; System.arraycopy(na.dense, (int) begin, copy, 0, intLen); result = cx.newArray(scope, copy); } else { Scriptable resultArray = cx.newArray(scope, 0); for (long last = begin; last != end; last++) { Object temp = getRawElem(thisObj, last); if (temp != NOT_FOUND) { setElem(cx, resultArray, last - begin, temp); } } // Need to set length for sparse result array setLengthProperty(cx, resultArray, end - begin); result = resultArray; } } } else { // (count == 0) if (cx.getLanguageVersion() == Context.VERSION_1_2) { /* Emulate C JS1.2; if no elements are removed, return undefined. */ result = Undefined.instance; } else { result = cx.newArray(scope, 0); } } /* Find the direction (up or down) to copy and make way for argv. */ long delta = argc - count; if (denseMode && length + delta < Integer.MAX_VALUE && na.ensureCapacity((int) (length + delta))) { System.arraycopy(na.dense, (int) end, na.dense, (int) (begin + argc), (int) (length - end)); if (argc > 0) { System.arraycopy(args, 2, na.dense, (int) begin, argc); } if (delta < 0) { Arrays.fill(na.dense, (int) (length + delta), (int) length, NOT_FOUND); } na.length = length + delta; return result; } if (delta > 0) { for (long last = length - 1; last >= end; last--) { Object temp = getRawElem(thisObj, last); setRawElem(cx, thisObj, last + delta, temp); } } else if (delta < 0) { for (long last = end; last < length; last++) { Object temp = getRawElem(thisObj, last); setRawElem(cx, thisObj, last + delta, temp); } } /* Copy from argv into the hole to complete the splice. */ int argoffset = args.length - argc; for (int i = 0; i < argc; i++) { setElem(cx, thisObj, begin + i, args[i + argoffset]); } /* Update length in case we deleted elements from the end. */ setLengthProperty(cx, thisObj, length + delta); return result; } /* * See Ecma 262v3 15.4.4.4 */ private static Scriptable js_concat(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { // create an empty Array to return. scope = getTopLevelScope(scope); Function ctor = ScriptRuntime.getExistingCtor(cx, scope, "Array"); Scriptable result = ctor.construct(cx, scope, ScriptRuntime.emptyArgs); if (thisObj instanceof NativeArray && result instanceof NativeArray) { NativeArray denseThis = (NativeArray) thisObj; NativeArray denseResult = (NativeArray) result; if (denseThis.denseOnly && denseResult.denseOnly) { // First calculate length of resulting array boolean canUseDense = true; int length = (int) denseThis.length; for (int i = 0; i < args.length && canUseDense; i++) { if (args[i] instanceof NativeArray) { // only try to use dense approach for Array-like // objects that are actually NativeArrays final NativeArray arg = (NativeArray) args[i]; canUseDense = arg.denseOnly; length += arg.length; } else { length++; } } if (canUseDense && denseResult.ensureCapacity(length)) { System.arraycopy(denseThis.dense, 0, denseResult.dense, 0, (int) denseThis.length); int cursor = (int) denseThis.length; for (int i = 0; i < args.length && canUseDense; i++) { if (args[i] instanceof NativeArray) { NativeArray arg = (NativeArray) args[i]; System.arraycopy(arg.dense, 0, denseResult.dense, cursor, (int)arg.length); cursor += (int)arg.length; } else { denseResult.dense[cursor++] = args[i]; } } denseResult.length = length; return result; } } } long length; long slot = 0; /* Put the target in the result array; only add it as an array * if it looks like one. */ if (ScriptRuntime.instanceOf(thisObj, ctor, cx)) { length = getLengthProperty(cx, thisObj); // Copy from the target object into the result for (slot = 0; slot < length; slot++) { Object temp = getRawElem(thisObj, slot); if (temp != NOT_FOUND) { setElem(cx, result, slot, temp); } } } else { setElem(cx, result, slot++, thisObj); } /* Copy from the arguments into the result. If any argument * has a numeric length property, treat it as an array and add * elements separately; otherwise, just copy the argument. */ for (int i = 0; i < args.length; i++) { if (ScriptRuntime.instanceOf(args[i], ctor, cx)) { // ScriptRuntime.instanceOf => instanceof Scriptable Scriptable arg = (Scriptable)args[i]; length = getLengthProperty(cx, arg); for (long j = 0; j < length; j++, slot++) { Object temp = getRawElem(arg, j); if (temp != NOT_FOUND) { setElem(cx, result, slot, temp); } } } else { setElem(cx, result, slot++, args[i]); } } setLengthProperty(cx, result, slot); return result; } private Scriptable js_slice(Context cx, Scriptable thisObj, Object[] args) { Scriptable scope = getTopLevelScope(this); Scriptable result = cx.newArray(scope, 0); long length = getLengthProperty(cx, thisObj); long begin, end; if (args.length == 0) { begin = 0; end = length; } else { begin = toSliceIndex(ScriptRuntime.toInteger(args[0]), length); if (args.length == 1) { end = length; } else { end = toSliceIndex(ScriptRuntime.toInteger(args[1]), length); } } for (long slot = begin; slot < end; slot++) { Object temp = getRawElem(thisObj, slot); if (temp != NOT_FOUND) { setElem(cx, result, slot - begin, temp); } } setLengthProperty(cx, result, Math.max(0, end - begin)); return result; } private static long toSliceIndex(double value, long length) { long result; if (value < 0.0) { if (value + length < 0.0) { result = 0; } else { result = (long)(value + length); } } else if (value > length) { result = length; } else { result = (long)value; } return result; } /** * Implements the methods "indexOf" and "lastIndexOf". */ private Object indexOfHelper(Context cx, Scriptable thisObj, Object[] args, boolean isLast) { Object compareTo = args.length > 0 ? args[0] : Undefined.instance; long length = getLengthProperty(cx, thisObj); long start; if (isLast) { // lastIndexOf /* * From http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:lastIndexOf * The index at which to start searching backwards. Defaults to the * array's length, i.e. the whole array will be searched. If the * index is greater than or equal to the length of the array, the * whole array will be searched. If negative, it is taken as the * offset from the end of the array. Note that even when the index * is negative, the array is still searched from back to front. If * the calculated index is less than 0, -1 is returned, i.e. the * array will not be searched. */ if (args.length < 2) { // default start = length-1; } else { start = (long)ScriptRuntime.toInteger(args[1]); if (start >= length) start = length-1; else if (start < 0) start += length; if (start < 0) return NEGATIVE_ONE; } } else { // indexOf /* * From http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:indexOf * The index at which to begin the search. Defaults to 0, i.e. the * whole array will be searched. If the index is greater than or * equal to the length of the array, -1 is returned, i.e. the array * will not be searched. If negative, it is taken as the offset from * the end of the array. Note that even when the index is negative, * the array is still searched from front to back. If the calculated * index is less than 0, the whole array will be searched. */ if (args.length < 2) { // default start = 0; } else { start = (long)ScriptRuntime.toInteger(args[1]); if (start < 0) { start += length; if (start < 0) start = 0; } if (start > length - 1) return NEGATIVE_ONE; } } if (thisObj instanceof NativeArray) { NativeArray na = (NativeArray) thisObj; if (na.denseOnly) { if (isLast) { for (int i=(int)start; i >= 0; i--) { if (na.dense[i] != Scriptable.NOT_FOUND && ScriptRuntime.shallowEq(na.dense[i], compareTo)) { return Long.valueOf(i); } } } else { for (int i=(int)start; i < length; i++) { if (na.dense[i] != Scriptable.NOT_FOUND && ScriptRuntime.shallowEq(na.dense[i], compareTo)) { return Long.valueOf(i); } } } return NEGATIVE_ONE; } } if (isLast) { for (long i=start; i >= 0; i--) { Object val = getRawElem(thisObj, i); if (val != NOT_FOUND && ScriptRuntime.shallowEq(val, compareTo)) { return Long.valueOf(i); } } } else { for (long i=start; i < length; i++) { Object val = getRawElem(thisObj, i); if (val != NOT_FOUND && ScriptRuntime.shallowEq(val, compareTo)) { return Long.valueOf(i); } } } return NEGATIVE_ONE; } /** * Implements the methods "every", "filter", "forEach", "map", and "some". */ private Object iterativeMethod(Context cx, int id, Scriptable scope, Scriptable thisObj, Object[] args) { Object callbackArg = args.length > 0 ? args[0] : Undefined.instance; if (callbackArg == null || !(callbackArg instanceof Function)) { throw ScriptRuntime.notFunctionError(callbackArg); } Function f = (Function) callbackArg; Scriptable parent = ScriptableObject.getTopLevelScope(f); Scriptable thisArg; if (args.length < 2 || args[1] == null || args[1] == Undefined.instance) { thisArg = parent; } else { thisArg = ScriptRuntime.toObject(cx, scope, args[1]); } long length = getLengthProperty(cx, thisObj); int resultLength = id == Id_map ? (int) length : 0; Scriptable array = cx.newArray(scope, resultLength); long j=0; for (long i=0; i < length; i++) { Object[] innerArgs = new Object[3]; Object elem = getRawElem(thisObj, i); if (elem == Scriptable.NOT_FOUND) { continue; } innerArgs[0] = elem; innerArgs[1] = Long.valueOf(i); innerArgs[2] = thisObj; Object result = f.call(cx, parent, thisArg, innerArgs); switch (id) { case Id_every: if (!ScriptRuntime.toBoolean(result)) return Boolean.FALSE; break; case Id_filter: if (ScriptRuntime.toBoolean(result)) setElem(cx, array, j++, innerArgs[0]); break; case Id_forEach: break; case Id_map: setElem(cx, array, i, result); break; case Id_some: if (ScriptRuntime.toBoolean(result)) return Boolean.TRUE; break; } } switch (id) { case Id_every: return Boolean.TRUE; case Id_filter: case Id_map: return array; case Id_some: return Boolean.FALSE; case Id_forEach: default: return Undefined.instance; } } /** * Implements the methods "reduce" and "reduceRight". */ private Object reduceMethod(Context cx, int id, Scriptable scope, Scriptable thisObj, Object[] args) { Object callbackArg = args.length > 0 ? args[0] : Undefined.instance; if (callbackArg == null || !(callbackArg instanceof Function)) { throw ScriptRuntime.notFunctionError(callbackArg); } Function f = (Function) callbackArg; Scriptable parent = ScriptableObject.getTopLevelScope(f); long length = getLengthProperty(cx, thisObj); // hack to serve both reduce and reduceRight with the same loop boolean movingLeft = id == Id_reduce; Object value = args.length > 1 ? args[1] : Scriptable.NOT_FOUND; for (long i = 0; i < length; i++) { long index = movingLeft ? i : (length - 1 - i); Object elem = getRawElem(thisObj, index); if (elem == Scriptable.NOT_FOUND) { continue; } if (value == Scriptable.NOT_FOUND) { // no initial value passed, use first element found as inital value value = elem; } else { Object[] innerArgs = { value, elem, index, thisObj }; value = f.call(cx, parent, parent, innerArgs); } } if (value == Scriptable.NOT_FOUND) { // reproduce spidermonkey error message throw ScriptRuntime.typeError0("msg.empty.array.reduce"); } return value; } // methods to implement java.util.List public boolean contains(Object o) { return indexOf(o) > -1; } public Object[] toArray() { return toArray(ScriptRuntime.emptyArgs); } public Object[] toArray(Object[] a) { long longLen = length; if (longLen > Integer.MAX_VALUE) { throw new IllegalStateException(); } int len = (int) longLen; Object[] array = a.length >= len ? a : (Object[]) java.lang.reflect.Array .newInstance(a.getClass().getComponentType(), len); for (int i = 0; i < len; i++) { array[i] = get(i); } return array; } public boolean containsAll(Collection c) { for (Object aC : c) if (!contains(aC)) return false; return true; } public int size() { long longLen = length; if (longLen > Integer.MAX_VALUE) { throw new IllegalStateException(); } return (int) longLen; } public Object get(long index) { if (index < 0 || index >= length) { throw new IndexOutOfBoundsException(); } Object value = getRawElem(this, index); if (value == Scriptable.NOT_FOUND || value == Undefined.instance) { return null; } else if (value instanceof Wrapper) { return ((Wrapper) value).unwrap(); } else { return value; } } public Object get(int index) { return get((long) index); } public int indexOf(Object o) { long longLen = length; if (longLen > Integer.MAX_VALUE) { throw new IllegalStateException(); } int len = (int) longLen; if (o == null) { for (int i = 0; i < len; i++) { if (get(i) == null) { return i; } } } else { for (int i = 0; i < len; i++) { if (o.equals(get(i))) { return i; } } } return -1; } public int lastIndexOf(Object o) { long longLen = length; if (longLen > Integer.MAX_VALUE) { throw new IllegalStateException(); } int len = (int) longLen; if (o == null) { for (int i = len - 1; i >= 0; i--) { if (get(i) == null) { return i; } } } else { for (int i = len - 1; i >= 0; i--) { if (o.equals(get(i))) { return i; } } } return -1; } public Iterator iterator() { return listIterator(0); } public ListIterator listIterator() { return listIterator(0); } public ListIterator listIterator(final int start) { long longLen = length; if (longLen > Integer.MAX_VALUE) { throw new IllegalStateException(); } final int len = (int) longLen; if (start < 0 || start > len) { throw new IndexOutOfBoundsException("Index: " + start); } return new ListIterator() { int cursor = start; public boolean hasNext() { return cursor < len; } public Object next() { if (cursor == len) { throw new NoSuchElementException(); } return get(cursor++); } public boolean hasPrevious() { return cursor > 0; } public Object previous() { if (cursor == 0) { throw new NoSuchElementException(); } return get(--cursor); } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } public void remove() { throw new UnsupportedOperationException(); } public void add(Object o) { throw new UnsupportedOperationException(); } public void set(Object o) { throw new UnsupportedOperationException(); } }; } public boolean add(Object o) { throw new UnsupportedOperationException(); } public boolean remove(Object o) { throw new UnsupportedOperationException(); } public boolean addAll(Collection c) { throw new UnsupportedOperationException(); } public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } public void clear() { throw new UnsupportedOperationException(); } public void add(int index, Object element) { throw new UnsupportedOperationException(); } public boolean addAll(int index, Collection c) { throw new UnsupportedOperationException(); } public Object set(int index, Object element) { throw new UnsupportedOperationException(); } public Object remove(int index) { throw new UnsupportedOperationException(); } public List subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); } // #string_id_map# @Override protected int findPrototypeId(String s) { int id; // #generated# Last update: 2005-09-26 15:47:42 EDT L0: { id = 0; String X = null; int c; L: switch (s.length()) { case 3: c=s.charAt(0); if (c=='m') { if (s.charAt(2)=='p' && s.charAt(1)=='a') {id=Id_map; break L0;} } else if (c=='p') { if (s.charAt(2)=='p' && s.charAt(1)=='o') {id=Id_pop; break L0;} } break L; case 4: switch (s.charAt(2)) { case 'i': X="join";id=Id_join; break L; case 'm': X="some";id=Id_some; break L; case 'r': X="sort";id=Id_sort; break L; case 's': X="push";id=Id_push; break L; } break L; case 5: c=s.charAt(1); if (c=='h') { X="shift";id=Id_shift; } else if (c=='l') { X="slice";id=Id_slice; } else if (c=='v') { X="every";id=Id_every; } break L; case 6: c=s.charAt(0); if (c=='c') { X="concat";id=Id_concat; } else if (c=='f') { X="filter";id=Id_filter; } else if (c=='s') { X="splice";id=Id_splice; } else if (c=='r') { X="reduce";id=Id_reduce; } break L; case 7: switch (s.charAt(0)) { case 'f': X="forEach";id=Id_forEach; break L; case 'i': X="indexOf";id=Id_indexOf; break L; case 'r': X="reverse";id=Id_reverse; break L; case 'u': X="unshift";id=Id_unshift; break L; } break L; case 8: c=s.charAt(3); if (c=='o') { X="toSource";id=Id_toSource; } else if (c=='t') { X="toString";id=Id_toString; } break L; case 11: c=s.charAt(0); if (c=='c') { X="constructor";id=Id_constructor; } else if (c=='l') { X="lastIndexOf";id=Id_lastIndexOf; } else if (c=='r') { X="reduceRight";id=Id_reduceRight; } break L; case 14: X="toLocaleString";id=Id_toLocaleString; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# return id; } private static final int Id_constructor = 1, Id_toString = 2, Id_toLocaleString = 3, Id_toSource = 4, Id_join = 5, Id_reverse = 6, Id_sort = 7, Id_push = 8, Id_pop = 9, Id_shift = 10, Id_unshift = 11, Id_splice = 12, Id_concat = 13, Id_slice = 14, Id_indexOf = 15, Id_lastIndexOf = 16, Id_every = 17, Id_filter = 18, Id_forEach = 19, Id_map = 20, Id_some = 21, Id_reduce = 22, Id_reduceRight = 23, MAX_PROTOTYPE_ID = 23; // #/string_id_map# private static final int ConstructorId_join = -Id_join, ConstructorId_reverse = -Id_reverse, ConstructorId_sort = -Id_sort, ConstructorId_push = -Id_push, ConstructorId_pop = -Id_pop, ConstructorId_shift = -Id_shift, ConstructorId_unshift = -Id_unshift, ConstructorId_splice = -Id_splice, ConstructorId_concat = -Id_concat, ConstructorId_slice = -Id_slice, ConstructorId_indexOf = -Id_indexOf, ConstructorId_lastIndexOf = -Id_lastIndexOf, ConstructorId_every = -Id_every, ConstructorId_filter = -Id_filter, ConstructorId_forEach = -Id_forEach, ConstructorId_map = -Id_map, ConstructorId_some = -Id_some, ConstructorId_reduce = -Id_reduce, ConstructorId_reduceRight = -Id_reduceRight, ConstructorId_isArray = -24; /** * Internal representation of the JavaScript array's length property. */ private long length; /** * Attributes of the array's length property */ private int lengthAttr = DONTENUM | PERMANENT; /** * Fast storage for dense arrays. Sparse arrays will use the superclass's * hashtable storage scheme. */ private Object[] dense; /** * True if all numeric properties are stored in dense. */ private boolean denseOnly; /** * The maximum size of dense that will be allocated initially. */ private static int maximumInitialCapacity = 10000; /** * The default capacity for dense. */ private static final int DEFAULT_INITIAL_CAPACITY = 10; /** * The factor to grow dense by. */ private static final double GROW_FACTOR = 1.5; private static final int MAX_PRE_GROW_SIZE = (int)(Integer.MAX_VALUE / GROW_FACTOR); } rhino-1.7R4/src/org/mozilla/javascript/NativeBoolean.java000066400000000000000000000103551176760007500235070ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * This class implements the Boolean native object. * See ECMA 15.6. * @author Norris Boyd */ final class NativeBoolean extends IdScriptableObject { static final long serialVersionUID = -3716996899943880933L; private static final Object BOOLEAN_TAG = "Boolean"; static void init(Scriptable scope, boolean sealed) { NativeBoolean obj = new NativeBoolean(false); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } NativeBoolean(boolean b) { booleanValue = b; } @Override public String getClassName() { return "Boolean"; } @Override public Object getDefaultValue(Class typeHint) { // This is actually non-ECMA, but will be proposed // as a change in round 2. if (typeHint == ScriptRuntime.BooleanClass) return ScriptRuntime.wrapBoolean(booleanValue); return super.getDefaultValue(typeHint); } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=1; s="constructor"; break; case Id_toString: arity=0; s="toString"; break; case Id_toSource: arity=0; s="toSource"; break; case Id_valueOf: arity=0; s="valueOf"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(BOOLEAN_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(BOOLEAN_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); if (id == Id_constructor) { boolean b; if (args.length == 0) { b = false; } else { b = args[0] instanceof ScriptableObject && ((ScriptableObject) args[0]).avoidObjectDetection() ? true : ScriptRuntime.toBoolean(args[0]); } if (thisObj == null) { // new Boolean(val) creates a new boolean object. return new NativeBoolean(b); } // Boolean(val) converts val to a boolean. return ScriptRuntime.wrapBoolean(b); } // The rest of Boolean.prototype methods require thisObj to be Boolean if (!(thisObj instanceof NativeBoolean)) throw incompatibleCallError(f); boolean value = ((NativeBoolean)thisObj).booleanValue; switch (id) { case Id_toString: return value ? "true" : "false"; case Id_toSource: return value ? "(new Boolean(true))" : "(new Boolean(false))"; case Id_valueOf: return ScriptRuntime.wrapBoolean(value); } throw new IllegalArgumentException(String.valueOf(id)); } // #string_id_map# @Override protected int findPrototypeId(String s) { int id; // #generated# Last update: 2007-05-09 08:15:31 EDT L0: { id = 0; String X = null; int c; int s_length = s.length(); if (s_length==7) { X="valueOf";id=Id_valueOf; } else if (s_length==8) { c=s.charAt(3); if (c=='o') { X="toSource";id=Id_toSource; } else if (c=='t') { X="toString";id=Id_toString; } } else if (s_length==11) { X="constructor";id=Id_constructor; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# return id; } private static final int Id_constructor = 1, Id_toString = 2, Id_toSource = 3, Id_valueOf = 4, MAX_PROTOTYPE_ID = 4; // #/string_id_map# private boolean booleanValue; } rhino-1.7R4/src/org/mozilla/javascript/NativeCall.java000066400000000000000000000073611176760007500230060ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * This class implements the activation object. * * See ECMA 10.1.6 * * @see org.mozilla.javascript.Arguments * @author Norris Boyd */ public final class NativeCall extends IdScriptableObject { static final long serialVersionUID = -7471457301304454454L; private static final Object CALL_TAG = "Call"; static void init(Scriptable scope, boolean sealed) { NativeCall obj = new NativeCall(); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } NativeCall() { } NativeCall(NativeFunction function, Scriptable scope, Object[] args) { this.function = function; setParentScope(scope); // leave prototype null this.originalArgs = (args == null) ? ScriptRuntime.emptyArgs : args; // initialize values of arguments int paramAndVarCount = function.getParamAndVarCount(); int paramCount = function.getParamCount(); if (paramAndVarCount != 0) { for (int i = 0; i < paramCount; ++i) { String name = function.getParamOrVarName(i); Object val = i < args.length ? args[i] : Undefined.instance; defineProperty(name, val, PERMANENT); } } // initialize "arguments" property but only if it was not overridden by // the parameter with the same name if (!super.has("arguments", this)) { defineProperty("arguments", new Arguments(this), PERMANENT); } if (paramAndVarCount != 0) { for (int i = paramCount; i < paramAndVarCount; ++i) { String name = function.getParamOrVarName(i); if (!super.has(name, this)) { if (function.getParamOrVarConst(i)) defineProperty(name, Undefined.instance, CONST); else defineProperty(name, Undefined.instance, PERMANENT); } } } } @Override public String getClassName() { return "Call"; } @Override protected int findPrototypeId(String s) { return s.equals("constructor") ? Id_constructor : 0; } @Override protected void initPrototypeId(int id) { String s; int arity; if (id == Id_constructor) { arity=1; s="constructor"; } else { throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(CALL_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(CALL_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); if (id == Id_constructor) { if (thisObj != null) { throw Context.reportRuntimeError1("msg.only.from.new", "Call"); } ScriptRuntime.checkDeprecated(cx, "Call"); NativeCall result = new NativeCall(); result.setPrototype(getObjectPrototype(scope)); return result; } throw new IllegalArgumentException(String.valueOf(id)); } private static final int Id_constructor = 1, MAX_PROTOTYPE_ID = 1; NativeFunction function; Object[] originalArgs; transient NativeCall parentActivationCall; } rhino-1.7R4/src/org/mozilla/javascript/NativeContinuation.java000066400000000000000000000056551176760007500246110ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; public final class NativeContinuation extends IdScriptableObject implements Function { static final long serialVersionUID = 1794167133757605367L; private static final Object FTAG = "Continuation"; private Object implementation; public static void init(Context cx, Scriptable scope, boolean sealed) { NativeContinuation obj = new NativeContinuation(); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } public Object getImplementation() { return implementation; } public void initImplementation(Object implementation) { this.implementation = implementation; } @Override public String getClassName() { return "Continuation"; } public Scriptable construct(Context cx, Scriptable scope, Object[] args) { throw Context.reportRuntimeError("Direct call is not supported"); } public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { return Interpreter.restartContinuation(this, cx, scope, args); } public static boolean isContinuationConstructor(IdFunctionObject f) { if (f.hasTag(FTAG) && f.methodId() == Id_constructor) { return true; } return false; } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=0; s="constructor"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(FTAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(FTAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_constructor: throw Context.reportRuntimeError("Direct call is not supported"); } throw new IllegalArgumentException(String.valueOf(id)); } // #string_id_map# @Override protected int findPrototypeId(String s) { int id; // #generated# Last update: 2007-05-09 08:16:40 EDT L0: { id = 0; String X = null; if (s.length()==11) { X="constructor";id=Id_constructor; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# return id; } private static final int Id_constructor = 1, MAX_PROTOTYPE_ID = 1; // #/string_id_map# } rhino-1.7R4/src/org/mozilla/javascript/NativeDate.java000066400000000000000000001553371176760007500230170ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.util.Date; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.TimeZone; import java.util.SimpleTimeZone; /** * This class implements the Date native object. * See ECMA 15.9. * @author Mike McCabe */ final class NativeDate extends IdScriptableObject { static final long serialVersionUID = -8307438915861678966L; private static final Object DATE_TAG = "Date"; private static final String js_NaN_date_str = "Invalid Date"; private static final DateFormat isoFormat; static { isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); isoFormat.setTimeZone(new SimpleTimeZone(0, "UTC")); isoFormat.setLenient(false); } static void init(Scriptable scope, boolean sealed) { NativeDate obj = new NativeDate(); // Set the value of the prototype Date to NaN ('invalid date'); obj.date = ScriptRuntime.NaN; obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } private NativeDate() { if (thisTimeZone == null) { // j.u.TimeZone is synchronized, so setting class statics from it // should be OK. thisTimeZone = TimeZone.getDefault(); LocalTZA = thisTimeZone.getRawOffset(); } } @Override public String getClassName() { return "Date"; } @Override public Object getDefaultValue(Class typeHint) { if (typeHint == null) typeHint = ScriptRuntime.StringClass; return super.getDefaultValue(typeHint); } double getJSTimeValue() { return date; } @Override protected void fillConstructorProperties(IdFunctionObject ctor) { addIdFunctionProperty(ctor, DATE_TAG, ConstructorId_now, "now", 0); addIdFunctionProperty(ctor, DATE_TAG, ConstructorId_parse, "parse", 1); addIdFunctionProperty(ctor, DATE_TAG, ConstructorId_UTC, "UTC", 1); super.fillConstructorProperties(ctor); } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=1; s="constructor"; break; case Id_toString: arity=0; s="toString"; break; case Id_toTimeString: arity=0; s="toTimeString"; break; case Id_toDateString: arity=0; s="toDateString"; break; case Id_toLocaleString: arity=0; s="toLocaleString"; break; case Id_toLocaleTimeString: arity=0; s="toLocaleTimeString"; break; case Id_toLocaleDateString: arity=0; s="toLocaleDateString"; break; case Id_toUTCString: arity=0; s="toUTCString"; break; case Id_toSource: arity=0; s="toSource"; break; case Id_valueOf: arity=0; s="valueOf"; break; case Id_getTime: arity=0; s="getTime"; break; case Id_getYear: arity=0; s="getYear"; break; case Id_getFullYear: arity=0; s="getFullYear"; break; case Id_getUTCFullYear: arity=0; s="getUTCFullYear"; break; case Id_getMonth: arity=0; s="getMonth"; break; case Id_getUTCMonth: arity=0; s="getUTCMonth"; break; case Id_getDate: arity=0; s="getDate"; break; case Id_getUTCDate: arity=0; s="getUTCDate"; break; case Id_getDay: arity=0; s="getDay"; break; case Id_getUTCDay: arity=0; s="getUTCDay"; break; case Id_getHours: arity=0; s="getHours"; break; case Id_getUTCHours: arity=0; s="getUTCHours"; break; case Id_getMinutes: arity=0; s="getMinutes"; break; case Id_getUTCMinutes: arity=0; s="getUTCMinutes"; break; case Id_getSeconds: arity=0; s="getSeconds"; break; case Id_getUTCSeconds: arity=0; s="getUTCSeconds"; break; case Id_getMilliseconds: arity=0; s="getMilliseconds"; break; case Id_getUTCMilliseconds: arity=0; s="getUTCMilliseconds"; break; case Id_getTimezoneOffset: arity=0; s="getTimezoneOffset"; break; case Id_setTime: arity=1; s="setTime"; break; case Id_setMilliseconds: arity=1; s="setMilliseconds"; break; case Id_setUTCMilliseconds: arity=1; s="setUTCMilliseconds"; break; case Id_setSeconds: arity=2; s="setSeconds"; break; case Id_setUTCSeconds: arity=2; s="setUTCSeconds"; break; case Id_setMinutes: arity=3; s="setMinutes"; break; case Id_setUTCMinutes: arity=3; s="setUTCMinutes"; break; case Id_setHours: arity=4; s="setHours"; break; case Id_setUTCHours: arity=4; s="setUTCHours"; break; case Id_setDate: arity=1; s="setDate"; break; case Id_setUTCDate: arity=1; s="setUTCDate"; break; case Id_setMonth: arity=2; s="setMonth"; break; case Id_setUTCMonth: arity=2; s="setUTCMonth"; break; case Id_setFullYear: arity=3; s="setFullYear"; break; case Id_setUTCFullYear: arity=3; s="setUTCFullYear"; break; case Id_setYear: arity=1; s="setYear"; break; case Id_toISOString: arity=0; s="toISOString"; break; case Id_toJSON: arity=1; s="toJSON"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(DATE_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(DATE_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case ConstructorId_now: return ScriptRuntime.wrapNumber(now()); case ConstructorId_parse: { String dataStr = ScriptRuntime.toString(args, 0); return ScriptRuntime.wrapNumber(date_parseString(dataStr)); } case ConstructorId_UTC: return ScriptRuntime.wrapNumber(jsStaticFunction_UTC(args)); case Id_constructor: { // if called as a function, just return a string // representing the current time. if (thisObj != null) return date_format(now(), Id_toString); return jsConstructor(args); } case Id_toJSON: { if (thisObj instanceof NativeDate) { return ((NativeDate) thisObj).toISOString(); } final String toISOString = "toISOString"; Scriptable o = ScriptRuntime.toObject(cx, scope, thisObj); Object tv = ScriptRuntime.toPrimitive(o, ScriptRuntime.NumberClass); if (tv instanceof Number) { double d = ((Number) tv).doubleValue(); if (d != d || Double.isInfinite(d)) { return null; } } Object toISO = o.get(toISOString, o); if (toISO == NOT_FOUND) { throw ScriptRuntime.typeError2("msg.function.not.found.in", toISOString, ScriptRuntime.toString(o)); } if ( !(toISO instanceof Callable) ) { throw ScriptRuntime.typeError3("msg.isnt.function.in", toISOString, ScriptRuntime.toString(o), ScriptRuntime.toString(toISO)); } Object result = ((Callable) toISO).call(cx, scope, o, ScriptRuntime.emptyArgs); if ( !ScriptRuntime.isPrimitive(result) ) { throw ScriptRuntime.typeError1("msg.toisostring.must.return.primitive", ScriptRuntime.toString(result)); } return result; } } // The rest of Date.prototype methods require thisObj to be Date if (!(thisObj instanceof NativeDate)) throw incompatibleCallError(f); NativeDate realThis = (NativeDate)thisObj; double t = realThis.date; switch (id) { case Id_toString: case Id_toTimeString: case Id_toDateString: if (t == t) { return date_format(t, id); } return js_NaN_date_str; case Id_toLocaleString: case Id_toLocaleTimeString: case Id_toLocaleDateString: if (t == t) { return toLocale_helper(t, id); } return js_NaN_date_str; case Id_toUTCString: if (t == t) { return js_toUTCString(t); } return js_NaN_date_str; case Id_toSource: return "(new Date("+ScriptRuntime.toString(t)+"))"; case Id_valueOf: case Id_getTime: return ScriptRuntime.wrapNumber(t); case Id_getYear: case Id_getFullYear: case Id_getUTCFullYear: if (t == t) { if (id != Id_getUTCFullYear) t = LocalTime(t); t = YearFromTime(t); if (id == Id_getYear) { if (cx.hasFeature(Context.FEATURE_NON_ECMA_GET_YEAR)) { if (1900 <= t && t < 2000) { t -= 1900; } } else { t -= 1900; } } } return ScriptRuntime.wrapNumber(t); case Id_getMonth: case Id_getUTCMonth: if (t == t) { if (id == Id_getMonth) t = LocalTime(t); t = MonthFromTime(t); } return ScriptRuntime.wrapNumber(t); case Id_getDate: case Id_getUTCDate: if (t == t) { if (id == Id_getDate) t = LocalTime(t); t = DateFromTime(t); } return ScriptRuntime.wrapNumber(t); case Id_getDay: case Id_getUTCDay: if (t == t) { if (id == Id_getDay) t = LocalTime(t); t = WeekDay(t); } return ScriptRuntime.wrapNumber(t); case Id_getHours: case Id_getUTCHours: if (t == t) { if (id == Id_getHours) t = LocalTime(t); t = HourFromTime(t); } return ScriptRuntime.wrapNumber(t); case Id_getMinutes: case Id_getUTCMinutes: if (t == t) { if (id == Id_getMinutes) t = LocalTime(t); t = MinFromTime(t); } return ScriptRuntime.wrapNumber(t); case Id_getSeconds: case Id_getUTCSeconds: if (t == t) { if (id == Id_getSeconds) t = LocalTime(t); t = SecFromTime(t); } return ScriptRuntime.wrapNumber(t); case Id_getMilliseconds: case Id_getUTCMilliseconds: if (t == t) { if (id == Id_getMilliseconds) t = LocalTime(t); t = msFromTime(t); } return ScriptRuntime.wrapNumber(t); case Id_getTimezoneOffset: if (t == t) { t = (t - LocalTime(t)) / msPerMinute; } return ScriptRuntime.wrapNumber(t); case Id_setTime: t = TimeClip(ScriptRuntime.toNumber(args, 0)); realThis.date = t; return ScriptRuntime.wrapNumber(t); case Id_setMilliseconds: case Id_setUTCMilliseconds: case Id_setSeconds: case Id_setUTCSeconds: case Id_setMinutes: case Id_setUTCMinutes: case Id_setHours: case Id_setUTCHours: t = makeTime(t, args, id); realThis.date = t; return ScriptRuntime.wrapNumber(t); case Id_setDate: case Id_setUTCDate: case Id_setMonth: case Id_setUTCMonth: case Id_setFullYear: case Id_setUTCFullYear: t = makeDate(t, args, id); realThis.date = t; return ScriptRuntime.wrapNumber(t); case Id_setYear: { double year = ScriptRuntime.toNumber(args, 0); if (year != year || Double.isInfinite(year)) { t = ScriptRuntime.NaN; } else { if (t != t) { t = 0; } else { t = LocalTime(t); } if (year >= 0 && year <= 99) year += 1900; double day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); t = MakeDate(day, TimeWithinDay(t)); t = internalUTC(t); t = TimeClip(t); } } realThis.date = t; return ScriptRuntime.wrapNumber(t); case Id_toISOString: return realThis.toISOString(); default: throw new IllegalArgumentException(String.valueOf(id)); } } private String toISOString() { if (date == date) { synchronized (isoFormat) { return isoFormat.format(new Date((long) date)); } } String msg = ScriptRuntime.getMessage0("msg.invalid.date"); throw ScriptRuntime.constructError("RangeError", msg); } /* ECMA helper functions */ private static final double HalfTimeDomain = 8.64e15; private static final double HoursPerDay = 24.0; private static final double MinutesPerHour = 60.0; private static final double SecondsPerMinute = 60.0; private static final double msPerSecond = 1000.0; private static final double MinutesPerDay = (HoursPerDay * MinutesPerHour); private static final double SecondsPerDay = (MinutesPerDay * SecondsPerMinute); private static final double SecondsPerHour = (MinutesPerHour * SecondsPerMinute); private static final double msPerDay = (SecondsPerDay * msPerSecond); private static final double msPerHour = (SecondsPerHour * msPerSecond); private static final double msPerMinute = (SecondsPerMinute * msPerSecond); private static double Day(double t) { return Math.floor(t / msPerDay); } private static double TimeWithinDay(double t) { double result; result = t % msPerDay; if (result < 0) result += msPerDay; return result; } private static boolean IsLeapYear(int year) { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } /* math here has to be f.p, because we need * floor((1968 - 1969) / 4) == -1 */ private static double DayFromYear(double y) { return ((365 * ((y)-1970) + Math.floor(((y)-1969)/4.0) - Math.floor(((y)-1901)/100.0) + Math.floor(((y)-1601)/400.0))); } private static double TimeFromYear(double y) { return DayFromYear(y) * msPerDay; } private static int YearFromTime(double t) { int lo = (int) Math.floor((t / msPerDay) / 366) + 1970; int hi = (int) Math.floor((t / msPerDay) / 365) + 1970; int mid; /* above doesn't work for negative dates... */ if (hi < lo) { int temp = lo; lo = hi; hi = temp; } /* Use a simple binary search algorithm to find the right year. This seems like brute force... but the computation of hi and lo years above lands within one year of the correct answer for years within a thousand years of 1970; the loop below only requires six iterations for year 270000. */ while (hi > lo) { mid = (hi + lo) / 2; if (TimeFromYear(mid) > t) { hi = mid - 1; } else { lo = mid + 1; if (TimeFromYear(lo) > t) { return mid; } } } return lo; } private static double DayFromMonth(int m, int year) { int day = m * 30; if (m >= 7) { day += m / 2 - 1; } else if (m >= 2) { day += (m - 1) / 2 - 1; } else { day += m; } if (m >= 2 && IsLeapYear(year)) { ++day; } return day; } private static int MonthFromTime(double t) { int year = YearFromTime(t); int d = (int)(Day(t) - DayFromYear(year)); d -= 31 + 28; if (d < 0) { return (d < -28) ? 0 : 1; } if (IsLeapYear(year)) { if (d == 0) return 1; // 29 February --d; } // d: date count from 1 March int estimate = d / 30; // approx number of month since March int mstart; switch (estimate) { case 0: return 2; case 1: mstart = 31; break; case 2: mstart = 31+30; break; case 3: mstart = 31+30+31; break; case 4: mstart = 31+30+31+30; break; case 5: mstart = 31+30+31+30+31; break; case 6: mstart = 31+30+31+30+31+31; break; case 7: mstart = 31+30+31+30+31+31+30; break; case 8: mstart = 31+30+31+30+31+31+30+31; break; case 9: mstart = 31+30+31+30+31+31+30+31+30; break; case 10: return 11; //Late december default: throw Kit.codeBug(); } // if d < mstart then real month since March == estimate - 1 return (d >= mstart) ? estimate + 2 : estimate + 1; } private static int DateFromTime(double t) { int year = YearFromTime(t); int d = (int)(Day(t) - DayFromYear(year)); d -= 31 + 28; if (d < 0) { return (d < -28) ? d + 31 + 28 + 1 : d + 28 + 1; } if (IsLeapYear(year)) { if (d == 0) return 29; // 29 February --d; } // d: date count from 1 March int mdays, mstart; switch (d / 30) { // approx number of month since March case 0: return d + 1; case 1: mdays = 31; mstart = 31; break; case 2: mdays = 30; mstart = 31+30; break; case 3: mdays = 31; mstart = 31+30+31; break; case 4: mdays = 30; mstart = 31+30+31+30; break; case 5: mdays = 31; mstart = 31+30+31+30+31; break; case 6: mdays = 31; mstart = 31+30+31+30+31+31; break; case 7: mdays = 30; mstart = 31+30+31+30+31+31+30; break; case 8: mdays = 31; mstart = 31+30+31+30+31+31+30+31; break; case 9: mdays = 30; mstart = 31+30+31+30+31+31+30+31+30; break; case 10: return d - (31+30+31+30+31+31+30+31+30) + 1; //Late december default: throw Kit.codeBug(); } d -= mstart; if (d < 0) { // wrong estimate: sfhift to previous month d += mdays; } return d + 1; } private static int WeekDay(double t) { double result; result = Day(t) + 4; result = result % 7; if (result < 0) result += 7; return (int) result; } private static double now() { return System.currentTimeMillis(); } private static double DaylightSavingTA(double t) { // Another workaround! The JRE doesn't seem to know about DST // before year 1 AD, so we map to equivalent dates for the // purposes of finding DST. To be safe, we do this for years // before 1970. if (t < 0.0) { int year = EquivalentYear(YearFromTime(t)); double day = MakeDay(year, MonthFromTime(t), DateFromTime(t)); t = MakeDate(day, TimeWithinDay(t)); } Date date = new Date((long) t); if (thisTimeZone.inDaylightTime(date)) return msPerHour; else return 0; } /* * Find a year for which any given date will fall on the same weekday. * * This function should be used with caution when used other than * for determining DST; it hasn't been proven not to produce an * incorrect year for times near year boundaries. */ private static int EquivalentYear(int year) { int day = (int) DayFromYear(year) + 4; day = day % 7; if (day < 0) day += 7; // Years and leap years on which Jan 1 is a Sunday, Monday, etc. if (IsLeapYear(year)) { switch (day) { case 0: return 1984; case 1: return 1996; case 2: return 1980; case 3: return 1992; case 4: return 1976; case 5: return 1988; case 6: return 1972; } } else { switch (day) { case 0: return 1978; case 1: return 1973; case 2: return 1985; case 3: return 1986; case 4: return 1981; case 5: return 1971; case 6: return 1977; } } // Unreachable throw Kit.codeBug(); } private static double LocalTime(double t) { return t + LocalTZA + DaylightSavingTA(t); } private static double internalUTC(double t) { return t - LocalTZA - DaylightSavingTA(t - LocalTZA); } private static int HourFromTime(double t) { double result; result = Math.floor(t / msPerHour) % HoursPerDay; if (result < 0) result += HoursPerDay; return (int) result; } private static int MinFromTime(double t) { double result; result = Math.floor(t / msPerMinute) % MinutesPerHour; if (result < 0) result += MinutesPerHour; return (int) result; } private static int SecFromTime(double t) { double result; result = Math.floor(t / msPerSecond) % SecondsPerMinute; if (result < 0) result += SecondsPerMinute; return (int) result; } private static int msFromTime(double t) { double result; result = t % msPerSecond; if (result < 0) result += msPerSecond; return (int) result; } private static double MakeTime(double hour, double min, double sec, double ms) { return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms; } private static double MakeDay(double year, double month, double date) { year += Math.floor(month / 12); month = month % 12; if (month < 0) month += 12; double yearday = Math.floor(TimeFromYear(year) / msPerDay); double monthday = DayFromMonth((int)month, (int)year); return yearday + monthday + date - 1; } private static double MakeDate(double day, double time) { return day * msPerDay + time; } private static double TimeClip(double d) { if (d != d || d == Double.POSITIVE_INFINITY || d == Double.NEGATIVE_INFINITY || Math.abs(d) > HalfTimeDomain) { return ScriptRuntime.NaN; } if (d > 0.0) return Math.floor(d + 0.); else return Math.ceil(d + 0.); } /* end of ECMA helper functions */ /* find UTC time from given date... no 1900 correction! */ private static double date_msecFromDate(double year, double mon, double mday, double hour, double min, double sec, double msec) { double day; double time; double result; day = MakeDay(year, mon, mday); time = MakeTime(hour, min, sec, msec); result = MakeDate(day, time); return result; } /* compute the time in msec (unclipped) from the given args */ private static final int MAXARGS = 7; private static double date_msecFromArgs(Object[] args) { double array[] = new double[MAXARGS]; int loop; double d; for (loop = 0; loop < MAXARGS; loop++) { if (loop < args.length) { d = ScriptRuntime.toNumber(args[loop]); if (d != d || Double.isInfinite(d)) { return ScriptRuntime.NaN; } array[loop] = ScriptRuntime.toInteger(args[loop]); } else { if (loop == 2) { array[loop] = 1; /* Default the date argument to 1. */ } else { array[loop] = 0; } } } /* adjust 2-digit years into the 20th century */ if (array[0] >= 0 && array[0] <= 99) array[0] += 1900; return date_msecFromDate(array[0], array[1], array[2], array[3], array[4], array[5], array[6]); } private static double jsStaticFunction_UTC(Object[] args) { return TimeClip(date_msecFromArgs(args)); } private static double date_parseString(String s) { try { if (s.length() == 24) { final Date d; synchronized(isoFormat) { d = isoFormat.parse(s); } return d.getTime(); } } catch (java.text.ParseException ex) {} int year = -1; int mon = -1; int mday = -1; int hour = -1; int min = -1; int sec = -1; char c = 0; char si = 0; int i = 0; int n = -1; double tzoffset = -1; char prevc = 0; int limit = 0; boolean seenplusminus = false; limit = s.length(); while (i < limit) { c = s.charAt(i); i++; if (c <= ' ' || c == ',' || c == '-') { if (i < limit) { si = s.charAt(i); if (c == '-' && '0' <= si && si <= '9') { prevc = c; } } continue; } if (c == '(') { /* comments) */ int depth = 1; while (i < limit) { c = s.charAt(i); i++; if (c == '(') depth++; else if (c == ')') if (--depth <= 0) break; } continue; } if ('0' <= c && c <= '9') { n = c - '0'; while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') { n = n * 10 + c - '0'; i++; } /* allow TZA before the year, so * 'Wed Nov 05 21:49:11 GMT-0800 1997' * works */ /* uses of seenplusminus allow : in TZA, so Java * no-timezone style of GMT+4:30 works */ if ((prevc == '+' || prevc == '-')/* && year>=0 */) { /* make ':' case below change tzoffset */ seenplusminus = true; /* offset */ if (n < 24) n = n * 60; /* EG. "GMT-3" */ else n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */ if (prevc == '+') /* plus means east of GMT */ n = -n; if (tzoffset != 0 && tzoffset != -1) return ScriptRuntime.NaN; tzoffset = n; } else if (n >= 70 || (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) { if (year >= 0) return ScriptRuntime.NaN; else if (c <= ' ' || c == ',' || c == '/' || i >= limit) year = n < 100 ? n + 1900 : n; else return ScriptRuntime.NaN; } else if (c == ':') { if (hour < 0) hour = /*byte*/ n; else if (min < 0) min = /*byte*/ n; else return ScriptRuntime.NaN; } else if (c == '/') { if (mon < 0) mon = /*byte*/ n-1; else if (mday < 0) mday = /*byte*/ n; else return ScriptRuntime.NaN; } else if (i < limit && c != ',' && c > ' ' && c != '-') { return ScriptRuntime.NaN; } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */ if (tzoffset < 0) tzoffset -= n; else tzoffset += n; } else if (hour >= 0 && min < 0) { min = /*byte*/ n; } else if (min >= 0 && sec < 0) { sec = /*byte*/ n; } else if (mday < 0) { mday = /*byte*/ n; } else { return ScriptRuntime.NaN; } prevc = 0; } else if (c == '/' || c == ':' || c == '+' || c == '-') { prevc = c; } else { int st = i - 1; while (i < limit) { c = s.charAt(i); if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))) break; i++; } int letterCount = i - st; if (letterCount < 2) return ScriptRuntime.NaN; /* * Use ported code from jsdate.c rather than the locale-specific * date-parsing code from Java, to keep js and rhino consistent. * Is this the right strategy? */ String wtb = "am;pm;" +"monday;tuesday;wednesday;thursday;friday;" +"saturday;sunday;" +"january;february;march;april;may;june;" +"july;august;september;october;november;december;" +"gmt;ut;utc;est;edt;cst;cdt;mst;mdt;pst;pdt;"; int index = 0; for (int wtbOffset = 0; ;) { int wtbNext = wtb.indexOf(';', wtbOffset); if (wtbNext < 0) return ScriptRuntime.NaN; if (wtb.regionMatches(true, wtbOffset, s, st, letterCount)) break; wtbOffset = wtbNext + 1; ++index; } if (index < 2) { /* * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as * 12:30, instead of blindly adding 12 if PM. */ if (hour > 12 || hour < 0) { return ScriptRuntime.NaN; } else if (index == 0) { // AM if (hour == 12) hour = 0; } else { // PM if (hour != 12) hour += 12; } } else if ((index -= 2) < 7) { // ignore week days } else if ((index -= 7) < 12) { // month if (mon < 0) { mon = index; } else { return ScriptRuntime.NaN; } } else { index -= 12; // timezones switch (index) { case 0 /* gmt */: tzoffset = 0; break; case 1 /* ut */: tzoffset = 0; break; case 2 /* utc */: tzoffset = 0; break; case 3 /* est */: tzoffset = 5 * 60; break; case 4 /* edt */: tzoffset = 4 * 60; break; case 5 /* cst */: tzoffset = 6 * 60; break; case 6 /* cdt */: tzoffset = 5 * 60; break; case 7 /* mst */: tzoffset = 7 * 60; break; case 8 /* mdt */: tzoffset = 6 * 60; break; case 9 /* pst */: tzoffset = 8 * 60; break; case 10 /* pdt */:tzoffset = 7 * 60; break; default: Kit.codeBug(); } } } } if (year < 0 || mon < 0 || mday < 0) return ScriptRuntime.NaN; if (sec < 0) sec = 0; if (min < 0) min = 0; if (hour < 0) hour = 0; double msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0); if (tzoffset == -1) { /* no time zone specified, have to use local */ return internalUTC(msec); } else { return msec + tzoffset * msPerMinute; } } private static String date_format(double t, int methodId) { StringBuffer result = new StringBuffer(60); double local = LocalTime(t); /* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */ /* Tue Oct 31 2000 */ /* 09:41:40 GMT-0800 (PST) */ if (methodId != Id_toTimeString) { appendWeekDayName(result, WeekDay(local)); result.append(' '); appendMonthName(result, MonthFromTime(local)); result.append(' '); append0PaddedUint(result, DateFromTime(local), 2); result.append(' '); int year = YearFromTime(local); if (year < 0) { result.append('-'); year = -year; } append0PaddedUint(result, year, 4); if (methodId != Id_toDateString) result.append(' '); } if (methodId != Id_toDateString) { append0PaddedUint(result, HourFromTime(local), 2); result.append(':'); append0PaddedUint(result, MinFromTime(local), 2); result.append(':'); append0PaddedUint(result, SecFromTime(local), 2); // offset from GMT in minutes. The offset includes daylight // savings, if it applies. int minutes = (int) Math.floor((LocalTZA + DaylightSavingTA(t)) / msPerMinute); // map 510 minutes to 0830 hours int offset = (minutes / 60) * 100 + minutes % 60; if (offset > 0) { result.append(" GMT+"); } else { result.append(" GMT-"); offset = -offset; } append0PaddedUint(result, offset, 4); if (timeZoneFormatter == null) timeZoneFormatter = new SimpleDateFormat("zzz"); // Find an equivalent year before getting the timezone // comment. See DaylightSavingTA. if (t < 0.0) { int equiv = EquivalentYear(YearFromTime(local)); double day = MakeDay(equiv, MonthFromTime(t), DateFromTime(t)); t = MakeDate(day, TimeWithinDay(t)); } result.append(" ("); Date date = new Date((long) t); synchronized (timeZoneFormatter) { result.append(timeZoneFormatter.format(date)); } result.append(')'); } return result.toString(); } /* the javascript constructor */ private static Object jsConstructor(Object[] args) { NativeDate obj = new NativeDate(); // if called as a constructor with no args, // return a new Date with the current time. if (args.length == 0) { obj.date = now(); return obj; } // if called with just one arg - if (args.length == 1) { Object arg0 = args[0]; if (arg0 instanceof Scriptable) arg0 = ((Scriptable) arg0).getDefaultValue(null); double date; if (arg0 instanceof CharSequence) { // it's a string; parse it. date = date_parseString(arg0.toString()); } else { // if it's not a string, use it as a millisecond date date = ScriptRuntime.toNumber(arg0); } obj.date = TimeClip(date); return obj; } double time = date_msecFromArgs(args); if (!Double.isNaN(time) && !Double.isInfinite(time)) time = TimeClip(internalUTC(time)); obj.date = time; return obj; } private static String toLocale_helper(double t, int methodId) { DateFormat formatter; switch (methodId) { case Id_toLocaleString: if (localeDateTimeFormatter == null) { localeDateTimeFormatter = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); } formatter = localeDateTimeFormatter; break; case Id_toLocaleTimeString: if (localeTimeFormatter == null) { localeTimeFormatter = DateFormat.getTimeInstance(DateFormat.LONG); } formatter = localeTimeFormatter; break; case Id_toLocaleDateString: if (localeDateFormatter == null) { localeDateFormatter = DateFormat.getDateInstance(DateFormat.LONG); } formatter = localeDateFormatter; break; default: throw new AssertionError(); // unreachable } synchronized (formatter) { return formatter.format(new Date((long) t)); } } private static String js_toUTCString(double date) { StringBuffer result = new StringBuffer(60); appendWeekDayName(result, WeekDay(date)); result.append(", "); append0PaddedUint(result, DateFromTime(date), 2); result.append(' '); appendMonthName(result, MonthFromTime(date)); result.append(' '); int year = YearFromTime(date); if (year < 0) { result.append('-'); year = -year; } append0PaddedUint(result, year, 4); result.append(' '); append0PaddedUint(result, HourFromTime(date), 2); result.append(':'); append0PaddedUint(result, MinFromTime(date), 2); result.append(':'); append0PaddedUint(result, SecFromTime(date), 2); result.append(" GMT"); return result.toString(); } private static void append0PaddedUint(StringBuffer sb, int i, int minWidth) { if (i < 0) Kit.codeBug(); int scale = 1; --minWidth; if (i >= 10) { if (i < 1000 * 1000 * 1000) { for (;;) { int newScale = scale * 10; if (i < newScale) { break; } --minWidth; scale = newScale; } } else { // Separated case not to check against 10 * 10^9 overflow minWidth -= 9; scale = 1000 * 1000 * 1000; } } while (minWidth > 0) { sb.append('0'); --minWidth; } while (scale != 1) { sb.append((char)('0' + (i / scale))); i %= scale; scale /= 10; } sb.append((char)('0' + i)); } private static void appendMonthName(StringBuffer sb, int index) { // Take advantage of the fact that all month abbreviations // have the same length to minimize amount of strings runtime has // to keep in memory String months = "Jan"+"Feb"+"Mar"+"Apr"+"May"+"Jun" +"Jul"+"Aug"+"Sep"+"Oct"+"Nov"+"Dec"; index *= 3; for (int i = 0; i != 3; ++i) { sb.append(months.charAt(index + i)); } } private static void appendWeekDayName(StringBuffer sb, int index) { String days = "Sun"+"Mon"+"Tue"+"Wed"+"Thu"+"Fri"+"Sat"; index *= 3; for (int i = 0; i != 3; ++i) { sb.append(days.charAt(index + i)); } } private static double makeTime(double date, Object[] args, int methodId) { int maxargs; boolean local = true; switch (methodId) { case Id_setUTCMilliseconds: local = false; // fallthrough case Id_setMilliseconds: maxargs = 1; break; case Id_setUTCSeconds: local = false; // fallthrough case Id_setSeconds: maxargs = 2; break; case Id_setUTCMinutes: local = false; // fallthrough case Id_setMinutes: maxargs = 3; break; case Id_setUTCHours: local = false; // fallthrough case Id_setHours: maxargs = 4; break; default: Kit.codeBug(); maxargs = 0; } int i; double conv[] = new double[4]; double hour, min, sec, msec; double lorutime; /* Local or UTC version of date */ double time; double result; /* just return NaN if the date is already NaN */ if (date != date) return date; /* Satisfy the ECMA rule that if a function is called with * fewer arguments than the specified formal arguments, the * remaining arguments are set to undefined. Seems like all * the Date.setWhatever functions in ECMA are only varargs * beyond the first argument; this should be set to undefined * if it's not given. This means that "d = new Date(); * d.setMilliseconds()" returns NaN. Blech. */ if (args.length == 0) args = ScriptRuntime.padArguments(args, 1); for (i = 0; i < args.length && i < maxargs; i++) { conv[i] = ScriptRuntime.toNumber(args[i]); // limit checks that happen in MakeTime in ECMA. if (conv[i] != conv[i] || Double.isInfinite(conv[i])) { return ScriptRuntime.NaN; } conv[i] = ScriptRuntime.toInteger(conv[i]); } if (local) lorutime = LocalTime(date); else lorutime = date; i = 0; int stop = args.length; if (maxargs >= 4 && i < stop) hour = conv[i++]; else hour = HourFromTime(lorutime); if (maxargs >= 3 && i < stop) min = conv[i++]; else min = MinFromTime(lorutime); if (maxargs >= 2 && i < stop) sec = conv[i++]; else sec = SecFromTime(lorutime); if (maxargs >= 1 && i < stop) msec = conv[i++]; else msec = msFromTime(lorutime); time = MakeTime(hour, min, sec, msec); result = MakeDate(Day(lorutime), time); if (local) result = internalUTC(result); date = TimeClip(result); return date; } private static double makeDate(double date, Object[] args, int methodId) { int maxargs; boolean local = true; switch (methodId) { case Id_setUTCDate: local = false; // fallthrough case Id_setDate: maxargs = 1; break; case Id_setUTCMonth: local = false; // fallthrough case Id_setMonth: maxargs = 2; break; case Id_setUTCFullYear: local = false; // fallthrough case Id_setFullYear: maxargs = 3; break; default: Kit.codeBug(); maxargs = 0; } int i; double conv[] = new double[3]; double year, month, day; double lorutime; /* local or UTC version of date */ double result; /* See arg padding comment in makeTime.*/ if (args.length == 0) args = ScriptRuntime.padArguments(args, 1); for (i = 0; i < args.length && i < maxargs; i++) { conv[i] = ScriptRuntime.toNumber(args[i]); // limit checks that happen in MakeDate in ECMA. if (conv[i] != conv[i] || Double.isInfinite(conv[i])) { return ScriptRuntime.NaN; } conv[i] = ScriptRuntime.toInteger(conv[i]); } /* return NaN if date is NaN and we're not setting the year, * If we are, use 0 as the time. */ if (date != date) { if (args.length < 3) { return ScriptRuntime.NaN; } else { lorutime = 0; } } else { if (local) lorutime = LocalTime(date); else lorutime = date; } i = 0; int stop = args.length; if (maxargs >= 3 && i < stop) year = conv[i++]; else year = YearFromTime(lorutime); if (maxargs >= 2 && i < stop) month = conv[i++]; else month = MonthFromTime(lorutime); if (maxargs >= 1 && i < stop) day = conv[i++]; else day = DateFromTime(lorutime); day = MakeDay(year, month, day); /* day within year */ result = MakeDate(day, TimeWithinDay(lorutime)); if (local) result = internalUTC(result); date = TimeClip(result); return date; } // #string_id_map# @Override protected int findPrototypeId(String s) { int id; // #generated# Last update: 2009-07-22 05:44:02 EST L0: { id = 0; String X = null; int c; L: switch (s.length()) { case 6: c=s.charAt(0); if (c=='g') { X="getDay";id=Id_getDay; } else if (c=='t') { X="toJSON";id=Id_toJSON; } break L; case 7: switch (s.charAt(3)) { case 'D': c=s.charAt(0); if (c=='g') { X="getDate";id=Id_getDate; } else if (c=='s') { X="setDate";id=Id_setDate; } break L; case 'T': c=s.charAt(0); if (c=='g') { X="getTime";id=Id_getTime; } else if (c=='s') { X="setTime";id=Id_setTime; } break L; case 'Y': c=s.charAt(0); if (c=='g') { X="getYear";id=Id_getYear; } else if (c=='s') { X="setYear";id=Id_setYear; } break L; case 'u': X="valueOf";id=Id_valueOf; break L; } break L; case 8: switch (s.charAt(3)) { case 'H': c=s.charAt(0); if (c=='g') { X="getHours";id=Id_getHours; } else if (c=='s') { X="setHours";id=Id_setHours; } break L; case 'M': c=s.charAt(0); if (c=='g') { X="getMonth";id=Id_getMonth; } else if (c=='s') { X="setMonth";id=Id_setMonth; } break L; case 'o': X="toSource";id=Id_toSource; break L; case 't': X="toString";id=Id_toString; break L; } break L; case 9: X="getUTCDay";id=Id_getUTCDay; break L; case 10: c=s.charAt(3); if (c=='M') { c=s.charAt(0); if (c=='g') { X="getMinutes";id=Id_getMinutes; } else if (c=='s') { X="setMinutes";id=Id_setMinutes; } } else if (c=='S') { c=s.charAt(0); if (c=='g') { X="getSeconds";id=Id_getSeconds; } else if (c=='s') { X="setSeconds";id=Id_setSeconds; } } else if (c=='U') { c=s.charAt(0); if (c=='g') { X="getUTCDate";id=Id_getUTCDate; } else if (c=='s') { X="setUTCDate";id=Id_setUTCDate; } } break L; case 11: switch (s.charAt(3)) { case 'F': c=s.charAt(0); if (c=='g') { X="getFullYear";id=Id_getFullYear; } else if (c=='s') { X="setFullYear";id=Id_setFullYear; } break L; case 'M': X="toGMTString";id=Id_toGMTString; break L; case 'S': X="toISOString";id=Id_toISOString; break L; case 'T': X="toUTCString";id=Id_toUTCString; break L; case 'U': c=s.charAt(0); if (c=='g') { c=s.charAt(9); if (c=='r') { X="getUTCHours";id=Id_getUTCHours; } else if (c=='t') { X="getUTCMonth";id=Id_getUTCMonth; } } else if (c=='s') { c=s.charAt(9); if (c=='r') { X="setUTCHours";id=Id_setUTCHours; } else if (c=='t') { X="setUTCMonth";id=Id_setUTCMonth; } } break L; case 's': X="constructor";id=Id_constructor; break L; } break L; case 12: c=s.charAt(2); if (c=='D') { X="toDateString";id=Id_toDateString; } else if (c=='T') { X="toTimeString";id=Id_toTimeString; } break L; case 13: c=s.charAt(0); if (c=='g') { c=s.charAt(6); if (c=='M') { X="getUTCMinutes";id=Id_getUTCMinutes; } else if (c=='S') { X="getUTCSeconds";id=Id_getUTCSeconds; } } else if (c=='s') { c=s.charAt(6); if (c=='M') { X="setUTCMinutes";id=Id_setUTCMinutes; } else if (c=='S') { X="setUTCSeconds";id=Id_setUTCSeconds; } } break L; case 14: c=s.charAt(0); if (c=='g') { X="getUTCFullYear";id=Id_getUTCFullYear; } else if (c=='s') { X="setUTCFullYear";id=Id_setUTCFullYear; } else if (c=='t') { X="toLocaleString";id=Id_toLocaleString; } break L; case 15: c=s.charAt(0); if (c=='g') { X="getMilliseconds";id=Id_getMilliseconds; } else if (c=='s') { X="setMilliseconds";id=Id_setMilliseconds; } break L; case 17: X="getTimezoneOffset";id=Id_getTimezoneOffset; break L; case 18: c=s.charAt(0); if (c=='g') { X="getUTCMilliseconds";id=Id_getUTCMilliseconds; } else if (c=='s') { X="setUTCMilliseconds";id=Id_setUTCMilliseconds; } else if (c=='t') { c=s.charAt(8); if (c=='D') { X="toLocaleDateString";id=Id_toLocaleDateString; } else if (c=='T') { X="toLocaleTimeString";id=Id_toLocaleTimeString; } } break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# return id; } private static final int ConstructorId_now = -3, ConstructorId_parse = -2, ConstructorId_UTC = -1, Id_constructor = 1, Id_toString = 2, Id_toTimeString = 3, Id_toDateString = 4, Id_toLocaleString = 5, Id_toLocaleTimeString = 6, Id_toLocaleDateString = 7, Id_toUTCString = 8, Id_toSource = 9, Id_valueOf = 10, Id_getTime = 11, Id_getYear = 12, Id_getFullYear = 13, Id_getUTCFullYear = 14, Id_getMonth = 15, Id_getUTCMonth = 16, Id_getDate = 17, Id_getUTCDate = 18, Id_getDay = 19, Id_getUTCDay = 20, Id_getHours = 21, Id_getUTCHours = 22, Id_getMinutes = 23, Id_getUTCMinutes = 24, Id_getSeconds = 25, Id_getUTCSeconds = 26, Id_getMilliseconds = 27, Id_getUTCMilliseconds = 28, Id_getTimezoneOffset = 29, Id_setTime = 30, Id_setMilliseconds = 31, Id_setUTCMilliseconds = 32, Id_setSeconds = 33, Id_setUTCSeconds = 34, Id_setMinutes = 35, Id_setUTCMinutes = 36, Id_setHours = 37, Id_setUTCHours = 38, Id_setDate = 39, Id_setUTCDate = 40, Id_setMonth = 41, Id_setUTCMonth = 42, Id_setFullYear = 43, Id_setUTCFullYear = 44, Id_setYear = 45, Id_toISOString = 46, Id_toJSON = 47, MAX_PROTOTYPE_ID = Id_toJSON; private static final int Id_toGMTString = Id_toUTCString; // Alias, see Ecma B.2.6 // #/string_id_map# /* cached values */ private static TimeZone thisTimeZone; private static double LocalTZA; private static DateFormat timeZoneFormatter; private static DateFormat localeDateTimeFormatter; private static DateFormat localeDateFormatter; private static DateFormat localeTimeFormatter; private double date; } rhino-1.7R4/src/org/mozilla/javascript/NativeError.java000066400000000000000000000173641176760007500232300ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * * The class of error objects * * ECMA 15.11 */ final class NativeError extends IdScriptableObject { static final long serialVersionUID = -5338413581437645187L; private static final Object ERROR_TAG = "Error"; private RhinoException stackProvider; static void init(Scriptable scope, boolean sealed) { NativeError obj = new NativeError(); ScriptableObject.putProperty(obj, "name", "Error"); ScriptableObject.putProperty(obj, "message", ""); ScriptableObject.putProperty(obj, "fileName", ""); ScriptableObject.putProperty(obj, "lineNumber", Integer.valueOf(0)); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } static NativeError make(Context cx, Scriptable scope, IdFunctionObject ctorObj, Object[] args) { Scriptable proto = (Scriptable)(ctorObj.get("prototype", ctorObj)); NativeError obj = new NativeError(); obj.setPrototype(proto); obj.setParentScope(scope); int arglen = args.length; if (arglen >= 1) { ScriptableObject.putProperty(obj, "message", ScriptRuntime.toString(args[0])); if (arglen >= 2) { ScriptableObject.putProperty(obj, "fileName", args[1]); if (arglen >= 3) { int line = ScriptRuntime.toInt32(args[2]); ScriptableObject.putProperty(obj, "lineNumber", Integer.valueOf(line)); } } } return obj; } @Override public String getClassName() { return "Error"; } @Override public String toString() { // According to spec, Error.prototype.toString() may return undefined. Object toString = js_toString(this); return toString instanceof String ? (String) toString : super.toString(); } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=1; s="constructor"; break; case Id_toString: arity=0; s="toString"; break; case Id_toSource: arity=0; s="toSource"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(ERROR_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(ERROR_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_constructor: return make(cx, scope, f, args); case Id_toString: return js_toString(thisObj); case Id_toSource: return js_toSource(cx, scope, thisObj); } throw new IllegalArgumentException(String.valueOf(id)); } public void setStackProvider(RhinoException re) { // We go some extra miles to make sure the stack property is only // generated on demand, is cached after the first access, and is // overwritable like an ordinary property. Hence this setup with // the getter and setter below. if (stackProvider == null) { stackProvider = re; try { defineProperty("stack", null, NativeError.class.getMethod("getStack"), NativeError.class.getMethod("setStack", Object.class), 0); } catch (NoSuchMethodException nsm) { // should not happen throw new RuntimeException(nsm); } } } public Object getStack() { Object value = stackProvider == null ? NOT_FOUND : stackProvider.getScriptStackTrace(); // We store the stack as local property both to cache it // and to make the property writable setStack(value); return value; } public void setStack(Object value) { if (stackProvider != null) { stackProvider = null; delete("stack"); } put("stack", this, value); } private static Object js_toString(Scriptable thisObj) { Object name = ScriptableObject.getProperty(thisObj, "name"); if (name == NOT_FOUND || name == Undefined.instance) { name = "Error"; } else { name = ScriptRuntime.toString(name); } Object msg = ScriptableObject.getProperty(thisObj, "message"); final Object result; if (msg == NOT_FOUND || msg == Undefined.instance) { result = Undefined.instance; } else { result = ((String) name) + ": " + ScriptRuntime.toString(msg); } return result; } private static String js_toSource(Context cx, Scriptable scope, Scriptable thisObj) { // Emulation of SpiderMonkey behavior Object name = ScriptableObject.getProperty(thisObj, "name"); Object message = ScriptableObject.getProperty(thisObj, "message"); Object fileName = ScriptableObject.getProperty(thisObj, "fileName"); Object lineNumber = ScriptableObject.getProperty(thisObj, "lineNumber"); StringBuffer sb = new StringBuffer(); sb.append("(new "); if (name == NOT_FOUND) { name = Undefined.instance; } sb.append(ScriptRuntime.toString(name)); sb.append("("); if (message != NOT_FOUND || fileName != NOT_FOUND || lineNumber != NOT_FOUND) { if (message == NOT_FOUND) { message = ""; } sb.append(ScriptRuntime.uneval(cx, scope, message)); if (fileName != NOT_FOUND || lineNumber != NOT_FOUND) { sb.append(", "); if (fileName == NOT_FOUND) { fileName = ""; } sb.append(ScriptRuntime.uneval(cx, scope, fileName)); if (lineNumber != NOT_FOUND) { int line = ScriptRuntime.toInt32(lineNumber); if (line != 0) { sb.append(", "); sb.append(ScriptRuntime.toString(line)); } } } } sb.append("))"); return sb.toString(); } private static String getString(Scriptable obj, String id) { Object value = ScriptableObject.getProperty(obj, id); if (value == NOT_FOUND) return ""; return ScriptRuntime.toString(value); } @Override protected int findPrototypeId(String s) { int id; // #string_id_map# // #generated# Last update: 2007-05-09 08:15:45 EDT L0: { id = 0; String X = null; int c; int s_length = s.length(); if (s_length==8) { c=s.charAt(3); if (c=='o') { X="toSource";id=Id_toSource; } else if (c=='t') { X="toString";id=Id_toString; } } else if (s_length==11) { X="constructor";id=Id_constructor; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# return id; } private static final int Id_constructor = 1, Id_toString = 2, Id_toSource = 3, MAX_PROTOTYPE_ID = 3; // #/string_id_map# } rhino-1.7R4/src/org/mozilla/javascript/NativeFunction.java000066400000000000000000000100301176760007500237030ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import org.mozilla.javascript.debug.DebuggableScript; /** * This class implements the Function native object. * See ECMA 15.3. * @author Norris Boyd */ public abstract class NativeFunction extends BaseFunction { static final long serialVersionUID = 8713897114082216401L; public final void initScriptFunction(Context cx, Scriptable scope) { ScriptRuntime.setFunctionProtoAndParent(this, scope); } /** * @param indent How much to indent the decompiled result * * @param flags Flags specifying format of decompilation output */ @Override final String decompile(int indent, int flags) { String encodedSource = getEncodedSource(); if (encodedSource == null) { return super.decompile(indent, flags); } else { UintMap properties = new UintMap(1); properties.put(Decompiler.INITIAL_INDENT_PROP, indent); return Decompiler.decompile(encodedSource, flags, properties); } } @Override public int getLength() { int paramCount = getParamCount(); if (getLanguageVersion() != Context.VERSION_1_2) { return paramCount; } Context cx = Context.getContext(); NativeCall activation = ScriptRuntime.findFunctionActivation(cx, this); if (activation == null) { return paramCount; } return activation.originalArgs.length; } @Override public int getArity() { return getParamCount(); } /** * @deprecated Use {@link BaseFunction#getFunctionName()} instead. * For backwards compatibility keep an old method name used by * Batik and possibly others. */ public String jsGet_name() { return getFunctionName(); } /** * Get encoded source string. */ public String getEncodedSource() { return null; } public DebuggableScript getDebuggableView() { return null; } /** * Resume execution of a suspended generator. * @param cx The current context * @param scope Scope for the parent generator function * @param operation The resumption operation (next, send, etc.. ) * @param state The generator state (has locals, stack, etc.) * @param value The return value of yield (if required). * @return The next yielded value (if any) */ public Object resumeGenerator(Context cx, Scriptable scope, int operation, Object state, Object value) { throw new EvaluatorException("resumeGenerator() not implemented"); } protected abstract int getLanguageVersion(); /** * Get number of declared parameters. It should be 0 for scripts. */ protected abstract int getParamCount(); /** * Get number of declared parameters and variables defined through var * statements. */ protected abstract int getParamAndVarCount(); /** * Get parameter or variable name. * If index < {@link #getParamCount()}, then return the name of the * corresponding parameter. Otherwise return the name of variable. */ protected abstract String getParamOrVarName(int index); /** * Get parameter or variable const-ness. * If index < {@link #getParamCount()}, then return the const-ness * of the corresponding parameter. Otherwise return whether the variable is * const. */ protected boolean getParamOrVarConst(int index) { // By default return false to preserve compatibility with existing // classes subclassing this class, which are mostly generated by jsc // from earlier Rhino versions. See Bugzilla #396117. return false; } } rhino-1.7R4/src/org/mozilla/javascript/NativeGenerator.java000066400000000000000000000212221176760007500240510ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * This class implements generator objects. See * http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7#Generators * * @author Norris Boyd */ public final class NativeGenerator extends IdScriptableObject { private static final long serialVersionUID = 1645892441041347273L; private static final Object GENERATOR_TAG = "Generator"; static NativeGenerator init(ScriptableObject scope, boolean sealed) { // Generator // Can't use "NativeGenerator().exportAsJSClass" since we don't want // to define "Generator" as a constructor in the top-level scope. NativeGenerator prototype = new NativeGenerator(); if (scope != null) { prototype.setParentScope(scope); prototype.setPrototype(getObjectPrototype(scope)); } prototype.activatePrototypeMap(MAX_PROTOTYPE_ID); if (sealed) { prototype.sealObject(); } // Need to access Generator prototype when constructing // Generator instances, but don't have a generator constructor // to use to find the prototype. Use the "associateValue" // approach instead. if (scope != null) { scope.associateValue(GENERATOR_TAG, prototype); } return prototype; } /** * Only for constructing the prototype object. */ private NativeGenerator() { } public NativeGenerator(Scriptable scope, NativeFunction function, Object savedState) { this.function = function; this.savedState = savedState; // Set parent and prototype properties. Since we don't have a // "Generator" constructor in the top scope, we stash the // prototype in the top scope's associated value. Scriptable top = ScriptableObject.getTopLevelScope(scope); this.setParentScope(top); NativeGenerator prototype = (NativeGenerator) ScriptableObject.getTopScopeValue(top, GENERATOR_TAG); this.setPrototype(prototype); } public static final int GENERATOR_SEND = 0, GENERATOR_THROW = 1, GENERATOR_CLOSE = 2; @Override public String getClassName() { return "Generator"; } private static class CloseGeneratorAction implements ContextAction { private NativeGenerator generator; CloseGeneratorAction(NativeGenerator generator) { this.generator = generator; } public Object run(Context cx) { Scriptable scope = ScriptableObject.getTopLevelScope(generator); Callable closeGenerator = new Callable() { public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { return ((NativeGenerator)thisObj).resume(cx, scope, GENERATOR_CLOSE, new GeneratorClosedException()); } }; return ScriptRuntime.doTopCall(closeGenerator, cx, scope, generator, null); } } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_close: arity=1; s="close"; break; case Id_next: arity=1; s="next"; break; case Id_send: arity=0; s="send"; break; case Id_throw: arity=0; s="throw"; break; case Id___iterator__: arity=1; s="__iterator__"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(GENERATOR_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(GENERATOR_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); if (!(thisObj instanceof NativeGenerator)) throw incompatibleCallError(f); NativeGenerator generator = (NativeGenerator) thisObj; switch (id) { case Id_close: // need to run any pending finally clauses return generator.resume(cx, scope, GENERATOR_CLOSE, new GeneratorClosedException()); case Id_next: // arguments to next() are ignored generator.firstTime = false; return generator.resume(cx, scope, GENERATOR_SEND, Undefined.instance); case Id_send: { Object arg = args.length > 0 ? args[0] : Undefined.instance; if (generator.firstTime && !arg.equals(Undefined.instance)) { throw ScriptRuntime.typeError0("msg.send.newborn"); } return generator.resume(cx, scope, GENERATOR_SEND, arg); } case Id_throw: return generator.resume(cx, scope, GENERATOR_THROW, args.length > 0 ? args[0] : Undefined.instance); case Id___iterator__: return thisObj; default: throw new IllegalArgumentException(String.valueOf(id)); } } private Object resume(Context cx, Scriptable scope, int operation, Object value) { if (savedState == null) { if (operation == GENERATOR_CLOSE) return Undefined.instance; Object thrown; if (operation == GENERATOR_THROW) { thrown = value; } else { thrown = NativeIterator.getStopIterationObject(scope); } throw new JavaScriptException(thrown, lineSource, lineNumber); } try { synchronized (this) { // generator execution is necessarily single-threaded and // non-reentrant. // See https://bugzilla.mozilla.org/show_bug.cgi?id=349263 if (locked) throw ScriptRuntime.typeError0("msg.already.exec.gen"); locked = true; } return function.resumeGenerator(cx, scope, operation, savedState, value); } catch (GeneratorClosedException e) { // On closing a generator in the compile path, the generator // throws a special exception. This ensures execution of all pending // finalizers and will not get caught by user code. return Undefined.instance; } catch (RhinoException e) { lineNumber = e.lineNumber(); lineSource = e.lineSource(); savedState = null; throw e; } finally { synchronized (this) { locked = false; } if (operation == GENERATOR_CLOSE) savedState = null; } } // #string_id_map# @Override protected int findPrototypeId(String s) { int id; // #generated# Last update: 2007-06-14 13:13:03 EDT L0: { id = 0; String X = null; int c; int s_length = s.length(); if (s_length==4) { c=s.charAt(0); if (c=='n') { X="next";id=Id_next; } else if (c=='s') { X="send";id=Id_send; } } else if (s_length==5) { c=s.charAt(0); if (c=='c') { X="close";id=Id_close; } else if (c=='t') { X="throw";id=Id_throw; } } else if (s_length==12) { X="__iterator__";id=Id___iterator__; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# return id; } private static final int Id_close = 1, Id_next = 2, Id_send = 3, Id_throw = 4, Id___iterator__ = 5, MAX_PROTOTYPE_ID = 5; // #/string_id_map# private NativeFunction function; private Object savedState; private String lineSource; private int lineNumber; private boolean firstTime = true; private boolean locked; public static class GeneratorClosedException extends RuntimeException { private static final long serialVersionUID = 2561315658662379681L; } } rhino-1.7R4/src/org/mozilla/javascript/NativeGlobal.java000066400000000000000000000642461176760007500233400ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.io.Serializable; import org.mozilla.javascript.xml.XMLLib; import static org.mozilla.javascript.ScriptableObject.DONTENUM; import static org.mozilla.javascript.ScriptableObject.READONLY; import static org.mozilla.javascript.ScriptableObject.PERMANENT; /** * This class implements the global native object (function and value * properties only). * * See ECMA 15.1.[12]. * * @author Mike Shaver */ public class NativeGlobal implements Serializable, IdFunctionCall { static final long serialVersionUID = 6080442165748707530L; public static void init(Context cx, Scriptable scope, boolean sealed) { NativeGlobal obj = new NativeGlobal(); for (int id = 1; id <= LAST_SCOPE_FUNCTION_ID; ++id) { String name; int arity = 1; switch (id) { case Id_decodeURI: name = "decodeURI"; break; case Id_decodeURIComponent: name = "decodeURIComponent"; break; case Id_encodeURI: name = "encodeURI"; break; case Id_encodeURIComponent: name = "encodeURIComponent"; break; case Id_escape: name = "escape"; break; case Id_eval: name = "eval"; break; case Id_isFinite: name = "isFinite"; break; case Id_isNaN: name = "isNaN"; break; case Id_isXMLName: name = "isXMLName"; break; case Id_parseFloat: name = "parseFloat"; break; case Id_parseInt: name = "parseInt"; arity = 2; break; case Id_unescape: name = "unescape"; break; case Id_uneval: name = "uneval"; break; default: throw Kit.codeBug(); } IdFunctionObject f = new IdFunctionObject(obj, FTAG, id, name, arity, scope); if (sealed) { f.sealObject(); } f.exportAsScopeProperty(); } ScriptableObject.defineProperty( scope, "NaN", ScriptRuntime.NaNobj, READONLY|DONTENUM|PERMANENT); ScriptableObject.defineProperty( scope, "Infinity", ScriptRuntime.wrapNumber(Double.POSITIVE_INFINITY), READONLY|DONTENUM|PERMANENT); ScriptableObject.defineProperty( scope, "undefined", Undefined.instance, READONLY|DONTENUM|PERMANENT); String[] errorMethods = { "ConversionError", "EvalError", "RangeError", "ReferenceError", "SyntaxError", "TypeError", "URIError", "InternalError", "JavaException" }; /* Each error constructor gets its own Error object as a prototype, with the 'name' property set to the name of the error. */ for (int i = 0; i < errorMethods.length; i++) { String name = errorMethods[i]; ScriptableObject errorProto = (ScriptableObject) ScriptRuntime.newObject(cx, scope, "Error", ScriptRuntime.emptyArgs); errorProto.put("name", errorProto, name); errorProto.put("message", errorProto, ""); IdFunctionObject ctor = new IdFunctionObject(obj, FTAG, Id_new_CommonError, name, 1, scope); ctor.markAsConstructor(errorProto); errorProto.put("constructor", errorProto, ctor); errorProto.setAttributes("constructor", ScriptableObject.DONTENUM); if (sealed) { errorProto.sealObject(); ctor.sealObject(); } ctor.exportAsScopeProperty(); } } public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (f.hasTag(FTAG)) { int methodId = f.methodId(); switch (methodId) { case Id_decodeURI: case Id_decodeURIComponent: { String str = ScriptRuntime.toString(args, 0); return decode(str, methodId == Id_decodeURI); } case Id_encodeURI: case Id_encodeURIComponent: { String str = ScriptRuntime.toString(args, 0); return encode(str, methodId == Id_encodeURI); } case Id_escape: return js_escape(args); case Id_eval: return js_eval(cx, scope, args); case Id_isFinite: { boolean result; if (args.length < 1) { result = false; } else { double d = ScriptRuntime.toNumber(args[0]); result = (d == d && d != Double.POSITIVE_INFINITY && d != Double.NEGATIVE_INFINITY); } return ScriptRuntime.wrapBoolean(result); } case Id_isNaN: { // The global method isNaN, as per ECMA-262 15.1.2.6. boolean result; if (args.length < 1) { result = true; } else { double d = ScriptRuntime.toNumber(args[0]); result = (d != d); } return ScriptRuntime.wrapBoolean(result); } case Id_isXMLName: { Object name = (args.length == 0) ? Undefined.instance : args[0]; XMLLib xmlLib = XMLLib.extractFromScope(scope); return ScriptRuntime.wrapBoolean( xmlLib.isXMLName(cx, name)); } case Id_parseFloat: return js_parseFloat(args); case Id_parseInt: return js_parseInt(args); case Id_unescape: return js_unescape(args); case Id_uneval: { Object value = (args.length != 0) ? args[0] : Undefined.instance; return ScriptRuntime.uneval(cx, scope, value); } case Id_new_CommonError: // The implementation of all the ECMA error constructors // (SyntaxError, TypeError, etc.) return NativeError.make(cx, scope, f, args); } } throw f.unknown(); } /** * The global method parseInt, as per ECMA-262 15.1.2.2. */ private Object js_parseInt(Object[] args) { String s = ScriptRuntime.toString(args, 0); int radix = ScriptRuntime.toInt32(args, 1); int len = s.length(); if (len == 0) return ScriptRuntime.NaNobj; boolean negative = false; int start = 0; char c; do { c = s.charAt(start); if (!ScriptRuntime.isStrWhiteSpaceChar(c)) break; start++; } while (start < len); if (c == '+' || (negative = (c == '-'))) start++; final int NO_RADIX = -1; if (radix == 0) { radix = NO_RADIX; } else if (radix < 2 || radix > 36) { return ScriptRuntime.NaNobj; } else if (radix == 16 && len - start > 1 && s.charAt(start) == '0') { c = s.charAt(start+1); if (c == 'x' || c == 'X') start += 2; } if (radix == NO_RADIX) { radix = 10; if (len - start > 1 && s.charAt(start) == '0') { c = s.charAt(start+1); if (c == 'x' || c == 'X') { radix = 16; start += 2; } else if ('0' <= c && c <= '9') { radix = 8; start++; } } } double d = ScriptRuntime.stringToNumber(s, start, radix); return ScriptRuntime.wrapNumber(negative ? -d : d); } /** * The global method parseFloat, as per ECMA-262 15.1.2.3. * * @param args the arguments to parseFloat, ignoring args[>=1] */ private Object js_parseFloat(Object[] args) { if (args.length < 1) return ScriptRuntime.NaNobj; String s = ScriptRuntime.toString(args[0]); int len = s.length(); int start = 0; // Scan forward to skip whitespace char c; for (;;) { if (start == len) { return ScriptRuntime.NaNobj; } c = s.charAt(start); if (!ScriptRuntime.isStrWhiteSpaceChar(c)) { break; } ++start; } int i = start; if (c == '+' || c == '-') { ++i; if (i == len) { return ScriptRuntime.NaNobj; } c = s.charAt(i); } if (c == 'I') { // check for "Infinity" if (i+8 <= len && s.regionMatches(i, "Infinity", 0, 8)) { double d; if (s.charAt(start) == '-') { d = Double.NEGATIVE_INFINITY; } else { d = Double.POSITIVE_INFINITY; } return ScriptRuntime.wrapNumber(d); } return ScriptRuntime.NaNobj; } // Find the end of the legal bit int decimal = -1; int exponent = -1; boolean exponentValid = false; for (; i < len; i++) { switch (s.charAt(i)) { case '.': if (decimal != -1) // Only allow a single decimal point. break; decimal = i; continue; case 'e': case 'E': if (exponent != -1) { break; } else if (i == len - 1) { break; } exponent = i; continue; case '+': case '-': // Only allow '+' or '-' after 'e' or 'E' if (exponent != i-1) { break; } else if (i == len - 1) { --i; break; } continue; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (exponent != -1) { exponentValid = true; } continue; default: break; } break; } if (exponent != -1 && !exponentValid) { i = exponent; } s = s.substring(start, i); try { return Double.valueOf(s); } catch (NumberFormatException ex) { return ScriptRuntime.NaNobj; } } /** * The global method escape, as per ECMA-262 15.1.2.4. * Includes code for the 'mask' argument supported by the C escape * method, which used to be part of the browser imbedding. Blame * for the strange constant names should be directed there. */ private Object js_escape(Object[] args) { final int URL_XALPHAS = 1, URL_XPALPHAS = 2, URL_PATH = 4; String s = ScriptRuntime.toString(args, 0); int mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH; if (args.length > 1) { // the 'mask' argument. Non-ECMA. double d = ScriptRuntime.toNumber(args[1]); if (d != d || ((mask = (int) d) != d) || 0 != (mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))) { throw Context.reportRuntimeError0("msg.bad.esc.mask"); } } StringBuffer sb = null; for (int k = 0, L = s.length(); k != L; ++k) { int c = s.charAt(k); if (mask != 0 && ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '@' || c == '*' || c == '_' || c == '-' || c == '.' || (0 != (mask & URL_PATH) && (c == '/' || c == '+')))) { if (sb != null) { sb.append((char)c); } } else { if (sb == null) { sb = new StringBuffer(L + 3); sb.append(s); sb.setLength(k); } int hexSize; if (c < 256) { if (c == ' ' && mask == URL_XPALPHAS) { sb.append('+'); continue; } sb.append('%'); hexSize = 2; } else { sb.append('%'); sb.append('u'); hexSize = 4; } // append hexadecimal form of c left-padded with 0 for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) { int digit = 0xf & (c >> shift); int hc = (digit < 10) ? '0' + digit : 'A' - 10 + digit; sb.append((char)hc); } } } return (sb == null) ? s : sb.toString(); } /** * The global unescape method, as per ECMA-262 15.1.2.5. */ private Object js_unescape(Object[] args) { String s = ScriptRuntime.toString(args, 0); int firstEscapePos = s.indexOf('%'); if (firstEscapePos >= 0) { int L = s.length(); char[] buf = s.toCharArray(); int destination = firstEscapePos; for (int k = firstEscapePos; k != L;) { char c = buf[k]; ++k; if (c == '%' && k != L) { int end, start; if (buf[k] == 'u') { start = k + 1; end = k + 5; } else { start = k; end = k + 2; } if (end <= L) { int x = 0; for (int i = start; i != end; ++i) { x = Kit.xDigitToInt(buf[i], x); } if (x >= 0) { c = (char)x; k = end; } } } buf[destination] = c; ++destination; } s = new String(buf, 0, destination); } return s; } /** * This is an indirect call to eval, and thus uses the global environment. * Direct calls are executed via ScriptRuntime.callSpecial(). */ private Object js_eval(Context cx, Scriptable scope, Object[] args) { Scriptable global = ScriptableObject.getTopLevelScope(scope); return ScriptRuntime.evalSpecial(cx, global, global, args, "eval code", 1); } static boolean isEvalFunction(Object functionObj) { if (functionObj instanceof IdFunctionObject) { IdFunctionObject function = (IdFunctionObject)functionObj; if (function.hasTag(FTAG) && function.methodId() == Id_eval) { return true; } } return false; } /** * @deprecated Use {@link ScriptRuntime#constructError(String,String)} * instead. */ public static EcmaError constructError(Context cx, String error, String message, Scriptable scope) { return ScriptRuntime.constructError(error, message); } /** * @deprecated Use * {@link ScriptRuntime#constructError(String,String,String,int,String,int)} * instead. */ public static EcmaError constructError(Context cx, String error, String message, Scriptable scope, String sourceName, int lineNumber, int columnNumber, String lineSource) { return ScriptRuntime.constructError(error, message, sourceName, lineNumber, lineSource, columnNumber); } /* * ECMA 3, 15.1.3 URI Handling Function Properties * * The following are implementations of the algorithms * given in the ECMA specification for the hidden functions * 'Encode' and 'Decode'. */ private static String encode(String str, boolean fullUri) { byte[] utf8buf = null; StringBuffer sb = null; for (int k = 0, length = str.length(); k != length; ++k) { char C = str.charAt(k); if (encodeUnescaped(C, fullUri)) { if (sb != null) { sb.append(C); } } else { if (sb == null) { sb = new StringBuffer(length + 3); sb.append(str); sb.setLength(k); utf8buf = new byte[6]; } if (0xDC00 <= C && C <= 0xDFFF) { throw uriError(); } int V; if (C < 0xD800 || 0xDBFF < C) { V = C; } else { k++; if (k == length) { throw uriError(); } char C2 = str.charAt(k); if (!(0xDC00 <= C2 && C2 <= 0xDFFF)) { throw uriError(); } V = ((C - 0xD800) << 10) + (C2 - 0xDC00) + 0x10000; } int L = oneUcs4ToUtf8Char(utf8buf, V); for (int j = 0; j < L; j++) { int d = 0xff & utf8buf[j]; sb.append('%'); sb.append(toHexChar(d >>> 4)); sb.append(toHexChar(d & 0xf)); } } } return (sb == null) ? str : sb.toString(); } private static char toHexChar(int i) { if (i >> 4 != 0) Kit.codeBug(); return (char)((i < 10) ? i + '0' : i - 10 + 'A'); } private static int unHex(char c) { if ('A' <= c && c <= 'F') { return c - 'A' + 10; } else if ('a' <= c && c <= 'f') { return c - 'a' + 10; } else if ('0' <= c && c <= '9') { return c - '0'; } else { return -1; } } private static int unHex(char c1, char c2) { int i1 = unHex(c1); int i2 = unHex(c2); if (i1 >= 0 && i2 >= 0) { return (i1 << 4) | i2; } return -1; } private static String decode(String str, boolean fullUri) { char[] buf = null; int bufTop = 0; for (int k = 0, length = str.length(); k != length;) { char C = str.charAt(k); if (C != '%') { if (buf != null) { buf[bufTop++] = C; } ++k; } else { if (buf == null) { // decode always compress so result can not be bigger then // str.length() buf = new char[length]; str.getChars(0, k, buf, 0); bufTop = k; } int start = k; if (k + 3 > length) throw uriError(); int B = unHex(str.charAt(k + 1), str.charAt(k + 2)); if (B < 0) throw uriError(); k += 3; if ((B & 0x80) == 0) { C = (char)B; } else { // Decode UTF-8 sequence into ucs4Char and encode it into // UTF-16 int utf8Tail, ucs4Char, minUcs4Char; if ((B & 0xC0) == 0x80) { // First UTF-8 should be ouside 0x80..0xBF throw uriError(); } else if ((B & 0x20) == 0) { utf8Tail = 1; ucs4Char = B & 0x1F; minUcs4Char = 0x80; } else if ((B & 0x10) == 0) { utf8Tail = 2; ucs4Char = B & 0x0F; minUcs4Char = 0x800; } else if ((B & 0x08) == 0) { utf8Tail = 3; ucs4Char = B & 0x07; minUcs4Char = 0x10000; } else if ((B & 0x04) == 0) { utf8Tail = 4; ucs4Char = B & 0x03; minUcs4Char = 0x200000; } else if ((B & 0x02) == 0) { utf8Tail = 5; ucs4Char = B & 0x01; minUcs4Char = 0x4000000; } else { // First UTF-8 can not be 0xFF or 0xFE throw uriError(); } if (k + 3 * utf8Tail > length) throw uriError(); for (int j = 0; j != utf8Tail; j++) { if (str.charAt(k) != '%') throw uriError(); B = unHex(str.charAt(k + 1), str.charAt(k + 2)); if (B < 0 || (B & 0xC0) != 0x80) throw uriError(); ucs4Char = (ucs4Char << 6) | (B & 0x3F); k += 3; } // Check for overlongs and other should-not-present codes if (ucs4Char < minUcs4Char || (ucs4Char >= 0xD800 && ucs4Char <= 0xDFFF)) { ucs4Char = INVALID_UTF8; } else if (ucs4Char == 0xFFFE || ucs4Char == 0xFFFF) { ucs4Char = 0xFFFD; } if (ucs4Char >= 0x10000) { ucs4Char -= 0x10000; if (ucs4Char > 0xFFFFF) { throw uriError(); } char H = (char)((ucs4Char >>> 10) + 0xD800); C = (char)((ucs4Char & 0x3FF) + 0xDC00); buf[bufTop++] = H; } else { C = (char)ucs4Char; } } if (fullUri && URI_DECODE_RESERVED.indexOf(C) >= 0) { for (int x = start; x != k; x++) { buf[bufTop++] = str.charAt(x); } } else { buf[bufTop++] = C; } } } return (buf == null) ? str : new String(buf, 0, bufTop); } private static boolean encodeUnescaped(char c, boolean fullUri) { if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9')) { return true; } if ("-_.!~*'()".indexOf(c) >= 0) { return true; } if (fullUri) { return URI_DECODE_RESERVED.indexOf(c) >= 0; } return false; } private static EcmaError uriError() { return ScriptRuntime.constructError("URIError", ScriptRuntime.getMessage0("msg.bad.uri")); } private static final String URI_DECODE_RESERVED = ";/?:@&=+$,#"; private static final int INVALID_UTF8 = Integer.MAX_VALUE; /* Convert one UCS-4 char and write it into a UTF-8 buffer, which must be * at least 6 bytes long. Return the number of UTF-8 bytes of data written. */ private static int oneUcs4ToUtf8Char(byte[] utf8Buffer, int ucs4Char) { int utf8Length = 1; //JS_ASSERT(ucs4Char <= 0x7FFFFFFF); if ((ucs4Char & ~0x7F) == 0) utf8Buffer[0] = (byte)ucs4Char; else { int i; int a = ucs4Char >>> 11; utf8Length = 2; while (a != 0) { a >>>= 5; utf8Length++; } i = utf8Length; while (--i > 0) { utf8Buffer[i] = (byte)((ucs4Char & 0x3F) | 0x80); ucs4Char >>>= 6; } utf8Buffer[0] = (byte)(0x100 - (1 << (8-utf8Length)) + ucs4Char); } return utf8Length; } private static final Object FTAG = "Global"; private static final int Id_decodeURI = 1, Id_decodeURIComponent = 2, Id_encodeURI = 3, Id_encodeURIComponent = 4, Id_escape = 5, Id_eval = 6, Id_isFinite = 7, Id_isNaN = 8, Id_isXMLName = 9, Id_parseFloat = 10, Id_parseInt = 11, Id_unescape = 12, Id_uneval = 13, LAST_SCOPE_FUNCTION_ID = 13, Id_new_CommonError = 14; } rhino-1.7R4/src/org/mozilla/javascript/NativeIterator.java000066400000000000000000000206601176760007500237210ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.util.Iterator; /** * This class implements iterator objects. See * http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7#Iterators * * @author Norris Boyd */ public final class NativeIterator extends IdScriptableObject { private static final long serialVersionUID = -4136968203581667681L; private static final Object ITERATOR_TAG = "Iterator"; static void init(ScriptableObject scope, boolean sealed) { // Iterator NativeIterator iterator = new NativeIterator(); iterator.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); // Generator NativeGenerator.init(scope, sealed); // StopIteration NativeObject obj = new StopIteration(); obj.setPrototype(getObjectPrototype(scope)); obj.setParentScope(scope); if (sealed) { obj.sealObject(); } ScriptableObject.defineProperty(scope, STOP_ITERATION, obj, ScriptableObject.DONTENUM); // Use "associateValue" so that generators can continue to // throw StopIteration even if the property of the global // scope is replaced or deleted. scope.associateValue(ITERATOR_TAG, obj); } /** * Only for constructing the prototype object. */ private NativeIterator() { } private NativeIterator(Object objectIterator) { this.objectIterator = objectIterator; } /** * Get the value of the "StopIteration" object. Note that this value * is stored in the top-level scope using "associateValue" so the * value can still be found even if a script overwrites or deletes * the global "StopIteration" property. * @param scope a scope whose parent chain reaches a top-level scope * @return the StopIteration object */ public static Object getStopIterationObject(Scriptable scope) { Scriptable top = ScriptableObject.getTopLevelScope(scope); return ScriptableObject.getTopScopeValue(top, ITERATOR_TAG); } private static final String STOP_ITERATION = "StopIteration"; public static final String ITERATOR_PROPERTY_NAME = "__iterator__"; static class StopIteration extends NativeObject { private static final long serialVersionUID = 2485151085722377663L; @Override public String getClassName() { return STOP_ITERATION; } /* StopIteration has custom instanceof behavior since it * doesn't have a constructor. */ @Override public boolean hasInstance(Scriptable instance) { return instance instanceof StopIteration; } } @Override public String getClassName() { return "Iterator"; } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=2; s="constructor"; break; case Id_next: arity=0; s="next"; break; case Id___iterator__: arity=1; s=ITERATOR_PROPERTY_NAME; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(ITERATOR_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(ITERATOR_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); if (id == Id_constructor) { return jsConstructor(cx, scope, thisObj, args); } if (!(thisObj instanceof NativeIterator)) throw incompatibleCallError(f); NativeIterator iterator = (NativeIterator) thisObj; switch (id) { case Id_next: return iterator.next(cx, scope); case Id___iterator__: /// XXX: what about argument? SpiderMonkey apparently ignores it return thisObj; default: throw new IllegalArgumentException(String.valueOf(id)); } } /* The JavaScript constructor */ private static Object jsConstructor(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (args.length == 0 || args[0] == null || args[0] == Undefined.instance) { Object argument = args.length == 0 ? Undefined.instance : args[0]; throw ScriptRuntime.typeError1("msg.no.properties", ScriptRuntime.toString(argument)); } Scriptable obj = ScriptRuntime.toObject(scope, args[0]); boolean keyOnly = args.length > 1 && ScriptRuntime.toBoolean(args[1]); if (thisObj != null) { // Called as a function. Convert to iterator if possible. // For objects that implement java.lang.Iterable or // java.util.Iterator, have JavaScript Iterator call the underlying // iteration methods Iterator iterator = VMBridge.instance.getJavaIterator(cx, scope, obj); if (iterator != null) { scope = ScriptableObject.getTopLevelScope(scope); return cx.getWrapFactory().wrap(cx, scope, new WrappedJavaIterator(iterator, scope), WrappedJavaIterator.class); } // Otherwise, just call the runtime routine Scriptable jsIterator = ScriptRuntime.toIterator(cx, scope, obj, keyOnly); if (jsIterator != null) { return jsIterator; } } // Otherwise, just set up to iterate over the properties of the object. // Do not call __iterator__ method. Object objectIterator = ScriptRuntime.enumInit(obj, cx, keyOnly ? ScriptRuntime.ENUMERATE_KEYS_NO_ITERATOR : ScriptRuntime.ENUMERATE_ARRAY_NO_ITERATOR); ScriptRuntime.setEnumNumbers(objectIterator, true); NativeIterator result = new NativeIterator(objectIterator); result.setPrototype(ScriptableObject.getClassPrototype(scope, result.getClassName())); result.setParentScope(scope); return result; } private Object next(Context cx, Scriptable scope) { Boolean b = ScriptRuntime.enumNext(this.objectIterator); if (!b.booleanValue()) { // Out of values. Throw StopIteration. throw new JavaScriptException( NativeIterator.getStopIterationObject(scope), null, 0); } return ScriptRuntime.enumId(this.objectIterator, cx); } static public class WrappedJavaIterator { WrappedJavaIterator(Iterator iterator, Scriptable scope) { this.iterator = iterator; this.scope = scope; } public Object next() { if (!iterator.hasNext()) { // Out of values. Throw StopIteration. throw new JavaScriptException( NativeIterator.getStopIterationObject(scope), null, 0); } return iterator.next(); } public Object __iterator__(boolean b) { return this; } private Iterator iterator; private Scriptable scope; } // #string_id_map# @Override protected int findPrototypeId(String s) { int id; // #generated# Last update: 2007-06-11 09:43:19 EDT L0: { id = 0; String X = null; int s_length = s.length(); if (s_length==4) { X="next";id=Id_next; } else if (s_length==11) { X="constructor";id=Id_constructor; } else if (s_length==12) { X="__iterator__";id=Id___iterator__; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# return id; } private static final int Id_constructor = 1, Id_next = 2, Id___iterator__ = 3, MAX_PROTOTYPE_ID = 3; // #/string_id_map# private Object objectIterator; } rhino-1.7R4/src/org/mozilla/javascript/NativeJSON.java000066400000000000000000000376411176760007500227100ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import org.mozilla.javascript.json.JsonParser; import java.util.Stack; import java.util.Collection; import java.util.Iterator; import java.util.Arrays; import java.util.List; import java.util.LinkedList; /** * This class implements the JSON native object. * See ECMA 15.12. * @author Matthew Crumley, Raphael Speyer */ public final class NativeJSON extends IdScriptableObject { static final long serialVersionUID = -4567599697595654984L; private static final Object JSON_TAG = "JSON"; private static final int MAX_STRINGIFY_GAP_LENGTH = 10; static void init(Scriptable scope, boolean sealed) { NativeJSON obj = new NativeJSON(); obj.activatePrototypeMap(MAX_ID); obj.setPrototype(getObjectPrototype(scope)); obj.setParentScope(scope); if (sealed) { obj.sealObject(); } ScriptableObject.defineProperty(scope, "JSON", obj, ScriptableObject.DONTENUM); } private NativeJSON() { } @Override public String getClassName() { return "JSON"; } @Override protected void initPrototypeId(int id) { if (id <= LAST_METHOD_ID) { String name; int arity; switch (id) { case Id_toSource: arity = 0; name = "toSource"; break; case Id_parse: arity = 2; name = "parse"; break; case Id_stringify: arity = 3; name = "stringify"; break; default: throw new IllegalStateException(String.valueOf(id)); } initPrototypeMethod(JSON_TAG, id, name, arity); } else { throw new IllegalStateException(String.valueOf(id)); } } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(JSON_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int methodId = f.methodId(); switch (methodId) { case Id_toSource: return "JSON"; case Id_parse: { String jtext = ScriptRuntime.toString(args, 0); Object reviver = null; if (args.length > 1) { reviver = args[1]; } if (reviver instanceof Callable) { return parse(cx, scope, jtext, (Callable) reviver); } else { return parse(cx, scope, jtext); } } case Id_stringify: { Object value = null, replacer = null, space = null; switch (args.length) { default: case 3: space = args[2]; case 2: replacer = args[1]; case 1: value = args[0]; case 0: } return stringify(cx, scope, value, replacer, space); } default: throw new IllegalStateException(String.valueOf(methodId)); } } private static Object parse(Context cx, Scriptable scope, String jtext) { try { return new JsonParser(cx, scope).parseValue(jtext); } catch (JsonParser.ParseException ex) { throw ScriptRuntime.constructError("SyntaxError", ex.getMessage()); } } public static Object parse(Context cx, Scriptable scope, String jtext, Callable reviver) { Object unfiltered = parse(cx, scope, jtext); Scriptable root = cx.newObject(scope); root.put("", root, unfiltered); return walk(cx, scope, reviver, root, ""); } private static Object walk(Context cx, Scriptable scope, Callable reviver, Scriptable holder, Object name) { final Object property; if (name instanceof Number) { property = holder.get( ((Number) name).intValue(), holder); } else { property = holder.get( ((String) name), holder); } if (property instanceof Scriptable) { Scriptable val = ((Scriptable) property); if (val instanceof NativeArray) { int len = (int) ((NativeArray) val).getLength(); for (int i = 0; i < len; i++) { Object newElement = walk(cx, scope, reviver, val, i); if (newElement == Undefined.instance) { val.delete(i); } else { val.put(i, val, newElement); } } } else { Object[] keys = val.getIds(); for (Object p : keys) { Object newElement = walk(cx, scope, reviver, val, p); if (newElement == Undefined.instance) { if (p instanceof Number) val.delete(((Number) p).intValue()); else val.delete((String) p); } else { if (p instanceof Number) val.put(((Number) p).intValue(), val, newElement); else val.put((String) p, val, newElement); } } } } return reviver.call(cx, scope, holder, new Object[] { name, property }); } private static String repeat(char c, int count) { char chars[] = new char[count]; Arrays.fill(chars, c); return new String(chars); } private static class StringifyState { StringifyState(Context cx, Scriptable scope, String indent, String gap, Callable replacer, List propertyList, Object space) { this.cx = cx; this.scope = scope; this.indent = indent; this.gap = gap; this.replacer = replacer; this.propertyList = propertyList; this.space = space; } Stack stack = new Stack(); String indent; String gap; Callable replacer; List propertyList; Object space; Context cx; Scriptable scope; } public static Object stringify(Context cx, Scriptable scope, Object value, Object replacer, Object space) { String indent = ""; String gap = ""; List propertyList = null; Callable replacerFunction = null; if (replacer instanceof Callable) { replacerFunction = (Callable) replacer; } else if (replacer instanceof NativeArray) { propertyList = new LinkedList(); NativeArray replacerArray = (NativeArray) replacer; for (int i : replacerArray.getIndexIds()) { Object v = replacerArray.get(i, replacerArray); if (v instanceof String || v instanceof Number) { propertyList.add(v); } else if (v instanceof NativeString || v instanceof NativeNumber) { propertyList.add(ScriptRuntime.toString(v)); } } } if (space instanceof NativeNumber) { space = ScriptRuntime.toNumber(space); } else if (space instanceof NativeString) { space = ScriptRuntime.toString(space); } if (space instanceof Number) { int gapLength = (int) ScriptRuntime.toInteger(space); gapLength = Math.min(MAX_STRINGIFY_GAP_LENGTH, gapLength); gap = (gapLength > 0) ? repeat(' ', gapLength) : ""; space = gapLength; } else if (space instanceof String) { gap = (String) space; if (gap.length() > MAX_STRINGIFY_GAP_LENGTH) { gap = gap.substring(0, MAX_STRINGIFY_GAP_LENGTH); } } StringifyState state = new StringifyState(cx, scope, indent, gap, replacerFunction, propertyList, space); ScriptableObject wrapper = new NativeObject(); wrapper.setParentScope(scope); wrapper.setPrototype(ScriptableObject.getObjectPrototype(scope)); wrapper.defineProperty("", value, 0); return str("", wrapper, state); } private static Object str(Object key, Scriptable holder, StringifyState state) { Object value = null; if (key instanceof String) { value = getProperty(holder, (String) key); } else { value = getProperty(holder, ((Number) key).intValue()); } if (value instanceof Scriptable) { Object toJSON = getProperty((Scriptable) value, "toJSON"); if (toJSON instanceof Callable) { value = callMethod(state.cx, (Scriptable) value, "toJSON", new Object[] { key }); } } if (state.replacer != null) { value = state.replacer.call(state.cx, state.scope, holder, new Object[] { key, value }); } if (value instanceof NativeNumber) { value = ScriptRuntime.toNumber(value); } else if (value instanceof NativeString) { value = ScriptRuntime.toString(value); } else if (value instanceof NativeBoolean) { value = ((NativeBoolean) value).getDefaultValue(ScriptRuntime.BooleanClass); } if (value == null) return "null"; if (value.equals(Boolean.TRUE)) return "true"; if (value.equals(Boolean.FALSE)) return "false"; if (value instanceof CharSequence) { return quote(value.toString()); } if (value instanceof Number) { double d = ((Number) value).doubleValue(); if (d == d && d != Double.POSITIVE_INFINITY && d != Double.NEGATIVE_INFINITY) { return ScriptRuntime.toString(value); } else { return "null"; } } if (value instanceof Scriptable && !(value instanceof Callable)) { if (value instanceof NativeArray) { return ja((NativeArray) value, state); } return jo((Scriptable) value, state); } return Undefined.instance; } private static String join(Collection objs, String delimiter) { if (objs == null || objs.isEmpty()) { return ""; } Iterator iter = objs.iterator(); if (!iter.hasNext()) return ""; StringBuilder builder = new StringBuilder(iter.next().toString()); while (iter.hasNext()) { builder.append(delimiter).append(iter.next().toString()); } return builder.toString(); } private static String jo(Scriptable value, StringifyState state) { if (state.stack.search(value) != -1) { throw ScriptRuntime.typeError0("msg.cyclic.value"); } state.stack.push(value); String stepback = state.indent; state.indent = state.indent + state.gap; Object[] k = null; if (state.propertyList != null) { k = state.propertyList.toArray(); } else { k = value.getIds(); } List partial = new LinkedList(); for (Object p : k) { Object strP = str(p, value, state); if (strP != Undefined.instance) { String member = quote(p.toString()) + ":"; if (state.gap.length() > 0) { member = member + " "; } member = member + strP; partial.add(member); } } final String finalValue; if (partial.isEmpty()) { finalValue = "{}"; } else { if (state.gap.length() == 0) { finalValue = '{' + join(partial, ",") + '}'; } else { String separator = ",\n" + state.indent; String properties = join(partial, separator); finalValue = "{\n" + state.indent + properties + '\n' + stepback + '}'; } } state.stack.pop(); state.indent = stepback; return finalValue; } private static String ja(NativeArray value, StringifyState state) { if (state.stack.search(value) != -1) { throw ScriptRuntime.typeError0("msg.cyclic.value"); } state.stack.push(value); String stepback = state.indent; state.indent = state.indent + state.gap; List partial = new LinkedList(); int len = (int) value.getLength(); for (int index = 0; index < len; index++) { Object strP = str(index, value, state); if (strP == Undefined.instance) { partial.add("null"); } else { partial.add(strP); } } final String finalValue; if (partial.isEmpty()) { finalValue = "[]"; } else { if (state.gap.length() == 0) { finalValue = '[' + join(partial, ",") + ']'; } else { String separator = ",\n" + state.indent; String properties = join(partial, separator); finalValue = "[\n" + state.indent + properties + '\n' + stepback + ']'; } } state.stack.pop(); state.indent = stepback; return finalValue; } private static String quote(String string) { StringBuffer product = new StringBuffer(string.length()+2); // two extra chars for " on either side product.append('"'); int length = string.length(); for (int i = 0; i < length; i++) { char c = string.charAt(i); switch (c) { case '"': product.append("\\\""); break; case '\\': product.append("\\\\"); break; case '\b': product.append("\\b"); break; case '\f': product.append("\\f"); break; case '\n': product.append("\\n"); break; case '\r': product.append("\\r"); break; case '\t': product.append("\\t"); break; default: if (c < ' ') { product.append("\\u"); String hex = String.format("%04x", (int) c); product.append(hex); } else { product.append(c); } break; } } product.append('"'); return product.toString(); } // #string_id_map# @Override protected int findPrototypeId(String s) { int id; // #generated# Last update: 2009-05-25 16:01:00 EDT { id = 0; String X = null; L: switch (s.length()) { case 5: X="parse";id=Id_parse; break L; case 8: X="toSource";id=Id_toSource; break L; case 9: X="stringify";id=Id_stringify; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# return id; } private static final int Id_toSource = 1, Id_parse = 2, Id_stringify = 3, LAST_METHOD_ID = 3, MAX_ID = 3; // #/string_id_map# } rhino-1.7R4/src/org/mozilla/javascript/NativeJavaArray.java000066400000000000000000000100411176760007500240000ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.lang.reflect.Array; /** * This class reflects Java arrays into the JavaScript environment. * * @author Mike Shaver * @see NativeJavaClass * @see NativeJavaObject * @see NativeJavaPackage */ public class NativeJavaArray extends NativeJavaObject { static final long serialVersionUID = -924022554283675333L; @Override public String getClassName() { return "JavaArray"; } public static NativeJavaArray wrap(Scriptable scope, Object array) { return new NativeJavaArray(scope, array); } @Override public Object unwrap() { return array; } public NativeJavaArray(Scriptable scope, Object array) { super(scope, null, ScriptRuntime.ObjectClass); Class cl = array.getClass(); if (!cl.isArray()) { throw new RuntimeException("Array expected"); } this.array = array; this.length = Array.getLength(array); this.cls = cl.getComponentType(); } @Override public boolean has(String id, Scriptable start) { return id.equals("length") || super.has(id, start); } @Override public boolean has(int index, Scriptable start) { return 0 <= index && index < length; } @Override public Object get(String id, Scriptable start) { if (id.equals("length")) return Integer.valueOf(length); Object result = super.get(id, start); if (result == NOT_FOUND && !ScriptableObject.hasProperty(getPrototype(), id)) { throw Context.reportRuntimeError2( "msg.java.member.not.found", array.getClass().getName(), id); } return result; } @Override public Object get(int index, Scriptable start) { if (0 <= index && index < length) { Context cx = Context.getContext(); Object obj = Array.get(array, index); return cx.getWrapFactory().wrap(cx, this, obj, cls); } return Undefined.instance; } @Override public void put(String id, Scriptable start, Object value) { // Ignore assignments to "length"--it's readonly. if (!id.equals("length")) throw Context.reportRuntimeError1( "msg.java.array.member.not.found", id); } @Override public void put(int index, Scriptable start, Object value) { if (0 <= index && index < length) { Array.set(array, index, Context.jsToJava(value, cls)); } else { throw Context.reportRuntimeError2( "msg.java.array.index.out.of.bounds", String.valueOf(index), String.valueOf(length - 1)); } } @Override public Object getDefaultValue(Class hint) { if (hint == null || hint == ScriptRuntime.StringClass) return array.toString(); if (hint == ScriptRuntime.BooleanClass) return Boolean.TRUE; if (hint == ScriptRuntime.NumberClass) return ScriptRuntime.NaNobj; return this; } @Override public Object[] getIds() { Object[] result = new Object[length]; int i = length; while (--i >= 0) result[i] = Integer.valueOf(i); return result; } @Override public boolean hasInstance(Scriptable value) { if (!(value instanceof Wrapper)) return false; Object instance = ((Wrapper)value).unwrap(); return cls.isInstance(instance); } @Override public Scriptable getPrototype() { if (prototype == null) { prototype = ScriptableObject.getArrayPrototype(this.getParentScope()); } return prototype; } Object array; int length; Class cls; } rhino-1.7R4/src/org/mozilla/javascript/NativeJavaClass.java000066400000000000000000000267151176760007500240060ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.lang.reflect.*; import java.util.Map; /** * This class reflects Java classes into the JavaScript environment, mainly * for constructors and static members. We lazily reflect properties, * and currently do not guarantee that a single j.l.Class is only * reflected once into the JS environment, although we should. * The only known case where multiple reflections * are possible occurs when a j.l.Class is wrapped as part of a * method return or property access, rather than by walking the * Packages/java tree. * * @author Mike Shaver * @see NativeJavaArray * @see NativeJavaObject * @see NativeJavaPackage */ public class NativeJavaClass extends NativeJavaObject implements Function { static final long serialVersionUID = -6460763940409461664L; // Special property for getting the underlying Java class object. static final String javaClassPropertyName = "__javaObject__"; public NativeJavaClass() { } public NativeJavaClass(Scriptable scope, Class cl) { this(scope, cl, false); } public NativeJavaClass(Scriptable scope, Class cl, boolean isAdapter) { super(scope, cl, null, isAdapter); } @Override protected void initMembers() { Class cl = (Class)javaObject; members = JavaMembers.lookupClass(parent, cl, cl, isAdapter); staticFieldAndMethods = members.getFieldAndMethodsObjects(this, cl, true); } @Override public String getClassName() { return "JavaClass"; } @Override public boolean has(String name, Scriptable start) { return members.has(name, true) || javaClassPropertyName.equals(name); } @Override public Object get(String name, Scriptable start) { // When used as a constructor, ScriptRuntime.newObject() asks // for our prototype to create an object of the correct type. // We don't really care what the object is, since we're returning // one constructed out of whole cloth, so we return null. if (name.equals("prototype")) return null; if (staticFieldAndMethods != null) { Object result = staticFieldAndMethods.get(name); if (result != null) return result; } if (members.has(name, true)) { return members.get(this, name, javaObject, true); } Context cx = Context.getContext(); Scriptable scope = ScriptableObject.getTopLevelScope(start); WrapFactory wrapFactory = cx.getWrapFactory(); if (javaClassPropertyName.equals(name)) { return wrapFactory.wrap(cx, scope, javaObject, ScriptRuntime.ClassClass); } // experimental: look for nested classes by appending $name to // current class' name. Class nestedClass = findNestedClass(getClassObject(), name); if (nestedClass != null) { Scriptable nestedValue = wrapFactory.wrapJavaClass(cx, scope, nestedClass); nestedValue.setParentScope(this); return nestedValue; } throw members.reportMemberNotFound(name); } @Override public void put(String name, Scriptable start, Object value) { members.put(this, name, javaObject, value, true); } @Override public Object[] getIds() { return members.getIds(true); } public Class getClassObject() { return (Class) super.unwrap(); } @Override public Object getDefaultValue(Class hint) { if (hint == null || hint == ScriptRuntime.StringClass) return this.toString(); if (hint == ScriptRuntime.BooleanClass) return Boolean.TRUE; if (hint == ScriptRuntime.NumberClass) return ScriptRuntime.NaNobj; return this; } public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { // If it looks like a "cast" of an object to this class type, // walk the prototype chain to see if there's a wrapper of a // object that's an instanceof this class. if (args.length == 1 && args[0] instanceof Scriptable) { Class c = getClassObject(); Scriptable p = (Scriptable) args[0]; do { if (p instanceof Wrapper) { Object o = ((Wrapper) p).unwrap(); if (c.isInstance(o)) return p; } p = p.getPrototype(); } while (p != null); } return construct(cx, scope, args); } public Scriptable construct(Context cx, Scriptable scope, Object[] args) { Class classObject = getClassObject(); int modifiers = classObject.getModifiers(); if (! (Modifier.isInterface(modifiers) || Modifier.isAbstract(modifiers))) { NativeJavaMethod ctors = members.ctors; int index = ctors.findCachedFunction(cx, args); if (index < 0) { String sig = NativeJavaMethod.scriptSignature(args); throw Context.reportRuntimeError2( "msg.no.java.ctor", classObject.getName(), sig); } // Found the constructor, so try invoking it. return constructSpecific(cx, scope, args, ctors.methods[index]); } else { if (args.length == 0) { throw Context.reportRuntimeError0("msg.adapter.zero.args"); } Scriptable topLevel = ScriptableObject.getTopLevelScope(this); String msg = ""; try { // When running on Android create an InterfaceAdapter since our // bytecode generation won't work on Dalvik VM. if ("Dalvik".equals(System.getProperty("java.vm.name")) && classObject.isInterface()) { Object obj = createInterfaceAdapter(classObject, ScriptableObject.ensureScriptableObject(args[0])); return cx.getWrapFactory().wrapAsJavaObject(cx, scope, obj, null); } // use JavaAdapter to construct a new class on the fly that // implements/extends this interface/abstract class. Object v = topLevel.get("JavaAdapter", topLevel); if (v != NOT_FOUND) { Function f = (Function) v; // Args are (interface, js object) Object[] adapterArgs = { this, args[0] }; return f.construct(cx, topLevel, adapterArgs); } } catch (Exception ex) { // fall through to error String m = ex.getMessage(); if (m != null) msg = m; } throw Context.reportRuntimeError2( "msg.cant.instantiate", msg, classObject.getName()); } } static Scriptable constructSpecific(Context cx, Scriptable scope, Object[] args, MemberBox ctor) { Object instance = constructInternal(args, ctor); // we need to force this to be wrapped, because construct _has_ // to return a scriptable Scriptable topLevel = ScriptableObject.getTopLevelScope(scope); return cx.getWrapFactory().wrapNewObject(cx, topLevel, instance); } static Object constructInternal(Object[] args, MemberBox ctor) { Class[] argTypes = ctor.argTypes; if (ctor.vararg) { // marshall the explicit parameter Object[] newArgs = new Object[argTypes.length]; for (int i = 0; i < argTypes.length-1; i++) { newArgs[i] = Context.jsToJava(args[i], argTypes[i]); } Object varArgs; // Handle special situation where a single variable parameter // is given and it is a Java or ECMA array. if (args.length == argTypes.length && (args[args.length-1] == null || args[args.length-1] instanceof NativeArray || args[args.length-1] instanceof NativeJavaArray)) { // convert the ECMA array into a native array varArgs = Context.jsToJava(args[args.length-1], argTypes[argTypes.length - 1]); } else { // marshall the variable parameter Class componentType = argTypes[argTypes.length - 1]. getComponentType(); varArgs = Array.newInstance(componentType, args.length - argTypes.length + 1); for (int i=0; i < Array.getLength(varArgs); i++) { Object value = Context.jsToJava(args[argTypes.length-1 + i], componentType); Array.set(varArgs, i, value); } } // add varargs newArgs[argTypes.length-1] = varArgs; // replace the original args with the new one args = newArgs; } else { Object[] origArgs = args; for (int i = 0; i < args.length; i++) { Object arg = args[i]; Object x = Context.jsToJava(arg, argTypes[i]); if (x != arg) { if (args == origArgs) { args = origArgs.clone(); } args[i] = x; } } } return ctor.newInstance(args); } @Override public String toString() { return "[JavaClass " + getClassObject().getName() + "]"; } /** * Determines if prototype is a wrapped Java object and performs * a Java "instanceof". * Exception: if value is an instance of NativeJavaClass, it isn't * considered an instance of the Java class; this forestalls any * name conflicts between java.lang.Class's methods and the * static methods exposed by a JavaNativeClass. */ @Override public boolean hasInstance(Scriptable value) { if (value instanceof Wrapper && !(value instanceof NativeJavaClass)) { Object instance = ((Wrapper)value).unwrap(); return getClassObject().isInstance(instance); } // value wasn't something we understand return false; } private static Class findNestedClass(Class parentClass, String name) { String nestedClassName = parentClass.getName() + '$' + name; ClassLoader loader = parentClass.getClassLoader(); if (loader == null) { // ALERT: if loader is null, nested class should be loaded // via system class loader which can be different from the // loader that brought Rhino classes that Class.forName() would // use, but ClassLoader.getSystemClassLoader() is Java 2 only return Kit.classOrNull(nestedClassName); } else { return Kit.classOrNull(loader, nestedClassName); } } private Map staticFieldAndMethods; } rhino-1.7R4/src/org/mozilla/javascript/NativeJavaConstructor.java000066400000000000000000000027441176760007500252620ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * This class reflects a single Java constructor into the JavaScript * environment. It satisfies a request for an overloaded constructor, * as introduced in LiveConnect 3. * All NativeJavaConstructors behave as JSRef `bound' methods, in that they * always construct the same NativeJavaClass regardless of any reparenting * that may occur. * * @author Frank Mitchell * @see NativeJavaMethod * @see NativeJavaPackage * @see NativeJavaClass */ public class NativeJavaConstructor extends BaseFunction { static final long serialVersionUID = -8149253217482668463L; MemberBox ctor; public NativeJavaConstructor(MemberBox ctor) { this.ctor = ctor; } @Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { return NativeJavaClass.constructSpecific(cx, scope, args, ctor); } @Override public String getFunctionName() { String sig = JavaMembers.liveConnectSignature(ctor.argTypes); return "".concat(sig); } @Override public String toString() { return "[JavaConstructor " + ctor.getName() + "]"; } } rhino-1.7R4/src/org/mozilla/javascript/NativeJavaMethod.java000066400000000000000000000547001176760007500241540ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.lang.reflect.*; import java.util.Arrays; import java.util.LinkedList; /** * This class reflects Java methods into the JavaScript environment and * handles overloading of methods. * * @author Mike Shaver * @see NativeJavaArray * @see NativeJavaPackage * @see NativeJavaClass */ public class NativeJavaMethod extends BaseFunction { static final long serialVersionUID = -3440381785576412928L; NativeJavaMethod(MemberBox[] methods) { this.functionName = methods[0].getName(); this.methods = methods; } NativeJavaMethod(MemberBox[] methods, String name) { this.functionName = name; this.methods = methods; } NativeJavaMethod(MemberBox method, String name) { this.functionName = name; this.methods = new MemberBox[] { method }; } public NativeJavaMethod(Method method, String name) { this(new MemberBox(method), name); } @Override public String getFunctionName() { return functionName; } static String scriptSignature(Object[] values) { StringBuffer sig = new StringBuffer(); for (int i = 0; i != values.length; ++i) { Object value = values[i]; String s; if (value == null) { s = "null"; } else if (value instanceof Boolean) { s = "boolean"; } else if (value instanceof String) { s = "string"; } else if (value instanceof Number) { s = "number"; } else if (value instanceof Scriptable) { if (value instanceof Undefined) { s = "undefined"; } else if (value instanceof Wrapper) { Object wrapped = ((Wrapper)value).unwrap(); s = wrapped.getClass().getName(); } else if (value instanceof Function) { s = "function"; } else { s = "object"; } } else { s = JavaMembers.javaSignature(value.getClass()); } if (i != 0) { sig.append(','); } sig.append(s); } return sig.toString(); } @Override String decompile(int indent, int flags) { StringBuffer sb = new StringBuffer(); boolean justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG)); if (!justbody) { sb.append("function "); sb.append(getFunctionName()); sb.append("() {"); } sb.append("/*\n"); sb.append(toString()); sb.append(justbody ? "*/\n" : "*/}\n"); return sb.toString(); } @Override public String toString() { StringBuffer sb = new StringBuffer(); for (int i = 0, N = methods.length; i != N; ++i) { // Check member type, we also use this for overloaded constructors if (methods[i].isMethod()) { Method method = methods[i].method(); sb.append(JavaMembers.javaSignature(method.getReturnType())); sb.append(' '); sb.append(method.getName()); } else { sb.append(methods[i].getName()); } sb.append(JavaMembers.liveConnectSignature(methods[i].argTypes)); sb.append('\n'); } return sb.toString(); } @Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { // Find a method that matches the types given. if (methods.length == 0) { throw new RuntimeException("No methods defined for call"); } int index = findCachedFunction(cx, args); if (index < 0) { Class c = methods[0].method().getDeclaringClass(); String sig = c.getName() + '.' + getFunctionName() + '(' + scriptSignature(args) + ')'; throw Context.reportRuntimeError1("msg.java.no_such_method", sig); } MemberBox meth = methods[index]; Class[] argTypes = meth.argTypes; if (meth.vararg) { // marshall the explicit parameters Object[] newArgs = new Object[argTypes.length]; for (int i = 0; i < argTypes.length-1; i++) { newArgs[i] = Context.jsToJava(args[i], argTypes[i]); } Object varArgs; // Handle special situation where a single variable parameter // is given and it is a Java or ECMA array or is null. if (args.length == argTypes.length && (args[args.length-1] == null || args[args.length-1] instanceof NativeArray || args[args.length-1] instanceof NativeJavaArray)) { // convert the ECMA array into a native array varArgs = Context.jsToJava(args[args.length-1], argTypes[argTypes.length - 1]); } else { // marshall the variable parameters Class componentType = argTypes[argTypes.length - 1]. getComponentType(); varArgs = Array.newInstance(componentType, args.length - argTypes.length + 1); for (int i = 0; i < Array.getLength(varArgs); i++) { Object value = Context.jsToJava(args[argTypes.length-1 + i], componentType); Array.set(varArgs, i, value); } } // add varargs newArgs[argTypes.length-1] = varArgs; // replace the original args with the new one args = newArgs; } else { // First, we marshall the args. Object[] origArgs = args; for (int i = 0; i < args.length; i++) { Object arg = args[i]; Object coerced = Context.jsToJava(arg, argTypes[i]); if (coerced != arg) { if (origArgs == args) { args = args.clone(); } args[i] = coerced; } } } Object javaObject; if (meth.isStatic()) { javaObject = null; // don't need an object } else { Scriptable o = thisObj; Class c = meth.getDeclaringClass(); for (;;) { if (o == null) { throw Context.reportRuntimeError3( "msg.nonjava.method", getFunctionName(), ScriptRuntime.toString(thisObj), c.getName()); } if (o instanceof Wrapper) { javaObject = ((Wrapper)o).unwrap(); if (c.isInstance(javaObject)) { break; } } o = o.getPrototype(); } } if (debug) { printDebug("Calling ", meth, args); } Object retval = meth.invoke(javaObject, args); Class staticType = meth.method().getReturnType(); if (debug) { Class actualType = (retval == null) ? null : retval.getClass(); System.err.println(" ----- Returned " + retval + " actual = " + actualType + " expect = " + staticType); } Object wrapped = cx.getWrapFactory().wrap(cx, scope, retval, staticType); if (debug) { Class actualType = (wrapped == null) ? null : wrapped.getClass(); System.err.println(" ----- Wrapped as " + wrapped + " class = " + actualType); } if (wrapped == null && staticType == Void.TYPE) { wrapped = Undefined.instance; } return wrapped; } int findCachedFunction(Context cx, Object[] args) { if (methods.length > 1) { if (overloadCache != null) { for (ResolvedOverload ovl : overloadCache) { if (ovl.matches(args)) { return ovl.index; } } } else { overloadCache = new LinkedList(); } int index = findFunction(cx, methods, args); // As a sanity measure, don't let the lookup cache grow longer // than twice the number of overloaded methods if (overloadCache.size() < methods.length * 2) { synchronized (overloadCache) { ResolvedOverload ovl = new ResolvedOverload(args, index); if (!overloadCache.contains(ovl)) { overloadCache.addFirst(ovl); } } } return index; } return findFunction(cx, methods, args); } /** * Find the index of the correct function to call given the set of methods * or constructors and the arguments. * If no function can be found to call, return -1. */ static int findFunction(Context cx, MemberBox[] methodsOrCtors, Object[] args) { if (methodsOrCtors.length == 0) { return -1; } else if (methodsOrCtors.length == 1) { MemberBox member = methodsOrCtors[0]; Class[] argTypes = member.argTypes; int alength = argTypes.length; if (member.vararg) { alength--; if ( alength > args.length) { return -1; } } else { if (alength != args.length) { return -1; } } for (int j = 0; j != alength; ++j) { if (!NativeJavaObject.canConvert(args[j], argTypes[j])) { if (debug) printDebug("Rejecting (args can't convert) ", member, args); return -1; } } if (debug) printDebug("Found ", member, args); return 0; } int firstBestFit = -1; int[] extraBestFits = null; int extraBestFitsCount = 0; search: for (int i = 0; i < methodsOrCtors.length; i++) { MemberBox member = methodsOrCtors[i]; Class[] argTypes = member.argTypes; int alength = argTypes.length; if (member.vararg) { alength--; if ( alength > args.length) { continue search; } } else { if (alength != args.length) { continue search; } } for (int j = 0; j < alength; j++) { if (!NativeJavaObject.canConvert(args[j], argTypes[j])) { if (debug) printDebug("Rejecting (args can't convert) ", member, args); continue search; } } if (firstBestFit < 0) { if (debug) printDebug("Found first applicable ", member, args); firstBestFit = i; } else { // Compare with all currently fit methods. // The loop starts from -1 denoting firstBestFit and proceed // until extraBestFitsCount to avoid extraBestFits allocation // in the most common case of no ambiguity int betterCount = 0; // number of times member was prefered over // best fits int worseCount = 0; // number of times best fits were prefered // over member for (int j = -1; j != extraBestFitsCount; ++j) { int bestFitIndex; if (j == -1) { bestFitIndex = firstBestFit; } else { bestFitIndex = extraBestFits[j]; } MemberBox bestFit = methodsOrCtors[bestFitIndex]; if (cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS) && (bestFit.member().getModifiers() & Modifier.PUBLIC) != (member.member().getModifiers() & Modifier.PUBLIC)) { // When FEATURE_ENHANCED_JAVA_ACCESS gives us access // to non-public members, continue to prefer public // methods in overloading if ((bestFit.member().getModifiers() & Modifier.PUBLIC) == 0) ++betterCount; else ++worseCount; } else { int preference = preferSignature(args, argTypes, member.vararg, bestFit.argTypes, bestFit.vararg ); if (preference == PREFERENCE_AMBIGUOUS) { break; } else if (preference == PREFERENCE_FIRST_ARG) { ++betterCount; } else if (preference == PREFERENCE_SECOND_ARG) { ++worseCount; } else { if (preference != PREFERENCE_EQUAL) Kit.codeBug(); // This should not happen in theory // but on some JVMs, Class.getMethods will return all // static methods of the class hierarchy, even if // a derived class's parameters match exactly. // We want to call the derived class's method. if (bestFit.isStatic() && bestFit.getDeclaringClass().isAssignableFrom( member.getDeclaringClass())) { // On some JVMs, Class.getMethods will return all // static methods of the class hierarchy, even if // a derived class's parameters match exactly. // We want to call the derived class's method. if (debug) printDebug( "Substituting (overridden static)", member, args); if (j == -1) { firstBestFit = i; } else { extraBestFits[j] = i; } } else { if (debug) printDebug( "Ignoring same signature member ", member, args); } continue search; } } } if (betterCount == 1 + extraBestFitsCount) { // member was prefered over all best fits if (debug) printDebug( "New first applicable ", member, args); firstBestFit = i; extraBestFitsCount = 0; } else if (worseCount == 1 + extraBestFitsCount) { // all best fits were prefered over member, ignore it if (debug) printDebug( "Rejecting (all current bests better) ", member, args); } else { // some ambiguity was present, add member to best fit set if (debug) printDebug( "Added to best fit set ", member, args); if (extraBestFits == null) { // Allocate maximum possible array extraBestFits = new int[methodsOrCtors.length - 1]; } extraBestFits[extraBestFitsCount] = i; ++extraBestFitsCount; } } } if (firstBestFit < 0) { // Nothing was found return -1; } else if (extraBestFitsCount == 0) { // single best fit return firstBestFit; } // report remaining ambiguity StringBuffer buf = new StringBuffer(); for (int j = -1; j != extraBestFitsCount; ++j) { int bestFitIndex; if (j == -1) { bestFitIndex = firstBestFit; } else { bestFitIndex = extraBestFits[j]; } buf.append("\n "); buf.append(methodsOrCtors[bestFitIndex].toJavaDeclaration()); } MemberBox firstFitMember = methodsOrCtors[firstBestFit]; String memberName = firstFitMember.getName(); String memberClass = firstFitMember.getDeclaringClass().getName(); if (methodsOrCtors[0].isCtor()) { throw Context.reportRuntimeError3( "msg.constructor.ambiguous", memberName, scriptSignature(args), buf.toString()); } else { throw Context.reportRuntimeError4( "msg.method.ambiguous", memberClass, memberName, scriptSignature(args), buf.toString()); } } /** Types are equal */ private static final int PREFERENCE_EQUAL = 0; private static final int PREFERENCE_FIRST_ARG = 1; private static final int PREFERENCE_SECOND_ARG = 2; /** No clear "easy" conversion */ private static final int PREFERENCE_AMBIGUOUS = 3; /** * Determine which of two signatures is the closer fit. * Returns one of PREFERENCE_EQUAL, PREFERENCE_FIRST_ARG, * PREFERENCE_SECOND_ARG, or PREFERENCE_AMBIGUOUS. */ private static int preferSignature(Object[] args, Class[] sig1, boolean vararg1, Class[] sig2, boolean vararg2 ) { int totalPreference = 0; for (int j = 0; j < args.length; j++) { Class type1 = vararg1 && j >= sig1.length ? sig1[sig1.length-1] : sig1[j]; Class type2 = vararg2 && j >= sig2.length ? sig2[sig2.length-1] : sig2[j]; if (type1 == type2) { continue; } Object arg = args[j]; // Determine which of type1, type2 is easier to convert from arg. int rank1 = NativeJavaObject.getConversionWeight(arg, type1); int rank2 = NativeJavaObject.getConversionWeight(arg, type2); int preference; if (rank1 < rank2) { preference = PREFERENCE_FIRST_ARG; } else if (rank1 > rank2) { preference = PREFERENCE_SECOND_ARG; } else { // Equal ranks if (rank1 == NativeJavaObject.CONVERSION_NONTRIVIAL) { if (type1.isAssignableFrom(type2)) { preference = PREFERENCE_SECOND_ARG; } else if (type2.isAssignableFrom(type1)) { preference = PREFERENCE_FIRST_ARG; } else { preference = PREFERENCE_AMBIGUOUS; } } else { preference = PREFERENCE_AMBIGUOUS; } } totalPreference |= preference; if (totalPreference == PREFERENCE_AMBIGUOUS) { break; } } return totalPreference; } private static final boolean debug = false; private static void printDebug(String msg, MemberBox member, Object[] args) { if (debug) { StringBuffer sb = new StringBuffer(); sb.append(" ----- "); sb.append(msg); sb.append(member.getDeclaringClass().getName()); sb.append('.'); if (member.isMethod()) { sb.append(member.getName()); } sb.append(JavaMembers.liveConnectSignature(member.argTypes)); sb.append(" for arguments ("); sb.append(scriptSignature(args)); sb.append(')'); System.out.println(sb); } } MemberBox[] methods; private String functionName; private transient LinkedList overloadCache; } class ResolvedOverload { final Class[] types; final int index; ResolvedOverload(Object[] args, int index) { this.index = index; types = new Class[args.length]; for (int i = 0, l = args.length; i < l; i++) { Object arg = args[i]; if (arg instanceof Wrapper) arg = ((Wrapper)arg).unwrap(); types[i] = arg == null ? null : arg.getClass(); } } boolean matches(Object[] args) { if (args.length != types.length) { return false; } for (int i = 0, l = args.length; i < l; i++) { Object arg = args[i]; if (arg instanceof Wrapper) arg = ((Wrapper)arg).unwrap(); if (arg == null) { if (types[i] != null) return false; } else if (arg.getClass() != types[i]) { return false; } } return true; } @Override public boolean equals(Object other) { if (!(other instanceof ResolvedOverload)) { return false; } ResolvedOverload ovl = (ResolvedOverload) other; return Arrays.equals(types, ovl.types) && index == ovl.index; } @Override public int hashCode() { return Arrays.hashCode(types); } } rhino-1.7R4/src/org/mozilla/javascript/NativeJavaObject.java000066400000000000000000000773571176760007500241570ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.io.*; import java.lang.reflect.*; import java.util.Map; import java.util.Date; /** * This class reflects non-Array Java objects into the JavaScript environment. It * reflect fields directly, and uses NativeJavaMethod objects to reflect (possibly * overloaded) methods.

* * @author Mike Shaver * @see NativeJavaArray * @see NativeJavaPackage * @see NativeJavaClass */ public class NativeJavaObject implements Scriptable, Wrapper, Serializable { static final long serialVersionUID = -6948590651130498591L; public NativeJavaObject() { } public NativeJavaObject(Scriptable scope, Object javaObject, Class staticType) { this(scope, javaObject, staticType, false); } public NativeJavaObject(Scriptable scope, Object javaObject, Class staticType, boolean isAdapter) { this.parent = scope; this.javaObject = javaObject; this.staticType = staticType; this.isAdapter = isAdapter; initMembers(); } protected void initMembers() { Class dynamicType; if (javaObject != null) { dynamicType = javaObject.getClass(); } else { dynamicType = staticType; } members = JavaMembers.lookupClass(parent, dynamicType, staticType, isAdapter); fieldAndMethods = members.getFieldAndMethodsObjects(this, javaObject, false); } public boolean has(String name, Scriptable start) { return members.has(name, false); } public boolean has(int index, Scriptable start) { return false; } public Object get(String name, Scriptable start) { if (fieldAndMethods != null) { Object result = fieldAndMethods.get(name); if (result != null) { return result; } } // TODO: passing 'this' as the scope is bogus since it has // no parent scope return members.get(this, name, javaObject, false); } public Object get(int index, Scriptable start) { throw members.reportMemberNotFound(Integer.toString(index)); } public void put(String name, Scriptable start, Object value) { // We could be asked to modify the value of a property in the // prototype. Since we can't add a property to a Java object, // we modify it in the prototype rather than copy it down. if (prototype == null || members.has(name, false)) members.put(this, name, javaObject, value, false); else prototype.put(name, prototype, value); } public void put(int index, Scriptable start, Object value) { throw members.reportMemberNotFound(Integer.toString(index)); } public boolean hasInstance(Scriptable value) { // This is an instance of a Java class, so always return false return false; } public void delete(String name) { } public void delete(int index) { } public Scriptable getPrototype() { if (prototype == null && javaObject instanceof String) { return TopLevel.getBuiltinPrototype( ScriptableObject.getTopLevelScope(parent), TopLevel.Builtins.String); } return prototype; } /** * Sets the prototype of the object. */ public void setPrototype(Scriptable m) { prototype = m; } /** * Returns the parent (enclosing) scope of the object. */ public Scriptable getParentScope() { return parent; } /** * Sets the parent (enclosing) scope of the object. */ public void setParentScope(Scriptable m) { parent = m; } public Object[] getIds() { return members.getIds(false); } /** @deprecated Use {@link Context#getWrapFactory()} together with calling {@link WrapFactory#wrap(Context, Scriptable, Object, Class)} */ public static Object wrap(Scriptable scope, Object obj, Class staticType) { Context cx = Context.getContext(); return cx.getWrapFactory().wrap(cx, scope, obj, staticType); } public Object unwrap() { return javaObject; } public String getClassName() { return "JavaObject"; } public Object getDefaultValue(Class hint) { Object value; if (hint == null) { if (javaObject instanceof Boolean) { hint = ScriptRuntime.BooleanClass; } } if (hint == null || hint == ScriptRuntime.StringClass) { value = javaObject.toString(); } else { String converterName; if (hint == ScriptRuntime.BooleanClass) { converterName = "booleanValue"; } else if (hint == ScriptRuntime.NumberClass) { converterName = "doubleValue"; } else { throw Context.reportRuntimeError0("msg.default.value"); } Object converterObject = get(converterName, this); if (converterObject instanceof Function) { Function f = (Function)converterObject; value = f.call(Context.getContext(), f.getParentScope(), this, ScriptRuntime.emptyArgs); } else { if (hint == ScriptRuntime.NumberClass && javaObject instanceof Boolean) { boolean b = ((Boolean)javaObject).booleanValue(); value = ScriptRuntime.wrapNumber(b ? 1.0 : 0.0); } else { value = javaObject.toString(); } } } return value; } /** * Determine whether we can/should convert between the given type and the * desired one. This should be superceded by a conversion-cost calculation * function, but for now I'll hide behind precedent. */ public static boolean canConvert(Object fromObj, Class to) { int weight = getConversionWeight(fromObj, to); return (weight < CONVERSION_NONE); } private static final int JSTYPE_UNDEFINED = 0; // undefined type private static final int JSTYPE_NULL = 1; // null private static final int JSTYPE_BOOLEAN = 2; // boolean private static final int JSTYPE_NUMBER = 3; // number private static final int JSTYPE_STRING = 4; // string private static final int JSTYPE_JAVA_CLASS = 5; // JavaClass private static final int JSTYPE_JAVA_OBJECT = 6; // JavaObject private static final int JSTYPE_JAVA_ARRAY = 7; // JavaArray private static final int JSTYPE_OBJECT = 8; // Scriptable static final byte CONVERSION_TRIVIAL = 1; static final byte CONVERSION_NONTRIVIAL = 0; static final byte CONVERSION_NONE = 99; /** * Derive a ranking based on how "natural" the conversion is. * The special value CONVERSION_NONE means no conversion is possible, * and CONVERSION_NONTRIVIAL signals that more type conformance testing * is required. * Based on * * "preferred method conversions" from Live Connect 3 */ static int getConversionWeight(Object fromObj, Class to) { int fromCode = getJSTypeCode(fromObj); switch (fromCode) { case JSTYPE_UNDEFINED: if (to == ScriptRuntime.StringClass || to == ScriptRuntime.ObjectClass) { return 1; } break; case JSTYPE_NULL: if (!to.isPrimitive()) { return 1; } break; case JSTYPE_BOOLEAN: // "boolean" is #1 if (to == Boolean.TYPE) { return 1; } else if (to == ScriptRuntime.BooleanClass) { return 2; } else if (to == ScriptRuntime.ObjectClass) { return 3; } else if (to == ScriptRuntime.StringClass) { return 4; } break; case JSTYPE_NUMBER: if (to.isPrimitive()) { if (to == Double.TYPE) { return 1; } else if (to != Boolean.TYPE) { return 1 + getSizeRank(to); } } else { if (to == ScriptRuntime.StringClass) { // native numbers are #1-8 return 9; } else if (to == ScriptRuntime.ObjectClass) { return 10; } else if (ScriptRuntime.NumberClass.isAssignableFrom(to)) { // "double" is #1 return 2; } } break; case JSTYPE_STRING: if (to == ScriptRuntime.StringClass) { return 1; } else if (to.isInstance(fromObj)) { return 2; } else if (to.isPrimitive()) { if (to == Character.TYPE) { return 3; } else if (to != Boolean.TYPE) { return 4; } } break; case JSTYPE_JAVA_CLASS: if (to == ScriptRuntime.ClassClass) { return 1; } else if (to == ScriptRuntime.ObjectClass) { return 3; } else if (to == ScriptRuntime.StringClass) { return 4; } break; case JSTYPE_JAVA_OBJECT: case JSTYPE_JAVA_ARRAY: Object javaObj = fromObj; if (javaObj instanceof Wrapper) { javaObj = ((Wrapper)javaObj).unwrap(); } if (to.isInstance(javaObj)) { return CONVERSION_NONTRIVIAL; } if (to == ScriptRuntime.StringClass) { return 2; } else if (to.isPrimitive() && to != Boolean.TYPE) { return (fromCode == JSTYPE_JAVA_ARRAY) ? CONVERSION_NONE : 2 + getSizeRank(to); } break; case JSTYPE_OBJECT: // Other objects takes #1-#3 spots if (to != ScriptRuntime.ObjectClass && to.isInstance(fromObj)) { // No conversion required, but don't apply for java.lang.Object return 1; } if (to.isArray()) { if (fromObj instanceof NativeArray) { // This is a native array conversion to a java array // Array conversions are all equal, and preferable to object // and string conversion, per LC3. return 2; } } else if (to == ScriptRuntime.ObjectClass) { return 3; } else if (to == ScriptRuntime.StringClass) { return 4; } else if (to == ScriptRuntime.DateClass) { if (fromObj instanceof NativeDate) { // This is a native date to java date conversion return 1; } } else if (to.isInterface()) { if (fromObj instanceof NativeObject || fromObj instanceof NativeFunction) { // See comments in createInterfaceAdapter return 1; } return 12; } else if (to.isPrimitive() && to != Boolean.TYPE) { return 4 + getSizeRank(to); } break; } return CONVERSION_NONE; } static int getSizeRank(Class aType) { if (aType == Double.TYPE) { return 1; } else if (aType == Float.TYPE) { return 2; } else if (aType == Long.TYPE) { return 3; } else if (aType == Integer.TYPE) { return 4; } else if (aType == Short.TYPE) { return 5; } else if (aType == Character.TYPE) { return 6; } else if (aType == Byte.TYPE) { return 7; } else if (aType == Boolean.TYPE) { return CONVERSION_NONE; } else { return 8; } } private static int getJSTypeCode(Object value) { if (value == null) { return JSTYPE_NULL; } else if (value == Undefined.instance) { return JSTYPE_UNDEFINED; } else if (value instanceof CharSequence) { return JSTYPE_STRING; } else if (value instanceof Number) { return JSTYPE_NUMBER; } else if (value instanceof Boolean) { return JSTYPE_BOOLEAN; } else if (value instanceof Scriptable) { if (value instanceof NativeJavaClass) { return JSTYPE_JAVA_CLASS; } else if (value instanceof NativeJavaArray) { return JSTYPE_JAVA_ARRAY; } else if (value instanceof Wrapper) { return JSTYPE_JAVA_OBJECT; } else { return JSTYPE_OBJECT; } } else if (value instanceof Class) { return JSTYPE_JAVA_CLASS; } else { Class valueClass = value.getClass(); if (valueClass.isArray()) { return JSTYPE_JAVA_ARRAY; } else { return JSTYPE_JAVA_OBJECT; } } } /** * Not intended for public use. Callers should use the * public API Context.toType. * @deprecated as of 1.5 Release 4 * @see org.mozilla.javascript.Context#jsToJava(Object, Class) */ public static Object coerceType(Class type, Object value) { return coerceTypeImpl(type, value); } /** * Type-munging for field setting and method invocation. * Conforms to LC3 specification */ static Object coerceTypeImpl(Class type, Object value) { if (value != null && value.getClass() == type) { return value; } switch (getJSTypeCode(value)) { case JSTYPE_NULL: // raise error if type.isPrimitive() if (type.isPrimitive()) { reportConversionError(value, type); } return null; case JSTYPE_UNDEFINED: if (type == ScriptRuntime.StringClass || type == ScriptRuntime.ObjectClass) { return "undefined"; } else { reportConversionError("undefined", type); } break; case JSTYPE_BOOLEAN: // Under LC3, only JS Booleans can be coerced into a Boolean value if (type == Boolean.TYPE || type == ScriptRuntime.BooleanClass || type == ScriptRuntime.ObjectClass) { return value; } else if (type == ScriptRuntime.StringClass) { return value.toString(); } else { reportConversionError(value, type); } break; case JSTYPE_NUMBER: if (type == ScriptRuntime.StringClass) { return ScriptRuntime.toString(value); } else if (type == ScriptRuntime.ObjectClass) { return coerceToNumber(Double.TYPE, value); } else if ((type.isPrimitive() && type != Boolean.TYPE) || ScriptRuntime.NumberClass.isAssignableFrom(type)) { return coerceToNumber(type, value); } else { reportConversionError(value, type); } break; case JSTYPE_STRING: if (type == ScriptRuntime.StringClass || type.isInstance(value)) { return value.toString(); } else if (type == Character.TYPE || type == ScriptRuntime.CharacterClass) { // Special case for converting a single char string to a // character // Placed here because it applies *only* to JS strings, // not other JS objects converted to strings if (((CharSequence)value).length() == 1) { return Character.valueOf(((CharSequence)value).charAt(0)); } else { return coerceToNumber(type, value); } } else if ((type.isPrimitive() && type != Boolean.TYPE) || ScriptRuntime.NumberClass.isAssignableFrom(type)) { return coerceToNumber(type, value); } else { reportConversionError(value, type); } break; case JSTYPE_JAVA_CLASS: if (value instanceof Wrapper) { value = ((Wrapper)value).unwrap(); } if (type == ScriptRuntime.ClassClass || type == ScriptRuntime.ObjectClass) { return value; } else if (type == ScriptRuntime.StringClass) { return value.toString(); } else { reportConversionError(value, type); } break; case JSTYPE_JAVA_OBJECT: case JSTYPE_JAVA_ARRAY: if (value instanceof Wrapper) { value = ((Wrapper)value).unwrap(); } if (type.isPrimitive()) { if (type == Boolean.TYPE) { reportConversionError(value, type); } return coerceToNumber(type, value); } else { if (type == ScriptRuntime.StringClass) { return value.toString(); } else { if (type.isInstance(value)) { return value; } else { reportConversionError(value, type); } } } break; case JSTYPE_OBJECT: if (type == ScriptRuntime.StringClass) { return ScriptRuntime.toString(value); } else if (type.isPrimitive()) { if (type == Boolean.TYPE) { reportConversionError(value, type); } return coerceToNumber(type, value); } else if (type.isInstance(value)) { return value; } else if (type == ScriptRuntime.DateClass && value instanceof NativeDate) { double time = ((NativeDate)value).getJSTimeValue(); // XXX: This will replace NaN by 0 return new Date((long)time); } else if (type.isArray() && value instanceof NativeArray) { // Make a new java array, and coerce the JS array components // to the target (component) type. NativeArray array = (NativeArray) value; long length = array.getLength(); Class arrayType = type.getComponentType(); Object Result = Array.newInstance(arrayType, (int)length); for (int i = 0 ; i < length ; ++i) { try { Array.set(Result, i, coerceTypeImpl( arrayType, array.get(i, array))); } catch (EvaluatorException ee) { reportConversionError(value, type); } } return Result; } else if (value instanceof Wrapper) { value = ((Wrapper)value).unwrap(); if (type.isInstance(value)) return value; reportConversionError(value, type); } else if (type.isInterface() && (value instanceof NativeObject || value instanceof NativeFunction)) { // Try to use function/object as implementation of Java interface. return createInterfaceAdapter(type, (ScriptableObject) value); } else { reportConversionError(value, type); } break; } return value; } protected static Object createInterfaceAdapter(Classtype, ScriptableObject so) { // XXX: Currently only instances of ScriptableObject are // supported since the resulting interface proxies should // be reused next time conversion is made and generic // Callable has no storage for it. Weak references can // address it but for now use this restriction. Object key = Kit.makeHashKeyFromPair(COERCED_INTERFACE_KEY, type); Object old = so.getAssociatedValue(key); if (old != null) { // Function was already wrapped return old; } Context cx = Context.getContext(); Object glue = InterfaceAdapter.create(cx, type, so); // Store for later retrieval glue = so.associateValue(key, glue); return glue; } private static Object coerceToNumber(Class type, Object value) { Class valueClass = value.getClass(); // Character if (type == Character.TYPE || type == ScriptRuntime.CharacterClass) { if (valueClass == ScriptRuntime.CharacterClass) { return value; } return Character.valueOf((char)toInteger(value, ScriptRuntime.CharacterClass, Character.MIN_VALUE, Character.MAX_VALUE)); } // Double, Float if (type == ScriptRuntime.ObjectClass || type == ScriptRuntime.DoubleClass || type == Double.TYPE) { return valueClass == ScriptRuntime.DoubleClass ? value : new Double(toDouble(value)); } if (type == ScriptRuntime.FloatClass || type == Float.TYPE) { if (valueClass == ScriptRuntime.FloatClass) { return value; } else { double number = toDouble(value); if (Double.isInfinite(number) || Double.isNaN(number) || number == 0.0) { return new Float((float)number); } else { double absNumber = Math.abs(number); if (absNumber < Float.MIN_VALUE) { return new Float((number > 0.0) ? +0.0 : -0.0); } else if (absNumber > Float.MAX_VALUE) { return new Float((number > 0.0) ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY); } else { return new Float((float)number); } } } } // Integer, Long, Short, Byte if (type == ScriptRuntime.IntegerClass || type == Integer.TYPE) { if (valueClass == ScriptRuntime.IntegerClass) { return value; } else { return Integer.valueOf((int)toInteger(value, ScriptRuntime.IntegerClass, Integer.MIN_VALUE, Integer.MAX_VALUE)); } } if (type == ScriptRuntime.LongClass || type == Long.TYPE) { if (valueClass == ScriptRuntime.LongClass) { return value; } else { /* Long values cannot be expressed exactly in doubles. * We thus use the largest and smallest double value that * has a value expressible as a long value. We build these * numerical values from their hexidecimal representations * to avoid any problems caused by attempting to parse a * decimal representation. */ final double max = Double.longBitsToDouble(0x43dfffffffffffffL); final double min = Double.longBitsToDouble(0xc3e0000000000000L); return Long.valueOf(toInteger(value, ScriptRuntime.LongClass, min, max)); } } if (type == ScriptRuntime.ShortClass || type == Short.TYPE) { if (valueClass == ScriptRuntime.ShortClass) { return value; } else { return Short.valueOf((short)toInteger(value, ScriptRuntime.ShortClass, Short.MIN_VALUE, Short.MAX_VALUE)); } } if (type == ScriptRuntime.ByteClass || type == Byte.TYPE) { if (valueClass == ScriptRuntime.ByteClass) { return value; } else { return Byte.valueOf((byte)toInteger(value, ScriptRuntime.ByteClass, Byte.MIN_VALUE, Byte.MAX_VALUE)); } } return new Double(toDouble(value)); } private static double toDouble(Object value) { if (value instanceof Number) { return ((Number)value).doubleValue(); } else if (value instanceof String) { return ScriptRuntime.toNumber((String)value); } else if (value instanceof Scriptable) { if (value instanceof Wrapper) { // XXX: optimize tail-recursion? return toDouble(((Wrapper)value).unwrap()); } else { return ScriptRuntime.toNumber(value); } } else { Method meth; try { meth = value.getClass().getMethod("doubleValue", (Class [])null); } catch (NoSuchMethodException e) { meth = null; } catch (SecurityException e) { meth = null; } if (meth != null) { try { return ((Number)meth.invoke(value, (Object [])null)).doubleValue(); } catch (IllegalAccessException e) { // XXX: ignore, or error message? reportConversionError(value, Double.TYPE); } catch (InvocationTargetException e) { // XXX: ignore, or error message? reportConversionError(value, Double.TYPE); } } return ScriptRuntime.toNumber(value.toString()); } } private static long toInteger(Object value, Class type, double min, double max) { double d = toDouble(value); if (Double.isInfinite(d) || Double.isNaN(d)) { // Convert to string first, for more readable message reportConversionError(ScriptRuntime.toString(value), type); } if (d > 0.0) { d = Math.floor(d); } else { d = Math.ceil(d); } if (d < min || d > max) { // Convert to string first, for more readable message reportConversionError(ScriptRuntime.toString(value), type); } return (long)d; } static void reportConversionError(Object value, Class type) { // It uses String.valueOf(value), not value.toString() since // value can be null, bug 282447. throw Context.reportRuntimeError2( "msg.conversion.not.allowed", String.valueOf(value), JavaMembers.javaSignature(type)); } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeBoolean(isAdapter); if (isAdapter) { if (adapter_writeAdapterObject == null) { throw new IOException(); } Object[] args = { javaObject, out }; try { adapter_writeAdapterObject.invoke(null, args); } catch (Exception ex) { throw new IOException(); } } else { out.writeObject(javaObject); } if (staticType != null) { out.writeObject(staticType.getClass().getName()); } else { out.writeObject(null); } } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); isAdapter = in.readBoolean(); if (isAdapter) { if (adapter_readAdapterObject == null) throw new ClassNotFoundException(); Object[] args = { this, in }; try { javaObject = adapter_readAdapterObject.invoke(null, args); } catch (Exception ex) { throw new IOException(); } } else { javaObject = in.readObject(); } String className = (String)in.readObject(); if (className != null) { staticType = Class.forName(className); } else { staticType = null; } initMembers(); } /** * The prototype of this object. */ protected Scriptable prototype; /** * The parent scope of this object. */ protected Scriptable parent; protected transient Object javaObject; protected transient Class staticType; protected transient JavaMembers members; private transient Map fieldAndMethods; protected transient boolean isAdapter; private static final Object COERCED_INTERFACE_KEY = "Coerced Interface"; private static Method adapter_writeAdapterObject; private static Method adapter_readAdapterObject; static { // Reflection in java is verbose Class[] sig2 = new Class[2]; Class cl = Kit.classOrNull("org.mozilla.javascript.JavaAdapter"); if (cl != null) { try { sig2[0] = ScriptRuntime.ObjectClass; sig2[1] = Kit.classOrNull("java.io.ObjectOutputStream"); adapter_writeAdapterObject = cl.getMethod("writeAdapterObject", sig2); sig2[0] = ScriptRuntime.ScriptableClass; sig2[1] = Kit.classOrNull("java.io.ObjectInputStream"); adapter_readAdapterObject = cl.getMethod("readAdapterObject", sig2); } catch (NoSuchMethodException e) { adapter_writeAdapterObject = null; adapter_readAdapterObject = null; } } } } rhino-1.7R4/src/org/mozilla/javascript/NativeJavaPackage.java000066400000000000000000000140671176760007500242710ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.io.IOException; import java.io.ObjectInputStream; import java.util.HashSet; import java.util.Set; /** * This class reflects Java packages into the JavaScript environment. We * lazily reflect classes and subpackages, and use a caching/sharing * system to ensure that members reflected into one JavaPackage appear * in all other references to the same package (as with Packages.java.lang * and java.lang). * * @author Mike Shaver * @see NativeJavaArray * @see NativeJavaObject * @see NativeJavaClass */ public class NativeJavaPackage extends ScriptableObject { static final long serialVersionUID = 7445054382212031523L; NativeJavaPackage(boolean internalUsage, String packageName, ClassLoader classLoader) { this.packageName = packageName; this.classLoader = classLoader; } /** * @deprecated NativeJavaPackage is an internal class, do not use * it directly. */ public NativeJavaPackage(String packageName, ClassLoader classLoader) { this(false, packageName, classLoader); } /** * @deprecated NativeJavaPackage is an internal class, do not use * it directly. */ public NativeJavaPackage(String packageName) { this(false, packageName, Context.getCurrentContext().getApplicationClassLoader()); } @Override public String getClassName() { return "JavaPackage"; } @Override public boolean has(String id, Scriptable start) { return true; } @Override public boolean has(int index, Scriptable start) { return false; } @Override public void put(String id, Scriptable start, Object value) { // Can't add properties to Java packages. Sorry. } @Override public void put(int index, Scriptable start, Object value) { throw Context.reportRuntimeError0("msg.pkg.int"); } @Override public Object get(String id, Scriptable start) { return getPkgProperty(id, start, true); } @Override public Object get(int index, Scriptable start) { return NOT_FOUND; } // set up a name which is known to be a package so we don't // need to look for a class by that name NativeJavaPackage forcePackage(String name, Scriptable scope) { Object cached = super.get(name, this); if (cached != null && cached instanceof NativeJavaPackage) { return (NativeJavaPackage) cached; } else { String newPackage = packageName.length() == 0 ? name : packageName + "." + name; NativeJavaPackage pkg = new NativeJavaPackage(true, newPackage, classLoader); ScriptRuntime.setObjectProtoAndParent(pkg, scope); super.put(name, this, pkg); return pkg; } } synchronized Object getPkgProperty(String name, Scriptable start, boolean createPkg) { Object cached = super.get(name, start); if (cached != NOT_FOUND) return cached; if (negativeCache != null && negativeCache.contains(name)) { // Performance optimization: see bug 421071 return null; } String className = (packageName.length() == 0) ? name : packageName + '.' + name; Context cx = Context.getContext(); ClassShutter shutter = cx.getClassShutter(); Scriptable newValue = null; if (shutter == null || shutter.visibleToScripts(className)) { Class cl = null; if (classLoader != null) { cl = Kit.classOrNull(classLoader, className); } else { cl = Kit.classOrNull(className); } if (cl != null) { WrapFactory wrapFactory = cx.getWrapFactory(); newValue = wrapFactory.wrapJavaClass(cx, getTopLevelScope(this), cl); newValue.setPrototype(getPrototype()); } } if (newValue == null) { if (createPkg) { NativeJavaPackage pkg; pkg = new NativeJavaPackage(true, className, classLoader); ScriptRuntime.setObjectProtoAndParent(pkg, getParentScope()); newValue = pkg; } else { // add to negative cache if (negativeCache == null) negativeCache = new HashSet(); negativeCache.add(name); } } if (newValue != null) { // Make it available for fast lookup and sharing of // lazily-reflected constructors and static members. super.put(name, start, newValue); } return newValue; } @Override public Object getDefaultValue(Class ignored) { return toString(); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.classLoader = Context.getCurrentContext().getApplicationClassLoader(); } @Override public String toString() { return "[JavaPackage " + packageName + "]"; } @Override public boolean equals(Object obj) { if(obj instanceof NativeJavaPackage) { NativeJavaPackage njp = (NativeJavaPackage)obj; return packageName.equals(njp.packageName) && classLoader == njp.classLoader; } return false; } @Override public int hashCode() { return packageName.hashCode() ^ (classLoader == null ? 0 : classLoader.hashCode()); } private String packageName; private transient ClassLoader classLoader; private Set negativeCache = null; } rhino-1.7R4/src/org/mozilla/javascript/NativeJavaTopPackage.java000066400000000000000000000130121176760007500247410ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * This class reflects Java packages into the JavaScript environment. We * lazily reflect classes and subpackages, and use a caching/sharing * system to ensure that members reflected into one JavaPackage appear * in all other references to the same package (as with Packages.java.lang * and java.lang). * * @author Mike Shaver * @see NativeJavaArray * @see NativeJavaObject * @see NativeJavaClass */ public class NativeJavaTopPackage extends NativeJavaPackage implements Function, IdFunctionCall { static final long serialVersionUID = -1455787259477709999L; // we know these are packages so we can skip the class check // note that this is ok even if the package isn't present. private static final String[][] commonPackages = { {"java", "lang", "reflect"}, {"java", "io"}, {"java", "math"}, {"java", "net"}, {"java", "util", "zip"}, {"java", "text", "resources"}, {"java", "applet"}, {"javax", "swing"} }; NativeJavaTopPackage(ClassLoader loader) { super(true, "", loader); } public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { return construct(cx, scope, args); } public Scriptable construct(Context cx, Scriptable scope, Object[] args) { ClassLoader loader = null; if (args.length != 0) { Object arg = args[0]; if (arg instanceof Wrapper) { arg = ((Wrapper)arg).unwrap(); } if (arg instanceof ClassLoader) { loader = (ClassLoader)arg; } } if (loader == null) { Context.reportRuntimeError0("msg.not.classloader"); return null; } NativeJavaPackage pkg = new NativeJavaPackage(true, "", loader); ScriptRuntime.setObjectProtoAndParent(pkg, scope); return pkg; } public static void init(Context cx, Scriptable scope, boolean sealed) { ClassLoader loader = cx.getApplicationClassLoader(); final NativeJavaTopPackage top = new NativeJavaTopPackage(loader); top.setPrototype(getObjectPrototype(scope)); top.setParentScope(scope); for (int i = 0; i != commonPackages.length; i++) { NativeJavaPackage parent = top; for (int j = 0; j != commonPackages[i].length; j++) { parent = parent.forcePackage(commonPackages[i][j], scope); } } // getClass implementation IdFunctionObject getClass = new IdFunctionObject(top, FTAG, Id_getClass, "getClass", 1, scope); // We want to get a real alias, and not a distinct JavaPackage // with the same packageName, so that we share classes and top // that are underneath. String[] topNames = ScriptRuntime.getTopPackageNames(); NativeJavaPackage[] topPackages = new NativeJavaPackage[topNames.length]; for (int i=0; i < topNames.length; i++) { topPackages[i] = (NativeJavaPackage)top.get(topNames[i], top); } // It's safe to downcast here since initStandardObjects takes // a ScriptableObject. ScriptableObject global = (ScriptableObject) scope; if (sealed) { getClass.sealObject(); } getClass.exportAsScopeProperty(); global.defineProperty("Packages", top, ScriptableObject.DONTENUM); for (int i=0; i < topNames.length; i++) { global.defineProperty(topNames[i], topPackages[i], ScriptableObject.DONTENUM); } } public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (f.hasTag(FTAG)) { if (f.methodId() == Id_getClass) { return js_getClass(cx, scope, args); } } throw f.unknown(); } private Scriptable js_getClass(Context cx, Scriptable scope, Object[] args) { if (args.length > 0 && args[0] instanceof Wrapper) { Scriptable result = this; Class cl = ((Wrapper) args[0]).unwrap().getClass(); // Evaluate the class name by getting successive properties of // the string to find the appropriate NativeJavaClass object String name = cl.getName(); int offset = 0; for (;;) { int index = name.indexOf('.', offset); String propName = index == -1 ? name.substring(offset) : name.substring(offset, index); Object prop = result.get(propName, result); if (!(prop instanceof Scriptable)) break; // fall through to error result = (Scriptable) prop; if (index == -1) return result; offset = index+1; } } throw Context.reportRuntimeError0("msg.not.java.obj"); } private static final Object FTAG = "JavaTopPackage"; private static final int Id_getClass = 1; } rhino-1.7R4/src/org/mozilla/javascript/NativeMath.java000066400000000000000000000341031176760007500230160ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * This class implements the Math native object. * See ECMA 15.8. * @author Norris Boyd */ final class NativeMath extends IdScriptableObject { static final long serialVersionUID = -8838847185801131569L; private static final Object MATH_TAG = "Math"; static void init(Scriptable scope, boolean sealed) { NativeMath obj = new NativeMath(); obj.activatePrototypeMap(MAX_ID); obj.setPrototype(getObjectPrototype(scope)); obj.setParentScope(scope); if (sealed) { obj.sealObject(); } ScriptableObject.defineProperty(scope, "Math", obj, ScriptableObject.DONTENUM); } private NativeMath() { } @Override public String getClassName() { return "Math"; } @Override protected void initPrototypeId(int id) { if (id <= LAST_METHOD_ID) { String name; int arity; switch (id) { case Id_toSource: arity = 0; name = "toSource"; break; case Id_abs: arity = 1; name = "abs"; break; case Id_acos: arity = 1; name = "acos"; break; case Id_asin: arity = 1; name = "asin"; break; case Id_atan: arity = 1; name = "atan"; break; case Id_atan2: arity = 2; name = "atan2"; break; case Id_ceil: arity = 1; name = "ceil"; break; case Id_cos: arity = 1; name = "cos"; break; case Id_exp: arity = 1; name = "exp"; break; case Id_floor: arity = 1; name = "floor"; break; case Id_log: arity = 1; name = "log"; break; case Id_max: arity = 2; name = "max"; break; case Id_min: arity = 2; name = "min"; break; case Id_pow: arity = 2; name = "pow"; break; case Id_random: arity = 0; name = "random"; break; case Id_round: arity = 1; name = "round"; break; case Id_sin: arity = 1; name = "sin"; break; case Id_sqrt: arity = 1; name = "sqrt"; break; case Id_tan: arity = 1; name = "tan"; break; default: throw new IllegalStateException(String.valueOf(id)); } initPrototypeMethod(MATH_TAG, id, name, arity); } else { String name; double x; switch (id) { case Id_E: x = Math.E; name = "E"; break; case Id_PI: x = Math.PI; name = "PI"; break; case Id_LN10: x = 2.302585092994046; name = "LN10"; break; case Id_LN2: x = 0.6931471805599453; name = "LN2"; break; case Id_LOG2E: x = 1.4426950408889634; name = "LOG2E"; break; case Id_LOG10E: x = 0.4342944819032518; name = "LOG10E"; break; case Id_SQRT1_2: x = 0.7071067811865476; name = "SQRT1_2"; break; case Id_SQRT2: x = 1.4142135623730951; name = "SQRT2"; break; default: throw new IllegalStateException(String.valueOf(id)); } initPrototypeValue(id, name, ScriptRuntime.wrapNumber(x), DONTENUM | READONLY | PERMANENT); } } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(MATH_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } double x; int methodId = f.methodId(); switch (methodId) { case Id_toSource: return "Math"; case Id_abs: x = ScriptRuntime.toNumber(args, 0); // abs(-0.0) should be 0.0, but -0.0 < 0.0 == false x = (x == 0.0) ? 0.0 : (x < 0.0) ? -x : x; break; case Id_acos: case Id_asin: x = ScriptRuntime.toNumber(args, 0); if (x == x && -1.0 <= x && x <= 1.0) { x = (methodId == Id_acos) ? Math.acos(x) : Math.asin(x); } else { x = Double.NaN; } break; case Id_atan: x = ScriptRuntime.toNumber(args, 0); x = Math.atan(x); break; case Id_atan2: x = ScriptRuntime.toNumber(args, 0); x = Math.atan2(x, ScriptRuntime.toNumber(args, 1)); break; case Id_ceil: x = ScriptRuntime.toNumber(args, 0); x = Math.ceil(x); break; case Id_cos: x = ScriptRuntime.toNumber(args, 0); x = (x == Double.POSITIVE_INFINITY || x == Double.NEGATIVE_INFINITY) ? Double.NaN : Math.cos(x); break; case Id_exp: x = ScriptRuntime.toNumber(args, 0); x = (x == Double.POSITIVE_INFINITY) ? x : (x == Double.NEGATIVE_INFINITY) ? 0.0 : Math.exp(x); break; case Id_floor: x = ScriptRuntime.toNumber(args, 0); x = Math.floor(x); break; case Id_log: x = ScriptRuntime.toNumber(args, 0); // Java's log(<0) = -Infinity; we need NaN x = (x < 0) ? Double.NaN : Math.log(x); break; case Id_max: case Id_min: x = (methodId == Id_max) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; for (int i = 0; i != args.length; ++i) { double d = ScriptRuntime.toNumber(args[i]); if (d != d) { x = d; // NaN break; } if (methodId == Id_max) { // if (x < d) x = d; does not work due to -0.0 >= +0.0 x = Math.max(x, d); } else { x = Math.min(x, d); } } break; case Id_pow: x = ScriptRuntime.toNumber(args, 0); x = js_pow(x, ScriptRuntime.toNumber(args, 1)); break; case Id_random: x = Math.random(); break; case Id_round: x = ScriptRuntime.toNumber(args, 0); if (x == x && x != Double.POSITIVE_INFINITY && x != Double.NEGATIVE_INFINITY) { // Round only finite x long l = Math.round(x); if (l != 0) { x = l; } else { // We must propagate the sign of d into the result if (x < 0.0) { x = ScriptRuntime.negativeZero; } else if (x != 0.0) { x = 0.0; } } } break; case Id_sin: x = ScriptRuntime.toNumber(args, 0); x = (x == Double.POSITIVE_INFINITY || x == Double.NEGATIVE_INFINITY) ? Double.NaN : Math.sin(x); break; case Id_sqrt: x = ScriptRuntime.toNumber(args, 0); x = Math.sqrt(x); break; case Id_tan: x = ScriptRuntime.toNumber(args, 0); x = Math.tan(x); break; default: throw new IllegalStateException(String.valueOf(methodId)); } return ScriptRuntime.wrapNumber(x); } // See Ecma 15.8.2.13 private double js_pow(double x, double y) { double result; if (y != y) { // y is NaN, result is always NaN result = y; } else if (y == 0) { // Java's pow(NaN, 0) = NaN; we need 1 result = 1.0; } else if (x == 0) { // Many differences from Java's Math.pow if (1 / x > 0) { result = (y > 0) ? 0 : Double.POSITIVE_INFINITY; } else { // x is -0, need to check if y is an odd integer long y_long = (long)y; if (y_long == y && (y_long & 0x1) != 0) { result = (y > 0) ? -0.0 : Double.NEGATIVE_INFINITY; } else { result = (y > 0) ? 0.0 : Double.POSITIVE_INFINITY; } } } else { result = Math.pow(x, y); if (result != result) { // Check for broken Java implementations that gives NaN // when they should return something else if (y == Double.POSITIVE_INFINITY) { if (x < -1.0 || 1.0 < x) { result = Double.POSITIVE_INFINITY; } else if (-1.0 < x && x < 1.0) { result = 0; } } else if (y == Double.NEGATIVE_INFINITY) { if (x < -1.0 || 1.0 < x) { result = 0; } else if (-1.0 < x && x < 1.0) { result = Double.POSITIVE_INFINITY; } } else if (x == Double.POSITIVE_INFINITY) { result = (y > 0) ? Double.POSITIVE_INFINITY : 0.0; } else if (x == Double.NEGATIVE_INFINITY) { long y_long = (long)y; if (y_long == y && (y_long & 0x1) != 0) { // y is odd integer result = (y > 0) ? Double.NEGATIVE_INFINITY : -0.0; } else { result = (y > 0) ? Double.POSITIVE_INFINITY : 0.0; } } } } return result; } // #string_id_map# @Override protected int findPrototypeId(String s) { int id; // #generated# Last update: 2004-03-17 13:51:32 CET L0: { id = 0; String X = null; int c; L: switch (s.length()) { case 1: if (s.charAt(0)=='E') {id=Id_E; break L0;} break L; case 2: if (s.charAt(0)=='P' && s.charAt(1)=='I') {id=Id_PI; break L0;} break L; case 3: switch (s.charAt(0)) { case 'L': if (s.charAt(2)=='2' && s.charAt(1)=='N') {id=Id_LN2; break L0;} break L; case 'a': if (s.charAt(2)=='s' && s.charAt(1)=='b') {id=Id_abs; break L0;} break L; case 'c': if (s.charAt(2)=='s' && s.charAt(1)=='o') {id=Id_cos; break L0;} break L; case 'e': if (s.charAt(2)=='p' && s.charAt(1)=='x') {id=Id_exp; break L0;} break L; case 'l': if (s.charAt(2)=='g' && s.charAt(1)=='o') {id=Id_log; break L0;} break L; case 'm': c=s.charAt(2); if (c=='n') { if (s.charAt(1)=='i') {id=Id_min; break L0;} } else if (c=='x') { if (s.charAt(1)=='a') {id=Id_max; break L0;} } break L; case 'p': if (s.charAt(2)=='w' && s.charAt(1)=='o') {id=Id_pow; break L0;} break L; case 's': if (s.charAt(2)=='n' && s.charAt(1)=='i') {id=Id_sin; break L0;} break L; case 't': if (s.charAt(2)=='n' && s.charAt(1)=='a') {id=Id_tan; break L0;} break L; } break L; case 4: switch (s.charAt(1)) { case 'N': X="LN10";id=Id_LN10; break L; case 'c': X="acos";id=Id_acos; break L; case 'e': X="ceil";id=Id_ceil; break L; case 'q': X="sqrt";id=Id_sqrt; break L; case 's': X="asin";id=Id_asin; break L; case 't': X="atan";id=Id_atan; break L; } break L; case 5: switch (s.charAt(0)) { case 'L': X="LOG2E";id=Id_LOG2E; break L; case 'S': X="SQRT2";id=Id_SQRT2; break L; case 'a': X="atan2";id=Id_atan2; break L; case 'f': X="floor";id=Id_floor; break L; case 'r': X="round";id=Id_round; break L; } break L; case 6: c=s.charAt(0); if (c=='L') { X="LOG10E";id=Id_LOG10E; } else if (c=='r') { X="random";id=Id_random; } break L; case 7: X="SQRT1_2";id=Id_SQRT1_2; break L; case 8: X="toSource";id=Id_toSource; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; } // #/generated# return id; } private static final int Id_toSource = 1, Id_abs = 2, Id_acos = 3, Id_asin = 4, Id_atan = 5, Id_atan2 = 6, Id_ceil = 7, Id_cos = 8, Id_exp = 9, Id_floor = 10, Id_log = 11, Id_max = 12, Id_min = 13, Id_pow = 14, Id_random = 15, Id_round = 16, Id_sin = 17, Id_sqrt = 18, Id_tan = 19, LAST_METHOD_ID = 19; private static final int Id_E = LAST_METHOD_ID + 1, Id_PI = LAST_METHOD_ID + 2, Id_LN10 = LAST_METHOD_ID + 3, Id_LN2 = LAST_METHOD_ID + 4, Id_LOG2E = LAST_METHOD_ID + 5, Id_LOG10E = LAST_METHOD_ID + 6, Id_SQRT1_2 = LAST_METHOD_ID + 7, Id_SQRT2 = LAST_METHOD_ID + 8, MAX_ID = LAST_METHOD_ID + 8; // #/string_id_map# } rhino-1.7R4/src/org/mozilla/javascript/NativeNumber.java000066400000000000000000000205641176760007500233630ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * This class implements the Number native object. * * See ECMA 15.7. * * @author Norris Boyd */ final class NativeNumber extends IdScriptableObject { static final long serialVersionUID = 3504516769741512101L; private static final Object NUMBER_TAG = "Number"; private static final int MAX_PRECISION = 100; static void init(Scriptable scope, boolean sealed) { NativeNumber obj = new NativeNumber(0.0); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } NativeNumber(double number) { doubleValue = number; } @Override public String getClassName() { return "Number"; } @Override protected void fillConstructorProperties(IdFunctionObject ctor) { final int attr = ScriptableObject.DONTENUM | ScriptableObject.PERMANENT | ScriptableObject.READONLY; ctor.defineProperty("NaN", ScriptRuntime.NaNobj, attr); ctor.defineProperty("POSITIVE_INFINITY", ScriptRuntime.wrapNumber(Double.POSITIVE_INFINITY), attr); ctor.defineProperty("NEGATIVE_INFINITY", ScriptRuntime.wrapNumber(Double.NEGATIVE_INFINITY), attr); ctor.defineProperty("MAX_VALUE", ScriptRuntime.wrapNumber(Double.MAX_VALUE), attr); ctor.defineProperty("MIN_VALUE", ScriptRuntime.wrapNumber(Double.MIN_VALUE), attr); super.fillConstructorProperties(ctor); } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=1; s="constructor"; break; case Id_toString: arity=1; s="toString"; break; case Id_toLocaleString: arity=1; s="toLocaleString"; break; case Id_toSource: arity=0; s="toSource"; break; case Id_valueOf: arity=0; s="valueOf"; break; case Id_toFixed: arity=1; s="toFixed"; break; case Id_toExponential: arity=1; s="toExponential"; break; case Id_toPrecision: arity=1; s="toPrecision"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(NUMBER_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(NUMBER_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); if (id == Id_constructor) { double val = (args.length >= 1) ? ScriptRuntime.toNumber(args[0]) : 0.0; if (thisObj == null) { // new Number(val) creates a new Number object. return new NativeNumber(val); } // Number(val) converts val to a number value. return ScriptRuntime.wrapNumber(val); } // The rest of Number.prototype methods require thisObj to be Number if (!(thisObj instanceof NativeNumber)) throw incompatibleCallError(f); double value = ((NativeNumber)thisObj).doubleValue; switch (id) { case Id_toString: case Id_toLocaleString: { // toLocaleString is just an alias for toString for now int base = (args.length == 0 || args[0] == Undefined.instance) ? 10 : ScriptRuntime.toInt32(args[0]); return ScriptRuntime.numberToString(value, base); } case Id_toSource: return "(new Number("+ScriptRuntime.toString(value)+"))"; case Id_valueOf: return ScriptRuntime.wrapNumber(value); case Id_toFixed: return num_to(value, args, DToA.DTOSTR_FIXED, DToA.DTOSTR_FIXED, -20, 0); case Id_toExponential: { // Handle special values before range check if(Double.isNaN(value)) { return "NaN"; } if(Double.isInfinite(value)) { if(value >= 0) { return "Infinity"; } else { return "-Infinity"; } } // General case return num_to(value, args, DToA.DTOSTR_STANDARD_EXPONENTIAL, DToA.DTOSTR_EXPONENTIAL, 0, 1); } case Id_toPrecision: { // Undefined precision, fall back to ToString() if(args.length == 0 || args[0] == Undefined.instance) { return ScriptRuntime.numberToString(value, 10); } // Handle special values before range check if(Double.isNaN(value)) { return "NaN"; } if(Double.isInfinite(value)) { if(value >= 0) { return "Infinity"; } else { return "-Infinity"; } } return num_to(value, args, DToA.DTOSTR_STANDARD, DToA.DTOSTR_PRECISION, 1, 0); } default: throw new IllegalArgumentException(String.valueOf(id)); } } @Override public String toString() { return ScriptRuntime.numberToString(doubleValue, 10); } private static String num_to(double val, Object[] args, int zeroArgMode, int oneArgMode, int precisionMin, int precisionOffset) { int precision; if (args.length == 0) { precision = 0; oneArgMode = zeroArgMode; } else { /* We allow a larger range of precision than ECMA requires; this is permitted by ECMA. */ precision = ScriptRuntime.toInt32(args[0]); if (precision < precisionMin || precision > MAX_PRECISION) { String msg = ScriptRuntime.getMessage1( "msg.bad.precision", ScriptRuntime.toString(args[0])); throw ScriptRuntime.constructError("RangeError", msg); } } StringBuilder sb = new StringBuilder(); DToA.JS_dtostr(sb, oneArgMode, precision + precisionOffset, val); return sb.toString(); } // #string_id_map# @Override protected int findPrototypeId(String s) { int id; // #generated# Last update: 2007-05-09 08:15:50 EDT L0: { id = 0; String X = null; int c; L: switch (s.length()) { case 7: c=s.charAt(0); if (c=='t') { X="toFixed";id=Id_toFixed; } else if (c=='v') { X="valueOf";id=Id_valueOf; } break L; case 8: c=s.charAt(3); if (c=='o') { X="toSource";id=Id_toSource; } else if (c=='t') { X="toString";id=Id_toString; } break L; case 11: c=s.charAt(0); if (c=='c') { X="constructor";id=Id_constructor; } else if (c=='t') { X="toPrecision";id=Id_toPrecision; } break L; case 13: X="toExponential";id=Id_toExponential; break L; case 14: X="toLocaleString";id=Id_toLocaleString; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# return id; } private static final int Id_constructor = 1, Id_toString = 2, Id_toLocaleString = 3, Id_toSource = 4, Id_valueOf = 5, Id_toFixed = 6, Id_toExponential = 7, Id_toPrecision = 8, MAX_PROTOTYPE_ID = 8; // #/string_id_map# private double doubleValue; } rhino-1.7R4/src/org/mozilla/javascript/NativeObject.java000066400000000000000000000626441176760007500233460ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; import java.util.AbstractCollection; import java.util.AbstractSet; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; /** * This class implements the Object native object. * See ECMA 15.2. * @author Norris Boyd */ public class NativeObject extends IdScriptableObject implements Map { static final long serialVersionUID = -6345305608474346996L; private static final Object OBJECT_TAG = "Object"; static void init(Scriptable scope, boolean sealed) { NativeObject obj = new NativeObject(); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } @Override public String getClassName() { return "Object"; } @Override public String toString() { return ScriptRuntime.defaultObjectToString(this); } @Override protected void fillConstructorProperties(IdFunctionObject ctor) { addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_getPrototypeOf, "getPrototypeOf", 1); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_keys, "keys", 1); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_getOwnPropertyNames, "getOwnPropertyNames", 1); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_getOwnPropertyDescriptor, "getOwnPropertyDescriptor", 2); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_defineProperty, "defineProperty", 3); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_isExtensible, "isExtensible", 1); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_preventExtensions, "preventExtensions", 1); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_defineProperties, "defineProperties", 2); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_create, "create", 2); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_isSealed, "isSealed", 1); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_isFrozen, "isFrozen", 1); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_seal, "seal", 1); addIdFunctionProperty(ctor, OBJECT_TAG, ConstructorId_freeze, "freeze", 1); super.fillConstructorProperties(ctor); } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=1; s="constructor"; break; case Id_toString: arity=0; s="toString"; break; case Id_toLocaleString: arity=0; s="toLocaleString"; break; case Id_valueOf: arity=0; s="valueOf"; break; case Id_hasOwnProperty: arity=1; s="hasOwnProperty"; break; case Id_propertyIsEnumerable: arity=1; s="propertyIsEnumerable"; break; case Id_isPrototypeOf: arity=1; s="isPrototypeOf"; break; case Id_toSource: arity=0; s="toSource"; break; case Id___defineGetter__: arity=2; s="__defineGetter__"; break; case Id___defineSetter__: arity=2; s="__defineSetter__"; break; case Id___lookupGetter__: arity=1; s="__lookupGetter__"; break; case Id___lookupSetter__: arity=1; s="__lookupSetter__"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(OBJECT_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(OBJECT_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_constructor: { if (thisObj != null) { // BaseFunction.construct will set up parent, proto return f.construct(cx, scope, args); } if (args.length == 0 || args[0] == null || args[0] == Undefined.instance) { return new NativeObject(); } return ScriptRuntime.toObject(cx, scope, args[0]); } case Id_toLocaleString: // For now just alias toString case Id_toString: { if (cx.hasFeature(Context.FEATURE_TO_STRING_AS_SOURCE)) { String s = ScriptRuntime.defaultObjectToSource(cx, scope, thisObj, args); int L = s.length(); if (L != 0 && s.charAt(0) == '(' && s.charAt(L - 1) == ')') { // Strip () that surrounds toSource s = s.substring(1, L - 1); } return s; } return ScriptRuntime.defaultObjectToString(thisObj); } case Id_valueOf: return thisObj; case Id_hasOwnProperty: { boolean result; if (args.length == 0) { result = false; } else { String s = ScriptRuntime.toStringIdOrIndex(cx, args[0]); if (s == null) { int index = ScriptRuntime.lastIndexResult(cx); result = thisObj.has(index, thisObj); } else { result = thisObj.has(s, thisObj); } } return ScriptRuntime.wrapBoolean(result); } case Id_propertyIsEnumerable: { boolean result; if (args.length == 0) { result = false; } else { String s = ScriptRuntime.toStringIdOrIndex(cx, args[0]); if (s == null) { int index = ScriptRuntime.lastIndexResult(cx); result = thisObj.has(index, thisObj); if (result && thisObj instanceof ScriptableObject) { ScriptableObject so = (ScriptableObject)thisObj; int attrs = so.getAttributes(index); result = ((attrs & ScriptableObject.DONTENUM) == 0); } } else { result = thisObj.has(s, thisObj); if (result && thisObj instanceof ScriptableObject) { ScriptableObject so = (ScriptableObject)thisObj; int attrs = so.getAttributes(s); result = ((attrs & ScriptableObject.DONTENUM) == 0); } } } return ScriptRuntime.wrapBoolean(result); } case Id_isPrototypeOf: { boolean result = false; if (args.length != 0 && args[0] instanceof Scriptable) { Scriptable v = (Scriptable) args[0]; do { v = v.getPrototype(); if (v == thisObj) { result = true; break; } } while (v != null); } return ScriptRuntime.wrapBoolean(result); } case Id_toSource: return ScriptRuntime.defaultObjectToSource(cx, scope, thisObj, args); case Id___defineGetter__: case Id___defineSetter__: { if (args.length < 2 || !(args[1] instanceof Callable)) { Object badArg = (args.length >= 2 ? args[1] : Undefined.instance); throw ScriptRuntime.notFunctionError(badArg); } if (!(thisObj instanceof ScriptableObject)) { throw Context.reportRuntimeError2( "msg.extend.scriptable", thisObj.getClass().getName(), String.valueOf(args[0])); } ScriptableObject so = (ScriptableObject)thisObj; String name = ScriptRuntime.toStringIdOrIndex(cx, args[0]); int index = (name != null ? 0 : ScriptRuntime.lastIndexResult(cx)); Callable getterOrSetter = (Callable)args[1]; boolean isSetter = (id == Id___defineSetter__); so.setGetterOrSetter(name, index, getterOrSetter, isSetter); if (so instanceof NativeArray) ((NativeArray)so).setDenseOnly(false); } return Undefined.instance; case Id___lookupGetter__: case Id___lookupSetter__: { if (args.length < 1 || !(thisObj instanceof ScriptableObject)) return Undefined.instance; ScriptableObject so = (ScriptableObject)thisObj; String name = ScriptRuntime.toStringIdOrIndex(cx, args[0]); int index = (name != null ? 0 : ScriptRuntime.lastIndexResult(cx)); boolean isSetter = (id == Id___lookupSetter__); Object gs; for (;;) { gs = so.getGetterOrSetter(name, index, isSetter); if (gs != null) break; // If there is no getter or setter for the object itself, // how about the prototype? Scriptable v = so.getPrototype(); if (v == null) break; if (v instanceof ScriptableObject) so = (ScriptableObject)v; else break; } if (gs != null) return gs; } return Undefined.instance; case ConstructorId_getPrototypeOf: { Object arg = args.length < 1 ? Undefined.instance : args[0]; Scriptable obj = ensureScriptable(arg); return obj.getPrototype(); } case ConstructorId_keys: { Object arg = args.length < 1 ? Undefined.instance : args[0]; Scriptable obj = ensureScriptable(arg); Object[] ids = obj.getIds(); for (int i = 0; i < ids.length; i++) { ids[i] = ScriptRuntime.toString(ids[i]); } return cx.newArray(scope, ids); } case ConstructorId_getOwnPropertyNames: { Object arg = args.length < 1 ? Undefined.instance : args[0]; ScriptableObject obj = ensureScriptableObject(arg); Object[] ids = obj.getAllIds(); for (int i = 0; i < ids.length; i++) { ids[i] = ScriptRuntime.toString(ids[i]); } return cx.newArray(scope, ids); } case ConstructorId_getOwnPropertyDescriptor: { Object arg = args.length < 1 ? Undefined.instance : args[0]; // TODO(norris): There's a deeper issue here if // arg instanceof Scriptable. Should we create a new // interface to admit the new ECMAScript 5 operations? ScriptableObject obj = ensureScriptableObject(arg); Object nameArg = args.length < 2 ? Undefined.instance : args[1]; String name = ScriptRuntime.toString(nameArg); Scriptable desc = obj.getOwnPropertyDescriptor(cx, name); return desc == null ? Undefined.instance : desc; } case ConstructorId_defineProperty: { Object arg = args.length < 1 ? Undefined.instance : args[0]; ScriptableObject obj = ensureScriptableObject(arg); Object name = args.length < 2 ? Undefined.instance : args[1]; Object descArg = args.length < 3 ? Undefined.instance : args[2]; ScriptableObject desc = ensureScriptableObject(descArg); obj.defineOwnProperty(cx, name, desc); return obj; } case ConstructorId_isExtensible: { Object arg = args.length < 1 ? Undefined.instance : args[0]; ScriptableObject obj = ensureScriptableObject(arg); return Boolean.valueOf(obj.isExtensible()); } case ConstructorId_preventExtensions: { Object arg = args.length < 1 ? Undefined.instance : args[0]; ScriptableObject obj = ensureScriptableObject(arg); obj.preventExtensions(); return obj; } case ConstructorId_defineProperties: { Object arg = args.length < 1 ? Undefined.instance : args[0]; ScriptableObject obj = ensureScriptableObject(arg); Object propsObj = args.length < 2 ? Undefined.instance : args[1]; Scriptable props = Context.toObject(propsObj, getParentScope()); obj.defineOwnProperties(cx, ensureScriptableObject(props)); return obj; } case ConstructorId_create: { Object arg = args.length < 1 ? Undefined.instance : args[0]; Scriptable obj = (arg == null) ? null : ensureScriptable(arg); ScriptableObject newObject = new NativeObject(); newObject.setParentScope(this.getParentScope()); newObject.setPrototype(obj); if (args.length > 1 && args[1] != Undefined.instance) { Scriptable props = Context.toObject(args[1], getParentScope()); newObject.defineOwnProperties(cx, ensureScriptableObject(props)); } return newObject; } case ConstructorId_isSealed: { Object arg = args.length < 1 ? Undefined.instance : args[0]; ScriptableObject obj = ensureScriptableObject(arg); if (obj.isExtensible()) return Boolean.FALSE; for (Object name: obj.getAllIds()) { Object configurable = obj.getOwnPropertyDescriptor(cx, name).get("configurable"); if (Boolean.TRUE.equals(configurable)) return Boolean.FALSE; } return Boolean.TRUE; } case ConstructorId_isFrozen: { Object arg = args.length < 1 ? Undefined.instance : args[0]; ScriptableObject obj = ensureScriptableObject(arg); if (obj.isExtensible()) return Boolean.FALSE; for (Object name: obj.getAllIds()) { ScriptableObject desc = obj.getOwnPropertyDescriptor(cx, name); if (Boolean.TRUE.equals(desc.get("configurable"))) return Boolean.FALSE; if (isDataDescriptor(desc) && Boolean.TRUE.equals(desc.get("writable"))) return Boolean.FALSE; } return Boolean.TRUE; } case ConstructorId_seal: { Object arg = args.length < 1 ? Undefined.instance : args[0]; ScriptableObject obj = ensureScriptableObject(arg); for (Object name: obj.getAllIds()) { ScriptableObject desc = obj.getOwnPropertyDescriptor(cx, name); if (Boolean.TRUE.equals(desc.get("configurable"))) { desc.put("configurable", desc, Boolean.FALSE); obj.defineOwnProperty(cx, name, desc, false); } } obj.preventExtensions(); return obj; } case ConstructorId_freeze: { Object arg = args.length < 1 ? Undefined.instance : args[0]; ScriptableObject obj = ensureScriptableObject(arg); for (Object name: obj.getAllIds()) { ScriptableObject desc = obj.getOwnPropertyDescriptor(cx, name); if (isDataDescriptor(desc) && Boolean.TRUE.equals(desc.get("writable"))) desc.put("writable", desc, Boolean.FALSE); if (Boolean.TRUE.equals(desc.get("configurable"))) desc.put("configurable", desc, Boolean.FALSE); obj.defineOwnProperty(cx, name, desc, false); } obj.preventExtensions(); return obj; } default: throw new IllegalArgumentException(String.valueOf(id)); } } // methods implementing java.util.Map public boolean containsKey(Object key) { if (key instanceof String) { return has((String) key, this); } else if (key instanceof Number) { return has(((Number) key).intValue(), this); } return false; } public boolean containsValue(Object value) { for (Object obj : values()) { if (value == obj || value != null && value.equals(obj)) { return true; } } return false; } public Object remove(Object key) { Object value = get(key); if (key instanceof String) { delete((String) key); } else if (key instanceof Number) { delete(((Number) key).intValue()); } return value; } public Set keySet() { return new KeySet(); } public Collection values() { return new ValueCollection(); } public Set> entrySet() { return new EntrySet(); } public Object put(Object key, Object value) { throw new UnsupportedOperationException(); } public void putAll(Map m) { throw new UnsupportedOperationException(); } public void clear() { throw new UnsupportedOperationException(); } class EntrySet extends AbstractSet> { @Override public Iterator> iterator() { return new Iterator>() { Object[] ids = getIds(); Object key = null; int index = 0; public boolean hasNext() { return index < ids.length; } public Map.Entry next() { final Object ekey = key = ids[index++]; final Object value = get(key); return new Map.Entry() { public Object getKey() { return ekey; } public Object getValue() { return value; } public Object setValue(Object value) { throw new UnsupportedOperationException(); } public boolean equals(Object other) { if (!(other instanceof Map.Entry)) { return false; } Map.Entry e = (Map.Entry) other; return (ekey == null ? e.getKey() == null : ekey.equals(e.getKey())) && (value == null ? e.getValue() == null : value.equals(e.getValue())); } public int hashCode() { return (ekey == null ? 0 : ekey.hashCode()) ^ (value == null ? 0 : value.hashCode()); } public String toString() { return ekey + "=" + value; } }; } public void remove() { if (key == null) { throw new IllegalStateException(); } NativeObject.this.remove(key); key = null; } }; } @Override public int size() { return NativeObject.this.size(); } } class KeySet extends AbstractSet { @Override public boolean contains(Object key) { return containsKey(key); } @Override public Iterator iterator() { return new Iterator() { Object[] ids = getIds(); Object key; int index = 0; public boolean hasNext() { return index < ids.length; } public Object next() { try { return (key = ids[index++]); } catch(ArrayIndexOutOfBoundsException e) { key = null; throw new NoSuchElementException(); } } public void remove() { if (key == null) { throw new IllegalStateException(); } NativeObject.this.remove(key); key = null; } }; } @Override public int size() { return NativeObject.this.size(); } } class ValueCollection extends AbstractCollection { @Override public Iterator iterator() { return new Iterator() { Object[] ids = getIds(); Object key; int index = 0; public boolean hasNext() { return index < ids.length; } public Object next() { return get((key = ids[index++])); } public void remove() { if (key == null) { throw new IllegalStateException(); } NativeObject.this.remove(key); key = null; } }; } @Override public int size() { return NativeObject.this.size(); } } // #string_id_map# @Override protected int findPrototypeId(String s) { int id; // #generated# Last update: 2007-05-09 08:15:55 EDT L0: { id = 0; String X = null; int c; L: switch (s.length()) { case 7: X="valueOf";id=Id_valueOf; break L; case 8: c=s.charAt(3); if (c=='o') { X="toSource";id=Id_toSource; } else if (c=='t') { X="toString";id=Id_toString; } break L; case 11: X="constructor";id=Id_constructor; break L; case 13: X="isPrototypeOf";id=Id_isPrototypeOf; break L; case 14: c=s.charAt(0); if (c=='h') { X="hasOwnProperty";id=Id_hasOwnProperty; } else if (c=='t') { X="toLocaleString";id=Id_toLocaleString; } break L; case 16: c=s.charAt(2); if (c=='d') { c=s.charAt(8); if (c=='G') { X="__defineGetter__";id=Id___defineGetter__; } else if (c=='S') { X="__defineSetter__";id=Id___defineSetter__; } } else if (c=='l') { c=s.charAt(8); if (c=='G') { X="__lookupGetter__";id=Id___lookupGetter__; } else if (c=='S') { X="__lookupSetter__";id=Id___lookupSetter__; } } break L; case 20: X="propertyIsEnumerable";id=Id_propertyIsEnumerable; break L; } if (X!=null && X!=s && !X.equals(s)) id = 0; break L0; } // #/generated# return id; } private static final int ConstructorId_getPrototypeOf = -1, ConstructorId_keys = -2, ConstructorId_getOwnPropertyNames = -3, ConstructorId_getOwnPropertyDescriptor = -4, ConstructorId_defineProperty = -5, ConstructorId_isExtensible = -6, ConstructorId_preventExtensions = -7, ConstructorId_defineProperties= -8, ConstructorId_create = -9, ConstructorId_isSealed = -10, ConstructorId_isFrozen = -11, ConstructorId_seal = -12, ConstructorId_freeze = -13, Id_constructor = 1, Id_toString = 2, Id_toLocaleString = 3, Id_valueOf = 4, Id_hasOwnProperty = 5, Id_propertyIsEnumerable = 6, Id_isPrototypeOf = 7, Id_toSource = 8, Id___defineGetter__ = 9, Id___defineSetter__ = 10, Id___lookupGetter__ = 11, Id___lookupSetter__ = 12, MAX_PROTOTYPE_ID = 12; // #/string_id_map# } rhino-1.7R4/src/org/mozilla/javascript/NativeScript.java000066400000000000000000000130261176760007500233720ustar00rootroot00000000000000/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript; /** * The JavaScript Script object. * * Note that the C version of the engine uses XDR as the format used * by freeze and thaw. Since this depends on the internal format of * structures in the C runtime, we cannot duplicate it. * * Since we cannot replace 'this' as a result of the compile method, * will forward requests to execute to the nonnull 'script' field. * * @since 1.3 * @author Norris Boyd */ class NativeScript extends BaseFunction { static final long serialVersionUID = -6795101161980121700L; private static final Object SCRIPT_TAG = "Script"; static void init(Scriptable scope, boolean sealed) { NativeScript obj = new NativeScript(null); obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed); } private NativeScript(Script script) { this.script = script; } /** * Returns the name of this JavaScript class, "Script". */ @Override public String getClassName() { return "Script"; } @Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (script != null) { return script.exec(cx, scope); } return Undefined.instance; } @Override public Scriptable construct(Context cx, Scriptable scope, Object[] args) { throw Context.reportRuntimeError0("msg.script.is.not.constructor"); } @Override public int getLength() { return 0; } @Override public int getArity() { return 0; } @Override String decompile(int indent, int flags) { if (script instanceof NativeFunction) { return ((NativeFunction)script).decompile(indent, flags); } return super.decompile(indent, flags); } @Override protected void initPrototypeId(int id) { String s; int arity; switch (id) { case Id_constructor: arity=1; s="constructor"; break; case Id_toString: arity=0; s="toString"; break; case Id_exec: arity=0; s="exec"; break; case Id_compile: arity=1; s="compile"; break; default: throw new IllegalArgumentException(String.valueOf(id)); } initPrototypeMethod(SCRIPT_TAG, id, s, arity); } @Override public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { if (!f.hasTag(SCRIPT_TAG)) { return super.execIdCall(f, cx, scope, thisObj, args); } int id = f.methodId(); switch (id) { case Id_constructor: { String source = (args.length == 0) ? "" : ScriptRuntime.toString(args[0]); Script script = compile(cx, source); NativeScript nscript = new NativeScript(script); ScriptRuntime.setObjectProtoAndParent(nscript, scope); return nscript; } case Id_toString: { NativeScript real = realThis(thisObj, f); Script realScript = real.script; if (realScript == null) { return ""; } return cx.decompileScript(realScript, 0); } case Id_exec: { throw Context.reportRuntimeError1( "msg.cant.call.indirect", "exec"); } case Id_compile: { NativeScript real = realThis(thisObj, f); String source = ScriptRuntime.toString(args, 0); real.script = compile(cx, source); return real; } } throw new IllegalArgumentException(String.valueOf(id)); } private static NativeScript realThis(Scriptable thisObj, IdFunctionObject f) { if (!(thisObj instanceof NativeScript)) throw incompatibleCallError(f); return (NativeScript)thisObj; } private static Script compile(Context cx, String source) { int[] linep = { 0 }; String filename = Context.getSourcePositionFromStack(linep); if (filename == null) { filename = "bar' js> var r = re.exec(t) js> if (r[1] != "boo();") { > throw "Bad result: " + r[1] > } else { > print("ok") > } ok js> var str = "< var matches = str.match(/(?:<<)xy/); js> print(matches.join(", ")); < var x = { foo: "bar" } js> var y = { __proto__: x }; js> y.foo; bar rhino-1.7R4/testsrc/doctests/413838.doctest000066400000000000000000000014571176760007500204060ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var map = new java.util.HashMap(); js> map.put("a","hi"); null js> map.put("b","hi"); null js> map.get("a") == map.get("b") true js> map.put("c",1) null js> map.put("c",1) 1.0 js> map.put("d",1) null js> map.get("c") == map.get("d") true js> map.get("a") == map.get("d") false js> map.put("e","1") null js> map.get("d") == map.get("e") true js> map.put("f", true) null js> map.put("g", true) null js> map.get("f") == map.get("g") true js> var obj = {} js> map.put("h", obj) null js> map.put("i", obj) null js> map.get("h") == map.get("i") true js> map.put("j", {}) null js> map.get("i") == map.get("j") falserhino-1.7R4/testsrc/doctests/423557.doctest000066400000000000000000000006261176760007500204020ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // Test for using keywords as identifiers // https://bugzilla.mozilla.org/show_bug.cgi?id=423557 js> var x = {if: 1} js> x.if 1 js> x.function = 3 3 js> x.if + x.function 4 js> delete x.if true js> x.if rhino-1.7R4/testsrc/doctests/429121.doctest000066400000000000000000000003711176760007500203700ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> encodeURIComponent('$ a ;') %24%20a%20%3B rhino-1.7R4/testsrc/doctests/433878.doctest000066400000000000000000000010611176760007500204030ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> version(170) 0 js> function f(a,b,c) { > let sum = a + b + c; > return sum / 3; > } js> f.toString() function f(a, b, c) { let sum = a + b + c; return sum / 3; } js> try { > eval("function f() { for (;;) let a=3; return 3; }"); > } catch (e) { > e; > } SyntaxError: SyntaxError: let declaration not directly within block rhino-1.7R4/testsrc/doctests/434041.doctest000066400000000000000000000007401176760007500203650ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // Regression test for bug https://bugzilla.mozilla.org/show_bug.cgi?id=434041 js> function add(_object, _key, _value) { > _object[_key] = _value; > } js> var o = {}; js> add(o, 'a', 'b'); js> o.toSource(); ({a:"b"}) js> add(o, 3, 'c'); js> o.toSource(); ({a:"b", 3:"c"})rhino-1.7R4/testsrc/doctests/439530.doctest000066400000000000000000000004571176760007500204020ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var obj = { run: function () { print("\nrunning"); } } js> var r = new java.lang.Runnable(obj); rhino-1.7R4/testsrc/doctests/441417.doctest000066400000000000000000000014641176760007500203760ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var friendInfo = xmlns="http://ode.apache.org/simpel/1.0/definition/XmlData"> xmlns=""/>; js> var msgIn = xmlns:xd="http://ode.apache.org/simpel/1.0/definition/XmlData"> > > John > Doe > (999)999-9999 > > ; js> friendInfo.name = msgIn.person.firstName.text() + " " + > msgIn.person.lastName.text(); John Doe rhino-1.7R4/testsrc/doctests/442922.doctest000066400000000000000000000006121176760007500203720ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var x = ; js> serialize(x, "x.ser"); js> deserialize("x.ser"); js> (new java.io.File("x.ser"))["delete"](); truerhino-1.7R4/testsrc/doctests/467396.doctest000066400000000000000000000007731176760007500204160ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var a = java.lang.reflect.Array.newInstance(java.lang.Integer, [17,4]); js> a [[Ljava.lang.Integer;@1543c88 js> a.length 17 js> a[0].length 4 js> var a = java.lang.reflect.Array.newInstance(java.lang.Integer, 17, 4); js> a [[Ljava.lang.Integer;@f11404 js> a.length 17 js> a[0].length 4 rhino-1.7R4/testsrc/doctests/473761.doctest000066400000000000000000000006501176760007500204010ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var xml = ; js> var order = xml.customer.order; js> order.orderid = "1"; 1 js> order.test = "expected_string"; expected_string js> xml.customer.order.test; expected_string rhino-1.7R4/testsrc/doctests/477233.doctest000066400000000000000000000011771176760007500204040ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var xml = > > One > > > Two > > ; js> var atom = new Namespace("http://www.w3.org/2005/Atom"); js> print(xml.atom::entry.(atom::title == "One")); One rhino-1.7R4/testsrc/doctests/480758.doctest000066400000000000000000000011461176760007500204060ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> function primBeget(proto) { > if (proto === null) { fail("Cannot beget from null."); } > if (proto === (void 0)) { fail("Cannot beget from undefined."); } > function F() {} > F.prototype = proto; > var result = new F(); > return result; > } js> var x = [1].concat(primBeget(Array.prototype)); js> x 1, js> x[1] js> typeof x[1] object js> x[1] instanceof Array truerhino-1.7R4/testsrc/doctests/524931.doctest000066400000000000000000000015561176760007500204030ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var x = bar; js> x.foo[0] = "baz"; baz js> x.foo[1] = "barf"; barf js> x baz barf js> var xmlTester=; js> xmlTester['data']['test'][0] = "test0"; test0 js> xmlTester['data']['test'][1] = "test1"; test1 js> xmlTester test0 test1 js> var xmlTester=; js> xmlTester['data']['test'][0] = subtest1; subtest1 js> xmlTester['data']['test'][1] = "test1"; test1 js> xmlTester subtest1 test1 rhino-1.7R4/testsrc/doctests/623246.doctest000066400000000000000000000004651176760007500204000ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var table = {}; js> table["0"] = 1; 1 js> table["+0"] js> table["-0"] js> table["0"] 1 js> table[0] 1 rhino-1.7R4/testsrc/doctests/700651.doctest000066400000000000000000000004411176760007500203660ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> escape(/[\u0000]/.exec("\u0000")) %00 js> escape(/[^\u0000]/.exec("\u0000")) null rhino-1.7R4/testsrc/doctests/Counter.doctest000066400000000000000000000005301176760007500212420ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> defineClass("Counter") js> c = new Counter(7) [object Counter] js> c.count 7 js> c.count 8 js> c.count 9 js> c.resetCount() js> c.count 0rhino-1.7R4/testsrc/doctests/Matrix.doctest000066400000000000000000000013751176760007500210770ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. Test of Matrix example. js> defineClass("Matrix") js> var m = new Matrix(2); // A constructor call, see "Matrix(int dimension)" js> m // Object.toString will call "Matrix.getClassName()" [object Matrix] js> m[0][0] = 3; 3 js> uneval(m[0]); // an array was created automatically! [3] js> uneval(m[1]); // array is created even if we don't set a value [] js> m.dim; // we can access the "dim" property 2 js> m.dim = 3; 3 js> m.dim; // but not modify the "dim" property 2 rhino-1.7R4/testsrc/doctests/arguments.doctest000066400000000000000000000066231176760007500216410ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var args = (function() { return arguments })() js> Object.getPrototypeOf(args) === Object.prototype true js> args.constructor === Object.prototype.constructor true js> Object.getOwnPropertyDescriptor(args, 'constructor').toSource(); ({value:function Object() { [native code for Object.Object, arity=1] } , writable:true, enumerable:false, configurable:true}) js> args.toString() [object Arguments] js> var toStr = Object.prototype.toString; js> var _ = Object.prototype.toString = function() { > return this === args ? > "executes Object.prototype.toString.call(arguments)" : > "'this' should be 'arguments'" > } js> args.toString() executes Object.prototype.toString.call(arguments) js> Object.prototype.toString = toStr; undefined js> var toLocStr = Object.prototype.toLocaleString; js> var _ = Object.prototype.toLocaleString = function() { > return this === args ? > "executes Object.prototype.toLocaleString.call(arguments)" : > "'this' should be 'arguments'" > } js> args.toLocaleString() executes Object.prototype.toLocaleString.call(arguments) js> Object.prototype.toLocaleString = toLocStr; undefined; js> (function() { return arguments[2] })('a','b','c') c js> (function(x,y,z) { return arguments[2] })('a','b','c') c js> (function(x) { > arguments[0] = "modified"; > return x; > })("original") modified js> (function(x) { > x = "modified"; > return arguments[0]; > })("original") modified js> (function(x) { > delete arguments[0]; > arguments[0] = "modified"; > return x; > })("original") original js> (function(x) { > delete x; > var x = "modified"; > return arguments[0] > })("original") modified js> (function(x) { > Object.defineProperty(arguments, 0, {get:function(){return "modified"}}); > return arguments[0]; > })("original") modified js> (function(x) { > Object.defineProperty(arguments, 0, {get:function(){return "modified"}}); > return x; > })("original") original js> (function(x) { > Object.defineProperty(arguments, 0, {value:"modified"}); > return arguments[0]; > })("original") modified js> (function(x) { > Object.defineProperty(arguments, 0, {value:"modified"}); > return x; > })("original") modified js> (function() { for (var i in arguments) print(i); })('a','b','c') 0 1 2 js> (function() { > arguments.a = 1; > Object.defineProperty(arguments, 'b', {value:2, enumerable:true}); > Object.defineProperty(arguments, 'c', {value:3, enumerable:false}); > Object.defineProperty(arguments, 0, {enumerable:false}); > for (var p in arguments) print(p); > })('hi') a b js> (function() { return Object.getOwnPropertyDescriptor(arguments, 0) === undefined })() true js> (function() { return Object.getOwnPropertyDescriptor(arguments, 0).toSource(); })("a") ({value:"a", writable:true, enumerable:true, configurable:true}) js> (function(x) { > Object.defineProperty(arguments, 0, {enumerable:false}); > return Object.getOwnPropertyDescriptor(arguments, 0).enumerable; > })("original") false js> (function() { > Object.defineProperty(arguments, 0, {value:2, writable:false}); > arguments[0] = 3; > return arguments[0]; > })(1); 2 rhino-1.7R4/testsrc/doctests/array.dense.doctest000066400000000000000000000016101176760007500220360ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // test various array methods with dense arrays js> var x = [] js> x[10] = 1 1 js> x.length 11 js> 0 in x false js> x.shift() js> x.length 10 js> 0 in x false js> x ,,,,,,,,,1 js> x.reverse() 1,,,,,,,,, js> x.length 10 js> 9 in x false js> x.reverse() ,,,,,,,,,1 js> x.length 10 js> 5 in x false js> x.unshift(2) 11 js> x 2,,,,,,,,,,1 js> 9 in x false js> var r = x.splice(3, 4, 3, 4, 5) js> r ,,, js> r.length 4 js> 2 in r false js> x.length 10 js> x 2,,,3,4,5,,,,1 js> x[5] 5 js> 8 in x false js> var s = x.slice(6, 8); js> s , js> s.length 2 js> 1 in s false js> var y = [] js> y[9] = 1 1 js> var z = y.concat(x) js> z ,,,,,,,,,1,2,,,3,4,5,,,,1 js> z.length 20 js> 2 in z false js> 12 in z false rhino-1.7R4/testsrc/doctests/array.isarray.doctest000066400000000000000000000012311176760007500224110ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> Array.isArray; function isArray() { [native code for Array.isArray, arity=1] } js> Array.isArray() false js> Array.isArray(undefined); false js> Array.isArray(null); false js> Array.isArray(true); false js> Array.isArray(1); false js> Array.isArray('hello'); false js> Array.isArray({}); false js> Array.isArray(function(){}) false js> (function() { print(Array.isArray(arguments)) })() false js> Array.isArray([]) true js> Array.isArray(new Array()) true rhino-1.7R4/testsrc/doctests/array.length.doctest000066400000000000000000000005761176760007500222330ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> function Array() { throw "don't call this" } js> [].length 0 js> [1].length 1 js> [,1,2].length 3 js> [1,,2].length 3 js> [1,2,].length 2 js> [,].length 1 js> [1,,].length 2 rhino-1.7R4/testsrc/doctests/array.sparse.doctest000066400000000000000000000025441176760007500222440ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // test various array methods with sparse arrays js> var x = [] js> x.length = 101 101 js> x[100] = 1 1 js> x.length 101 js> 0 in x false js> x.shift() js> x.length 100 js> 0 in x false js> x ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 js> x.reverse() 1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, js> x.length 100 js> 10 in x false js> x.reverse() ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 js> x.length 100 js> 10 in x false js> x.unshift(2) 101 js> x 2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 js> 10 in x false js> var r = x.splice(50, 5, 3, 4, 5) js> r ,,,, js> r.length 5 js> 3 in r false js> x.length 99 js> x 2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,3,4,5,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1 js> x[50] 3 js> 10 in x false js> var s = x.slice(60, 70); js> s ,,,,,,,,, js> s.length 10 js> 5 in s false js> var y = [] js> y.length = 100 100 js> var z = y.concat(x) js> z.length 199 js> 30 in z false js> 130 in z false rhino-1.7R4/testsrc/doctests/arrays.doctest000066400000000000000000000020421176760007500211240ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> [1,2,undefined,4].join(';') 1;2;;4 js> [1,2,null,4].join(';') 1;2;;4 js> var arr = []; arr[0] = 1; arr[1] = 2; arr[3] = 4; arr.join(';') 1;2;;4 js> var arr = [1,2,3,4]; delete arr[2]; arr.join(';') 1;2;;4 js> var arr = ["a","b","c","d"]; js> var _ = arr.length = 2; js> arr[2] === undefined true js> arr[1] === "b" true js> [1,2,3].reverse().toSource() [3, 2, 1] js> [2,1,3].sort().toSource() [1, 2, 3] js> var arr = [1,2,3]; arr.push(4); arr.toSource() [1, 2, 3, 4] js> var arr = [1,2,3]; arr.pop(); 3 js> arr.toSource() [1, 2] js> var arr = [1,2,3]; arr.shift(); 1 js> arr.toSource() [2, 3] js> var arr = [2,3]; arr.unshift(1); arr.toSource() [1, 2, 3] js> var arr = [1,2,3]; arr.splice(1, 1, "a", "b").toSource() [2] js> arr.toSource() [1, "a", "b", 3] js> [1,2,3].concat([4,5,6]).toSource() [1, 2, 3, 4, 5, 6] js> [1,2,3].indexOf(2) 1 rhino-1.7R4/testsrc/doctests/canonicalize.doctest000066400000000000000000000010371176760007500222650ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var obj = new java.lang.Object(); js> obj java.lang.Object@97a560 js> obj + "%%" java.lang.Object@97a560%% js> var obj = new java.lang.Object(); js> obj java.lang.Object@1d15445 js> "foo" + obj + "bar" foojava.lang.Object@1d15445bar js> var obj2 = new java.lang.Object(); js> obj + obj2 java.lang.Object@1d15445java.lang.Object@1f3aa07 rhino-1.7R4/testsrc/doctests/controlchars.doctest000066400000000000000000000021471176760007500223320ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var controlChars = [ > 0x200C, 0x200D, 0x200E, 0x200F, > 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, > 0x00AD, > 0x2061, 0x2062, 0x2063, 0x2064, > 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F > ]; js> function validInRegExpLiteral(num) { > eval('/.'+String.fromCharCode(num)+'./'); > } js> function validInStringLiteral(num) { > eval('"'+String.fromCharCode(num)+'"'); > } js> function validInComments(num) { > eval('/*'+String.fromCharCode(num)+'*/'); > } js> function check(test) { > return function(codePoint) { > try { > test(codePoint); > return true; > } catch (e) { > throw "problem with U+"+codePoint.toString(16).toUpperCase()+": "+e; > } > }; > } js> controlChars.every(check(validInRegExpLiteral)) true js> controlChars.every(check(validInStringLiteral)) true js> controlChars.every(check(validInComments)) true rhino-1.7R4/testsrc/doctests/date.parse.doctest000066400000000000000000000012721176760007500216550ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> Date.parse('1970-01-01T00:00:00.000Z') 0 js> Date.parse('1970-01-01T00:00:00.000A') NaN js> Date.parse('1971-02-02T10:10:10.001Z') 34337410001 js> var d = new Date() js> var _ = d.setMilliseconds(0); js> Date.parse(d.toISOString()) === d.valueOf(); true js> Date.parse(d.toISOString()) === Date.parse(d.toString()); true js> Date.parse(d.toISOString()) === Date.parse(d.toUTCString()); true js> Date.parse('1970-01-01T00:00:00.000Z a b c') NaN js> Date.parse('1970-01-01T00:00:00.000A') NaN rhino-1.7R4/testsrc/doctests/date.toisostring.doctest000066400000000000000000000017441176760007500231330ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Date.prototype.toISOString; function toISOString() { [native code for Date.toISOString, arity=0] } js> expectError(function() { > new Date(Infinity).toISOString() > }, RangeError); js> new Date(0).toISOString() 1970-01-01T00:00:00.000Z js> var isoFormat = /(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d).(\d\d\d)Z/; js> var now = new Date(); js> var matches = isoFormat.exec(now.toISOString()); js> matches[0] === now.toISOString() true js> matches[1] == now.getUTCFullYear() true js> matches[2] == now.getUTCMonth()+1 true js> matches[3] == now.getUTCDate() true js> matches[4] == now.getUTCHours() true js> matches[5] == now.getUTCMinutes() true js> matches[6] == now.getUTCSeconds() true js> matches[7] == now.getUTCMilliseconds() true rhino-1.7R4/testsrc/doctests/date.tojson.doctest000066400000000000000000000017351176760007500220630ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Date.prototype.toJSON; function toJSON() { [native code for Date.toJSON, arity=1] } js> Date.prototype.toJSON.call({ > valueOf: function() { return Infinity; } > }, '') null js> expectError(function() { > Date.prototype.toJSON.call({}, '') > }, TypeError) js> expectError(function() { > Date.prototype.toJSON.call(5, '') > }, TypeError) js> expectError(function() { > Date.prototype.toJSON.call({toISOString:5}, '') > }, TypeError) js> expectError(function() { > Date.prototype.toJSON.call({toISOString:function(){ return [] }}, '') > }, TypeError) js> Date.prototype.toJSON.call({toISOString: function() { return 'w00t' }}, '') w00t js> var now = new Date() js> now.toJSON('') === now.toISOString() true rhino-1.7R4/testsrc/doctests/error.tostring.doctest000066400000000000000000000020271176760007500226270ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js') js> var str = Error.prototype.toString js> str.call(new TypeError("msg")) TypeError: msg js> str.call(new TypeError()) // message is initialised to '' TypeError: js> str.call(new Error("msg")) Error: msg js> str.call(new Error()) // message is initialised to '' Error: js> str.call({name:"my error", message:"my message"}) my error: my message js> str.call({}) === undefined true js> str.call({name:"no message defined"}) === undefined true js> str.call({name:"message is undefined", message:undefined}) === undefined true js> str.call({name:"null message", message:null}) null message: null js> str.call({message:"no name defined"}) Error: no name defined js> str.call({name:undefined, message:"name is undefined"}) Error: name is undefined js> str.call({name:null, message:"null name"}) null: null name rhino-1.7R4/testsrc/doctests/eval.doctest000066400000000000000000000015341176760007500205570ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> // only direct calls to eval should use scope of call js> // indirect calls should be allowed, but use global scope instead js> var value = 'outer'; js> (function() { var value = "inner"; return eval("value"); })(); inner js> (function(_eval) { var value = "inner"; return _eval("value"); })(eval); outer js> (function(obj) { var value = "inner"; return obj.eval("value"); })({eval:eval}); outer js> (function(obj) { var value = "inner"; return obj.f("value"); })({f:eval}); outer js> (function(arr) { var value = "inner"; return arr[0]("value"); })([eval]); outer js> (function() { var value = "inner"; return eval("eval")("value"); })(); outer rhino-1.7R4/testsrc/doctests/expressionclosure.doctest000066400000000000000000000013041176760007500234170ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> version(180) 0 js> x = function(x) x; function (x) x js> x.toSource() (function (x) x) js> x(123) === 123 true js> x = function([a, b]) a + b; function ([a, b]) a + b js> x([1, 2]) 3 js> x.toSource() (function ([a, b]) a + b) js> function outer() { > var k = function(a) a + 1; > return function(b) k(b) * 2; > } js> outer function outer() { var k = function (a) a + 1; return function (b) k(b) * 2; } js> outer() function (b) k(b) * 2 js> outer()(4) 10 js> outer()(5) 12 rhino-1.7R4/testsrc/doctests/function.bind.doctest000066400000000000000000000026761176760007500224000ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Function.prototype.bind function bind() { [native code for Function.bind, arity=1] } js> expectTypeError(function() { > Function.prototype.bind.call({}) > }); js> typeof (function(){}).bind({}) function js> function Val() { > this.val = 0; > this.change = function(newVal) { this.val = newVal }; > this.valueOf = function() { return 1; } > } js> var a = new Val(), b = new Val(); js> a.change.bind(b)(1) js> [a.val, b.val].toSource() [0, 1] js> new (Val.bind({})) instanceof Val true js> new Val() instanceof Val.bind({}) true js> function add(a, b) { return a + b } js> var add1 = add.bind({}, 1) js> add1(2) 3 js> var add5 = add.bind({}, 5) js> add5(1) 6 js> add1(3) 4 js> function LazyAdd(a, b) { this.result = function() { return a + b } } js> var LazyAdd1 = LazyAdd.bind({}, 1) js> new LazyAdd1(4).result() 5 js> add1.length 1 js> Object.isExtensible(add1) true js> Object.getPrototypeOf(add1) === Function.prototype true js> expectTypeError(function() { > var x = add1.caller > }) js> expectTypeError(function() { > add1.caller = 1 > }) js> expectTypeError(function() { > var x = add1.arguments > }) js> expectTypeError(function() { > add1.arguments = 1 > }) rhino-1.7R4/testsrc/doctests/iterable.doctest000066400000000000000000000010451176760007500214140ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // Test of Creating a JavaScript Iterator from a Java Iterable or Iterator // See http://developer.mozilla.org/en/docs/New_in_Rhino_1.7R1 js> m = new java.util.LinkedHashMap() {} js> m.put("a",1); m.put("b",2); m {a=1.0, b=2.0} js> for (i in Iterator(m.values())) print(i) 1.0 2.0 js> for (i in Iterator(m.values().iterator())) print(i) 1.0 2.0 rhino-1.7R4/testsrc/doctests/iteratorKeys.doctest000066400000000000000000000006461176760007500223200ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> version(170) 0 js> var foo = { > __iterator__ : function(onlyKeys) { > print(onlyKeys); > yield [0, "a"]; > } > }; js> for each (let f in foo) {} false js> for (let f in foo) {} truerhino-1.7R4/testsrc/doctests/javaadapter.doctest000066400000000000000000000031351176760007500221110ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var x = new JavaAdapter(java.util.HashMap, {}) js> x {} js> x instanceof java.util.HashMap true js> x instanceof java.util.Map true js> x.put("foo", "bar") null js> x {foo=bar} js> x.get("foo") bar js> x = new JavaAdapter(java.util.HashMap, {}, {a: "b"}) {a=b} js> x.get("a") b js> x.remove("a") b js> x {} js> x.get("a") null js> x = new JavaAdapter(java.util.HashMap, {get: function(key) {return 2 + this.super$get(key)}}) {} js> x.put("foo", "bar") null js> x.get("foo") 2bar js> x.get("bar") 2.0 js> x = new JavaAdapter({}); x.class.superclass class java.lang.Object js> x.class.interfaces.length 0 js> var Appendable = java.lang.Appendable js> var Runnable = java.lang.Runnable js> function append() {return this} js> function run() {return "done"} js> var x = new JavaAdapter(Runnable, Appendable, {run: run, append: append}) js> x instanceof Appendable true js> x instanceof Runnable true js> x.append("foo") === x true js> x.run() js> // test access to protected methods js> x = JavaAdapter(java.util.Hashtable, {test: function() {this.rehash();}}); {} js> x.test() js> // test access to protected fields js> x = JavaAdapter(java.util.Vector, {test: function() {return this.elementCount;}}); [] js> x.test() 0 js> x.add(1) true js> x.test() 1 js> // test non-empty constructor with protected field js> x = JavaAdapter(java.util.Vector, {test: function() {return this.elementData.length;}}, 20); [] js> x.test() 20 rhino-1.7R4/testsrc/doctests/json.doctest000066400000000000000000000004731176760007500206020ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> ({"1": true})["1"] true js> JSON.parse("{\"1\": true}")["1"] true js> JSON.parse("{\"a\": true}")["a"] true rhino-1.7R4/testsrc/doctests/number.tostring.doctest000066400000000000000000000013531176760007500227670ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> 10000000000000000000000 1e+22 js> 100000000000000000000001 1.0000000000000001e+23 js> 1000000000000000000000001 1e+24 js> -10000000000000000000000 -1e+22 js> -100000000000000000000001 -1.0000000000000001e+23 js> -1000000000000000000000001 -1e+24 js> 0.1 0.1 js> -0.1 -0.1 js> 0.00001 0.00001 js> -0.00001 -0.00001 js> 0.000001 0.000001 js> -0.000001 -0.000001 js> 0.0000001 1e-7 js> -0.0000001 -1e-7 js> -0.0000000000000001 -1e-16 js> 0.0000000000000001 1e-16 js> 0.00000000000000000000000001 1e-26 js> -0.00000000000000000000000001 -1e-26 rhino-1.7R4/testsrc/doctests/object.create.doctest000066400000000000000000000022371176760007500223410ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.create; function create() { [native code for Object.create, arity=2] } js> expectTypeError(function() { Object.create() }); js> [undefined, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.create(value) }) > }) js> expectTypeError(function() { Object.create({}, null) }) js> var obj = Object.create({}); js> var obj = Object.create({}, {}); js> var obj = Object.create({}, undefined); js> var orig = {} js> var next = Object.create(orig); js> Object.getPrototypeOf(next) === orig; true js> var obj = Object.create({}, {a: {value:1}, b: {value:2}}); js> [obj.a, obj.b].toSource(); [1, 2] js> var orig = {a:1}; js> var obj = Object.create(orig, {a:{value:2}, b:{value:3}}); js> [obj.a, obj.b].toSource() [2, 3] js> expectTypeError(function() { Object.create({}, {b: {value:1}, c:1}) }); js> var obj = Object.create(null, {a: {value:1}}) js> Object.getPrototypeOf(obj) === null true rhino-1.7R4/testsrc/doctests/object.defineproperties.doctest000066400000000000000000000027301176760007500244430ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.defineProperties function defineProperties() { [native code for Object.defineProperties, arity=2] } js> expectTypeError(function() { Object.defineProperties() }); js> expectTypeError(function() { Object.defineProperties({}) }); js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.defineProperties(value, {}) }) > }) js> Object.defineProperties({}, {p: {value:1}}).p 1 js> var obj = Object.defineProperties({}, {a: {value:1}, b: {value:2}}); js> [obj.a, obj.b].toSource(); [1, 2] js> Object.defineProperties({}, {'wierd name': {value:1}})['wierd name'] 1 js> Object.defineProperties({}, {}).toSource() ({}) js> var obj = {a:1}; js> var obj = Object.defineProperties(obj, {a:{value:2}, b:{value:3}}); js> [obj.a, obj.b].toSource() [2, 3] js> expectTypeError(function() { Object.defineProperties({}, {a: null}) }) js> expectTypeError(function() { Object.defineProperties({}, {a: 1}) }) js> expectTypeError(function() { Object.defineProperties({}, {a: {get: 1}}) }) js> var obj = {a:1} js> expectTypeError(function() { > obj = Object.defineProperties(obj, {b: {value:1}, c:1}); > }); js> obj.b js> js> Object.defineProperties({}, {'0.0': {value:1}, 0: {value:2}})['0'] 2 rhino-1.7R4/testsrc/doctests/object.defineproperty.doctest000066400000000000000000000200221176760007500241250ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.defineProperty function defineProperty() { [native code for Object.defineProperty, arity=3] } js> expectTypeError(function() { Object.defineProperty() }); js> expectTypeError(function() { Object.defineProperty({}) }); js> expectTypeError(function() { Object.defineProperty({}, 'p') }); js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.defineProperty(value, 'p', {}) }) > }) js> Object.defineProperty({}, 'p', {value:1}).p 1 js> var obj = {} js> Object.defineProperty(obj, 'a', { > value: 1, > enumerable: false, > writable: false, > configurable: false > }) [object Object] js> for (var p in obj) print(p); // check it has no enumerable properties js> obj.a = 2; obj.a; // check that the property is not writable 1 js> delete obj.a; obj.a // check that the property is not deletable 1 js> var define = Object.defineProperty; js> var describe = Object.getOwnPropertyDescriptor; js> // when define new property with empty descriptor then default values are used for the descriptor js> var obj = define({}, 'a', {}); js> describe(obj, 'a').toSource() ({value:undefined, writable:false, enumerable:false, configurable:false}) js> // when define new property with data descriptor then those values are used for the descriptor js> var obj = define({}, 'a', { value: 2, writable: true }); js> var {value:v, writable:w} = describe(obj, 'a'); [v, w].toSource(); [2, true] js> obj.a 2 js> // when define new property with accessor descriptor then those values are used for the descriptor js> var obj = define({}, 'a', { get: function() { return 3; }, set: function(value) {} }); js> var {get:g, set:s} = describe(obj, 'a'); [g, s].toSource(); [(function () {return 3;}), (function (value) {})] js> obj.a 3 js> // when define existing property with empty descriptor then descriptor is left unchanged js> var descriptor = {value:1, writable:true, enumerable:true, configurable:true}; js> var obj = define({}, 'a', descriptor); js> var obj = define(obj, 'a', {}); js> describe(obj, 'a').toSource() ({value:1, writable:true, enumerable:true, configurable:true}) js> // when define existing property with same descriptor then descriptor is left unchanged js> var descriptor = {value:1, writable:true, enumerable:true, configurable:true}; js> var obj = define({}, 'a', descriptor); js> var obj = define(obj, 'a', descriptor); js> describe(obj, 'a').toSource() ({value:1, writable:true, enumerable:true, configurable:true}) js> // may not change configurable from false to true js> expectTypeError(function() { > var obj = define({}, 'a', {configurable : false}); > define(obj, 'a', {configurable : true}); > }); js> // may not change enumerable when configurable is false js> expectTypeError(function() { > var obj = define({}, 'a', {enumerable : true, configurable:false}); > define(obj, 'a', {enumerable : false}); > }); js> // may not change writable from false to true when configurable is false js> expectTypeError(function() { > var obj = define({}, 'a', {writable : false, configurable: false}); > define(obj, 'a', {writable : true}); > }); js> // may not change value when writable is false js> expectTypeError(function() { > var obj = define({}, 'a', {value : 1, writable:false}); > define(obj, 'a', {value : 2}); > }); js> // may not change getter when configurable is false js> expectTypeError(function() { > var obj = define({}, 'a', {get: function() { return 1 }, configurable:false}); > define(obj, 'a', {get: function() { return 1 }}); > }); js> // may not change setter when configurable is false js> expectTypeError(function() { > var obj = define({}, 'a', {set: function(val) {}, configurable:false}); > define(obj, 'a', {set: function(val) {}}); > }); js> // may not change from data property to accessor property when configurable is false js> expectTypeError(function() { > var obj = define({}, 'a', {value : 1, configurable:false}); > define(obj, 'a', {get : function() { return 1 }}); > }); js> // may not change from accessor property to data property when configurable is false js> expectTypeError(function() { > var obj = define({}, 'a', {get : function() { return 1 }, configurable:false}); > define(obj, 'a', {value : 1}); > }); js> // can change writable from true to false when configurable is false js> var obj = define({}, 'a', {writable:true, configurable:false}); js> var obj = define(obj, 'a', {writable:false}); js> // can set enumerable to the same value when configurable is false js> var obj = define({}, 'a', {enumerable:true, configurable:false}); js> var obj = define(obj, 'a', {enumerable:true}); js> // can change from data property to accessor property when configurable is true js> var obj = define({}, 'a', {value : 1, configurable: true}); js> var obj = define(obj, 'a', {get : function() { return 4 }}); js> obj.a 4 js> describe(obj, 'a').toSource() ({enumerable:false, configurable:true, get:(function () {return 4;})}) js> // can change from accessor property to data property when configurable is true js> var obj = define({}, 'a', {get : function() { return 2 }, configurable:true}); js> var obj = define(obj, 'a', {value : 5}); js> obj.a 5 js> describe(obj, 'a').toSource() ({value:5, writable:false, enumerable:false, configurable:true}) js> // can change enumerable and writable to true when configurable is true js> var obj = define({}, 'a', {writable : false, enumerable : false, configurable:true}); js> var obj = define(obj, 'a', {writable : true, enumerable : true, configurable:true}); js> // can change the value if writable is true js> var obj = define({}, 'a', {value:6, writable:true}) js> obj.a 6 js> var obj = define(obj, 'a', {value:7}) js> obj.a 7 js> // defining a new property should fail loudly when object is not extensible js> var obj = Object.preventExtensions({}); js> expectTypeError(function() { define(obj, 'a', {value:1}) }) js> // defining new property should succeed when object is extensible js> var obj = {} js> Object.isExtensible(obj); true js> obj.a = 8; obj.a 8 js> // changing existing property should succeed when object is not extensible js> var obj = define({}, 'a', {value:1, writable:true}); js> var obj = Object.preventExtensions(obj); js> obj.a = 9; obj.a 9 js> // defined getters and setters must be functions js> expectTypeError(function() { define({}, 'a', {get:1}); }) js> expectTypeError(function() { define({}, 'a', {set:1}); }) js> // make sure defineProperty works properly with numbers as ids js> Object.defineProperty({}, 0, {value:1, enumerable:true})['0'] 1 js> // make sure defineProperty works properly with arrays js> Object.defineProperty([], 0, {value:1, enumerable:true})[0] 1 js> // make sure defineProperty works properly with arrays js> Object.defineProperty([], 'a', {value:1, enumerable:true})['a'] 1 js> // make sure defineProperty updates length properly for arrays js> Object.defineProperty([], 0, {value:1}).length 1 js> // make sure that getters and setters are actually used to get and set property js> Object.defineProperty({}, 'a', {get:function() { return "get called"; }}).a get called js> Object.defineProperty({}, 'a', {set:function(val) { print("set called with "+val); }}).a = 1; undefined; set called with 1 js> // make sure defineProperty works for builtin properties js> Object.defineProperty(JSON, 'stringify', {value:1}).stringify 1 js> Object.defineProperty(JSON, 'parse', {get:function() {print('do get'); return undefined}}).parse do get js> // an accessor property without a setter behaves as if the setter were undefined js> // and thus the setter can be set to undefined even when configurable is false js> var obj = Object.defineProperty({}, 'a', {get:function(){return 1}}) js> var _ = Object.defineProperty(obj, 'a', {set:undefined}) js> rhino-1.7R4/testsrc/doctests/object.extensible.doctest000066400000000000000000000021071176760007500232340ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.isExtensible; function isExtensible() { [native code for Object.isExtensible, arity=1] } js> expectTypeError(function() { Object.isExtensible() }); js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.isExtensible(value) }) > }) js> Object.preventExtensions; function preventExtensions() { [native code for Object.preventExtensions, arity=1] } js> expectTypeError(function() { Object.preventExtensions() }); js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.preventExtensions(value) }) > }) js> var x = {}; js> Object.isExtensible(x); true js> var y = Object.preventExtensions(x); js> y === x; true js> Object.isExtensible(x); false js> x.a = 1; x.a js> js> x.__defineGetter__('b', function() { return 1 }); x.b js> rhino-1.7R4/testsrc/doctests/object.freeze.doctest000066400000000000000000000017731176760007500223620ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.freeze; function freeze() { [native code for Object.freeze, arity=1] } js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.freeze(value) }) > }) js> expectTypeError(function() { Object.freeze() }) js> var x = {} js> var y = Object.freeze(x) js> x === y true js> var obj = Object.defineProperty({}, 'a', {configurable:true, writable:true}) js> var _ = Object.freeze(obj) js> var a = Object.getOwnPropertyDescriptor(obj, 'a'); js> a.configurable false js> a.writable false js> Object.isExtensible(obj) false js> Object.isFrozen(obj) true js> var _ = Object.freeze([]) js> var _ = Object.freeze({}) js> var _ = Object.freeze(function(){}) js> var _ = Object.freeze(/a/) js> var _ = Object.freeze(RegExp) rhino-1.7R4/testsrc/doctests/object.getownpropertydescriptor.doctest000066400000000000000000000045521176760007500263070ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.getOwnPropertyDescriptor; function getOwnPropertyDescriptor() { [native code for Object.getOwnPropertyDescriptor, arity=2] } js> expectTypeError(function() { Object.getOwnPropertyDescriptor() }) js> var desc = Object.getOwnPropertyDescriptor({undefined:3}); js> desc.value 3 js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.getOwnPropertyDescriptor(value, 'p') }) > }) js> Object.getOwnPropertyDescriptor({}, 'p') === undefined; true js> var desc = Object.getOwnPropertyDescriptor({p:1}, 'p'); js> desc.value 1 js> desc.writable true js> desc.enumerable true js> desc.configurable true js> var desc = Object.getOwnPropertyDescriptor({ get p() {}, set p() {} }, 'p'); js> desc.value === undefined; true js> desc.writable === undefined; true js> desc.get.toSource() (function () {}) js> desc.set.toSource() (function () {}) js> desc.enumerable true js> desc.configurable true js> desc.__proto__ === Object.prototype true js> desc.__parent__; [object global] js> var func = function(){} js> func.a = 1; Object.getOwnPropertyDescriptor(func, 'a').toSource() ({value:1, writable:true, enumerable:true, configurable:true}) js> Object.getOwnPropertyDescriptor({undefined: 1}, undefined).toSource() ({value:1, writable:true, enumerable:true, configurable:true}) js> Object.getOwnPropertyDescriptor({0:1}, 0).toSource() ({value:1, writable:true, enumerable:true, configurable:true}) js> Object.getOwnPropertyDescriptor([1], 0).toSource() ({value:1, writable:true, enumerable:true, configurable:true}) js> Object.getOwnPropertyDescriptor([1], '0').toSource() ({value:1, writable:true, enumerable:true, configurable:true}) js> Object.getOwnPropertyDescriptor([1], 1) === undefined true js> Object.getOwnPropertyDescriptor([1], -1) === undefined true js> var arr = []; js> arr.a = 1; 1 js> Object.getOwnPropertyDescriptor(arr, 'a').toSource() ({value:1, writable:true, enumerable:true, configurable:true}) js> var arr = Object.defineProperty([], 'a', {value:1, writable:false,}) js> var desc = Object.getOwnPropertyDescriptor(arr, 'a'); ([desc.value, desc.writable]).toSource() [1, false] rhino-1.7R4/testsrc/doctests/object.getownpropertynames.doctest000066400000000000000000000033401176760007500252260ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.getOwnPropertyNames; function getOwnPropertyNames() { [native code for Object.getOwnPropertyNames, arity=1] } js> expectTypeError(function() { Object.getOwnPropertyNames() }) js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.getOwnPropertyNames(value) }) > }) js> Object.getOwnPropertyNames({}).toSource(); [] js> Object.getOwnPropertyNames({a:2}).toSource(); ["a"] js> Object.getOwnPropertyNames({a:1, b:2}).toSource(); ["a", "b"] js> Object.getOwnPropertyNames({'a.b':1, 'c d':2}).toSource(); ["a.b", "c d"] js> Object.getOwnPropertyNames([]).toSource(); ["length"] js> Object.getOwnPropertyNames(['a', 'b', 'c']).toSource(); ["0", "1", "2", "length"] js> function UserDefined() { this.a = 1; this.b = 2 }; js> var obj = new UserDefined() js> Object.getOwnPropertyNames(obj).toSource() ["a", "b"] js> UserDefined.prototype.c = 3; 3 js> Object.getOwnPropertyNames(obj).toSource() ["a", "b"] js> // test properties of result are enumerable js> for (var p in Object.getOwnPropertyNames({a:2, b:3})) print(p) 0 1 js> // test that properties of result are writable js> var k = Object.getOwnPropertyNames({a:2, b:3}); js> k[1] = 'c'; k.toSource(); ["a", "c"] js> // test that properties of result are configurable js> var k = Object.getOwnPropertyNames({a:2, b:3}) js> delete k[1]; true js> k a, js> // TODO test that the attributes of the properties can be changed js> var k = Object.getOwnPropertyNames({a:2, 5:6}) js> typeof k[1] string rhino-1.7R4/testsrc/doctests/object.getprototypeof.doctest000066400000000000000000000015751176760007500241740ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.getPrototypeOf; function getPrototypeOf() { [native code for Object.getPrototypeOf, arity=1] } js> expectTypeError(function() { Object.getPrototypeOf() }) js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.getPrototypeOf(value) }) > }) js> [(function(){}), [], {}].every(function(obj) { > return Object.getPrototypeOf(obj) === obj.__proto__; > }); true js> function UserDefined() {} js> [Date, UserDefined].every(function(type) { > var instance; > eval('instance = new '+type.name); > return Object.getPrototypeOf(instance) === type.prototype; > }); true rhino-1.7R4/testsrc/doctests/object.isfrozen.doctest000066400000000000000000000023611176760007500227330ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.isFrozen function isFrozen() { [native code for Object.isFrozen, arity=1] } js> expectTypeError(function() { Object.isFrozen() }); js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.isFrozen(value) }) > }) js> Object.isFrozen({}) false js> var obj = Object.preventExtensions({}); js> Object.isFrozen(obj); true js> var obj = Object.defineProperty({}, 'a', {configurable:true, writable:false}) js> var _ = Object.preventExtensions(obj); js> Object.isFrozen(obj); false js> var obj = Object.defineProperty({}, 'a', {configurable:false, writable:true}) js> var _ = Object.preventExtensions(obj); js> Object.isFrozen(obj); false js> var obj = Object.defineProperty({}, 'a', {configurable:false, writable:false}) js> var _ = Object.preventExtensions(obj); js> Object.isFrozen(obj); true js> var obj = Object.defineProperty({}, 'a', {configurable:false, set: function(){} }) js> var _ = Object.preventExtensions(obj); js> Object.isFrozen(obj); true rhino-1.7R4/testsrc/doctests/object.issealed.doctest000066400000000000000000000016221176760007500226640ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.isSealed function isSealed() { [native code for Object.isSealed, arity=1] } js> expectTypeError(function() { Object.isSealed() }); js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.isSealed(value) }) > }) js> Object.isSealed({}) false js> var obj = Object.preventExtensions({}); js> Object.isSealed(obj); true js> var obj = Object.defineProperty({}, 'a', {configurable:false}); js> var _ = Object.preventExtensions(obj); js> Object.isSealed(obj); true js> var obj = Object.defineProperty({}, 'a', {configurable:true}); js> var _ = Object.preventExtensions(obj); js> Object.isSealed(obj); false rhino-1.7R4/testsrc/doctests/object.keys.doctest000066400000000000000000000027231176760007500220510ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.keys; function keys() { [native code for Object.keys, arity=1] } js> expectTypeError(function() { Object.keys() }) js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.keys(value) }) > }) js> Object.keys({}).toSource(); [] js> Object.keys({a:2}).toSource(); ["a"] js> Object.keys({a:1, b:2}).toSource(); ["a", "b"] js> Object.keys({'a.b':1, 'c d':2}).toSource(); ["a.b", "c d"] js> Object.keys([]).toSource(); [] js> Object.keys(['a', 'b', 'c']).toSource(); ["0", "1", "2"] js> function UserDefined() { this.a = 1; this.b = 2 }; js> var obj = new UserDefined() js> Object.keys(obj).toSource() ["a", "b"] js> UserDefined.prototype.c = 3; 3 js> Object.keys(obj).toSource() ["a", "b"] js> // test properties of result are enumerable js> for (var p in Object.keys({a:2, b:3})) print(p) 0 1 js> // test that properties of result are writable js> var k = Object.keys({a:2, b:3}); js> k[1] = 'c'; k.toSource(); ["a", "c"] js> // test that properties of result are configurable js> var k = Object.keys({a:2, b:3}) js> delete k[1]; true js> k a, js> // TODO test that the attributes of the properties can be changed js> var k = Object.keys({ a:1, 3:2 }); js> typeof k[1]; string rhino-1.7R4/testsrc/doctests/object.seal.doctest000066400000000000000000000014241176760007500220170ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> Object.seal; function seal() { [native code for Object.seal, arity=1] } js> [undefined, null, true, 1, 'hello'].forEach(function(value) { > expectTypeError(function() { Object.seal(value) }) > }) js> expectTypeError(function() { Object.seal() }) js> var x = {} js> var y = Object.seal(x) js> x === y true js> var obj = Object.defineProperty({}, 'a', {configurable:true}) js> var _ = Object.seal(obj) js> Object.getOwnPropertyDescriptor(obj, 'a').configurable false js> Object.isExtensible(obj) false js> Object.isSealed(obj) true rhino-1.7R4/testsrc/doctests/parseint.doctest000066400000000000000000000007301176760007500214520ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> parseInt function parseInt() { [native code for parseInt, arity=2] } js> parseInt("0"); 0 js> parseInt("1") 1 js> parseInt("-1") -1 js> parseInt(" 2") 2 js> parseInt("3then some other chars") 3 js> parseInt('0xF') 15 js> parseInt('0xf') 15 js> parseInt('010') 8 rhino-1.7R4/testsrc/doctests/regexp.literals.doctest000066400000000000000000000005331176760007500227360ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> for (var i = 0; i < 4; i++) print(/a/g.exec("a")); a a a a js> var r = /a/g; for (var i = 0; i < 4; i++) print(r.exec("a")); a null a null rhino-1.7R4/testsrc/doctests/regexp.source.doctest000066400000000000000000000026351176760007500224240ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> x = RegExp('') /(?:)/ js> x.source js> RegExp('a').source a js> RegExp('\\\\').source \\ js> RegExp('\\\\\\\\').source \\\\ js> x = RegExp('/') /\// js> x.source \/ js> x.test('/') true js> x = RegExp('//') /\/\// js> x.source \/\/ js> x.test('//') true js> x = RegExp('\/') /\// js> x.source \/ js> x.test('/') true js> x = RegExp('\\/') /\// js> x.source \/ js> x.test('/') true js> x = RegExp('\\\/') /\// js> x.source \/ js> x.test('/') true js> x = RegExp('\\\\/') /\\// js> x.source \\/ js> x.test('/') false js> x.test('\\/') true js> x = RegExp('/abc\/foo\\/bar\\\/xyz/') /\/abc\/foo\/bar\/xyz\// js> x.source \/abc\/foo\/bar\/xyz\/ js> x.test('/abc/foo/bar/xyz/') true js> RegExp('[^/]*') /[^\/]*/ js> RegExp('[^\/]*') /[^\/]*/ js> RegExp('[^\\/]*') /[^\/]*/ js> /./.compile('') /(?:)/ js> /./.compile('a') /a/ js> /./.compile('\\\\') /\\/ js> /./.compile('\\\\\\\\') /\\\\/ js> /./.compile('/') /\// js> /./.compile('//') /\/\// js> /./.compile('\/') /\// js> /./.compile('\\/') /\// js> /./.compile('\\\/') /\// js> /./.compile('\\\\/') /\\// js> /./.compile('/abc\/foo\\/bar\\\/xyz/') /\/abc\/foo\/bar\/xyz\// js> /./.compile('[^/]*') /[^\/]*/ js> /./.compile('[^\/]*') /[^\/]*/ js> /./.compile('[^\\/]*') /[^\/]*/ rhino-1.7R4/testsrc/doctests/serialize.doctest000066400000000000000000000007521176760007500216200ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var obj = { a:3, b:"hi", 9:"nine", 12:1200 }; js> serialize(obj, "foo.bin"); js> obj2 = deserialize("foo.bin"); [object Object] js> uneval(obj) ({a:3, b:"hi", 9:"nine", 12:1200}) js> uneval(obj2) ({a:3, b:"hi", 9:"nine", 12:1200}) js> (new java.io.File("foo.bin"))["delete"](); true rhino-1.7R4/testsrc/doctests/string.trim.doctest000066400000000000000000000020041176760007500221010ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> String.prototype.trim; function trim() { [native code for String.trim, arity=0] } js> String.prototype.trim.call({toString: function() { return "a" }}); a js> " hello ".trim() === "hello"; true js> var chr = String.fromCharCode; js> var str = "" + > // ecma whitespace > chr(0x0009) + chr(0x000B) + chr(0x000C) + chr(0x0020) + chr(0x00A0) + chr(0xFEFF) + > // unicode whitespace > chr(0x1680) + chr(0x180E) + > chr(0x2000) + chr(0x2001) + chr(0x2002) + chr(0x2003) + chr(0x2004) + chr(0x2005) + chr(0x2006) + chr(0x2007) + chr(0x2008) + chr(0x2009) + chr(0x200A) + > chr(0x202F) + chr(0x205F) + chr(0x3000) + > // ecma line terminators > chr(0x000A) + chr(0x000D) + chr(0x2028) + chr(0x2029) + > > "abc"; js> str.trim() === "abc"; true rhino-1.7R4/testsrc/doctests/tail-call-in-try.doctest000066400000000000000000000010411176760007500227030ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // Fix bug reported in newsgroup: // Tail call optimization was interfering with catching exceptions. // The following program should print 7, but was resulting in an uncaught // exception. js> function g() { > throw 3; > } js> function f() { > try { > return g(); > } catch (e) { > return 7; > } > } js> f() 7rhino-1.7R4/testsrc/doctests/test2.doctest000066400000000000000000000006301176760007500206650ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> a = [] js> a[0] = 10 10 js> a[1] = 11 11 js> a[3] = 13 13 js> a[4] = 14 14 js> a[5] = 15 15 js> a.reverse() 15,14,13,,11,10 js> a.reverse() 10,11,,13,14,15 js> a.concat([16,17]) 10,11,,13,14,15,16,17 rhino-1.7R4/testsrc/doctests/util.js000066400000000000000000000007021176760007500175500ustar00rootroot00000000000000/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ function expectTypeError(code) { expectError(code, TypeError); } function expectError(code, error) { try { code(); throw (code.toSource() + ' should have thrown a '+error); } catch (e if e instanceof error) { // all good } } rhino-1.7R4/testsrc/doctests/whitespace.doctest000066400000000000000000000010761176760007500217650ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js') js> var bom = String.fromCharCode(0xFEFF); js> eval(bom); js> var _ = eval("(function(){return"+bom+"1;})"); js> expectError(function() { > eval("i"+bom+"f (false);"); > }, SyntaxError); js> parseInt(bom+"1") 1 js> parseFloat(bom+"1.5"); 1.5 js> (bom+"abc"+bom).trim().length 3 js> /\s/.test(bom) true js> (bom+"1"+bom) * 1 1 rhino-1.7R4/testsrc/doctests/with.doctest000066400000000000000000000021651176760007500206040ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> load('testsrc/doctests/util.js'); js> // when the variable is not in the with-object, it'll be set on the outer scope js> (function() { with ({}) { var foo = 1; }; return foo; })() 1 js> // when the function is not in the with-object, it'll be set on the outer scope js> (function() { with ({}) { function foo() { return 2; } }; return foo(); })() 2 js> // when the variable is in the with-object, it will be updated on the with-object js> (function() { var obj = {foo:0}; with (obj) { var foo = 3; }; return obj.foo; })() 3 js> // functions declared inside with blocks are always bound to the closest enclosing function js> (function() { function foo(){ return 0; }; with ({}) { function foo() { return 4; } }; return foo(); })() 4 js> // functions declared inside with blocks do not affect the properties of the with-obj js> (function() { var obj = {foo:5}; with (obj) { function foo() { return 0; } }; return obj.foo; })() 5 rhino-1.7R4/testsrc/doctests/xmlOptions.doctest000066400000000000000000000010211176760007500217730ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. js> var x = 1; js> x 1 js> var xmlLib = org.mozilla.javascript.xml.XMLLib.extractFromScope(this); js> xmlLib.isPrettyPrinting(); true js> xmlLib.setPrettyPrinting(false); js> xmlLib.isPrettyPrinting(); false js> x 1rhino-1.7R4/testsrc/jstests/000077500000000000000000000000001176760007500161055ustar00rootroot00000000000000rhino-1.7R4/testsrc/jstests/401561.jstest000066400000000000000000000015461176760007500201110ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // This function should never work (no x in lexical scope) function getX() { return x; } global = this; (function() { var x = 12345; (function() { // indirect call, not direct-call-optimized, // uses this scope's parent instead of getX's parent try { global["getX"](); } catch (e) { if (!(e instanceof ReferenceError)) throw("Expected ReferenceError from getX(), got " + e); return; } throw("Indirect call of getX() did not throw"); })(); })(); // call site triggers direct-call optimization of getX; // remove this line and the bug doesn't manifest! function neverCalled() { getX(); } "success" rhino-1.7R4/testsrc/jstests/420012.jstest000066400000000000000000000006561176760007500201020ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. var o = new Object; o.setX = function (id) { this.oid = id; } function setX(n) { if (n == "" || n == null) n = 0; var s = new Object; s.xyz = n; if (s != null) { o.setX(s.xyz); } } setX('x'); "success"; rhino-1.7R4/testsrc/jstests/437988.jstest000066400000000000000000000011001176760007500201210ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // Rhino must discover the abstract methods in the interface // of AbstractTableModel var tableModel = new javax.swing.table.AbstractTableModel() { getRowCount: function() { return 2; }, getColumnCount: function() { return 2; }, getValueAt: function(row, column) { return "ABC"; } }; var jTable = new javax.swing.JTable(tableModel); "success"; rhino-1.7R4/testsrc/jstests/524931.jstest000066400000000000000000000007061176760007500201150ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. var tmp=new XML(''); default xml namespace = "http://something"; var otherData = new XML(); otherData['@anAtt'] = "anATTValue"; tmp.data.otherData=otherData; "success"; rhino-1.7R4/testsrc/jstests/577141.jstest000066400000000000000000000005221176760007500201120ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. var ns = new Namespace( "dc", "http://purl.org/dc/elements/1.1" ); var x = new XML( "" ); x.setNamespace( ns ); "success"; rhino-1.7R4/testsrc/jstests/660799.jstest000066400000000000000000000026201176760007500201270ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. function assertThrows(s) { try { decodeURI(s); } catch (e) { if (!(e instanceof URIError)) { throw "decodeURI('" + s + "') threw " + e + " instead of URIError"; } return; } throw "Excpected decodeURI('" + s + "') to throw URIError."; } function assertEquals(a, b) { if (decodeURI(a) !== b) throw "Expected decodeURI('" + a + "') to be equal to " + b; } //Phase1: overlong sequences assertThrows("%C1%BF"); assertThrows("%E0%9F%BF"); assertThrows("%F0%88%80%80"); assertThrows("%F0%8F%BF%BF"); assertThrows("%F0%80%C0%80%80"); assertThrows("%F8%84%8F%BF%BF"); assertThrows("%FC%80%84%8F%BF%BF"); assertThrows("%C1%BF"); assertThrows("%E0%9F%BF"); //Phase 2:Out of Unicode range assertThrows("%F4%90%80%80%80"); assertThrows("%F8%84%90%80%80"); assertThrows("%FC%80%84%90%80%80"); assertThrows("%ED%A0%80"); assertThrows("%ED%AF%BF"); assertThrows("%ED%B0%80"); assertThrows("%ED%BF%BF"); //Phase 3:Valid sequences must be decoded correctly assertEquals("%7F", "\x7f"); assertEquals("%C2%80", "\x80"); assertEquals("%E0%A0%80", "\u0800"); assertEquals("%F0%90%80%80", "\uD800\uDC00"); assertEquals("%F4%8F%BF%BF", "\uDBFF\uDFFF"); "success" rhino-1.7R4/testsrc/jstests/688458.jstest000066400000000000000000000017461176760007500201410ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. // https://bugzilla.mozilla.org/show_bug.cgi?id=688458 var x = {NEGATIVE_INFINITY: 1, POSITIVE_INFINITY: 1}; var count1 = 0; var count2 = 0; var n = 100000; var running = true; new java.lang.Thread(function() { while (running) { x = {NEGATIVE_INFINITY: 1, POSITIVE_INFINITY: 1}; for (var i = 0; i < 16; i++) x["i" + i] = i; } }).start(); // Test for original read bug first for(var k = 0; k < n; k++) { if (!x.POSITIVE_INFINITY || !x.NEGATIVE_INFINITY) count1++; } // Now test for write bug introduced by first fix for(var k = 0; k < n; k++) { var M = x.k; if (M && M != k - 1) count2++; x.k = k; } running = false; if (count1 > 0 || count2 > 0) { throw new Error(count1 + " read bugs, " + count2 + " write bugs"); } "success"; rhino-1.7R4/testsrc/jstests/destructuringLvalue.jstest000066400000000000000000000012371176760007500234210ustar00rootroot00000000000000// This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. /* TODO(stevey): fix this test var obj = { p:3 }; var arr = [ 3 ]; [obj.p] = [9]; if (obj.p != 9) throw "obj.p not set by array destructuring assignment"; [arr[0]] = [9]; if (arr[0] != 9) throw "arr[0] not set by array destructuring assignment"; ({prop:obj.p} = {prop:12}); if (obj.p != 12) throw "obj.p not set by object destructuring assignment"; ({prop:arr[0]} = {prop:12}); if (arr[0] != 12) throw "arr[0] not set by object destructuring assignment"; */ "success" rhino-1.7R4/testsrc/opt-1.tests000066400000000000000000001474361176760007500164510ustar00rootroot00000000000000e4x/Expressions/11.1.1.js e4x/Expressions/11.1.2.js e4x/Expressions/11.1.3.js e4x/Expressions/11.1.4-06.js e4x/Expressions/11.1.4-07.js e4x/Expressions/11.1.5.js e4x/Expressions/11.2.1.js e4x/Expressions/11.2.2.js e4x/Expressions/11.2.3.js e4x/Expressions/11.2.4.js e4x/Expressions/11.3.1.js e4x/Expressions/11.3.2.js e4x/Expressions/11.4.1.js e4x/Expressions/11.5.1.js e4x/Expressions/11.6.3.js e4x/Expressions/regress-301545.js e4x/Expressions/regress-302531.js e4x/Expressions/regress-340024.js e4x/GC/regress-292455.js e4x/GC/regress-313952-01.js e4x/GC/regress-324117.js e4x/Namespace/13.2.1.js e4x/Namespace/13.2.2.js e4x/Namespace/13.2.5.js e4x/Namespace/regress-283972.js e4x/Namespace/regress-292863.js e4x/Namespace/regress-350442.js e4x/QName/13.3.1.js e4x/QName/13.3.2.js e4x/QName/13.3.5.js e4x/QName/regress-373595-01.js e4x/QName/regress-373595-02.js e4x/QName/regress-373595-03.js e4x/Regress/regress-263935.js e4x/Regress/regress-263936.js e4x/Regress/regress-264369.js e4x/Regress/regress-271545.js e4x/Regress/regress-277650.js e4x/Regress/regress-277664.js e4x/Regress/regress-277683.js e4x/Regress/regress-277935.js e4x/Regress/regress-283349.js e4x/Regress/regress-290056.js e4x/Regress/regress-301573.js e4x/Regress/regress-301596.js e4x/Regress/regress-301692.js e4x/Regress/regress-313799.js e4x/Regress/regress-325425.js e4x/Regress/regress-327691-01.js e4x/Regress/regress-327691-02.js e4x/Regress/regress-327697.js e4x/Regress/regress-328249.js e4x/Regress/regress-329257.js e4x/Regress/regress-331664.js e4x/Regress/regress-350206-1.js e4x/Regress/regress-350206.js e4x/Regress/regress-352103.js e4x/Regress/regress-354145-01.js e4x/Regress/regress-354145-02.js e4x/Regress/regress-354145-03.js e4x/Regress/regress-354145-04.js e4x/Regress/regress-354145-05.js e4x/Regress/regress-354145-07.js e4x/Regress/regress-355474-02.js e4x/Regress/regress-356238-01.js e4x/Regress/regress-369032.js e4x/Regress/regress-369536.js e4x/Regress/regress-372564.js e4x/Regress/regress-374106.js e4x/Regress/regress-374112.js e4x/Regress/regress-374116.js e4x/Regress/regress-374160.js e4x/Regress/regress-378492.js e4x/Regress/regress-407323.js e4x/Statements/12.1.js e4x/Statements/12.2.js e4x/Statements/12.3-01.js e4x/TypeConversion/10.1.2.js e4x/TypeConversion/10.3.1.js e4x/TypeConversion/10.3.js e4x/TypeConversion/10.4.1.js e4x/TypeConversion/10.4.js e4x/Types/9.1.1.1.js e4x/Types/9.1.1.2.js e4x/Types/9.1.1.3.js e4x/Types/9.1.1.6.js e4x/Types/9.2.1.1.js e4x/Types/9.2.1.2.js e4x/Types/9.2.1.8.js e4x/XML/13.4.1.js e4x/XML/13.4.2.js e4x/XML/13.4.3.10.js e4x/XML/13.4.4.12-1.js e4x/XML/13.4.4.12.js e4x/XML/13.4.4.13.js e4x/XML/13.4.4.14.js e4x/XML/13.4.4.15.js e4x/XML/13.4.4.16.js e4x/XML/13.4.4.18.js e4x/XML/13.4.4.19.js e4x/XML/13.4.4.2.js e4x/XML/13.4.4.20.js e4x/XML/13.4.4.21.js e4x/XML/13.4.4.23.js e4x/XML/13.4.4.24.js e4x/XML/13.4.4.25.js e4x/XML/13.4.4.27.js e4x/XML/13.4.4.3.js e4x/XML/13.4.4.30.js e4x/XML/13.4.4.31.js e4x/XML/13.4.4.32-01.js e4x/XML/13.4.4.32.js e4x/XML/13.4.4.33.js e4x/XML/13.4.4.34.js e4x/XML/13.4.4.35.js e4x/XML/13.4.4.36.js e4x/XML/13.4.4.37.js e4x/XML/13.4.4.38.js e4x/XML/13.4.4.39.js e4x/XML/13.4.4.4.js e4x/XML/13.4.4.40.js e4x/XML/13.4.4.5.js e4x/XML/13.4.4.7.js e4x/XML/13.4.4.8.js e4x/XML/regress-291930.js e4x/XML/regress-324688.js e4x/XML/regress-336921.js e4x/XMLList/13.5.1.js e4x/XMLList/13.5.2.js e4x/XMLList/13.5.4.10.js e4x/XMLList/13.5.4.11.js e4x/XMLList/13.5.4.12.js e4x/XMLList/13.5.4.13.js e4x/XMLList/13.5.4.14.js e4x/XMLList/13.5.4.15.js e4x/XMLList/13.5.4.16.js e4x/XMLList/13.5.4.17.js e4x/XMLList/13.5.4.18.js e4x/XMLList/13.5.4.19.js e4x/XMLList/13.5.4.2.js e4x/XMLList/13.5.4.20.js e4x/XMLList/13.5.4.21.js e4x/XMLList/13.5.4.22.js e4x/XMLList/13.5.4.3.js e4x/XMLList/13.5.4.4.js e4x/XMLList/13.5.4.5.js e4x/XMLList/13.5.4.6.js e4x/XMLList/13.5.4.7.js e4x/XMLList/13.5.4.8.js e4x/XMLList/13.5.4.9.js e4x/decompilation/regress-349814.js e4x/decompilation/regress-349815.js e4x/decompilation/regress-349822.js e4x/decompilation/regress-349956.js e4x/decompilation/regress-355474-01.js e4x/decompilation/regress-373678.js e4x/extensions/regress-305335.js e4x/extensions/regress-321547.js e4x/extensions/regress-327534.js e4x/extensions/regress-327897.js e4x/extensions/regress-354145-06.js e4x/extensions/regress-354151-01.js ecma/Array/15.4-1.js ecma/Array/15.4-2.js ecma/Array/15.4.1.1.js ecma/Array/15.4.1.2.js ecma/Array/15.4.1.3.js ecma/Array/15.4.1.js ecma/Array/15.4.2.1-1.js ecma/Array/15.4.2.1-2.js ecma/Array/15.4.2.1-3.js ecma/Array/15.4.2.2-1.js ecma/Array/15.4.2.2-2.js ecma/Array/15.4.2.3.js ecma/Array/15.4.3.2.js ecma/Array/15.4.4.1.js ecma/Array/15.4.4.2.js ecma/Array/15.4.4.3-1.js ecma/Array/15.4.4.4-1.js ecma/Array/15.4.4.4-2.js ecma/Array/15.4.4.5-1.js ecma/Array/15.4.4.5-2.js ecma/Array/15.4.4.js ecma/Array/15.4.5.1-2.js ecma/Array/15.4.5.2-1.js ecma/Array/15.4.5.2-2.js ecma/Boolean/15.6.2.js ecma/Boolean/15.6.3.1-1.js ecma/Boolean/15.6.3.1-2.js ecma/Boolean/15.6.3.1.js ecma/Boolean/15.6.4-1.js ecma/Boolean/15.6.4.1.js ecma/Boolean/15.6.4.2-2.js ecma/Boolean/15.6.4.2-3.js ecma/Boolean/15.6.4.2-4-n.js ecma/Boolean/15.6.4.3-1.js ecma/Boolean/15.6.4.3-2.js ecma/Boolean/15.6.4.3-3.js ecma/Boolean/15.6.4.3-4-n.js ecma/Boolean/15.6.4.3.js ecma/Boolean/15.6.4.js ecma/Date/15.9.1.1-1.js ecma/Date/15.9.1.1-2.js ecma/Date/15.9.1.13-1.js ecma/Date/15.9.2.1.js ecma/Date/15.9.2.2-1.js ecma/Date/15.9.2.2-2.js ecma/Date/15.9.2.2-3.js ecma/Date/15.9.2.2-5.js ecma/Date/15.9.2.2-6.js ecma/Date/15.9.3.1-2.js ecma/Date/15.9.3.1-3.js ecma/Date/15.9.3.1-4.js ecma/Date/15.9.3.1-5.js ecma/Date/15.9.3.2-2.js ecma/Date/15.9.3.2-3.js ecma/Date/15.9.3.2-4.js ecma/Date/15.9.3.2-5.js ecma/Date/15.9.3.8-1.js ecma/Date/15.9.3.8-2.js ecma/Date/15.9.3.8-3.js ecma/Date/15.9.3.8-4.js ecma/Date/15.9.3.8-5.js ecma/Date/15.9.4.2.js ecma/Date/15.9.4.3.js ecma/Date/15.9.5.1.js ecma/Date/15.9.5.10-1.js ecma/Date/15.9.5.10-10.js ecma/Date/15.9.5.10-11.js ecma/Date/15.9.5.10-12.js ecma/Date/15.9.5.10-13.js ecma/Date/15.9.5.10-4.js ecma/Date/15.9.5.10-5.js ecma/Date/15.9.5.10-6.js ecma/Date/15.9.5.10-7.js ecma/Date/15.9.5.10-8.js ecma/Date/15.9.5.10-9.js ecma/Date/15.9.5.11-1.js ecma/Date/15.9.5.11-3.js ecma/Date/15.9.5.11-4.js ecma/Date/15.9.5.11-5.js ecma/Date/15.9.5.11-6.js ecma/Date/15.9.5.11-7.js ecma/Date/15.9.5.12-1.js ecma/Date/15.9.5.12-3.js ecma/Date/15.9.5.12-4.js ecma/Date/15.9.5.12-5.js ecma/Date/15.9.5.12-6.js ecma/Date/15.9.5.12-7.js ecma/Date/15.9.5.12-8.js ecma/Date/15.9.5.13-1.js ecma/Date/15.9.5.13-2.js ecma/Date/15.9.5.13-3.js ecma/Date/15.9.5.13-4.js ecma/Date/15.9.5.13-5.js ecma/Date/15.9.5.13-6.js ecma/Date/15.9.5.13-7.js ecma/Date/15.9.5.13-8.js ecma/Date/15.9.5.14.js ecma/Date/15.9.5.15.js ecma/Date/15.9.5.16.js ecma/Date/15.9.5.17.js ecma/Date/15.9.5.19.js ecma/Date/15.9.5.2-2-n.js ecma/Date/15.9.5.2.js ecma/Date/15.9.5.20.js ecma/Date/15.9.5.21-1.js ecma/Date/15.9.5.21-2.js ecma/Date/15.9.5.21-3.js ecma/Date/15.9.5.21-4.js ecma/Date/15.9.5.21-5.js ecma/Date/15.9.5.21-6.js ecma/Date/15.9.5.21-7.js ecma/Date/15.9.5.21-8.js ecma/Date/15.9.5.22-2.js ecma/Date/15.9.5.22-3.js ecma/Date/15.9.5.22-4.js ecma/Date/15.9.5.22-5.js ecma/Date/15.9.5.22-6.js ecma/Date/15.9.5.22-7.js ecma/Date/15.9.5.22-8.js ecma/Date/15.9.5.23-1.js ecma/Date/15.9.5.23-10.js ecma/Date/15.9.5.23-11.js ecma/Date/15.9.5.23-12.js ecma/Date/15.9.5.23-13.js ecma/Date/15.9.5.23-14.js ecma/Date/15.9.5.23-15.js ecma/Date/15.9.5.23-16.js ecma/Date/15.9.5.23-17.js ecma/Date/15.9.5.23-18.js ecma/Date/15.9.5.23-2.js ecma/Date/15.9.5.23-3-n.js ecma/Date/15.9.5.23-4.js ecma/Date/15.9.5.23-5.js ecma/Date/15.9.5.23-6.js ecma/Date/15.9.5.23-7.js ecma/Date/15.9.5.23-8.js ecma/Date/15.9.5.23-9.js ecma/Date/15.9.5.24-1.js ecma/Date/15.9.5.24-2.js ecma/Date/15.9.5.24-3.js ecma/Date/15.9.5.24-4.js ecma/Date/15.9.5.24-5.js ecma/Date/15.9.5.24-6.js ecma/Date/15.9.5.24-7.js ecma/Date/15.9.5.24-8.js ecma/Date/15.9.5.25-1.js ecma/Date/15.9.5.26-1.js ecma/Date/15.9.5.27-1.js ecma/Date/15.9.5.28-1.js ecma/Date/15.9.5.29-1.js ecma/Date/15.9.5.3-2.js ecma/Date/15.9.5.30-1.js ecma/Date/15.9.5.31-1.js ecma/Date/15.9.5.32-1.js ecma/Date/15.9.5.33-1.js ecma/Date/15.9.5.34-1.js ecma/Date/15.9.5.35-1.js ecma/Date/15.9.5.36-1.js ecma/Date/15.9.5.36-2.js ecma/Date/15.9.5.36-4.js ecma/Date/15.9.5.36-5.js ecma/Date/15.9.5.36-6.js ecma/Date/15.9.5.36-7.js ecma/Date/15.9.5.37-2.js ecma/Date/15.9.5.37-3.js ecma/Date/15.9.5.37-4.js ecma/Date/15.9.5.37-5.js ecma/Date/15.9.5.4-1.js ecma/Date/15.9.5.4-2-n.js ecma/Date/15.9.5.6.js ecma/Date/15.9.5.7.js ecma/Date/15.9.5.8.js ecma/Date/15.9.5.9.js ecma/Date/15.9.5.js ecma/ExecutionContexts/10.1.3-1.js ecma/ExecutionContexts/10.1.3-2.js ecma/ExecutionContexts/10.1.3.js ecma/ExecutionContexts/10.1.4-1.js ecma/ExecutionContexts/10.1.4-10.js ecma/ExecutionContexts/10.1.4-3.js ecma/ExecutionContexts/10.1.4-4.js ecma/ExecutionContexts/10.1.4-5.js ecma/ExecutionContexts/10.1.4-6.js ecma/ExecutionContexts/10.1.4-7.js ecma/ExecutionContexts/10.1.4-8.js ecma/ExecutionContexts/10.1.5-1.js ecma/ExecutionContexts/10.1.5-2.js ecma/ExecutionContexts/10.1.5-3.js ecma/ExecutionContexts/10.1.5-4.js ecma/ExecutionContexts/10.1.8-2.js ecma/ExecutionContexts/10.1.8-3.js ecma/ExecutionContexts/10.2.1.js ecma/ExecutionContexts/10.2.2-1.js ecma/ExecutionContexts/10.2.2-2.js ecma/ExecutionContexts/10.2.3-1.js ecma/ExecutionContexts/10.2.3-2.js ecma/Expressions/11.1.1.js ecma/Expressions/11.10-1.js ecma/Expressions/11.10-2.js ecma/Expressions/11.10-3.js ecma/Expressions/11.12-1.js ecma/Expressions/11.12-2-n.js ecma/Expressions/11.12-3.js ecma/Expressions/11.12-4.js ecma/Expressions/11.13.1.js ecma/Expressions/11.13.2-1.js ecma/Expressions/11.13.2-2.js ecma/Expressions/11.13.2-3.js ecma/Expressions/11.13.2-4.js ecma/Expressions/11.13.2-5.js ecma/Expressions/11.14-1.js ecma/Expressions/11.2.1-1.js ecma/Expressions/11.2.1-2.js ecma/Expressions/11.2.1-3-n.js ecma/Expressions/11.2.1-4-n.js ecma/Expressions/11.2.1-5.js ecma/Expressions/11.2.2-1-n.js ecma/Expressions/11.2.2-1.js ecma/Expressions/11.2.2-10-n.js ecma/Expressions/11.2.2-11.js ecma/Expressions/11.2.2-2-n.js ecma/Expressions/11.2.2-3-n.js ecma/Expressions/11.2.2-4-n.js ecma/Expressions/11.2.2-5-n.js ecma/Expressions/11.2.2-6-n.js ecma/Expressions/11.2.2-7-n.js ecma/Expressions/11.2.2-8-n.js ecma/Expressions/11.2.2-9-n.js ecma/Expressions/11.2.3-1.js ecma/Expressions/11.2.3-2-n.js ecma/Expressions/11.2.3-3-n.js ecma/Expressions/11.2.3-4-n.js ecma/Expressions/11.2.3-5.js ecma/Expressions/11.3.1.js ecma/Expressions/11.3.2.js ecma/Expressions/11.4.2.js ecma/Expressions/11.4.3.js ecma/Expressions/11.4.4.js ecma/Expressions/11.4.5.js ecma/Expressions/11.4.6.js ecma/Expressions/11.4.8.js ecma/Expressions/11.4.9.js ecma/Expressions/11.5.1.js ecma/Expressions/11.5.2.js ecma/Expressions/11.5.3.js ecma/Expressions/11.6.1-1.js ecma/Expressions/11.6.1-2.js ecma/Expressions/11.6.1-3.js ecma/Expressions/11.6.2-1.js ecma/Expressions/11.6.3.js ecma/Expressions/11.7.1.js ecma/Expressions/11.7.2.js ecma/Expressions/11.8.1.js ecma/Expressions/11.8.2.js ecma/Expressions/11.8.3.js ecma/Expressions/11.9.2.js ecma/Expressions/11.9.3.js ecma/FunctionObjects/15.3.1.1-1.js ecma/FunctionObjects/15.3.1.1-2.js ecma/FunctionObjects/15.3.1.1-3.js ecma/FunctionObjects/15.3.2.1-1.js ecma/FunctionObjects/15.3.2.1-2.js ecma/FunctionObjects/15.3.2.1-3.js ecma/FunctionObjects/15.3.3.1-2.js ecma/FunctionObjects/15.3.3.1-3.js ecma/FunctionObjects/15.3.3.1-4.js ecma/FunctionObjects/15.3.3.2.js ecma/FunctionObjects/15.3.4-1.js ecma/FunctionObjects/15.3.4.1.js ecma/FunctionObjects/15.3.4.js ecma/FunctionObjects/15.3.5-1.js ecma/FunctionObjects/15.3.5-2.js ecma/FunctionObjects/15.3.5.1.js ecma/FunctionObjects/15.3.5.3.js ecma/GlobalObject/15.1-1-n.js ecma/GlobalObject/15.1-2-n.js ecma/GlobalObject/15.1.1.1.js ecma/GlobalObject/15.1.1.2.js ecma/GlobalObject/15.1.2.1-2.js ecma/GlobalObject/15.1.2.2-2.js ecma/GlobalObject/15.1.2.3-2.js ecma/GlobalObject/15.1.2.5-2.js ecma/GlobalObject/15.1.2.5-3.js ecma/LexicalConventions/7.1-1.js ecma/LexicalConventions/7.1-2.js ecma/LexicalConventions/7.1-3.js ecma/LexicalConventions/7.2-1.js ecma/LexicalConventions/7.2-2-n.js ecma/LexicalConventions/7.2-3-n.js ecma/LexicalConventions/7.2-4-n.js ecma/LexicalConventions/7.2-5-n.js ecma/LexicalConventions/7.2-6.js ecma/LexicalConventions/7.3-1.js ecma/LexicalConventions/7.3-10.js ecma/LexicalConventions/7.3-11.js ecma/LexicalConventions/7.3-12.js ecma/LexicalConventions/7.3-13-n.js ecma/LexicalConventions/7.3-2.js ecma/LexicalConventions/7.3-3.js ecma/LexicalConventions/7.3-4.js ecma/LexicalConventions/7.3-5.js ecma/LexicalConventions/7.3-6.js ecma/LexicalConventions/7.3-8.js ecma/LexicalConventions/7.3-9.js ecma/LexicalConventions/7.4.1-1-n.js ecma/LexicalConventions/7.4.1-2-n.js ecma/LexicalConventions/7.4.1-3-n.js ecma/LexicalConventions/7.4.2-1-n.js ecma/LexicalConventions/7.4.2-10-n.js ecma/LexicalConventions/7.4.2-11-n.js ecma/LexicalConventions/7.4.2-12-n.js ecma/LexicalConventions/7.4.2-13-n.js ecma/LexicalConventions/7.4.2-14-n.js ecma/LexicalConventions/7.4.2-15-n.js ecma/LexicalConventions/7.4.2-16-n.js ecma/LexicalConventions/7.4.2-2-n.js ecma/LexicalConventions/7.4.2-3-n.js ecma/LexicalConventions/7.4.2-4-n.js ecma/LexicalConventions/7.4.2-5-n.js ecma/LexicalConventions/7.4.2-6-n.js ecma/LexicalConventions/7.4.2-7-n.js ecma/LexicalConventions/7.4.2-8-n.js ecma/LexicalConventions/7.4.3-1-n.js ecma/LexicalConventions/7.4.3-10-n.js ecma/LexicalConventions/7.4.3-11-n.js ecma/LexicalConventions/7.4.3-13-n.js ecma/LexicalConventions/7.4.3-15-n.js ecma/LexicalConventions/7.4.3-16-n.js ecma/LexicalConventions/7.4.3-2-n.js ecma/LexicalConventions/7.4.3-3-n.js ecma/LexicalConventions/7.4.3-4-n.js ecma/LexicalConventions/7.4.3-5-n.js ecma/LexicalConventions/7.4.3-6-n.js ecma/LexicalConventions/7.4.3-7-n.js ecma/LexicalConventions/7.4.3-8-n.js ecma/LexicalConventions/7.4.3-9-n.js ecma/LexicalConventions/7.5-1.js ecma/LexicalConventions/7.5-10-n.js ecma/LexicalConventions/7.5-2-n.js ecma/LexicalConventions/7.5-3-n.js ecma/LexicalConventions/7.5-4-n.js ecma/LexicalConventions/7.5-5-n.js ecma/LexicalConventions/7.5-6.js ecma/LexicalConventions/7.5-7.js ecma/LexicalConventions/7.5-8-n.js ecma/LexicalConventions/7.5-9-n.js ecma/LexicalConventions/7.6.js ecma/LexicalConventions/7.7.1.js ecma/LexicalConventions/7.7.2.js ecma/LexicalConventions/7.7.3-1.js ecma/LexicalConventions/7.7.3-2.js ecma/LexicalConventions/7.7.3.js ecma/LexicalConventions/7.7.4.js ecma/LexicalConventions/7.8.2-n.js ecma/Math/15.8-2-n.js ecma/Math/15.8-3-n.js ecma/Math/15.8.1.1-1.js ecma/Math/15.8.1.1-2.js ecma/Math/15.8.1.2-1.js ecma/Math/15.8.1.3-1.js ecma/Math/15.8.1.3-2.js ecma/Math/15.8.1.4-1.js ecma/Math/15.8.1.4-2.js ecma/Math/15.8.1.5-1.js ecma/Math/15.8.1.5-2.js ecma/Math/15.8.1.6-1.js ecma/Math/15.8.1.6-2.js ecma/Math/15.8.1.7-1.js ecma/Math/15.8.1.7-2.js ecma/Math/15.8.1.8-1.js ecma/Math/15.8.1.8-2.js ecma/Math/15.8.1.8-3.js ecma/Math/15.8.2.1.js ecma/Math/15.8.2.10.js ecma/Math/15.8.2.12.js ecma/Math/15.8.2.13.js ecma/Math/15.8.2.14.js ecma/Math/15.8.2.15.js ecma/Math/15.8.2.16.js ecma/Math/15.8.2.17.js ecma/Math/15.8.2.18.js ecma/Math/15.8.2.2.js ecma/Math/15.8.2.3.js ecma/Math/15.8.2.4.js ecma/Math/15.8.2.5.js ecma/Math/15.8.2.6.js ecma/Math/15.8.2.7.js ecma/Math/15.8.2.8.js ecma/Math/15.8.2.9.js ecma/Number/15.7.2.js ecma/Number/15.7.3.1-1.js ecma/Number/15.7.3.1-2.js ecma/Number/15.7.3.1-3.js ecma/Number/15.7.3.2-1.js ecma/Number/15.7.3.2-2.js ecma/Number/15.7.3.2-3.js ecma/Number/15.7.3.3-1.js ecma/Number/15.7.3.3-2.js ecma/Number/15.7.3.3-3.js ecma/Number/15.7.3.4-1.js ecma/Number/15.7.3.4-2.js ecma/Number/15.7.3.4-3.js ecma/Number/15.7.3.4-4.js ecma/Number/15.7.3.5-1.js ecma/Number/15.7.3.5-2.js ecma/Number/15.7.3.5-3.js ecma/Number/15.7.3.5-4.js ecma/Number/15.7.3.6-1.js ecma/Number/15.7.3.6-4.js ecma/Number/15.7.3.js ecma/Number/15.7.4-1.js ecma/Number/15.7.4.1.js ecma/Number/15.7.4.2-1.js ecma/Number/15.7.4.2-2-n.js ecma/Number/15.7.4.2-3-n.js ecma/Number/15.7.4.2-4.js ecma/Number/15.7.4.3-1.js ecma/Number/15.7.4.3-2.js ecma/ObjectObjects/15.2.1.2.js ecma/ObjectObjects/15.2.2.1.js ecma/ObjectObjects/15.2.2.2.js ecma/ObjectObjects/15.2.3.1-1.js ecma/ObjectObjects/15.2.3.1-2.js ecma/ObjectObjects/15.2.3.1-3.js ecma/ObjectObjects/15.2.3.1-4.js ecma/ObjectObjects/15.2.3.js ecma/ObjectObjects/15.2.4.1.js ecma/ObjectObjects/15.2.4.2.js ecma/ObjectObjects/15.2.4.3.js ecma/SourceText/6-1.js ecma/SourceText/6-2.js ecma/Statements/12.10-1.js ecma/Statements/12.10.js ecma/Statements/12.5-1.js ecma/Statements/12.5-2.js ecma/Statements/12.6.2-1.js ecma/Statements/12.6.2-2.js ecma/Statements/12.6.2-4.js ecma/Statements/12.6.2-5.js ecma/Statements/12.6.2-6.js ecma/Statements/12.6.2-7.js ecma/Statements/12.6.2-8.js ecma/Statements/12.6.2-9-n.js ecma/Statements/12.6.3-1.js ecma/Statements/12.6.3-10.js ecma/Statements/12.6.3-11.js ecma/Statements/12.6.3-12.js ecma/Statements/12.6.3-19.js ecma/Statements/12.6.3-2.js ecma/Statements/12.6.3-3.js ecma/Statements/12.6.3-4.js ecma/Statements/12.6.3-5-n.js ecma/Statements/12.6.3-6-n.js ecma/Statements/12.6.3-7-n.js ecma/Statements/12.6.3-9-n.js ecma/Statements/12.7-1-n.js ecma/Statements/12.8-1-n.js ecma/Statements/12.9-1-n.js ecma/String/15.5.1.js ecma/String/15.5.2.js ecma/String/15.5.3.1-1.js ecma/String/15.5.3.1-2.js ecma/String/15.5.3.1-3.js ecma/String/15.5.3.1-4.js ecma/String/15.5.3.2-1.js ecma/String/15.5.3.2-2.js ecma/String/15.5.3.2-3.js ecma/String/15.5.3.js ecma/String/15.5.4.1.js ecma/String/15.5.4.10-1.js ecma/String/15.5.4.11-1.js ecma/String/15.5.4.11-3.js ecma/String/15.5.4.11-4.js ecma/String/15.5.4.11-6.js ecma/String/15.5.4.12-2.js ecma/String/15.5.4.12-3.js ecma/String/15.5.4.2-1.js ecma/String/15.5.4.2-2-n.js ecma/String/15.5.4.2-3.js ecma/String/15.5.4.2.js ecma/String/15.5.4.3-1.js ecma/String/15.5.4.3-2.js ecma/String/15.5.4.3-3-n.js ecma/String/15.5.4.4-1.js ecma/String/15.5.4.4-2.js ecma/String/15.5.4.4-3.js ecma/String/15.5.4.4-4.js ecma/String/15.5.4.5-1.js ecma/String/15.5.4.5-2.js ecma/String/15.5.4.5-3.js ecma/String/15.5.4.5-4.js ecma/String/15.5.4.5-5.js ecma/String/15.5.4.6-1.js ecma/String/15.5.4.7-2.js ecma/String/15.5.4.8-1.js ecma/String/15.5.4.8-3.js ecma/String/15.5.4.9-1.js ecma/String/15.5.4.js ecma/String/15.5.5.1.js ecma/TypeConversion/9.2.js ecma/TypeConversion/9.3-1.js ecma/TypeConversion/9.3.1-1.js ecma/TypeConversion/9.3.1-2.js ecma/TypeConversion/9.3.1-3.js ecma/TypeConversion/9.3.js ecma/TypeConversion/9.4-1.js ecma/TypeConversion/9.4-2.js ecma/TypeConversion/9.5-2.js ecma/TypeConversion/9.6.js ecma/TypeConversion/9.7.js ecma/TypeConversion/9.8.1.js ecma/TypeConversion/9.9-1.js ecma/Types/8.1.js ecma/Types/8.4.js ecma/Types/8.6.2.1-1.js ecma/extensions/10.1.4-9.js ecma/extensions/10.1.6.js ecma/extensions/10.1.8-1.js ecma/extensions/11.6.1-1.js ecma/extensions/11.6.1-2.js ecma/extensions/11.6.1-3.js ecma/extensions/11.6.2-1.js ecma/extensions/15-2.js ecma/extensions/15.2.1.1.js ecma/extensions/15.2.3-1.js ecma/extensions/15.2.4.js ecma/extensions/15.3.1.1-2.js ecma/extensions/15.3.2.1-1.js ecma/extensions/15.3.2.1-2.js ecma/extensions/15.4.3.js ecma/extensions/15.5.3.js ecma/extensions/15.5.4.2.js ecma/extensions/15.5.4.4-4.js ecma/extensions/15.5.4.5-6.js ecma/extensions/15.5.4.7-3.js ecma/extensions/15.6.3.1-5.js ecma/extensions/15.6.3.js ecma/extensions/15.6.4-2.js ecma/extensions/15.7.3.js ecma/extensions/15.7.4.js ecma/extensions/15.8-1.js ecma/extensions/15.9.5.js ecma/extensions/8.6.2.1-1.js ecma/extensions/9.9-1.js ecma/jsref.js ecma_2/Exceptions/boolean-001.js ecma_2/Exceptions/date-001.js ecma_2/Exceptions/date-002.js ecma_2/Exceptions/date-004.js ecma_2/Exceptions/exception-001.js ecma_2/Exceptions/exception-002.js ecma_2/Exceptions/exception-004.js ecma_2/Exceptions/exception-005.js ecma_2/Exceptions/exception-006.js ecma_2/Exceptions/exception-007.js ecma_2/Exceptions/exception-008.js ecma_2/Exceptions/exception-009.js ecma_2/Exceptions/exception-010-n.js ecma_2/Exceptions/exception-011-n.js ecma_2/Exceptions/expression-002.js ecma_2/Exceptions/expression-004.js ecma_2/Exceptions/expression-005.js ecma_2/Exceptions/expression-006.js ecma_2/Exceptions/expression-007.js ecma_2/Exceptions/expression-008.js ecma_2/Exceptions/expression-009.js ecma_2/Exceptions/expression-010.js ecma_2/Exceptions/expression-011.js ecma_2/Exceptions/expression-012.js ecma_2/Exceptions/expression-013.js ecma_2/Exceptions/expression-014.js ecma_2/Exceptions/expression-015.js ecma_2/Exceptions/expression-016.js ecma_2/Exceptions/expression-017.js ecma_2/Exceptions/global-001.js ecma_2/Exceptions/global-002.js ecma_2/Exceptions/lexical-001.js ecma_2/Exceptions/lexical-002.js ecma_2/Exceptions/lexical-003.js ecma_2/Exceptions/lexical-004.js ecma_2/Exceptions/lexical-005.js ecma_2/Exceptions/lexical-006.js ecma_2/Exceptions/lexical-007.js ecma_2/Exceptions/lexical-009.js ecma_2/Exceptions/lexical-010.js ecma_2/Exceptions/lexical-011.js ecma_2/Exceptions/lexical-012.js ecma_2/Exceptions/lexical-013.js ecma_2/Exceptions/lexical-014.js ecma_2/Exceptions/lexical-015.js ecma_2/Exceptions/lexical-016.js ecma_2/Exceptions/lexical-017.js ecma_2/Exceptions/lexical-018.js ecma_2/Exceptions/lexical-019.js ecma_2/Exceptions/lexical-020.js ecma_2/Exceptions/lexical-022.js ecma_2/Exceptions/lexical-023.js ecma_2/Exceptions/lexical-024.js ecma_2/Exceptions/lexical-025.js ecma_2/Exceptions/lexical-026.js ecma_2/Exceptions/lexical-027.js ecma_2/Exceptions/lexical-028.js ecma_2/Exceptions/lexical-029.js ecma_2/Exceptions/lexical-030.js ecma_2/Exceptions/lexical-031.js ecma_2/Exceptions/lexical-032.js ecma_2/Exceptions/lexical-033.js ecma_2/Exceptions/lexical-034.js ecma_2/Exceptions/lexical-035.js ecma_2/Exceptions/lexical-036.js ecma_2/Exceptions/lexical-037.js ecma_2/Exceptions/lexical-038.js ecma_2/Exceptions/lexical-039.js ecma_2/Exceptions/lexical-040.js ecma_2/Exceptions/lexical-041.js ecma_2/Exceptions/lexical-042.js ecma_2/Exceptions/lexical-047.js ecma_2/Exceptions/lexical-048.js ecma_2/Exceptions/lexical-049.js ecma_2/Exceptions/lexical-050.js ecma_2/Exceptions/lexical-051.js ecma_2/Exceptions/lexical-053.js ecma_2/Exceptions/lexical-054.js ecma_2/Exceptions/number-002.js ecma_2/Exceptions/number-003.js ecma_2/Exceptions/statement-001.js ecma_2/Exceptions/statement-002.js ecma_2/Exceptions/statement-003.js ecma_2/Exceptions/statement-004.js ecma_2/Exceptions/statement-005.js ecma_2/Exceptions/statement-006.js ecma_2/Exceptions/statement-007.js ecma_2/Exceptions/statement-008.js ecma_2/Exceptions/string-001.js ecma_2/Exceptions/string-002.js ecma_2/Expressions/StrictEquality-001.js ecma_2/FunctionObjects/apply-001-n.js ecma_2/FunctionObjects/call-1.js ecma_2/LexicalConventions/keywords-001.js ecma_2/LexicalConventions/regexp-literals-001.js ecma_2/LexicalConventions/regexp-literals-002.js ecma_2/RegExp/constructor-001.js ecma_2/RegExp/exec-002.js ecma_2/RegExp/function-001.js ecma_2/RegExp/hex-001.js ecma_2/RegExp/multiline-001.js ecma_2/RegExp/octal-001.js ecma_2/RegExp/octal-002.js ecma_2/RegExp/octal-003.js ecma_2/RegExp/properties-001.js ecma_2/RegExp/properties-002.js ecma_2/RegExp/regress-001.js ecma_2/RegExp/unicode-001.js ecma_2/Statements/dowhile-001.js ecma_2/Statements/dowhile-002.js ecma_2/Statements/dowhile-003.js ecma_2/Statements/dowhile-004.js ecma_2/Statements/dowhile-005.js ecma_2/Statements/dowhile-006.js ecma_2/Statements/dowhile-007.js ecma_2/Statements/forin-001.js ecma_2/Statements/forin-002.js ecma_2/Statements/if-001.js ecma_2/Statements/label-001.js ecma_2/Statements/label-002.js ecma_2/Statements/switch-002.js ecma_2/Statements/switch-003.js ecma_2/Statements/switch-004.js ecma_2/Statements/try-001.js ecma_2/Statements/try-003.js ecma_2/Statements/try-004.js ecma_2/Statements/try-005.js ecma_2/Statements/try-007.js ecma_2/Statements/try-008.js ecma_2/Statements/try-009.js ecma_2/Statements/try-012.js ecma_2/Statements/while-001.js ecma_2/Statements/while-002.js ecma_2/Statements/while-003.js ecma_2/Statements/while-004.js ecma_2/String/match-001.js ecma_2/String/match-002.js ecma_2/String/match-003.js ecma_2/String/match-004.js ecma_2/String/split-001.js ecma_2/String/split-002.js ecma_2/String/split-003.js ecma_2/extensions/constructor-001.js ecma_2/extensions/function-001.js ecma_2/extensions/instanceof-001.js ecma_2/extensions/instanceof-002.js ecma_2/extensions/instanceof-006.js ecma_2/instanceof/instanceof-001.js ecma_2/instanceof/instanceof-002.js ecma_2/instanceof/regress-7635.js ecma_2/jsref.js ecma_3/Array/15.4.4.11-01.js ecma_3/Array/15.4.4.3-1.js ecma_3/Array/15.4.4.4-001.js ecma_3/Array/regress-101488.js ecma_3/Array/regress-130451.js ecma_3/Array/regress-322135-01.js ecma_3/Date/15.9.4.3.js ecma_3/Date/15.9.5.3.js ecma_3/Date/15.9.5.4.js ecma_3/Date/15.9.5.6.js ecma_3/Date/15.9.5.7.js ecma_3/Exceptions/15.11.1.1.js ecma_3/Exceptions/15.11.4.4-1.js ecma_3/Exceptions/15.11.7.6-001.js ecma_3/Exceptions/15.11.7.6-002.js ecma_3/Exceptions/15.11.7.6-003.js ecma_3/Exceptions/binding-001.js ecma_3/Exceptions/regress-95101.js ecma_3/ExecutionContexts/10.1.3-1.js ecma_3/ExecutionContexts/10.1.3-2.js ecma_3/ExecutionContexts/10.1.3.js ecma_3/ExecutionContexts/10.1.4-1.js ecma_3/ExecutionContexts/10.6.1-01.js ecma_3/ExecutionContexts/regress-23346.js ecma_3/Expressions/11.10-01.js ecma_3/Expressions/11.10-03.js ecma_3/Expressions/11.6.1-1.js ecma_3/Expressions/11.7.1-01.js ecma_3/Expressions/11.7.2-01.js ecma_3/Expressions/11.7.3-01.js ecma_3/Expressions/11.9.6-1.js ecma_3/FunExpr/fe-001-n.js ecma_3/FunExpr/fe-001.js ecma_3/FunExpr/fe-002.js ecma_3/Function/15.3.4.3-1.js ecma_3/Function/15.3.4.4-1.js ecma_3/Function/arguments-002.js ecma_3/Function/call-001.js ecma_3/Function/regress-131964.js ecma_3/Function/regress-137181.js ecma_3/Function/regress-193555.js ecma_3/Function/regress-313570.js ecma_3/Function/regress-49286.js ecma_3/Function/regress-58274.js ecma_3/Function/regress-85880.js ecma_3/Function/regress-94506.js ecma_3/Function/regress-97921.js ecma_3/Function/scope-001.js ecma_3/Function/scope-002.js ecma_3/Number/15.7.4.5-1.js ecma_3/Number/15.7.4.6-1.js ecma_3/Number/15.7.4.7-1.js ecma_3/Number/15.7.4.7-2.js ecma_3/NumberFormatting/tostring-001.js ecma_3/Object/8.6.2.6-001.js ecma_3/Object/class-001.js ecma_3/Object/class-002.js ecma_3/Object/class-003.js ecma_3/Object/class-004.js ecma_3/Object/class-005.js ecma_3/Object/regress-361274.js ecma_3/Object/regress-385393-07.js ecma_3/Object/regress-72773.js ecma_3/Object/regress-79129-001.js ecma_3/Operators/11.13.1-001.js ecma_3/Operators/11.13.1-002.js ecma_3/Operators/11.4.1-001.js ecma_3/RegExp/15.10.2-1.js ecma_3/RegExp/15.10.2.12.js ecma_3/RegExp/15.10.3.1-1.js ecma_3/RegExp/15.10.3.1-2.js ecma_3/RegExp/15.10.4.1-1.js ecma_3/RegExp/15.10.4.1-2.js ecma_3/RegExp/15.10.4.1-3.js ecma_3/RegExp/15.10.4.1-4.js ecma_3/RegExp/15.10.4.1-5-n.js ecma_3/RegExp/15.10.6.2-1.js ecma_3/RegExp/15.10.6.2-2.js ecma_3/RegExp/octal-001.js ecma_3/RegExp/octal-002.js ecma_3/RegExp/perlstress-001.js ecma_3/RegExp/perlstress-002.js ecma_3/RegExp/regress-100199.js ecma_3/RegExp/regress-105972.js ecma_3/RegExp/regress-122076.js ecma_3/RegExp/regress-123437.js ecma_3/RegExp/regress-165353.js ecma_3/RegExp/regress-169497.js ecma_3/RegExp/regress-169534.js ecma_3/RegExp/regress-187133.js ecma_3/RegExp/regress-191479.js ecma_3/RegExp/regress-202564.js ecma_3/RegExp/regress-209067.js ecma_3/RegExp/regress-209919.js ecma_3/RegExp/regress-216591.js ecma_3/RegExp/regress-220367-001.js ecma_3/RegExp/regress-223273.js ecma_3/RegExp/regress-223535.js ecma_3/RegExp/regress-224676.js ecma_3/RegExp/regress-225289.js ecma_3/RegExp/regress-225343.js ecma_3/RegExp/regress-24712.js ecma_3/RegExp/regress-28686.js ecma_3/RegExp/regress-309840.js ecma_3/RegExp/regress-312351.js ecma_3/RegExp/regress-31316.js ecma_3/RegExp/regress-334158.js ecma_3/RegExp/regress-346090.js ecma_3/RegExp/regress-367888.js: ecma_3/RegExp/regress-375642.js: ecma_3/RegExp/regress-375715-02.js ecma_3/RegExp/regress-375715-03.js ecma_3/RegExp/regress-57572.js ecma_3/RegExp/regress-57631.js ecma_3/RegExp/regress-67773.js ecma_3/RegExp/regress-76683.js ecma_3/RegExp/regress-78156.js ecma_3/RegExp/regress-85721.js ecma_3/RegExp/regress-87231.js ecma_3/RegExp/regress-98306.js ecma_3/Statements/12.6.3.js ecma_3/Statements/regress-131348.js ecma_3/Statements/regress-157509.js ecma_3/Statements/regress-194364.js ecma_3/Statements/regress-226517.js ecma_3/Statements/regress-302439.js ecma_3/Statements/regress-324650.js ecma_3/Statements/regress-74474-001.js ecma_3/Statements/regress-74474-002.js ecma_3/Statements/regress-74474-003.js ecma_3/Statements/regress-83532-001.js ecma_3/Statements/regress-83532-002.js ecma_3/Statements/switch-001.js ecma_3/String/regress-104375.js ecma_3/String/regress-189898.js ecma_3/String/regress-313567.js ecma_3/String/regress-83293.js ecma_3/Unicode/uc-001-n.js ecma_3/Unicode/uc-002-n.js ecma_3/Unicode/uc-002.js ecma_3/Unicode/uc-003.js ecma_3/Unicode/uc-004.js ecma_3/Unicode/uc-005.js ecma_3/extensions/regress-103087.js ecma_3/extensions/regress-188206-01.js ecma_3/extensions/regress-188206-02.js ecma_3/extensions/regress-220367-002.js ecma_3/extensions/regress-228087.js ecma_3/extensions/regress-320854.js ecma_3/extensions/regress-327170.js ecma_3/extensions/regress-385393-03.js js-test-driver-begin.js js-test-driver-end.js js1_1/jsref.js js1_2/Array/array_split_1.js js1_2/Array/general1.js js1_2/Array/general2.js js1_2/Array/slice.js js1_2/Array/splice1.js js1_2/Array/splice2.js js1_2/Array/tostring_1.js js1_2/Array/tostring_2.js js1_2/Objects/toString-001.js js1_2/String/charCodeAt.js js1_2/String/concat.js js1_2/String/match.js js1_2/String/slice.js js1_2/function/Number.js js1_2/function/String.js js1_2/function/definition-1.js js1_2/function/length.js js1_2/function/nesting-1.js js1_2/function/nesting.js js1_2/function/regexparg-2-n.js js1_2/jsref.js js1_2/operator/strictEquality.js js1_2/regexp/RegExp_dollar_number.js js1_2/regexp/RegExp_input.js js1_2/regexp/RegExp_input_as_array.js js1_2/regexp/RegExp_lastIndex.js js1_2/regexp/RegExp_lastMatch.js js1_2/regexp/RegExp_lastMatch_as_array.js js1_2/regexp/RegExp_lastParen.js js1_2/regexp/RegExp_lastParen_as_array.js js1_2/regexp/RegExp_leftContext.js js1_2/regexp/RegExp_leftContext_as_array.js js1_2/regexp/RegExp_multiline.js js1_2/regexp/RegExp_multiline_as_array.js js1_2/regexp/RegExp_object.js js1_2/regexp/RegExp_rightContext.js js1_2/regexp/RegExp_rightContext_as_array.js js1_2/regexp/alphanumeric.js js1_2/regexp/asterisk.js js1_2/regexp/backslash.js js1_2/regexp/backspace.js js1_2/regexp/beginLine.js js1_2/regexp/character_class.js js1_2/regexp/compile.js js1_2/regexp/control_characters.js js1_2/regexp/digit.js js1_2/regexp/dot.js js1_2/regexp/endLine.js js1_2/regexp/everything.js js1_2/regexp/exec.js js1_2/regexp/flags.js js1_2/regexp/global.js js1_2/regexp/hexadecimal.js js1_2/regexp/ignoreCase.js js1_2/regexp/interval.js js1_2/regexp/octal.js js1_2/regexp/parentheses.js js1_2/regexp/regress-6359.js js1_2/regexp/regress-9141.js js1_2/regexp/simple_form.js js1_2/regexp/source.js js1_2/regexp/special_characters.js js1_2/regexp/string_replace.js js1_2/regexp/string_search.js js1_2/regexp/string_split.js js1_2/regexp/test.js js1_2/regexp/toString.js js1_2/regexp/vertical_bar.js js1_2/regexp/whitespace.js js1_2/regexp/word_boundary.js js1_2/regress/regress-144834.js js1_2/regress/regress-7703.js js1_2/statements/break.js js1_2/statements/do_while.js js1_2/statements/switch.js js1_2/statements/switch2.js js1_2/version120/boolean-001.js js1_3/Boolean/boolean-001.js js1_3/Script/delete-001.js js1_3/Script/function-002.js js1_3/Script/new-001.js js1_3/Script/switch-001.js js1_3/extensions/proto_10.js js1_3/extensions/proto_2.js js1_3/extensions/proto_5.js js1_3/inherit/proto_1.js js1_3/inherit/proto_10.js js1_3/inherit/proto_11.js js1_3/inherit/proto_12.js js1_3/inherit/proto_3.js js1_3/inherit/proto_4.js js1_3/inherit/proto_6.js js1_3/inherit/proto_7.js js1_3/inherit/proto_8.js js1_3/inherit/proto_9.js js1_3/jsref.js js1_3/regress/delete-001.js js1_3/regress/function-002.js js1_3/regress/new-001.js js1_3/regress/switch-001.js js1_4/Eval/eval-001.js js1_4/Eval/eval-002.js js1_4/Eval/eval-003.js js1_4/Functions/function-001.js js1_4/Regress/date-001-n.js js1_4/Regress/function-001.js js1_4/Regress/function-002.js js1_4/Regress/function-003.js js1_4/Regress/function-004-n.js js1_4/Regress/regress-7224.js js1_4/Regress/toString-001-n.js js1_4/jsref.js js1_5/Array/11.1.4.js js1_5/Array/array-001.js js1_5/Array/regress-101964.js js1_5/Array/regress-107138.js js1_5/Array/regress-108440.js js1_5/Array/regress-154338.js js1_5/Array/regress-178722.js js1_5/Array/regress-255555.js js1_5/Array/regress-299644.js js1_5/Array/regress-300858.js js1_5/Array/regress-310351.js js1_5/Array/regress-311515.js js1_5/Array/regress-313153.js js1_5/Array/regress-315509-01.js js1_5/Array/regress-345961.js js1_5/Array/regress-348810.js js1_5/Array/regress-350256-01.js js1_5/Array/regress-350256-02.js js1_5/Array/regress-360681-01.js js1_5/Array/regress-360681-02.js js1_5/Array/regress-364104.js js1_5/Array/regress-94257.js js1_5/Date/regress-188211.js js1_5/Date/regress-301738-01.js js1_5/Date/regress-309925-01.js js1_5/Date/regress-346027.js js1_5/Exceptions/catchguard-002-n.js js1_5/Exceptions/catchguard-003-n.js js1_5/Exceptions/regress-123002.js js1_5/Exceptions/regress-232182.js js1_5/Exceptions/regress-257751.js js1_5/Exceptions/regress-273931.js js1_5/Exceptions/regress-347674.js js1_5/Exceptions/regress-350837.js js1_5/Expressions/regress-192288.js js1_5/Expressions/regress-96526-argsub.js js1_5/Expressions/regress-96526-noargsub.js js1_5/Function/10.1.6.js js1_5/Function/15.3.4.4.js js1_5/Function/regress-123371.js js1_5/Function/regress-178389.js js1_5/Function/regress-292215.js js1_5/Function/regress-344052.js js1_5/GetSet/regress-375976.js js1_5/LexicalConventions/lexical-001.js js1_5/LexicalConventions/regress-177314.js js1_5/Object/regress-137000.js js1_5/Object/regress-192105.js js1_5/Object/regress-338709.js js1_5/Object/regress-382503.js js1_5/Object/regress-382532.js js1_5/Object/regress-90596-003.js js1_5/Regress/regress-104077.js js1_5/Regress/regress-110286.js js1_5/Regress/regress-111557.js js1_5/Regress/regress-114491.js js1_5/Regress/regress-114493.js js1_5/Regress/regress-115436.js js1_5/Regress/regress-116228.js js1_5/Regress/regress-118849.js js1_5/Regress/regress-127243.js js1_5/Regress/regress-127557.js js1_5/Regress/regress-131510-001.js js1_5/Regress/regress-140852.js js1_5/Regress/regress-140974.js js1_5/Regress/regress-146596.js js1_5/Regress/regress-152646.js js1_5/Regress/regress-155081-2.js js1_5/Regress/regress-155081.js js1_5/Regress/regress-159334.js js1_5/Regress/regress-162392.js js1_5/Regress/regress-165201.js js1_5/Regress/regress-167328.js js1_5/Regress/regress-167658.js js1_5/Regress/regress-168347.js js1_5/Regress/regress-170193.js js1_5/Regress/regress-174709.js js1_5/Regress/regress-176125.js js1_5/Regress/regress-185165.js js1_5/Regress/regress-191633.js js1_5/Regress/regress-192414.js js1_5/Regress/regress-193418.js js1_5/Regress/regress-203402.js js1_5/Regress/regress-203841.js js1_5/Regress/regress-204210.js js1_5/Regress/regress-210682.js js1_5/Regress/regress-211590.js js1_5/Regress/regress-214761.js js1_5/Regress/regress-216320.js js1_5/Regress/regress-224956.js js1_5/Regress/regress-229006.js js1_5/Regress/regress-230216-1.js js1_5/Regress/regress-230216-2.js js1_5/Regress/regress-230216-3.js js1_5/Regress/regress-233483-2.js js1_5/Regress/regress-233483.js js1_5/Regress/regress-238881.js js1_5/Regress/regress-238945.js js1_5/Regress/regress-243174.js js1_5/Regress/regress-243389-n.js js1_5/Regress/regress-243869.js js1_5/Regress/regress-244470.js js1_5/Regress/regress-244619.js js1_5/Regress/regress-245113.js js1_5/Regress/regress-245308.js js1_5/Regress/regress-246911.js js1_5/Regress/regress-246964.js js1_5/Regress/regress-247179.js js1_5/Regress/regress-253150.js js1_5/Regress/regress-254296.js js1_5/Regress/regress-254974.js js1_5/Regress/regress-256501.js js1_5/Regress/regress-256617.js js1_5/Regress/regress-256798.js js1_5/Regress/regress-260541.js js1_5/Regress/regress-261887.js js1_5/Regress/regress-274888.js js1_5/Regress/regress-275378.js js1_5/Regress/regress-276103.js js1_5/Regress/regress-278873.js js1_5/Regress/regress-280769-3.js js1_5/Regress/regress-280769-4.js js1_5/Regress/regress-281487.js js1_5/Regress/regress-281930.js js1_5/Regress/regress-283477.js js1_5/Regress/regress-286216.js js1_5/Regress/regress-288688.js js1_5/Regress/regress-289094.js js1_5/Regress/regress-290656.js js1_5/Regress/regress-294191.js js1_5/Regress/regress-294195-01.js js1_5/Regress/regress-294195-02.js js1_5/Regress/regress-295052.js js1_5/Regress/regress-295666.js js1_5/Regress/regress-306633.js js1_5/Regress/regress-306727.js js1_5/Regress/regress-306794.js js1_5/Regress/regress-308566.js js1_5/Regress/regress-310295.js js1_5/Regress/regress-310607.js js1_5/Regress/regress-310993.js js1_5/Regress/regress-311071.js js1_5/Regress/regress-311629.js js1_5/Regress/regress-312260.js js1_5/Regress/regress-31255.js js1_5/Regress/regress-314401.js js1_5/Regress/regress-315990.js js1_5/Regress/regress-317476.js js1_5/Regress/regress-317714-02.js js1_5/Regress/regress-319384.js js1_5/Regress/regress-320032.js js1_5/Regress/regress-321757.js js1_5/Regress/regress-321874.js js1_5/Regress/regress-322430.js js1_5/Regress/regress-326467.js js1_5/Regress/regress-328012.js js1_5/Regress/regress-328897.js js1_5/Regress/regress-329383.js js1_5/Regress/regress-330951.js js1_5/Regress/regress-334807-05.js js1_5/Regress/regress-334807-06.js js1_5/Regress/regress-338307.js js1_5/Regress/regress-340369.js js1_5/Regress/regress-341360.js js1_5/Regress/regress-343966.js js1_5/Regress/regress-344804.js js1_5/Regress/regress-344959.js js1_5/Regress/regress-346801.js js1_5/Regress/regress-349482-01.js js1_5/Regress/regress-349482-02.js js1_5/Regress/regress-349592.js js1_5/Regress/regress-350253.js js1_5/Regress/regress-350312.js js1_5/Regress/regress-350415.js js1_5/Regress/regress-351116.js js1_5/Regress/regress-351515.js js1_5/Regress/regress-352009.js js1_5/Regress/regress-352208.js js1_5/Regress/regress-360969-01.js js1_5/Regress/regress-360969-02.js js1_5/Regress/regress-360969-03.js js1_5/Regress/regress-360969-04.js js1_5/Regress/regress-366468.js js1_5/Regress/regress-367561-01.js js1_5/Regress/regress-379245.js js1_5/Regress/regress-39309.js js1_5/Regress/regress-398609.js js1_5/Regress/regress-406769.js js1_5/Regress/regress-407024.js js1_5/Regress/regress-407323.js js1_5/Regress/regress-407957.js js1_5/Regress/regress-57043.js js1_5/Regress/regress-68498-001.js js1_5/Regress/regress-68498-002.js js1_5/Regress/regress-68498-004.js js1_5/Regress/regress-69607.js js1_5/Regress/regress-71107.js js1_5/Regress/regress-76054.js js1_5/Regress/regress-80981.js js1_5/Regress/regress-82306.js js1_5/Regress/regress-90445.js js1_5/Regress/regress-96526-001.js js1_5/Scope/regress-154693.js js1_5/Scope/regress-184107.js js1_5/Scope/regress-185485.js js1_5/Scope/regress-191276.js js1_5/Scope/regress-192226.js js1_5/Scope/regress-202678-001.js js1_5/Scope/regress-202678-002.js js1_5/Scope/regress-208496-001.js js1_5/Scope/regress-208496-002.js js1_5/Scope/regress-220362.js js1_5/Scope/regress-77578-001.js js1_5/Scope/scope-002.js js1_5/Scope/scope-003.js js1_5/String/regress-107771.js js1_5/String/regress-112626.js js1_5/String/regress-179068.js js1_5/decompilation/regress-344120.js js1_5/decompilation/regress-349489.js js1_5/decompilation/regress-349663.js js1_5/decompilation/regress-350670.js js1_5/decompilation/regress-351625.js js1_5/decompilation/regress-351626.js js1_5/decompilation/regress-352022.js js1_5/decompilation/regress-352360.js js1_5/decompilation/regress-352873-01.js js1_5/decompilation/regress-352873-02.js js1_5/decompilation/regress-353120.js js1_5/decompilation/regress-354878.js js1_5/decompilation/regress-354910.js js1_5/decompilation/regress-371692.js js1_5/decompilation/regress-373678.js js1_5/decompilation/regress-375639.js js1_5/decompilation/regress-383721.js js1_5/decompilation/regress-406555.js js1_5/extensions/catchguard-001.js js1_5/extensions/catchguard-002.js js1_5/extensions/catchguard-003.js js1_5/extensions/getset-004.js js1_5/extensions/getset-005.js js1_5/extensions/getset-006.js js1_5/extensions/no-such-method.js js1_5/extensions/regress-104077.js js1_5/extensions/regress-178722.js js1_5/extensions/regress-220584.js js1_5/extensions/regress-225831.js js1_5/extensions/regress-226078.js js1_5/extensions/regress-237461.js js1_5/extensions/regress-245795.js js1_5/extensions/regress-255245.js js1_5/extensions/regress-291213.js js1_5/extensions/regress-311161.js js1_5/extensions/regress-311583.js js1_5/extensions/regress-311792-01.js js1_5/extensions/regress-311792-02.js js1_5/extensions/regress-312278.js js1_5/extensions/regress-313500.js js1_5/extensions/regress-313630.js js1_5/extensions/regress-313763.js js1_5/extensions/regress-313803.js js1_5/extensions/regress-313938.js js1_5/extensions/regress-314874.js js1_5/extensions/regress-319683.js js1_5/extensions/regress-322957.js js1_5/extensions/regress-325269.js js1_5/extensions/regress-327608.js js1_5/extensions/regress-328556.js js1_5/extensions/regress-338804-01.js js1_5/extensions/regress-338804-03.js js1_5/extensions/regress-339685.js js1_5/extensions/regress-340199.js js1_5/extensions/regress-341956-02.js js1_5/extensions/regress-341956-03.js js1_5/extensions/regress-346494-01.js js1_5/extensions/regress-350312-01.js js1_5/extensions/regress-350312-02.js js1_5/extensions/regress-350312-03.js js1_5/extensions/regress-351102-01.js js1_5/extensions/regress-351102-02.js js1_5/extensions/regress-351102-06.js js1_5/extensions/regress-351973.js js1_5/extensions/regress-352261.js js1_5/extensions/regress-352281.js js1_5/extensions/regress-354297.js js1_5/extensions/regress-354541-01.js js1_5/extensions/regress-354541-03.js js1_5/extensions/regress-355982.js js1_5/extensions/regress-356402.js js1_5/extensions/regress-363988.js js1_5/extensions/regress-365527.js js1_5/extensions/regress-365692.js js1_5/extensions/regress-366288.js js1_5/extensions/regress-366292.js js1_5/extensions/regress-366396.js js1_5/extensions/regress-367118-01.js js1_5/extensions/regress-367118-02.js js1_5/extensions/regress-367120-01.js js1_5/extensions/regress-367120-02.js js1_5/extensions/regress-367121.js js1_5/extensions/regress-367501-01.js js1_5/extensions/regress-367501-02.js js1_5/extensions/regress-367501-03.js js1_5/extensions/regress-367589.js js1_5/extensions/regress-369404.js js1_5/extensions/regress-374589.js js1_5/extensions/regress-375183.js js1_5/extensions/regress-380889.js js1_5/extensions/regress-385134.js js1_5/extensions/regress-394967.js js1_5/extensions/regress-396326.js js1_5/extensions/regress-407501.js js1_5/extensions/regress-44009.js js1_5/extensions/regress-50447.js js1_5/extensions/regress-90596-001.js js1_5/extensions/regress-90596-002.js js1_5/extensions/regress-96284-001.js js1_5/extensions/regress-96284-002.js js1_5/extensions/scope-001.js js1_6/Array/filter.js js1_6/Array/regress-304828.js js1_6/Array/regress-305002.js js1_6/Array/regress-310425-01.js js1_6/Array/regress-310425-02.js js1_6/Array/regress-320887.js js1_6/Array/regress-352742-01.js js1_6/Array/regress-352742-02.js js1_6/Array/regress-415451.js js1_6/Array/regress-415540.js js1_6/Regress/regress-301574.js js1_6/Regress/regress-311157-01.js js1_6/Regress/regress-311157-02.js js1_6/Regress/regress-314887.js js1_6/Regress/regress-351795.js js1_6/Regress/regress-352271.js js1_6/Regress/regress-378492.js js1_6/decompilation/regress-352084.js js1_6/extensions/regress-385393-08.js js1_7/GC/regress-341675.js js1_7/block/order-of-operation.js js1_7/block/regress-341939.js js1_7/block/regress-344139.js js1_7/block/regress-344370.js js1_7/block/regress-345542.js js1_7/block/regress-348685.js js1_7/block/regress-349283.js js1_7/block/regress-349298.js js1_7/block/regress-349507.js js1_7/block/regress-349653.js js1_7/block/regress-349962.js js1_7/block/regress-350279.js js1_7/block/regress-350730.js js1_7/block/regress-350793-01.js js1_7/block/regress-351497.js js1_7/block/regress-351606.js js1_7/block/regress-352092.js js1_7/block/regress-352185.js js1_7/block/regress-352212.js js1_7/block/regress-352267.js js1_7/block/regress-352616.js js1_7/block/regress-352624.js js1_7/block/regress-352907.js js1_7/block/regress-357754.js js1_7/block/regress-376410.js js1_7/block/regress-396900.js js1_7/block/regress-411279.js js1_7/decompilation/regress-349633.js js1_7/decompilation/regress-350810.js js1_7/decompilation/regress-352015.js js1_7/decompilation/regress-352025.js js1_7/decompilation/regress-352269.js js1_7/decompilation/regress-352272.js js1_7/decompilation/regress-352283.js js1_7/decompilation/regress-352732.js js1_7/decompilation/regress-355635.js js1_7/decompilation/regress-355786.js js1_7/decompilation/regress-375794.js js1_7/decompilation/regress-380506.js js1_7/expressions/destructuring-scope.js js1_7/expressions/regress-346203.js js1_7/expressions/regress-346645-01.js js1_7/expressions/regress-346645-02.js js1_7/expressions/regress-346645-03.js js1_7/expressions/regress-349624.js js1_7/expressions/regress-349818.js js1_7/extensions/basic-Iterator.js js1_7/extensions/basic-for-in.js js1_7/extensions/destructuring-order.js js1_7/extensions/iterator-ctor.js js1_7/extensions/regress-346021.js js1_7/extensions/regress-346642-02.js js1_7/extensions/regress-346773.js js1_7/extensions/regress-349619.js js1_7/extensions/regress-350312.js js1_7/extensions/regress-351070-02.js js1_7/extensions/regress-352797-01.js js1_7/extensions/regress-352885-01.js js1_7/extensions/regress-352885-02.js js1_7/extensions/regress-353214-02.js js1_7/extensions/regress-354499-01.js js1_7/extensions/regress-354499-02.js js1_7/extensions/regress-354945-01.js js1_7/extensions/regress-355052-01.js js1_7/extensions/regress-355052-02.js js1_7/extensions/regress-355052-03.js js1_7/extensions/regress-355410.js js1_7/extensions/regress-355512.js js1_7/extensions/regress-355578.js js1_7/extensions/regress-355583.js js1_7/extensions/regress-363040-01.js js1_7/extensions/regress-363040-02.js js1_7/extensions/regress-366668-01.js js1_7/extensions/regress-366668-02.js js1_7/extensions/regress-387955-01.js js1_7/extensions/regress-392308.js js1_7/extensions/regress-396326.js js1_7/geniter/326466-01.js js1_7/geniter/builtin-Iterator-function.js js1_7/geniter/evens.js js1_7/geniter/fibonacci-matrix-generator.js js1_7/geniter/iterator-toString.js js1_7/geniter/message-value-passing.js js1_7/geniter/multiple-close.js js1_7/geniter/nested-yield.js js1_7/geniter/pi-generator.js js1_7/geniter/regress-345736.js js1_7/geniter/regress-345855.js js1_7/geniter/regress-345879-01.js js1_7/geniter/regress-347593.js js1_7/geniter/regress-349012-02.js js1_7/geniter/regress-349012-03.js js1_7/geniter/regress-349012-04.js js1_7/geniter/regress-349012-05.js js1_7/geniter/regress-349023-01.js js1_7/geniter/regress-349023-02.js js1_7/geniter/regress-349023-03.js js1_7/geniter/regress-349362.js js1_7/geniter/regress-349851.js js1_7/geniter/regress-350621.js js1_7/geniter/regress-350809.js js1_7/geniter/regress-351120.js js1_7/geniter/regress-352197.js js1_7/geniter/regress-352876.js js1_7/geniter/regress-355834.js js1_7/geniter/regress-359062.js js1_7/geniter/regress-366941.js js1_7/geniter/regress-382335.js js1_7/geniter/regress-390918.js js1_7/geniter/send-no-rhs.js js1_7/geniter/sequential-yields.js js1_7/geniter/throw-after-close.js js1_7/geniter/throw-forever.js js1_7/geniter/unreachable-yield.js js1_7/geniter/yield-undefined.js js1_7/iterable/regress-341499.js js1_7/iterable/regress-341510.js js1_7/iterable/regress-341815.js js1_7/iterable/regress-341821.js js1_7/iterable/regress-354750-01.js js1_7/iterable/regress-355025.js js1_7/iterable/regress-355075-01.js js1_7/iterable/regress-355090.js js1_7/iterable/regress-412467.js js1_7/lexical/regress-346642-04.js js1_7/regress/regress-352640-01.js js1_7/regress/regress-352640-02.js js1_7/regress/regress-352640-03.js js1_7/regress/regress-352640-04.js js1_7/regress/regress-352797-02.js js1_7/regress/regress-352870-03.js js1_7/regress/regress-353079.js js1_7/regress/regress-355023.js js1_7/regress/regress-355832-01.js js1_7/regress/regress-361566.js js1_7/regress/regress-369666-01.js js1_7/regress/regress-369666-02.js js1_7/regress/regress-372331.js js1_7/regress/regress-373827-01.js js1_7/regress/regress-373827-02.js js1_7/regress/regress-373828.js js1_7/regress/regress-379442.js js1_7/regress/regress-385393-05.js js1_7/regress/regress-407727-01.js js1_7/regress/regress-407727-02.js js1_7/regress/regress-407957.js js1_7/regress/regress-414553.js lc2/Arrays/array-001.js lc2/Arrays/array-002.js lc2/Arrays/array-003.js lc2/Arrays/array-004.js lc2/Arrays/array-005.js lc2/Arrays/array-006-n.js lc2/Arrays/array-007-n.js lc2/Classes/class-001.js lc2/Classes/class-002.js lc2/JSToJava/character-001.js lc2/JSToJava/double-001.js lc2/JSToJava/double-002.js lc2/JSToJava/float-001.js lc2/JSToJava/float-002.js lc2/JSToJava/integer-001.js lc2/JSToJava/integer-002.js lc2/JSToJava/long-001.js lc2/JSToJava/long-002.js lc2/JSToJava/long-003-n.js lc2/JSToJava/short-001.js lc2/JSToJava/short-002.js lc2/JSToJava/short-003-n.js lc2/JavaToJS/String-001.js lc2/JavaToJS/boolean-001.js lc2/JavaToJS/boolean-003.js lc2/JavaToJS/boolean-004.js lc2/JavaToJS/boolean-005.js lc2/JavaToJS/char-001.js lc2/JavaToJS/char-002.js lc2/JavaToJS/enum-001.js lc2/JavaToJS/enum-002.js lc2/JavaToJS/null-001.js lc2/JavaToJS/number-001.js lc2/JavaToJS/number-002.js lc2/Methods/method-001.js lc2/Methods/method-002.js lc2/Methods/method-003.js lc2/Methods/method-004-n.js lc2/Methods/method-005.js lc2/Methods/method-006-n.js lc2/Methods/println-001.js lc2/Objects/object-001.js lc2/Objects/object-002.js lc2/Objects/object-003.js lc2/Objects/object-004.js lc2/Objects/object-005.js lc2/Objects/object-006.js lc2/Packages/package-001.js lc2/Packages/package-002.js lc2/Packages/package-003.js lc2/Packages/package-005.js lc2/Packages/package-006.js lc2/Packages/package-007-n.js lc2/Packages/package-008-n.js lc2/misc/constructor.js lc2/misc/wrapUnwrap.js lc3/ArrayMethods/byte-001.js lc3/ArrayMethods/byte-002.js lc3/ConvertBoolean/boolean-005-n.js lc3/ConvertBoolean/boolean-006-n.js lc3/ConvertBoolean/boolean-007-n.js lc3/ConvertBoolean/boolean-008-n.js lc3/ConvertBoolean/boolean-009-n.js lc3/ConvertBoolean/boolean-010-n.js lc3/ConvertBoolean/boolean-011-n.js lc3/ConvertBoolean/boolean-012-n.js lc3/ConvertBoolean/boolean-013-n.js lc3/ConvertNull/null-002.js lc3/ConvertNull/null-003-n.js lc3/ConvertNull/null-004-n.js lc3/ConvertNull/null-006-n.js lc3/ConvertString/string-004-n.js lc3/ConvertString/string-005-n.js lc3/ConvertString/string-007-n.js lc3/ConvertUndefined/undefined-001-n.js lc3/JSBoolean/boolean-002-n.js lc3/JSBoolean/boolean-003-n.js lc3/JSBoolean/boolean-004-n.js lc3/JSBoolean/boolean-005-n.js lc3/JSBoolean/boolean-006-n.js lc3/JSBoolean/boolean-007-n.js lc3/JSBoolean/boolean-008-n.js lc3/JSNull/ToBoolean-001-n.js lc3/JSNull/ToLong-001-n.js lc3/JSNull/ToNumber-001-n.js lc3/JSNumber/ToByte-002-n.js lc3/JSNumber/ToByte-003-n.js lc3/JSNumber/ToByte-005-n.js lc3/JSNumber/ToChar-002-n.js lc3/JSNumber/ToChar-003-n.js lc3/JSNumber/ToChar-005-n.js lc3/JSNumber/ToChar-006-n.js lc3/JSNumber/ToInt-002-n.js lc3/JSNumber/ToInt-003-n.js lc3/JSNumber/ToLong-002-n.js lc3/JSNumber/ToLong-003-n.js lc3/JSNumber/ToLong-004-n.js lc3/JSNumber/ToLong-005-n.js lc3/JSNumber/ToLong-006-n.js lc3/JSNumber/ToLong-007-n.js lc3/JSNumber/ToLong-008-n.js lc3/JSNumber/ToLong-009-n.js lc3/JSNumber/ToLong-010-n.js lc3/JSNumber/ToLong-011-n.js lc3/JSNumber/ToShort-003-n.js lc3/JSNumber/ToShort-005-n.js lc3/JSObject/ToDouble-002-n.js lc3/JSObject/ToDouble-003-n.js lc3/JSObject/ToFloat-002-n.js lc3/JSObject/ToFloat-003-n.js lc3/JSUndefined/undefined-002-n.js lc3/JSUndefined/undefined-003-n.js lc3/JSUndefined/undefined-004-n.js lc3/JSUndefined/undefined-005-n.js lc3/JSUndefined/undefined-006-n.js lc3/JSUndefined/undefined-008-n.js lc3/JSUndefined/undefined-009-n.js lc3/JSUndefined/undefined-010-n.js lc3/JavaArray/ToArray-002-n.js lc3/JavaArray/ToBoolean-001-n.js lc3/JavaObject/JavaObjectToBoolean-002-n.js lc3/JavaObject/JavaObjectToByte-002-n.js lc3/JavaObject/JavaObjectToByte-007-n.js lc3/JavaObject/JavaObjectToByte-008-n.js lc3/JavaObject/JavaObjectToChar-003-n.js lc3/JavaObject/JavaObjectToChar-005-n.js lc3/JavaObject/JavaObjectToChar-006-n.js lc3/JavaObject/JavaObjectToInt-002-n.js lc3/JavaObject/JavaObjectToInt-003-n.js lc3/JavaObject/JavaObjectToInt-004-n.js lc3/JavaObject/JavaObjectToLong-002-n.js lc3/JavaObject/JavaObjectToLong-003-n.js lc3/JavaObject/JavaObjectToLong-004-n.js lc3/JavaObject/JavaObjectToLong-006-n.js lc3/JavaObject/JavaObjectToShort-002-n.js lc3/JavaObject/JavaObjectToShort-003-n.js lc3/JavaObject/JavaObjectToShort-004-n.js lc3/StringMethods/string-001.js rhino-1.7R4/testsrc/opt0.tests000066400000000000000000001465431176760007500163710ustar00rootroot00000000000000e4x/Expressions/11.1.1.js e4x/Expressions/11.1.2.js e4x/Expressions/11.1.3.js e4x/Expressions/11.1.4-06.js e4x/Expressions/11.1.4-07.js e4x/Expressions/11.1.5.js e4x/Expressions/11.2.1.js e4x/Expressions/11.2.2.js e4x/Expressions/11.2.3.js e4x/Expressions/11.2.4.js e4x/Expressions/11.3.1.js e4x/Expressions/11.3.2.js e4x/Expressions/11.4.1.js e4x/Expressions/11.5.1.js e4x/Expressions/11.6.3.js e4x/Expressions/regress-301545.js e4x/Expressions/regress-302531.js e4x/Expressions/regress-340024.js e4x/GC/regress-292455.js e4x/GC/regress-313952-01.js e4x/GC/regress-324117.js e4x/Namespace/13.2.1.js e4x/Namespace/13.2.2.js e4x/Namespace/13.2.5.js e4x/Namespace/regress-283972.js e4x/Namespace/regress-292863.js e4x/Namespace/regress-350442.js e4x/QName/13.3.1.js e4x/QName/13.3.2.js e4x/QName/13.3.5.js e4x/QName/regress-373595-01.js e4x/QName/regress-373595-02.js e4x/QName/regress-373595-03.js e4x/Regress/regress-263935.js e4x/Regress/regress-263936.js e4x/Regress/regress-264369.js e4x/Regress/regress-271545.js e4x/Regress/regress-277650.js e4x/Regress/regress-277664.js e4x/Regress/regress-277683.js e4x/Regress/regress-277935.js e4x/Regress/regress-283349.js e4x/Regress/regress-290056.js e4x/Regress/regress-301573.js e4x/Regress/regress-301596.js e4x/Regress/regress-301692.js e4x/Regress/regress-313799.js e4x/Regress/regress-325425.js e4x/Regress/regress-327691-01.js e4x/Regress/regress-327691-02.js e4x/Regress/regress-327697.js e4x/Regress/regress-328249.js e4x/Regress/regress-329257.js e4x/Regress/regress-331664.js e4x/Regress/regress-350206-1.js e4x/Regress/regress-350206.js e4x/Regress/regress-352103.js e4x/Regress/regress-354145-01.js e4x/Regress/regress-354145-02.js e4x/Regress/regress-354145-03.js e4x/Regress/regress-354145-04.js e4x/Regress/regress-354145-05.js e4x/Regress/regress-354145-07.js e4x/Regress/regress-355474-02.js e4x/Regress/regress-356238-01.js e4x/Regress/regress-369032.js e4x/Regress/regress-369536.js e4x/Regress/regress-372564.js e4x/Regress/regress-374106.js e4x/Regress/regress-374112.js e4x/Regress/regress-374116.js e4x/Regress/regress-374160.js e4x/Regress/regress-378492.js e4x/Regress/regress-407323.js e4x/Statements/12.1.js e4x/Statements/12.2.js e4x/Statements/12.3-01.js e4x/TypeConversion/10.1.2.js e4x/TypeConversion/10.3.1.js e4x/TypeConversion/10.3.js e4x/TypeConversion/10.4.1.js e4x/TypeConversion/10.4.js e4x/Types/9.1.1.1.js e4x/Types/9.1.1.2.js e4x/Types/9.1.1.3.js e4x/Types/9.1.1.6.js e4x/Types/9.2.1.1.js e4x/Types/9.2.1.2.js e4x/Types/9.2.1.8.js e4x/XML/13.4.1.js e4x/XML/13.4.2.js e4x/XML/13.4.3.10.js e4x/XML/13.4.4.12-1.js e4x/XML/13.4.4.12.js e4x/XML/13.4.4.13.js e4x/XML/13.4.4.14.js e4x/XML/13.4.4.15.js e4x/XML/13.4.4.16.js e4x/XML/13.4.4.18.js e4x/XML/13.4.4.19.js e4x/XML/13.4.4.2.js e4x/XML/13.4.4.20.js e4x/XML/13.4.4.21.js e4x/XML/13.4.4.23.js e4x/XML/13.4.4.24.js e4x/XML/13.4.4.25.js e4x/XML/13.4.4.27.js e4x/XML/13.4.4.3.js e4x/XML/13.4.4.30.js e4x/XML/13.4.4.31.js e4x/XML/13.4.4.32-01.js e4x/XML/13.4.4.32.js e4x/XML/13.4.4.33.js e4x/XML/13.4.4.34.js e4x/XML/13.4.4.35.js e4x/XML/13.4.4.36.js e4x/XML/13.4.4.37.js e4x/XML/13.4.4.38.js e4x/XML/13.4.4.39.js e4x/XML/13.4.4.4.js e4x/XML/13.4.4.40.js e4x/XML/13.4.4.5.js e4x/XML/13.4.4.7.js e4x/XML/13.4.4.8.js e4x/XML/regress-291930.js e4x/XML/regress-324688.js e4x/XML/regress-336921.js e4x/XMLList/13.5.1.js e4x/XMLList/13.5.2.js e4x/XMLList/13.5.4.10.js e4x/XMLList/13.5.4.11.js e4x/XMLList/13.5.4.12.js e4x/XMLList/13.5.4.13.js e4x/XMLList/13.5.4.14.js e4x/XMLList/13.5.4.15.js e4x/XMLList/13.5.4.16.js e4x/XMLList/13.5.4.17.js e4x/XMLList/13.5.4.18.js e4x/XMLList/13.5.4.19.js e4x/XMLList/13.5.4.2.js e4x/XMLList/13.5.4.20.js e4x/XMLList/13.5.4.21.js e4x/XMLList/13.5.4.22.js e4x/XMLList/13.5.4.3.js e4x/XMLList/13.5.4.4.js e4x/XMLList/13.5.4.5.js e4x/XMLList/13.5.4.6.js e4x/XMLList/13.5.4.7.js e4x/XMLList/13.5.4.8.js e4x/XMLList/13.5.4.9.js e4x/decompilation/regress-349814.js e4x/decompilation/regress-349815.js e4x/decompilation/regress-349822.js e4x/decompilation/regress-349956.js e4x/decompilation/regress-355474-01.js e4x/decompilation/regress-373678.js e4x/extensions/regress-305335.js e4x/extensions/regress-321547.js e4x/extensions/regress-327534.js e4x/extensions/regress-327897.js e4x/extensions/regress-354145-06.js e4x/extensions/regress-354151-01.js ecma/Array/15.4-1.js ecma/Array/15.4-2.js ecma/Array/15.4.1.1.js ecma/Array/15.4.1.2.js ecma/Array/15.4.1.3.js ecma/Array/15.4.1.js ecma/Array/15.4.2.1-1.js ecma/Array/15.4.2.1-2.js ecma/Array/15.4.2.1-3.js ecma/Array/15.4.2.2-1.js ecma/Array/15.4.2.2-2.js ecma/Array/15.4.2.3.js ecma/Array/15.4.3.2.js ecma/Array/15.4.4.1.js ecma/Array/15.4.4.2.js ecma/Array/15.4.4.3-1.js ecma/Array/15.4.4.4-1.js ecma/Array/15.4.4.4-2.js ecma/Array/15.4.4.5-1.js ecma/Array/15.4.4.5-2.js ecma/Array/15.4.4.js ecma/Array/15.4.5.1-2.js ecma/Array/15.4.5.2-1.js ecma/Array/15.4.5.2-2.js ecma/Boolean/15.6.2.js ecma/Boolean/15.6.3.1-1.js ecma/Boolean/15.6.3.1-2.js ecma/Boolean/15.6.3.1.js ecma/Boolean/15.6.4-1.js ecma/Boolean/15.6.4.1.js ecma/Boolean/15.6.4.2-2.js ecma/Boolean/15.6.4.2-3.js ecma/Boolean/15.6.4.2-4-n.js ecma/Boolean/15.6.4.3-1.js ecma/Boolean/15.6.4.3-2.js ecma/Boolean/15.6.4.3-3.js ecma/Boolean/15.6.4.3-4-n.js ecma/Boolean/15.6.4.3.js ecma/Boolean/15.6.4.js ecma/Date/15.9.1.1-1.js ecma/Date/15.9.1.1-2.js ecma/Date/15.9.1.13-1.js ecma/Date/15.9.2.1.js ecma/Date/15.9.2.2-1.js ecma/Date/15.9.2.2-2.js ecma/Date/15.9.2.2-3.js ecma/Date/15.9.2.2-5.js ecma/Date/15.9.2.2-6.js ecma/Date/15.9.3.1-2.js ecma/Date/15.9.3.1-3.js ecma/Date/15.9.3.1-4.js ecma/Date/15.9.3.1-5.js ecma/Date/15.9.3.2-2.js ecma/Date/15.9.3.2-3.js ecma/Date/15.9.3.2-4.js ecma/Date/15.9.3.2-5.js ecma/Date/15.9.3.8-1.js ecma/Date/15.9.3.8-2.js ecma/Date/15.9.3.8-3.js ecma/Date/15.9.3.8-4.js ecma/Date/15.9.3.8-5.js ecma/Date/15.9.4.2.js ecma/Date/15.9.4.3.js ecma/Date/15.9.5.1.js ecma/Date/15.9.5.10-1.js ecma/Date/15.9.5.10-10.js ecma/Date/15.9.5.10-11.js ecma/Date/15.9.5.10-12.js ecma/Date/15.9.5.10-13.js ecma/Date/15.9.5.10-4.js ecma/Date/15.9.5.10-5.js ecma/Date/15.9.5.10-6.js ecma/Date/15.9.5.10-7.js ecma/Date/15.9.5.10-8.js ecma/Date/15.9.5.10-9.js ecma/Date/15.9.5.11-1.js ecma/Date/15.9.5.11-3.js ecma/Date/15.9.5.11-4.js ecma/Date/15.9.5.11-5.js ecma/Date/15.9.5.11-6.js ecma/Date/15.9.5.11-7.js ecma/Date/15.9.5.12-1.js ecma/Date/15.9.5.12-3.js ecma/Date/15.9.5.12-4.js ecma/Date/15.9.5.12-5.js ecma/Date/15.9.5.12-6.js ecma/Date/15.9.5.12-7.js ecma/Date/15.9.5.12-8.js ecma/Date/15.9.5.13-1.js ecma/Date/15.9.5.13-2.js ecma/Date/15.9.5.13-3.js ecma/Date/15.9.5.13-4.js ecma/Date/15.9.5.13-5.js ecma/Date/15.9.5.13-6.js ecma/Date/15.9.5.13-7.js ecma/Date/15.9.5.13-8.js ecma/Date/15.9.5.14.js ecma/Date/15.9.5.15.js ecma/Date/15.9.5.16.js ecma/Date/15.9.5.17.js ecma/Date/15.9.5.19.js ecma/Date/15.9.5.2-2-n.js ecma/Date/15.9.5.2.js ecma/Date/15.9.5.20.js ecma/Date/15.9.5.21-1.js ecma/Date/15.9.5.21-2.js ecma/Date/15.9.5.21-3.js ecma/Date/15.9.5.21-4.js ecma/Date/15.9.5.21-5.js ecma/Date/15.9.5.21-6.js ecma/Date/15.9.5.21-7.js ecma/Date/15.9.5.21-8.js ecma/Date/15.9.5.22-2.js ecma/Date/15.9.5.22-3.js ecma/Date/15.9.5.22-4.js ecma/Date/15.9.5.22-5.js ecma/Date/15.9.5.22-6.js ecma/Date/15.9.5.22-7.js ecma/Date/15.9.5.22-8.js ecma/Date/15.9.5.23-1.js ecma/Date/15.9.5.23-10.js ecma/Date/15.9.5.23-11.js ecma/Date/15.9.5.23-12.js ecma/Date/15.9.5.23-13.js ecma/Date/15.9.5.23-14.js ecma/Date/15.9.5.23-15.js ecma/Date/15.9.5.23-16.js ecma/Date/15.9.5.23-17.js ecma/Date/15.9.5.23-18.js ecma/Date/15.9.5.23-2.js ecma/Date/15.9.5.23-3-n.js ecma/Date/15.9.5.23-4.js ecma/Date/15.9.5.23-5.js ecma/Date/15.9.5.23-6.js ecma/Date/15.9.5.23-7.js ecma/Date/15.9.5.23-8.js ecma/Date/15.9.5.23-9.js ecma/Date/15.9.5.24-1.js ecma/Date/15.9.5.24-2.js ecma/Date/15.9.5.24-3.js ecma/Date/15.9.5.24-4.js ecma/Date/15.9.5.24-5.js ecma/Date/15.9.5.24-6.js ecma/Date/15.9.5.24-7.js ecma/Date/15.9.5.24-8.js ecma/Date/15.9.5.25-1.js ecma/Date/15.9.5.26-1.js ecma/Date/15.9.5.27-1.js ecma/Date/15.9.5.28-1.js ecma/Date/15.9.5.29-1.js ecma/Date/15.9.5.3-2.js ecma/Date/15.9.5.30-1.js ecma/Date/15.9.5.31-1.js ecma/Date/15.9.5.32-1.js ecma/Date/15.9.5.33-1.js ecma/Date/15.9.5.34-1.js ecma/Date/15.9.5.35-1.js ecma/Date/15.9.5.36-1.js ecma/Date/15.9.5.36-2.js ecma/Date/15.9.5.36-4.js ecma/Date/15.9.5.36-5.js ecma/Date/15.9.5.36-6.js ecma/Date/15.9.5.36-7.js ecma/Date/15.9.5.37-2.js ecma/Date/15.9.5.37-3.js ecma/Date/15.9.5.37-4.js ecma/Date/15.9.5.37-5.js ecma/Date/15.9.5.4-1.js ecma/Date/15.9.5.4-2-n.js ecma/Date/15.9.5.6.js ecma/Date/15.9.5.7.js ecma/Date/15.9.5.8.js ecma/Date/15.9.5.9.js ecma/Date/15.9.5.js ecma/ExecutionContexts/10.1.3-1.js ecma/ExecutionContexts/10.1.3-2.js ecma/ExecutionContexts/10.1.3.js ecma/ExecutionContexts/10.1.4-1.js ecma/ExecutionContexts/10.1.4-10.js ecma/ExecutionContexts/10.1.4-3.js ecma/ExecutionContexts/10.1.4-4.js ecma/ExecutionContexts/10.1.4-5.js ecma/ExecutionContexts/10.1.4-6.js ecma/ExecutionContexts/10.1.4-7.js ecma/ExecutionContexts/10.1.4-8.js ecma/ExecutionContexts/10.1.5-1.js ecma/ExecutionContexts/10.1.5-2.js ecma/ExecutionContexts/10.1.5-3.js ecma/ExecutionContexts/10.1.5-4.js ecma/ExecutionContexts/10.1.8-2.js ecma/ExecutionContexts/10.1.8-3.js ecma/ExecutionContexts/10.2.1.js ecma/ExecutionContexts/10.2.2-1.js ecma/ExecutionContexts/10.2.2-2.js ecma/ExecutionContexts/10.2.3-1.js ecma/ExecutionContexts/10.2.3-2.js ecma/Expressions/11.1.1.js ecma/Expressions/11.10-1.js ecma/Expressions/11.10-2.js ecma/Expressions/11.10-3.js ecma/Expressions/11.12-1.js ecma/Expressions/11.12-2-n.js ecma/Expressions/11.12-3.js ecma/Expressions/11.12-4.js ecma/Expressions/11.13.1.js ecma/Expressions/11.13.2-1.js ecma/Expressions/11.13.2-2.js ecma/Expressions/11.13.2-3.js ecma/Expressions/11.13.2-4.js ecma/Expressions/11.13.2-5.js ecma/Expressions/11.14-1.js ecma/Expressions/11.2.1-1.js ecma/Expressions/11.2.1-2.js ecma/Expressions/11.2.1-3-n.js ecma/Expressions/11.2.1-4-n.js ecma/Expressions/11.2.1-5.js ecma/Expressions/11.2.2-1-n.js ecma/Expressions/11.2.2-1.js ecma/Expressions/11.2.2-10-n.js ecma/Expressions/11.2.2-11.js ecma/Expressions/11.2.2-2-n.js ecma/Expressions/11.2.2-3-n.js ecma/Expressions/11.2.2-4-n.js ecma/Expressions/11.2.2-5-n.js ecma/Expressions/11.2.2-6-n.js ecma/Expressions/11.2.2-7-n.js ecma/Expressions/11.2.2-8-n.js ecma/Expressions/11.2.2-9-n.js ecma/Expressions/11.2.3-1.js ecma/Expressions/11.2.3-2-n.js ecma/Expressions/11.2.3-3-n.js ecma/Expressions/11.2.3-4-n.js ecma/Expressions/11.2.3-5.js ecma/Expressions/11.3.1.js ecma/Expressions/11.3.2.js ecma/Expressions/11.4.2.js ecma/Expressions/11.4.3.js ecma/Expressions/11.4.4.js ecma/Expressions/11.4.5.js ecma/Expressions/11.4.6.js ecma/Expressions/11.4.8.js ecma/Expressions/11.4.9.js ecma/Expressions/11.5.1.js ecma/Expressions/11.5.2.js ecma/Expressions/11.5.3.js ecma/Expressions/11.6.1-1.js ecma/Expressions/11.6.1-2.js ecma/Expressions/11.6.1-3.js ecma/Expressions/11.6.2-1.js ecma/Expressions/11.6.3.js ecma/Expressions/11.7.1.js ecma/Expressions/11.7.2.js ecma/Expressions/11.8.1.js ecma/Expressions/11.8.2.js ecma/Expressions/11.8.3.js ecma/Expressions/11.9.2.js ecma/Expressions/11.9.3.js ecma/FunctionObjects/15.3.1.1-1.js ecma/FunctionObjects/15.3.1.1-2.js ecma/FunctionObjects/15.3.1.1-3.js ecma/FunctionObjects/15.3.2.1-1.js ecma/FunctionObjects/15.3.2.1-2.js ecma/FunctionObjects/15.3.2.1-3.js ecma/FunctionObjects/15.3.3.1-2.js ecma/FunctionObjects/15.3.3.1-3.js ecma/FunctionObjects/15.3.3.1-4.js ecma/FunctionObjects/15.3.3.2.js ecma/FunctionObjects/15.3.4-1.js ecma/FunctionObjects/15.3.4.1.js ecma/FunctionObjects/15.3.4.js ecma/FunctionObjects/15.3.5-1.js ecma/FunctionObjects/15.3.5-2.js ecma/FunctionObjects/15.3.5.1.js ecma/FunctionObjects/15.3.5.3.js ecma/GlobalObject/15.1-1-n.js ecma/GlobalObject/15.1-2-n.js ecma/GlobalObject/15.1.1.1.js ecma/GlobalObject/15.1.1.2.js ecma/GlobalObject/15.1.2.1-2.js ecma/GlobalObject/15.1.2.2-2.js ecma/GlobalObject/15.1.2.3-2.js ecma/GlobalObject/15.1.2.5-2.js ecma/GlobalObject/15.1.2.5-3.js ecma/LexicalConventions/7.1-1.js ecma/LexicalConventions/7.1-2.js ecma/LexicalConventions/7.1-3.js ecma/LexicalConventions/7.2-1.js ecma/LexicalConventions/7.2-2-n.js ecma/LexicalConventions/7.2-3-n.js ecma/LexicalConventions/7.2-4-n.js ecma/LexicalConventions/7.2-5-n.js ecma/LexicalConventions/7.2-6.js ecma/LexicalConventions/7.3-1.js ecma/LexicalConventions/7.3-10.js ecma/LexicalConventions/7.3-11.js ecma/LexicalConventions/7.3-12.js ecma/LexicalConventions/7.3-13-n.js ecma/LexicalConventions/7.3-2.js ecma/LexicalConventions/7.3-3.js ecma/LexicalConventions/7.3-4.js ecma/LexicalConventions/7.3-5.js ecma/LexicalConventions/7.3-6.js ecma/LexicalConventions/7.3-8.js ecma/LexicalConventions/7.3-9.js ecma/LexicalConventions/7.4.1-1-n.js ecma/LexicalConventions/7.4.1-2-n.js ecma/LexicalConventions/7.4.1-3-n.js ecma/LexicalConventions/7.4.2-1-n.js ecma/LexicalConventions/7.4.2-10-n.js ecma/LexicalConventions/7.4.2-11-n.js ecma/LexicalConventions/7.4.2-12-n.js ecma/LexicalConventions/7.4.2-13-n.js ecma/LexicalConventions/7.4.2-14-n.js ecma/LexicalConventions/7.4.2-15-n.js ecma/LexicalConventions/7.4.2-16-n.js ecma/LexicalConventions/7.4.2-2-n.js ecma/LexicalConventions/7.4.2-3-n.js ecma/LexicalConventions/7.4.2-4-n.js ecma/LexicalConventions/7.4.2-5-n.js ecma/LexicalConventions/7.4.2-6-n.js ecma/LexicalConventions/7.4.2-7-n.js ecma/LexicalConventions/7.4.2-8-n.js ecma/LexicalConventions/7.4.3-1-n.js ecma/LexicalConventions/7.4.3-10-n.js ecma/LexicalConventions/7.4.3-11-n.js ecma/LexicalConventions/7.4.3-13-n.js ecma/LexicalConventions/7.4.3-15-n.js ecma/LexicalConventions/7.4.3-16-n.js ecma/LexicalConventions/7.4.3-2-n.js ecma/LexicalConventions/7.4.3-3-n.js ecma/LexicalConventions/7.4.3-4-n.js ecma/LexicalConventions/7.4.3-5-n.js ecma/LexicalConventions/7.4.3-6-n.js ecma/LexicalConventions/7.4.3-7-n.js ecma/LexicalConventions/7.4.3-8-n.js ecma/LexicalConventions/7.4.3-9-n.js ecma/LexicalConventions/7.5-1.js ecma/LexicalConventions/7.5-10-n.js ecma/LexicalConventions/7.5-2-n.js ecma/LexicalConventions/7.5-3-n.js ecma/LexicalConventions/7.5-4-n.js ecma/LexicalConventions/7.5-5-n.js ecma/LexicalConventions/7.5-6.js ecma/LexicalConventions/7.5-7.js ecma/LexicalConventions/7.5-8-n.js ecma/LexicalConventions/7.5-9-n.js ecma/LexicalConventions/7.6.js ecma/LexicalConventions/7.7.1.js ecma/LexicalConventions/7.7.2.js ecma/LexicalConventions/7.7.3-1.js ecma/LexicalConventions/7.7.3-2.js ecma/LexicalConventions/7.7.3.js ecma/LexicalConventions/7.7.4.js ecma/LexicalConventions/7.8.2-n.js ecma/Math/15.8-2-n.js ecma/Math/15.8-3-n.js ecma/Math/15.8.1.1-1.js ecma/Math/15.8.1.1-2.js ecma/Math/15.8.1.2-1.js ecma/Math/15.8.1.3-1.js ecma/Math/15.8.1.3-2.js ecma/Math/15.8.1.4-1.js ecma/Math/15.8.1.4-2.js ecma/Math/15.8.1.5-1.js ecma/Math/15.8.1.5-2.js ecma/Math/15.8.1.6-1.js ecma/Math/15.8.1.6-2.js ecma/Math/15.8.1.7-1.js ecma/Math/15.8.1.7-2.js ecma/Math/15.8.1.8-1.js ecma/Math/15.8.1.8-2.js ecma/Math/15.8.1.8-3.js ecma/Math/15.8.2.1.js ecma/Math/15.8.2.10.js ecma/Math/15.8.2.12.js ecma/Math/15.8.2.13.js ecma/Math/15.8.2.14.js ecma/Math/15.8.2.15.js ecma/Math/15.8.2.16.js ecma/Math/15.8.2.17.js ecma/Math/15.8.2.18.js ecma/Math/15.8.2.2.js ecma/Math/15.8.2.3.js ecma/Math/15.8.2.4.js ecma/Math/15.8.2.5.js ecma/Math/15.8.2.6.js ecma/Math/15.8.2.7.js ecma/Math/15.8.2.8.js ecma/Math/15.8.2.9.js ecma/Number/15.7.2.js ecma/Number/15.7.3.1-1.js ecma/Number/15.7.3.1-2.js ecma/Number/15.7.3.1-3.js ecma/Number/15.7.3.2-1.js ecma/Number/15.7.3.2-2.js ecma/Number/15.7.3.2-3.js ecma/Number/15.7.3.3-1.js ecma/Number/15.7.3.3-2.js ecma/Number/15.7.3.3-3.js ecma/Number/15.7.3.4-1.js ecma/Number/15.7.3.4-2.js ecma/Number/15.7.3.4-3.js ecma/Number/15.7.3.4-4.js ecma/Number/15.7.3.5-1.js ecma/Number/15.7.3.5-2.js ecma/Number/15.7.3.5-3.js ecma/Number/15.7.3.5-4.js ecma/Number/15.7.3.6-1.js ecma/Number/15.7.3.6-4.js ecma/Number/15.7.3.js ecma/Number/15.7.4-1.js ecma/Number/15.7.4.1.js ecma/Number/15.7.4.2-1.js ecma/Number/15.7.4.2-2-n.js ecma/Number/15.7.4.2-3-n.js ecma/Number/15.7.4.2-4.js ecma/Number/15.7.4.3-1.js ecma/Number/15.7.4.3-2.js ecma/ObjectObjects/15.2.1.2.js ecma/ObjectObjects/15.2.2.1.js ecma/ObjectObjects/15.2.2.2.js ecma/ObjectObjects/15.2.3.1-1.js ecma/ObjectObjects/15.2.3.1-2.js ecma/ObjectObjects/15.2.3.1-3.js ecma/ObjectObjects/15.2.3.1-4.js ecma/ObjectObjects/15.2.3.js ecma/ObjectObjects/15.2.4.1.js ecma/ObjectObjects/15.2.4.2.js ecma/ObjectObjects/15.2.4.3.js ecma/SourceText/6-1.js ecma/SourceText/6-2.js ecma/Statements/12.10-1.js ecma/Statements/12.10.js ecma/Statements/12.5-1.js ecma/Statements/12.5-2.js ecma/Statements/12.6.2-1.js ecma/Statements/12.6.2-2.js ecma/Statements/12.6.2-4.js ecma/Statements/12.6.2-5.js ecma/Statements/12.6.2-6.js ecma/Statements/12.6.2-7.js ecma/Statements/12.6.2-8.js ecma/Statements/12.6.2-9-n.js ecma/Statements/12.6.3-1.js ecma/Statements/12.6.3-10.js ecma/Statements/12.6.3-11.js ecma/Statements/12.6.3-12.js ecma/Statements/12.6.3-19.js ecma/Statements/12.6.3-2.js ecma/Statements/12.6.3-3.js ecma/Statements/12.6.3-4.js ecma/Statements/12.6.3-5-n.js ecma/Statements/12.6.3-6-n.js ecma/Statements/12.6.3-7-n.js ecma/Statements/12.6.3-9-n.js ecma/Statements/12.7-1-n.js ecma/Statements/12.8-1-n.js ecma/Statements/12.9-1-n.js ecma/String/15.5.1.js ecma/String/15.5.2.js ecma/String/15.5.3.1-1.js ecma/String/15.5.3.1-2.js ecma/String/15.5.3.1-3.js ecma/String/15.5.3.1-4.js ecma/String/15.5.3.2-1.js ecma/String/15.5.3.2-2.js ecma/String/15.5.3.2-3.js ecma/String/15.5.3.js ecma/String/15.5.4.1.js ecma/String/15.5.4.10-1.js ecma/String/15.5.4.11-1.js ecma/String/15.5.4.11-3.js ecma/String/15.5.4.11-4.js ecma/String/15.5.4.11-6.js ecma/String/15.5.4.12-2.js ecma/String/15.5.4.12-3.js ecma/String/15.5.4.2-1.js ecma/String/15.5.4.2-2-n.js ecma/String/15.5.4.2-3.js ecma/String/15.5.4.2.js ecma/String/15.5.4.3-1.js ecma/String/15.5.4.3-2.js ecma/String/15.5.4.3-3-n.js ecma/String/15.5.4.4-1.js ecma/String/15.5.4.4-2.js ecma/String/15.5.4.4-3.js ecma/String/15.5.4.4-4.js ecma/String/15.5.4.5-1.js ecma/String/15.5.4.5-2.js ecma/String/15.5.4.5-3.js ecma/String/15.5.4.5-4.js ecma/String/15.5.4.5-5.js ecma/String/15.5.4.6-1.js ecma/String/15.5.4.7-2.js ecma/String/15.5.4.8-1.js ecma/String/15.5.4.8-3.js ecma/String/15.5.4.9-1.js ecma/String/15.5.4.js ecma/String/15.5.5.1.js ecma/TypeConversion/9.2.js ecma/TypeConversion/9.3-1.js ecma/TypeConversion/9.3.1-1.js ecma/TypeConversion/9.3.1-2.js ecma/TypeConversion/9.3.1-3.js ecma/TypeConversion/9.3.js ecma/TypeConversion/9.4-1.js ecma/TypeConversion/9.4-2.js ecma/TypeConversion/9.5-2.js ecma/TypeConversion/9.6.js ecma/TypeConversion/9.7.js ecma/TypeConversion/9.8.1.js ecma/TypeConversion/9.9-1.js ecma/Types/8.1.js ecma/Types/8.4.js ecma/Types/8.6.2.1-1.js ecma/extensions/10.1.4-9.js ecma/extensions/10.1.6.js ecma/extensions/10.1.8-1.js ecma/extensions/11.6.1-1.js ecma/extensions/11.6.1-2.js ecma/extensions/11.6.1-3.js ecma/extensions/11.6.2-1.js ecma/extensions/15-2.js ecma/extensions/15.2.1.1.js ecma/extensions/15.2.3-1.js ecma/extensions/15.2.4.js ecma/extensions/15.3.1.1-2.js ecma/extensions/15.3.2.1-1.js ecma/extensions/15.3.2.1-2.js ecma/extensions/15.4.3.js ecma/extensions/15.5.3.js ecma/extensions/15.5.4.2.js ecma/extensions/15.5.4.4-4.js ecma/extensions/15.5.4.5-6.js ecma/extensions/15.5.4.7-3.js ecma/extensions/15.6.3.1-5.js ecma/extensions/15.6.3.js ecma/extensions/15.6.4-2.js ecma/extensions/15.7.3.js ecma/extensions/15.7.4.js ecma/extensions/15.8-1.js ecma/extensions/15.9.5.js ecma/extensions/8.6.2.1-1.js ecma/extensions/9.9-1.js ecma/jsref.js ecma_2/Exceptions/boolean-001.js ecma_2/Exceptions/date-001.js ecma_2/Exceptions/date-002.js ecma_2/Exceptions/date-004.js ecma_2/Exceptions/exception-001.js ecma_2/Exceptions/exception-002.js ecma_2/Exceptions/exception-004.js ecma_2/Exceptions/exception-005.js ecma_2/Exceptions/exception-006.js ecma_2/Exceptions/exception-007.js ecma_2/Exceptions/exception-008.js ecma_2/Exceptions/exception-009.js ecma_2/Exceptions/exception-010-n.js ecma_2/Exceptions/exception-011-n.js ecma_2/Exceptions/expression-002.js ecma_2/Exceptions/expression-004.js ecma_2/Exceptions/expression-005.js ecma_2/Exceptions/expression-006.js ecma_2/Exceptions/expression-007.js ecma_2/Exceptions/expression-008.js ecma_2/Exceptions/expression-009.js ecma_2/Exceptions/expression-010.js ecma_2/Exceptions/expression-011.js ecma_2/Exceptions/expression-012.js ecma_2/Exceptions/expression-013.js ecma_2/Exceptions/expression-014.js ecma_2/Exceptions/expression-015.js ecma_2/Exceptions/expression-016.js ecma_2/Exceptions/expression-017.js ecma_2/Exceptions/global-001.js ecma_2/Exceptions/global-002.js ecma_2/Exceptions/lexical-001.js ecma_2/Exceptions/lexical-002.js ecma_2/Exceptions/lexical-003.js ecma_2/Exceptions/lexical-004.js ecma_2/Exceptions/lexical-005.js ecma_2/Exceptions/lexical-006.js ecma_2/Exceptions/lexical-007.js ecma_2/Exceptions/lexical-009.js ecma_2/Exceptions/lexical-010.js ecma_2/Exceptions/lexical-011.js ecma_2/Exceptions/lexical-012.js ecma_2/Exceptions/lexical-013.js ecma_2/Exceptions/lexical-014.js ecma_2/Exceptions/lexical-015.js ecma_2/Exceptions/lexical-016.js ecma_2/Exceptions/lexical-017.js ecma_2/Exceptions/lexical-018.js ecma_2/Exceptions/lexical-019.js ecma_2/Exceptions/lexical-020.js ecma_2/Exceptions/lexical-022.js ecma_2/Exceptions/lexical-023.js ecma_2/Exceptions/lexical-024.js ecma_2/Exceptions/lexical-025.js ecma_2/Exceptions/lexical-026.js ecma_2/Exceptions/lexical-027.js ecma_2/Exceptions/lexical-028.js ecma_2/Exceptions/lexical-029.js ecma_2/Exceptions/lexical-030.js ecma_2/Exceptions/lexical-031.js ecma_2/Exceptions/lexical-032.js ecma_2/Exceptions/lexical-033.js ecma_2/Exceptions/lexical-034.js ecma_2/Exceptions/lexical-035.js ecma_2/Exceptions/lexical-036.js ecma_2/Exceptions/lexical-037.js ecma_2/Exceptions/lexical-038.js ecma_2/Exceptions/lexical-039.js ecma_2/Exceptions/lexical-040.js ecma_2/Exceptions/lexical-041.js ecma_2/Exceptions/lexical-042.js ecma_2/Exceptions/lexical-047.js ecma_2/Exceptions/lexical-048.js ecma_2/Exceptions/lexical-049.js ecma_2/Exceptions/lexical-050.js ecma_2/Exceptions/lexical-051.js ecma_2/Exceptions/lexical-053.js ecma_2/Exceptions/lexical-054.js ecma_2/Exceptions/number-002.js ecma_2/Exceptions/number-003.js ecma_2/Exceptions/statement-001.js ecma_2/Exceptions/statement-002.js ecma_2/Exceptions/statement-003.js ecma_2/Exceptions/statement-004.js ecma_2/Exceptions/statement-005.js ecma_2/Exceptions/statement-006.js ecma_2/Exceptions/statement-007.js ecma_2/Exceptions/statement-008.js ecma_2/Exceptions/string-001.js ecma_2/Exceptions/string-002.js ecma_2/Expressions/StrictEquality-001.js ecma_2/FunctionObjects/apply-001-n.js ecma_2/FunctionObjects/call-1.js ecma_2/LexicalConventions/keywords-001.js ecma_2/LexicalConventions/regexp-literals-001.js ecma_2/LexicalConventions/regexp-literals-002.js ecma_2/RegExp/constructor-001.js ecma_2/RegExp/exec-002.js ecma_2/RegExp/function-001.js ecma_2/RegExp/hex-001.js ecma_2/RegExp/multiline-001.js ecma_2/RegExp/octal-001.js ecma_2/RegExp/octal-002.js ecma_2/RegExp/octal-003.js ecma_2/RegExp/properties-001.js ecma_2/RegExp/properties-002.js ecma_2/RegExp/regress-001.js ecma_2/RegExp/unicode-001.js ecma_2/Statements/dowhile-001.js ecma_2/Statements/dowhile-002.js ecma_2/Statements/dowhile-003.js ecma_2/Statements/dowhile-004.js ecma_2/Statements/dowhile-005.js ecma_2/Statements/dowhile-006.js ecma_2/Statements/dowhile-007.js ecma_2/Statements/forin-001.js ecma_2/Statements/forin-002.js ecma_2/Statements/if-001.js ecma_2/Statements/label-001.js ecma_2/Statements/label-002.js ecma_2/Statements/switch-002.js ecma_2/Statements/switch-003.js ecma_2/Statements/switch-004.js ecma_2/Statements/try-001.js ecma_2/Statements/try-003.js ecma_2/Statements/try-004.js ecma_2/Statements/try-005.js ecma_2/Statements/try-007.js ecma_2/Statements/try-008.js ecma_2/Statements/try-009.js ecma_2/Statements/try-012.js ecma_2/Statements/while-001.js ecma_2/Statements/while-002.js ecma_2/Statements/while-003.js ecma_2/Statements/while-004.js ecma_2/String/match-001.js ecma_2/String/match-002.js ecma_2/String/match-003.js ecma_2/String/match-004.js ecma_2/String/split-001.js ecma_2/String/split-002.js ecma_2/String/split-003.js ecma_2/extensions/constructor-001.js ecma_2/extensions/function-001.js ecma_2/extensions/instanceof-001.js ecma_2/extensions/instanceof-002.js ecma_2/extensions/instanceof-006.js ecma_2/instanceof/instanceof-001.js ecma_2/instanceof/instanceof-002.js ecma_2/instanceof/regress-7635.js ecma_2/jsref.js ecma_3/Array/15.4.4.11-01.js ecma_3/Array/15.4.4.3-1.js ecma_3/Array/15.4.4.4-001.js ecma_3/Array/regress-101488.js ecma_3/Array/regress-130451.js ecma_3/Array/regress-322135-01.js ecma_3/Date/15.9.4.3.js ecma_3/Date/15.9.5.3.js ecma_3/Date/15.9.5.4.js ecma_3/Date/15.9.5.5.js ecma_3/Date/15.9.5.6.js ecma_3/Date/15.9.5.7.js ecma_3/Exceptions/15.11.1.1.js ecma_3/Exceptions/15.11.4.4-1.js ecma_3/Exceptions/15.11.7.6-001.js ecma_3/Exceptions/15.11.7.6-002.js ecma_3/Exceptions/15.11.7.6-003.js ecma_3/Exceptions/binding-001.js ecma_3/Exceptions/regress-95101.js ecma_3/ExecutionContexts/10.1.3-1.js ecma_3/ExecutionContexts/10.1.3-2.js ecma_3/ExecutionContexts/10.1.3.js ecma_3/ExecutionContexts/10.1.4-1.js ecma_3/ExecutionContexts/10.6.1-01.js ecma_3/ExecutionContexts/regress-23346.js ecma_3/Expressions/11.10-01.js ecma_3/Expressions/11.10-03.js ecma_3/Expressions/11.6.1-1.js ecma_3/Expressions/11.7.1-01.js ecma_3/Expressions/11.7.2-01.js ecma_3/Expressions/11.7.3-01.js ecma_3/Expressions/11.9.6-1.js ecma_3/FunExpr/fe-001-n.js ecma_3/FunExpr/fe-001.js ecma_3/FunExpr/fe-002.js ecma_3/Function/15.3.4.3-1.js ecma_3/Function/15.3.4.4-1.js ecma_3/Function/arguments-002.js ecma_3/Function/call-001.js ecma_3/Function/regress-131964.js ecma_3/Function/regress-137181.js ecma_3/Function/regress-193555.js ecma_3/Function/regress-313570.js ecma_3/Function/regress-49286.js ecma_3/Function/regress-58274.js ecma_3/Function/regress-85880.js ecma_3/Function/regress-94506.js ecma_3/Function/regress-97921.js ecma_3/Function/scope-001.js ecma_3/Function/scope-002.js ecma_3/Number/15.7.4.5-1.js ecma_3/Number/15.7.4.6-1.js ecma_3/Number/15.7.4.7-1.js ecma_3/Number/15.7.4.7-2.js ecma_3/NumberFormatting/tostring-001.js ecma_3/Object/8.6.2.6-001.js ecma_3/Object/class-001.js ecma_3/Object/class-002.js ecma_3/Object/class-003.js ecma_3/Object/class-004.js ecma_3/Object/class-005.js ecma_3/Object/regress-361274.js ecma_3/Object/regress-385393-07.js ecma_3/Object/regress-72773.js ecma_3/Object/regress-79129-001.js ecma_3/Operators/11.13.1-001.js ecma_3/Operators/11.13.1-002.js ecma_3/Operators/11.4.1-001.js ecma_3/RegExp/15.10.2-1.js ecma_3/RegExp/15.10.2.12.js ecma_3/RegExp/15.10.3.1-1.js ecma_3/RegExp/15.10.3.1-2.js ecma_3/RegExp/15.10.4.1-1.js ecma_3/RegExp/15.10.4.1-2.js ecma_3/RegExp/15.10.4.1-3.js ecma_3/RegExp/15.10.4.1-4.js ecma_3/RegExp/15.10.4.1-5-n.js ecma_3/RegExp/15.10.6.2-1.js ecma_3/RegExp/15.10.6.2-2.js ecma_3/RegExp/octal-001.js ecma_3/RegExp/octal-002.js ecma_3/RegExp/perlstress-001.js ecma_3/RegExp/perlstress-002.js ecma_3/RegExp/regress-100199.js ecma_3/RegExp/regress-105972.js ecma_3/RegExp/regress-122076.js ecma_3/RegExp/regress-123437.js ecma_3/RegExp/regress-165353.js ecma_3/RegExp/regress-169497.js ecma_3/RegExp/regress-169534.js ecma_3/RegExp/regress-187133.js ecma_3/RegExp/regress-191479.js ecma_3/RegExp/regress-202564.js ecma_3/RegExp/regress-209067.js ecma_3/RegExp/regress-209919.js ecma_3/RegExp/regress-216591.js ecma_3/RegExp/regress-220367-001.js ecma_3/RegExp/regress-223273.js ecma_3/RegExp/regress-223535.js ecma_3/RegExp/regress-224676.js ecma_3/RegExp/regress-225289.js ecma_3/RegExp/regress-225343.js ecma_3/RegExp/regress-24712.js ecma_3/RegExp/regress-28686.js ecma_3/RegExp/regress-309840.js ecma_3/RegExp/regress-312351.js ecma_3/RegExp/regress-31316.js ecma_3/RegExp/regress-334158.js ecma_3/RegExp/regress-346090.js ecma_3/RegExp/regress-367888.js: ecma_3/RegExp/regress-375642.js: ecma_3/RegExp/regress-375715-02.js ecma_3/RegExp/regress-375715-03.js ecma_3/RegExp/regress-57572.js ecma_3/RegExp/regress-57631.js ecma_3/RegExp/regress-67773.js ecma_3/RegExp/regress-76683.js ecma_3/RegExp/regress-78156.js ecma_3/RegExp/regress-85721.js ecma_3/RegExp/regress-87231.js ecma_3/RegExp/regress-98306.js ecma_3/Statements/12.6.3.js ecma_3/Statements/regress-131348.js ecma_3/Statements/regress-157509.js ecma_3/Statements/regress-194364.js ecma_3/Statements/regress-226517.js ecma_3/Statements/regress-74474-001.js ecma_3/Statements/regress-83532-001.js ecma_3/Statements/regress-83532-002.js ecma_3/Statements/switch-001.js ecma_3/String/regress-104375.js ecma_3/String/regress-189898.js ecma_3/String/regress-313567.js ecma_3/String/regress-83293.js ecma_3/Unicode/uc-001-n.js ecma_3/Unicode/uc-002-n.js ecma_3/Unicode/uc-002.js ecma_3/Unicode/uc-003.js ecma_3/Unicode/uc-004.js ecma_3/Unicode/uc-005.js ecma_3/extensions/regress-103087.js ecma_3/extensions/regress-188206-01.js ecma_3/extensions/regress-188206-02.js ecma_3/extensions/regress-220367-002.js ecma_3/extensions/regress-228087.js ecma_3/extensions/regress-320854.js ecma_3/extensions/regress-327170.js ecma_3/extensions/regress-385393-03.js js-test-driver-begin.js js-test-driver-end.js js1_1/jsref.js js1_2/Array/array_split_1.js js1_2/Array/general1.js js1_2/Array/general2.js js1_2/Array/slice.js js1_2/Array/splice1.js js1_2/Array/splice2.js js1_2/Array/tostring_1.js js1_2/Array/tostring_2.js js1_2/Objects/toString-001.js js1_2/String/charCodeAt.js js1_2/String/concat.js js1_2/String/match.js js1_2/String/slice.js js1_2/function/Number.js js1_2/function/String.js js1_2/function/definition-1.js js1_2/function/length.js js1_2/function/nesting-1.js js1_2/function/nesting.js js1_2/function/regexparg-2-n.js js1_2/jsref.js js1_2/operator/strictEquality.js js1_2/regexp/RegExp_dollar_number.js js1_2/regexp/RegExp_input.js js1_2/regexp/RegExp_input_as_array.js js1_2/regexp/RegExp_lastIndex.js js1_2/regexp/RegExp_lastMatch.js js1_2/regexp/RegExp_lastMatch_as_array.js js1_2/regexp/RegExp_lastParen.js js1_2/regexp/RegExp_lastParen_as_array.js js1_2/regexp/RegExp_leftContext.js js1_2/regexp/RegExp_leftContext_as_array.js js1_2/regexp/RegExp_multiline.js js1_2/regexp/RegExp_multiline_as_array.js js1_2/regexp/RegExp_object.js js1_2/regexp/RegExp_rightContext.js js1_2/regexp/RegExp_rightContext_as_array.js js1_2/regexp/alphanumeric.js js1_2/regexp/asterisk.js js1_2/regexp/backslash.js js1_2/regexp/backspace.js js1_2/regexp/beginLine.js js1_2/regexp/character_class.js js1_2/regexp/compile.js js1_2/regexp/control_characters.js js1_2/regexp/digit.js js1_2/regexp/dot.js js1_2/regexp/endLine.js js1_2/regexp/everything.js js1_2/regexp/exec.js js1_2/regexp/flags.js js1_2/regexp/global.js js1_2/regexp/hexadecimal.js js1_2/regexp/ignoreCase.js js1_2/regexp/interval.js js1_2/regexp/octal.js js1_2/regexp/parentheses.js js1_2/regexp/regress-6359.js js1_2/regexp/regress-9141.js js1_2/regexp/simple_form.js js1_2/regexp/source.js js1_2/regexp/special_characters.js js1_2/regexp/string_replace.js js1_2/regexp/string_search.js js1_2/regexp/string_split.js js1_2/regexp/test.js js1_2/regexp/toString.js js1_2/regexp/vertical_bar.js js1_2/regexp/whitespace.js js1_2/regexp/word_boundary.js js1_2/regress/regress-144834.js js1_2/regress/regress-7703.js js1_2/statements/break.js js1_2/statements/do_while.js js1_2/statements/switch.js js1_2/statements/switch2.js js1_2/version120/boolean-001.js js1_3/Boolean/boolean-001.js js1_3/Script/delete-001.js js1_3/Script/function-002.js js1_3/Script/new-001.js js1_3/Script/switch-001.js js1_3/extensions/proto_10.js js1_3/extensions/proto_2.js js1_3/extensions/proto_5.js js1_3/inherit/proto_1.js js1_3/inherit/proto_10.js js1_3/inherit/proto_11.js js1_3/inherit/proto_12.js js1_3/inherit/proto_3.js js1_3/inherit/proto_4.js js1_3/inherit/proto_6.js js1_3/inherit/proto_7.js js1_3/inherit/proto_8.js js1_3/inherit/proto_9.js js1_3/jsref.js js1_3/regress/delete-001.js js1_3/regress/function-002.js js1_3/regress/new-001.js js1_3/regress/switch-001.js js1_4/Eval/eval-001.js js1_4/Eval/eval-002.js js1_4/Eval/eval-003.js js1_4/Functions/function-001.js js1_4/Regress/date-001-n.js js1_4/Regress/function-001.js js1_4/Regress/function-002.js js1_4/Regress/function-003.js js1_4/Regress/function-004-n.js js1_4/Regress/regress-7224.js js1_4/Regress/toString-001-n.js js1_4/jsref.js js1_5/Array/11.1.4.js js1_5/Array/array-001.js js1_5/Array/regress-101964.js js1_5/Array/regress-107138.js js1_5/Array/regress-108440.js js1_5/Array/regress-154338.js js1_5/Array/regress-178722.js js1_5/Array/regress-255555.js js1_5/Array/regress-299644.js js1_5/Array/regress-300858.js js1_5/Array/regress-310351.js js1_5/Array/regress-311515.js js1_5/Array/regress-313153.js js1_5/Array/regress-315509-01.js js1_5/Array/regress-345961.js js1_5/Array/regress-348810.js js1_5/Array/regress-350256-01.js js1_5/Array/regress-350256-02.js js1_5/Array/regress-360681-01.js js1_5/Array/regress-360681-02.js js1_5/Array/regress-364104.js js1_5/Array/regress-94257.js js1_5/Date/regress-188211.js js1_5/Date/regress-301738-01.js js1_5/Date/regress-309925-01.js js1_5/Date/regress-346027.js js1_5/Exceptions/catchguard-002-n.js js1_5/Exceptions/catchguard-003-n.js js1_5/Exceptions/regress-123002.js js1_5/Exceptions/regress-232182.js js1_5/Exceptions/regress-273931.js js1_5/Exceptions/regress-347674.js js1_5/Exceptions/regress-350837.js js1_5/Expressions/regress-192288.js js1_5/Expressions/regress-96526-argsub.js js1_5/Expressions/regress-96526-noargsub.js js1_5/Function/10.1.6.js js1_5/Function/15.3.4.4.js js1_5/Function/regress-123371.js js1_5/Function/regress-178389.js js1_5/Function/regress-292215.js js1_5/Function/regress-344052.js js1_5/GetSet/regress-375976.js js1_5/LexicalConventions/lexical-001.js js1_5/LexicalConventions/regress-177314.js js1_5/Object/regress-137000.js js1_5/Object/regress-192105.js js1_5/Object/regress-338709.js js1_5/Object/regress-382503.js js1_5/Object/regress-382532.js js1_5/Object/regress-90596-003.js js1_5/Regress/regress-104077.js js1_5/Regress/regress-110286.js js1_5/Regress/regress-114491.js js1_5/Regress/regress-114493.js js1_5/Regress/regress-115436.js js1_5/Regress/regress-116228.js js1_5/Regress/regress-118849.js js1_5/Regress/regress-127243.js js1_5/Regress/regress-127557.js js1_5/Regress/regress-131510-001.js js1_5/Regress/regress-140852.js js1_5/Regress/regress-140974.js js1_5/Regress/regress-146596.js js1_5/Regress/regress-152646.js js1_5/Regress/regress-159334.js js1_5/Regress/regress-162392.js js1_5/Regress/regress-165201.js js1_5/Regress/regress-167658.js js1_5/Regress/regress-168347.js js1_5/Regress/regress-170193.js js1_5/Regress/regress-174709.js js1_5/Regress/regress-176125.js js1_5/Regress/regress-185165.js js1_5/Regress/regress-191633.js js1_5/Regress/regress-192414.js js1_5/Regress/regress-193418.js js1_5/Regress/regress-203402.js js1_5/Regress/regress-203841.js js1_5/Regress/regress-204210.js js1_5/Regress/regress-210682.js js1_5/Regress/regress-211590.js js1_5/Regress/regress-214761.js js1_5/Regress/regress-216320.js js1_5/Regress/regress-224956.js js1_5/Regress/regress-229006.js js1_5/Regress/regress-230216-1.js js1_5/Regress/regress-230216-2.js js1_5/Regress/regress-230216-3.js js1_5/Regress/regress-233483-2.js js1_5/Regress/regress-233483.js js1_5/Regress/regress-238881.js js1_5/Regress/regress-238945.js js1_5/Regress/regress-243174.js js1_5/Regress/regress-243389-n.js js1_5/Regress/regress-243869.js js1_5/Regress/regress-244619.js js1_5/Regress/regress-245113.js js1_5/Regress/regress-245308.js js1_5/Regress/regress-246911.js js1_5/Regress/regress-246964.js js1_5/Regress/regress-247179.js js1_5/Regress/regress-253150.js js1_5/Regress/regress-254296.js js1_5/Regress/regress-254974.js js1_5/Regress/regress-256501.js js1_5/Regress/regress-256617.js js1_5/Regress/regress-256798.js js1_5/Regress/regress-260541.js js1_5/Regress/regress-261887.js js1_5/Regress/regress-274888.js js1_5/Regress/regress-275378.js js1_5/Regress/regress-276103.js js1_5/Regress/regress-278873.js js1_5/Regress/regress-280769-3.js js1_5/Regress/regress-280769-4.js js1_5/Regress/regress-281487.js js1_5/Regress/regress-281930.js js1_5/Regress/regress-283477.js js1_5/Regress/regress-286216.js js1_5/Regress/regress-288688.js js1_5/Regress/regress-289094.js js1_5/Regress/regress-290656.js js1_5/Regress/regress-294191.js js1_5/Regress/regress-294195-01.js js1_5/Regress/regress-294195-02.js js1_5/Regress/regress-295052.js js1_5/Regress/regress-295666.js js1_5/Regress/regress-306633.js js1_5/Regress/regress-306727.js js1_5/Regress/regress-306794.js js1_5/Regress/regress-308566.js js1_5/Regress/regress-310295.js js1_5/Regress/regress-310607.js js1_5/Regress/regress-310993.js js1_5/Regress/regress-311071.js js1_5/Regress/regress-311629.js js1_5/Regress/regress-312260.js js1_5/Regress/regress-31255.js js1_5/Regress/regress-314401.js js1_5/Regress/regress-315990.js js1_5/Regress/regress-317476.js js1_5/Regress/regress-317714-02.js js1_5/Regress/regress-319384.js js1_5/Regress/regress-320032.js js1_5/Regress/regress-321757.js js1_5/Regress/regress-321874.js js1_5/Regress/regress-322430.js js1_5/Regress/regress-326467.js js1_5/Regress/regress-328012.js js1_5/Regress/regress-328897.js js1_5/Regress/regress-329383.js js1_5/Regress/regress-330951.js js1_5/Regress/regress-334807-05.js js1_5/Regress/regress-334807-06.js js1_5/Regress/regress-338307.js js1_5/Regress/regress-340369.js js1_5/Regress/regress-341360.js js1_5/Regress/regress-343966.js js1_5/Regress/regress-344804.js js1_5/Regress/regress-344959.js js1_5/Regress/regress-346801.js js1_5/Regress/regress-349482-02.js js1_5/Regress/regress-349592.js js1_5/Regress/regress-350253.js js1_5/Regress/regress-350312.js js1_5/Regress/regress-350415.js js1_5/Regress/regress-351116.js js1_5/Regress/regress-351515.js js1_5/Regress/regress-352009.js js1_5/Regress/regress-352208.js js1_5/Regress/regress-360969-01.js js1_5/Regress/regress-360969-02.js js1_5/Regress/regress-360969-03.js js1_5/Regress/regress-360969-04.js js1_5/Regress/regress-366468.js js1_5/Regress/regress-367561-01.js js1_5/Regress/regress-379245.js js1_5/Regress/regress-39309.js js1_5/Regress/regress-398609.js js1_5/Regress/regress-406769.js js1_5/Regress/regress-407024.js js1_5/Regress/regress-407323.js js1_5/Regress/regress-407957.js js1_5/Regress/regress-57043.js js1_5/Regress/regress-68498-001.js js1_5/Regress/regress-68498-002.js js1_5/Regress/regress-68498-004.js js1_5/Regress/regress-69607.js js1_5/Regress/regress-71107.js js1_5/Regress/regress-76054.js js1_5/Regress/regress-82306.js js1_5/Regress/regress-90445.js js1_5/Regress/regress-96526-001.js js1_5/Scope/regress-154693.js js1_5/Scope/regress-184107.js js1_5/Scope/regress-185485.js js1_5/Scope/regress-191276.js js1_5/Scope/regress-192226.js js1_5/Scope/regress-202678-001.js js1_5/Scope/regress-202678-002.js js1_5/Scope/regress-208496-001.js js1_5/Scope/regress-208496-002.js js1_5/Scope/regress-220362.js js1_5/Scope/regress-77578-001.js js1_5/Scope/scope-002.js js1_5/Scope/scope-003.js js1_5/String/regress-107771.js js1_5/String/regress-112626.js js1_5/String/regress-179068.js js1_5/decompilation/regress-344120.js js1_5/decompilation/regress-349489.js js1_5/decompilation/regress-349663.js js1_5/decompilation/regress-350670.js js1_5/decompilation/regress-351625.js js1_5/decompilation/regress-351626.js js1_5/decompilation/regress-352022.js js1_5/decompilation/regress-352360.js js1_5/decompilation/regress-352873-01.js js1_5/decompilation/regress-352873-02.js js1_5/decompilation/regress-353120.js js1_5/decompilation/regress-354878.js js1_5/decompilation/regress-354910.js js1_5/decompilation/regress-371692.js js1_5/decompilation/regress-373678.js js1_5/decompilation/regress-375639.js js1_5/decompilation/regress-383721.js js1_5/decompilation/regress-406555.js js1_5/extensions/catchguard-001.js js1_5/extensions/catchguard-002.js js1_5/extensions/catchguard-003.js js1_5/extensions/getset-004.js js1_5/extensions/getset-005.js js1_5/extensions/getset-006.js js1_5/extensions/no-such-method.js js1_5/extensions/regress-104077.js js1_5/extensions/regress-178722.js js1_5/extensions/regress-220584.js js1_5/extensions/regress-225831.js js1_5/extensions/regress-226078.js js1_5/extensions/regress-237461.js js1_5/extensions/regress-245795.js js1_5/extensions/regress-255245.js js1_5/extensions/regress-291213.js js1_5/extensions/regress-311161.js js1_5/extensions/regress-311583.js js1_5/extensions/regress-311792-01.js js1_5/extensions/regress-311792-02.js js1_5/extensions/regress-312278.js js1_5/extensions/regress-313500.js js1_5/extensions/regress-313630.js js1_5/extensions/regress-313763.js js1_5/extensions/regress-313803.js js1_5/extensions/regress-313938.js js1_5/extensions/regress-314874.js js1_5/extensions/regress-319683.js js1_5/extensions/regress-322957.js js1_5/extensions/regress-325269.js js1_5/extensions/regress-327608.js js1_5/extensions/regress-328556.js js1_5/extensions/regress-338804-01.js js1_5/extensions/regress-338804-03.js js1_5/extensions/regress-339685.js js1_5/extensions/regress-340199.js js1_5/extensions/regress-341956-02.js js1_5/extensions/regress-341956-03.js js1_5/extensions/regress-346494-01.js js1_5/extensions/regress-350312-01.js js1_5/extensions/regress-350312-02.js js1_5/extensions/regress-350312-03.js js1_5/extensions/regress-351102-01.js js1_5/extensions/regress-351102-02.js js1_5/extensions/regress-351102-06.js js1_5/extensions/regress-351973.js js1_5/extensions/regress-352261.js js1_5/extensions/regress-352281.js js1_5/extensions/regress-354297.js js1_5/extensions/regress-354541-01.js js1_5/extensions/regress-354541-03.js js1_5/extensions/regress-355982.js js1_5/extensions/regress-356402.js js1_5/extensions/regress-363988.js js1_5/extensions/regress-365527.js js1_5/extensions/regress-365692.js js1_5/extensions/regress-366288.js js1_5/extensions/regress-366292.js js1_5/extensions/regress-366396.js js1_5/extensions/regress-367118-01.js js1_5/extensions/regress-367118-02.js js1_5/extensions/regress-367120-01.js js1_5/extensions/regress-367120-02.js js1_5/extensions/regress-367121.js js1_5/extensions/regress-367501-01.js js1_5/extensions/regress-367501-02.js js1_5/extensions/regress-367501-03.js js1_5/extensions/regress-367589.js js1_5/extensions/regress-369404.js js1_5/extensions/regress-374589.js js1_5/extensions/regress-375183.js js1_5/extensions/regress-380889.js js1_5/extensions/regress-385134.js js1_5/extensions/regress-394967.js js1_5/extensions/regress-396326.js js1_5/extensions/regress-407501.js js1_5/extensions/regress-44009.js js1_5/extensions/regress-90596-001.js js1_5/extensions/regress-90596-002.js js1_5/extensions/regress-96284-001.js js1_5/extensions/regress-96284-002.js js1_5/extensions/scope-001.js js1_6/Array/filter.js js1_6/Array/regress-304828.js js1_6/Array/regress-305002.js js1_6/Array/regress-310425-01.js js1_6/Array/regress-310425-02.js js1_6/Array/regress-320887.js js1_6/Array/regress-352742-01.js js1_6/Array/regress-352742-02.js js1_6/Array/regress-415451.js js1_6/Array/regress-415540.js js1_6/Regress/regress-301574.js js1_6/Regress/regress-311157-01.js js1_6/Regress/regress-311157-02.js js1_6/Regress/regress-314887.js js1_6/Regress/regress-351795.js js1_6/Regress/regress-352271.js js1_6/Regress/regress-378492.js js1_6/decompilation/regress-352084.js js1_6/extensions/regress-385393-08.js js1_7/GC/regress-341675.js js1_7/block/order-of-operation.js js1_7/block/regress-341939.js js1_7/block/regress-344139.js js1_7/block/regress-344370.js js1_7/block/regress-345542.js js1_7/block/regress-348685.js js1_7/block/regress-349283.js js1_7/block/regress-349298.js js1_7/block/regress-349507.js js1_7/block/regress-349653.js js1_7/block/regress-349962.js js1_7/block/regress-350279.js js1_7/block/regress-350730.js js1_7/block/regress-350793-01.js js1_7/block/regress-351497.js js1_7/block/regress-351606.js js1_7/block/regress-352092.js js1_7/block/regress-352185.js js1_7/block/regress-352212.js js1_7/block/regress-352267.js js1_7/block/regress-352616.js js1_7/block/regress-352624.js js1_7/block/regress-352907.js js1_7/block/regress-357754.js js1_7/block/regress-376410.js js1_7/block/regress-396900.js js1_7/block/regress-411279.js js1_7/decompilation/regress-349633.js js1_7/decompilation/regress-350810.js js1_7/decompilation/regress-352015.js js1_7/decompilation/regress-352025.js js1_7/decompilation/regress-352269.js js1_7/decompilation/regress-352272.js js1_7/decompilation/regress-352283.js js1_7/decompilation/regress-352732.js js1_7/decompilation/regress-355635.js js1_7/decompilation/regress-355786.js js1_7/decompilation/regress-375794.js js1_7/decompilation/regress-380506.js js1_7/expressions/destructuring-scope.js js1_7/expressions/regress-346203.js js1_7/expressions/regress-346645-01.js js1_7/expressions/regress-346645-02.js js1_7/expressions/regress-346645-03.js js1_7/expressions/regress-349624.js js1_7/expressions/regress-349818.js js1_7/extensions/basic-Iterator.js js1_7/extensions/basic-for-in.js js1_7/extensions/destructuring-order.js js1_7/extensions/iterator-ctor.js js1_7/extensions/regress-346021.js js1_7/extensions/regress-346642-02.js js1_7/extensions/regress-346773.js js1_7/extensions/regress-349619.js js1_7/extensions/regress-350312.js js1_7/extensions/regress-351070-02.js js1_7/extensions/regress-352797-01.js js1_7/extensions/regress-352885-01.js js1_7/extensions/regress-352885-02.js js1_7/extensions/regress-353214-02.js js1_7/extensions/regress-354499-01.js js1_7/extensions/regress-354499-02.js js1_7/extensions/regress-354945-01.js js1_7/extensions/regress-355052-01.js js1_7/extensions/regress-355052-02.js js1_7/extensions/regress-355052-03.js js1_7/extensions/regress-355410.js js1_7/extensions/regress-355512.js js1_7/extensions/regress-355578.js js1_7/extensions/regress-355583.js js1_7/extensions/regress-363040-01.js js1_7/extensions/regress-363040-02.js js1_7/extensions/regress-366668-01.js js1_7/extensions/regress-366668-02.js js1_7/extensions/regress-387955-01.js js1_7/extensions/regress-392308.js js1_7/extensions/regress-396326.js js1_7/geniter/326466-01.js js1_7/geniter/builtin-Iterator-function.js js1_7/geniter/evens.js js1_7/geniter/fibonacci-matrix-generator.js js1_7/geniter/iterator-toString.js js1_7/geniter/message-value-passing.js js1_7/geniter/multiple-close.js js1_7/geniter/nested-yield.js js1_7/geniter/pi-generator.js js1_7/geniter/regress-345736.js js1_7/geniter/regress-345855.js js1_7/geniter/regress-345879-01.js js1_7/geniter/regress-347593.js js1_7/geniter/regress-349012-02.js js1_7/geniter/regress-349012-03.js js1_7/geniter/regress-349012-04.js js1_7/geniter/regress-349012-05.js js1_7/geniter/regress-349023-01.js js1_7/geniter/regress-349023-02.js js1_7/geniter/regress-349023-03.js js1_7/geniter/regress-349362.js js1_7/geniter/regress-349851.js js1_7/geniter/regress-350621.js js1_7/geniter/regress-350809.js js1_7/geniter/regress-351120.js js1_7/geniter/regress-352197.js js1_7/geniter/regress-352876.js js1_7/geniter/regress-355834.js js1_7/geniter/regress-359062.js js1_7/geniter/regress-366941.js js1_7/geniter/regress-382335.js js1_7/geniter/regress-390918.js js1_7/geniter/send-no-rhs.js js1_7/geniter/sequential-yields.js js1_7/geniter/throw-after-close.js js1_7/geniter/throw-forever.js js1_7/geniter/unreachable-yield.js js1_7/geniter/yield-undefined.js js1_7/iterable/regress-341499.js js1_7/iterable/regress-341510.js js1_7/iterable/regress-341815.js js1_7/iterable/regress-341821.js js1_7/iterable/regress-354750-01.js js1_7/iterable/regress-355025.js js1_7/iterable/regress-355075-01.js js1_7/iterable/regress-355090.js js1_7/iterable/regress-412467.js js1_7/lexical/regress-346642-04.js js1_7/regress/regress-352640-01.js js1_7/regress/regress-352640-02.js js1_7/regress/regress-352640-03.js js1_7/regress/regress-352640-04.js js1_7/regress/regress-352797-02.js js1_7/regress/regress-352870-03.js js1_7/regress/regress-353079.js js1_7/regress/regress-355023.js js1_7/regress/regress-355832-01.js js1_7/regress/regress-361566.js js1_7/regress/regress-369666-01.js js1_7/regress/regress-369666-02.js js1_7/regress/regress-372331.js js1_7/regress/regress-373827-01.js js1_7/regress/regress-373827-02.js js1_7/regress/regress-373828.js js1_7/regress/regress-379442.js js1_7/regress/regress-385393-05.js js1_7/regress/regress-407727-01.js js1_7/regress/regress-407727-02.js js1_7/regress/regress-407957.js js1_7/regress/regress-414553.js lc2/Arrays/array-001.js lc2/Arrays/array-002.js lc2/Arrays/array-003.js lc2/Arrays/array-004.js lc2/Arrays/array-005.js lc2/Arrays/array-006-n.js lc2/Arrays/array-007-n.js lc2/Classes/class-001.js lc2/Classes/class-002.js lc2/JSToJava/character-001.js lc2/JSToJava/double-001.js lc2/JSToJava/double-002.js lc2/JSToJava/float-001.js lc2/JSToJava/float-002.js lc2/JSToJava/integer-001.js lc2/JSToJava/integer-002.js lc2/JSToJava/long-001.js lc2/JSToJava/long-002.js lc2/JSToJava/long-003-n.js lc2/JSToJava/short-001.js lc2/JSToJava/short-002.js lc2/JSToJava/short-003-n.js lc2/JavaToJS/String-001.js lc2/JavaToJS/boolean-001.js lc2/JavaToJS/boolean-003.js lc2/JavaToJS/boolean-004.js lc2/JavaToJS/boolean-005.js lc2/JavaToJS/char-001.js lc2/JavaToJS/char-002.js lc2/JavaToJS/enum-001.js lc2/JavaToJS/enum-002.js lc2/JavaToJS/null-001.js lc2/JavaToJS/number-001.js lc2/JavaToJS/number-002.js lc2/Methods/method-001.js lc2/Methods/method-002.js lc2/Methods/method-003.js lc2/Methods/method-004-n.js lc2/Methods/method-005.js lc2/Methods/method-006-n.js lc2/Methods/println-001.js lc2/Objects/object-001.js lc2/Objects/object-002.js lc2/Objects/object-003.js lc2/Objects/object-004.js lc2/Objects/object-005.js lc2/Objects/object-006.js lc2/Packages/package-001.js lc2/Packages/package-002.js lc2/Packages/package-003.js lc2/Packages/package-005.js lc2/Packages/package-006.js lc2/Packages/package-007-n.js lc2/Packages/package-008-n.js lc2/misc/constructor.js lc3/ArrayMethods/byte-002.js lc3/ConvertBoolean/boolean-005-n.js lc3/ConvertBoolean/boolean-006-n.js lc3/ConvertBoolean/boolean-007-n.js lc3/ConvertBoolean/boolean-008-n.js lc3/ConvertBoolean/boolean-009-n.js lc3/ConvertBoolean/boolean-010-n.js lc3/ConvertBoolean/boolean-011-n.js lc3/ConvertBoolean/boolean-012-n.js lc3/ConvertBoolean/boolean-013-n.js lc3/ConvertNull/null-002.js lc3/ConvertNull/null-003-n.js lc3/ConvertNull/null-004-n.js lc3/ConvertNull/null-006-n.js lc3/ConvertString/string-004-n.js lc3/ConvertString/string-005-n.js lc3/ConvertString/string-007-n.js lc3/ConvertUndefined/undefined-001-n.js lc3/JSBoolean/boolean-002-n.js lc3/JSBoolean/boolean-003-n.js lc3/JSBoolean/boolean-004-n.js lc3/JSBoolean/boolean-005-n.js lc3/JSBoolean/boolean-006-n.js lc3/JSBoolean/boolean-007-n.js lc3/JSBoolean/boolean-008-n.js lc3/JSNull/ToBoolean-001-n.js lc3/JSNull/ToLong-001-n.js lc3/JSNull/ToNumber-001-n.js lc3/JSNumber/ToByte-002-n.js lc3/JSNumber/ToByte-003-n.js lc3/JSNumber/ToByte-005-n.js lc3/JSNumber/ToChar-002-n.js lc3/JSNumber/ToChar-003-n.js lc3/JSNumber/ToChar-005-n.js lc3/JSNumber/ToChar-006-n.js lc3/JSNumber/ToInt-002-n.js lc3/JSNumber/ToInt-003-n.js lc3/JSNumber/ToLong-002-n.js lc3/JSNumber/ToLong-003-n.js lc3/JSNumber/ToLong-004-n.js lc3/JSNumber/ToLong-005-n.js lc3/JSNumber/ToLong-006-n.js lc3/JSNumber/ToLong-007-n.js lc3/JSNumber/ToLong-008-n.js lc3/JSNumber/ToLong-009-n.js lc3/JSNumber/ToLong-010-n.js lc3/JSNumber/ToLong-011-n.js lc3/JSNumber/ToShort-003-n.js lc3/JSNumber/ToShort-005-n.js lc3/JSObject/ToDouble-002-n.js lc3/JSObject/ToDouble-003-n.js lc3/JSObject/ToFloat-002-n.js lc3/JSObject/ToFloat-003-n.js lc3/JSUndefined/undefined-002-n.js lc3/JSUndefined/undefined-003-n.js lc3/JSUndefined/undefined-004-n.js lc3/JSUndefined/undefined-005-n.js lc3/JSUndefined/undefined-006-n.js lc3/JSUndefined/undefined-008-n.js lc3/JSUndefined/undefined-009-n.js lc3/JSUndefined/undefined-010-n.js lc3/JavaArray/ToArray-002-n.js lc3/JavaArray/ToBoolean-001-n.js lc3/JavaObject/JavaObjectToBoolean-002-n.js lc3/JavaObject/JavaObjectToByte-002-n.js lc3/JavaObject/JavaObjectToByte-007-n.js lc3/JavaObject/JavaObjectToByte-008-n.js lc3/JavaObject/JavaObjectToChar-003-n.js lc3/JavaObject/JavaObjectToChar-005-n.js lc3/JavaObject/JavaObjectToChar-006-n.js lc3/JavaObject/JavaObjectToInt-002-n.js lc3/JavaObject/JavaObjectToInt-003-n.js lc3/JavaObject/JavaObjectToInt-004-n.js lc3/JavaObject/JavaObjectToLong-002-n.js lc3/JavaObject/JavaObjectToLong-003-n.js lc3/JavaObject/JavaObjectToLong-004-n.js lc3/JavaObject/JavaObjectToLong-006-n.js lc3/JavaObject/JavaObjectToShort-002-n.js lc3/JavaObject/JavaObjectToShort-003-n.js lc3/JavaObject/JavaObjectToShort-004-n.js lc3/StringMethods/string-001.js lc3/StringMethods/string-001.js rhino-1.7R4/testsrc/opt1.skip000066400000000000000000000015671176760007500161720ustar00rootroot00000000000000# Rhino skip list: opt1.skip. Tests to be run at -opt 1 # These tests are skipped by Rhino either because a bug with a regression # test has yet to be fixed, or because the test is not applicable to Rhino. # program too large/complex ecma_3/Statements/regress-302439.js ecma_3/Statements/regress-324650.js ecma_3/Statements/regress-74474-002.js ecma_3/Statements/regress-74474-003.js js1_5/Regress/regress-244470.js js1_5/Regress/regress-308085.js js1_5/Regress/regress-80981.js js1_5/Regress/regress-89443.js js1_5/extensions/regress-226507.js # program too large/complex; could have better error message js1_5/Regress/regress-111557.js js1_5/Regress/regress-155081-2.js js1_5/Regress/regress-155081.js js1_5/extensions/regress-311161.js # Missing line number information on error js1_5/Regress/regress-167328.js js1_5/extensions/regress-50447.js js1_5/Exceptions/regress-257751.js rhino-1.7R4/testsrc/opt9.tests000066400000000000000000001465431176760007500164020ustar00rootroot00000000000000e4x/Expressions/11.1.1.js e4x/Expressions/11.1.2.js e4x/Expressions/11.1.3.js e4x/Expressions/11.1.4-06.js e4x/Expressions/11.1.4-07.js e4x/Expressions/11.1.5.js e4x/Expressions/11.2.1.js e4x/Expressions/11.2.2.js e4x/Expressions/11.2.3.js e4x/Expressions/11.2.4.js e4x/Expressions/11.3.1.js e4x/Expressions/11.3.2.js e4x/Expressions/11.4.1.js e4x/Expressions/11.5.1.js e4x/Expressions/11.6.3.js e4x/Expressions/regress-301545.js e4x/Expressions/regress-302531.js e4x/Expressions/regress-340024.js e4x/GC/regress-292455.js e4x/GC/regress-313952-01.js e4x/GC/regress-324117.js e4x/Namespace/13.2.1.js e4x/Namespace/13.2.2.js e4x/Namespace/13.2.5.js e4x/Namespace/regress-283972.js e4x/Namespace/regress-292863.js e4x/Namespace/regress-350442.js e4x/QName/13.3.1.js e4x/QName/13.3.2.js e4x/QName/13.3.5.js e4x/QName/regress-373595-01.js e4x/QName/regress-373595-02.js e4x/QName/regress-373595-03.js e4x/Regress/regress-263935.js e4x/Regress/regress-263936.js e4x/Regress/regress-264369.js e4x/Regress/regress-271545.js e4x/Regress/regress-277650.js e4x/Regress/regress-277664.js e4x/Regress/regress-277683.js e4x/Regress/regress-277935.js e4x/Regress/regress-283349.js e4x/Regress/regress-290056.js e4x/Regress/regress-301573.js e4x/Regress/regress-301596.js e4x/Regress/regress-301692.js e4x/Regress/regress-313799.js e4x/Regress/regress-325425.js e4x/Regress/regress-327691-01.js e4x/Regress/regress-327691-02.js e4x/Regress/regress-327697.js e4x/Regress/regress-328249.js e4x/Regress/regress-329257.js e4x/Regress/regress-331664.js e4x/Regress/regress-350206-1.js e4x/Regress/regress-350206.js e4x/Regress/regress-352103.js e4x/Regress/regress-354145-01.js e4x/Regress/regress-354145-02.js e4x/Regress/regress-354145-03.js e4x/Regress/regress-354145-04.js e4x/Regress/regress-354145-05.js e4x/Regress/regress-354145-07.js e4x/Regress/regress-355474-02.js e4x/Regress/regress-356238-01.js e4x/Regress/regress-369032.js e4x/Regress/regress-369536.js e4x/Regress/regress-372564.js e4x/Regress/regress-374106.js e4x/Regress/regress-374112.js e4x/Regress/regress-374116.js e4x/Regress/regress-374160.js e4x/Regress/regress-378492.js e4x/Regress/regress-407323.js e4x/Statements/12.1.js e4x/Statements/12.2.js e4x/Statements/12.3-01.js e4x/TypeConversion/10.1.2.js e4x/TypeConversion/10.3.1.js e4x/TypeConversion/10.3.js e4x/TypeConversion/10.4.1.js e4x/TypeConversion/10.4.js e4x/Types/9.1.1.1.js e4x/Types/9.1.1.2.js e4x/Types/9.1.1.3.js e4x/Types/9.1.1.6.js e4x/Types/9.2.1.1.js e4x/Types/9.2.1.2.js e4x/Types/9.2.1.8.js e4x/XML/13.4.1.js e4x/XML/13.4.2.js e4x/XML/13.4.3.10.js e4x/XML/13.4.4.12-1.js e4x/XML/13.4.4.12.js e4x/XML/13.4.4.13.js e4x/XML/13.4.4.14.js e4x/XML/13.4.4.15.js e4x/XML/13.4.4.16.js e4x/XML/13.4.4.18.js e4x/XML/13.4.4.19.js e4x/XML/13.4.4.2.js e4x/XML/13.4.4.20.js e4x/XML/13.4.4.21.js e4x/XML/13.4.4.23.js e4x/XML/13.4.4.24.js e4x/XML/13.4.4.25.js e4x/XML/13.4.4.27.js e4x/XML/13.4.4.3.js e4x/XML/13.4.4.30.js e4x/XML/13.4.4.31.js e4x/XML/13.4.4.32-01.js e4x/XML/13.4.4.32.js e4x/XML/13.4.4.33.js e4x/XML/13.4.4.34.js e4x/XML/13.4.4.35.js e4x/XML/13.4.4.36.js e4x/XML/13.4.4.37.js e4x/XML/13.4.4.38.js e4x/XML/13.4.4.39.js e4x/XML/13.4.4.4.js e4x/XML/13.4.4.40.js e4x/XML/13.4.4.5.js e4x/XML/13.4.4.7.js e4x/XML/13.4.4.8.js e4x/XML/regress-291930.js e4x/XML/regress-324688.js e4x/XML/regress-336921.js e4x/XMLList/13.5.1.js e4x/XMLList/13.5.2.js e4x/XMLList/13.5.4.10.js e4x/XMLList/13.5.4.11.js e4x/XMLList/13.5.4.12.js e4x/XMLList/13.5.4.13.js e4x/XMLList/13.5.4.14.js e4x/XMLList/13.5.4.15.js e4x/XMLList/13.5.4.16.js e4x/XMLList/13.5.4.17.js e4x/XMLList/13.5.4.18.js e4x/XMLList/13.5.4.19.js e4x/XMLList/13.5.4.2.js e4x/XMLList/13.5.4.20.js e4x/XMLList/13.5.4.21.js e4x/XMLList/13.5.4.22.js e4x/XMLList/13.5.4.3.js e4x/XMLList/13.5.4.4.js e4x/XMLList/13.5.4.5.js e4x/XMLList/13.5.4.6.js e4x/XMLList/13.5.4.7.js e4x/XMLList/13.5.4.8.js e4x/XMLList/13.5.4.9.js e4x/decompilation/regress-349814.js e4x/decompilation/regress-349815.js e4x/decompilation/regress-349822.js e4x/decompilation/regress-349956.js e4x/decompilation/regress-355474-01.js e4x/decompilation/regress-373678.js e4x/extensions/regress-305335.js e4x/extensions/regress-321547.js e4x/extensions/regress-327534.js e4x/extensions/regress-327897.js e4x/extensions/regress-354145-06.js e4x/extensions/regress-354151-01.js ecma/Array/15.4-1.js ecma/Array/15.4-2.js ecma/Array/15.4.1.1.js ecma/Array/15.4.1.2.js ecma/Array/15.4.1.3.js ecma/Array/15.4.1.js ecma/Array/15.4.2.1-1.js ecma/Array/15.4.2.1-2.js ecma/Array/15.4.2.1-3.js ecma/Array/15.4.2.2-1.js ecma/Array/15.4.2.2-2.js ecma/Array/15.4.2.3.js ecma/Array/15.4.3.2.js ecma/Array/15.4.4.1.js ecma/Array/15.4.4.2.js ecma/Array/15.4.4.3-1.js ecma/Array/15.4.4.4-1.js ecma/Array/15.4.4.4-2.js ecma/Array/15.4.4.5-1.js ecma/Array/15.4.4.5-2.js ecma/Array/15.4.4.js ecma/Array/15.4.5.1-2.js ecma/Array/15.4.5.2-1.js ecma/Array/15.4.5.2-2.js ecma/Boolean/15.6.2.js ecma/Boolean/15.6.3.1-1.js ecma/Boolean/15.6.3.1-2.js ecma/Boolean/15.6.3.1.js ecma/Boolean/15.6.4-1.js ecma/Boolean/15.6.4.1.js ecma/Boolean/15.6.4.2-2.js ecma/Boolean/15.6.4.2-3.js ecma/Boolean/15.6.4.2-4-n.js ecma/Boolean/15.6.4.3-1.js ecma/Boolean/15.6.4.3-2.js ecma/Boolean/15.6.4.3-3.js ecma/Boolean/15.6.4.3-4-n.js ecma/Boolean/15.6.4.3.js ecma/Boolean/15.6.4.js ecma/Date/15.9.1.1-1.js ecma/Date/15.9.1.1-2.js ecma/Date/15.9.1.13-1.js ecma/Date/15.9.2.1.js ecma/Date/15.9.2.2-1.js ecma/Date/15.9.2.2-2.js ecma/Date/15.9.2.2-3.js ecma/Date/15.9.2.2-5.js ecma/Date/15.9.2.2-6.js ecma/Date/15.9.3.1-2.js ecma/Date/15.9.3.1-3.js ecma/Date/15.9.3.1-4.js ecma/Date/15.9.3.1-5.js ecma/Date/15.9.3.2-2.js ecma/Date/15.9.3.2-3.js ecma/Date/15.9.3.2-4.js ecma/Date/15.9.3.2-5.js ecma/Date/15.9.3.8-1.js ecma/Date/15.9.3.8-2.js ecma/Date/15.9.3.8-3.js ecma/Date/15.9.3.8-4.js ecma/Date/15.9.3.8-5.js ecma/Date/15.9.4.2.js ecma/Date/15.9.4.3.js ecma/Date/15.9.5.1.js ecma/Date/15.9.5.10-1.js ecma/Date/15.9.5.10-10.js ecma/Date/15.9.5.10-11.js ecma/Date/15.9.5.10-12.js ecma/Date/15.9.5.10-13.js ecma/Date/15.9.5.10-4.js ecma/Date/15.9.5.10-5.js ecma/Date/15.9.5.10-6.js ecma/Date/15.9.5.10-7.js ecma/Date/15.9.5.10-8.js ecma/Date/15.9.5.10-9.js ecma/Date/15.9.5.11-1.js ecma/Date/15.9.5.11-3.js ecma/Date/15.9.5.11-4.js ecma/Date/15.9.5.11-5.js ecma/Date/15.9.5.11-6.js ecma/Date/15.9.5.11-7.js ecma/Date/15.9.5.12-1.js ecma/Date/15.9.5.12-3.js ecma/Date/15.9.5.12-4.js ecma/Date/15.9.5.12-5.js ecma/Date/15.9.5.12-6.js ecma/Date/15.9.5.12-7.js ecma/Date/15.9.5.12-8.js ecma/Date/15.9.5.13-1.js ecma/Date/15.9.5.13-2.js ecma/Date/15.9.5.13-3.js ecma/Date/15.9.5.13-4.js ecma/Date/15.9.5.13-5.js ecma/Date/15.9.5.13-6.js ecma/Date/15.9.5.13-7.js ecma/Date/15.9.5.13-8.js ecma/Date/15.9.5.14.js ecma/Date/15.9.5.15.js ecma/Date/15.9.5.16.js ecma/Date/15.9.5.17.js ecma/Date/15.9.5.19.js ecma/Date/15.9.5.2-2-n.js ecma/Date/15.9.5.2.js ecma/Date/15.9.5.20.js ecma/Date/15.9.5.21-1.js ecma/Date/15.9.5.21-2.js ecma/Date/15.9.5.21-3.js ecma/Date/15.9.5.21-4.js ecma/Date/15.9.5.21-5.js ecma/Date/15.9.5.21-6.js ecma/Date/15.9.5.21-7.js ecma/Date/15.9.5.21-8.js ecma/Date/15.9.5.22-2.js ecma/Date/15.9.5.22-3.js ecma/Date/15.9.5.22-4.js ecma/Date/15.9.5.22-5.js ecma/Date/15.9.5.22-6.js ecma/Date/15.9.5.22-7.js ecma/Date/15.9.5.22-8.js ecma/Date/15.9.5.23-1.js ecma/Date/15.9.5.23-10.js ecma/Date/15.9.5.23-11.js ecma/Date/15.9.5.23-12.js ecma/Date/15.9.5.23-13.js ecma/Date/15.9.5.23-14.js ecma/Date/15.9.5.23-15.js ecma/Date/15.9.5.23-16.js ecma/Date/15.9.5.23-17.js ecma/Date/15.9.5.23-18.js ecma/Date/15.9.5.23-2.js ecma/Date/15.9.5.23-3-n.js ecma/Date/15.9.5.23-4.js ecma/Date/15.9.5.23-5.js ecma/Date/15.9.5.23-6.js ecma/Date/15.9.5.23-7.js ecma/Date/15.9.5.23-8.js ecma/Date/15.9.5.23-9.js ecma/Date/15.9.5.24-1.js ecma/Date/15.9.5.24-2.js ecma/Date/15.9.5.24-3.js ecma/Date/15.9.5.24-4.js ecma/Date/15.9.5.24-5.js ecma/Date/15.9.5.24-6.js ecma/Date/15.9.5.24-7.js ecma/Date/15.9.5.24-8.js ecma/Date/15.9.5.25-1.js ecma/Date/15.9.5.26-1.js ecma/Date/15.9.5.27-1.js ecma/Date/15.9.5.28-1.js ecma/Date/15.9.5.29-1.js ecma/Date/15.9.5.3-2.js ecma/Date/15.9.5.30-1.js ecma/Date/15.9.5.31-1.js ecma/Date/15.9.5.32-1.js ecma/Date/15.9.5.33-1.js ecma/Date/15.9.5.34-1.js ecma/Date/15.9.5.35-1.js ecma/Date/15.9.5.36-1.js ecma/Date/15.9.5.36-2.js ecma/Date/15.9.5.36-4.js ecma/Date/15.9.5.36-5.js ecma/Date/15.9.5.36-6.js ecma/Date/15.9.5.36-7.js ecma/Date/15.9.5.37-2.js ecma/Date/15.9.5.37-3.js ecma/Date/15.9.5.37-4.js ecma/Date/15.9.5.37-5.js ecma/Date/15.9.5.4-1.js ecma/Date/15.9.5.4-2-n.js ecma/Date/15.9.5.6.js ecma/Date/15.9.5.7.js ecma/Date/15.9.5.8.js ecma/Date/15.9.5.9.js ecma/Date/15.9.5.js ecma/ExecutionContexts/10.1.3-1.js ecma/ExecutionContexts/10.1.3-2.js ecma/ExecutionContexts/10.1.3.js ecma/ExecutionContexts/10.1.4-1.js ecma/ExecutionContexts/10.1.4-10.js ecma/ExecutionContexts/10.1.4-3.js ecma/ExecutionContexts/10.1.4-4.js ecma/ExecutionContexts/10.1.4-5.js ecma/ExecutionContexts/10.1.4-6.js ecma/ExecutionContexts/10.1.4-7.js ecma/ExecutionContexts/10.1.4-8.js ecma/ExecutionContexts/10.1.5-1.js ecma/ExecutionContexts/10.1.5-2.js ecma/ExecutionContexts/10.1.5-3.js ecma/ExecutionContexts/10.1.5-4.js ecma/ExecutionContexts/10.1.8-2.js ecma/ExecutionContexts/10.1.8-3.js ecma/ExecutionContexts/10.2.1.js ecma/ExecutionContexts/10.2.2-1.js ecma/ExecutionContexts/10.2.2-2.js ecma/ExecutionContexts/10.2.3-1.js ecma/ExecutionContexts/10.2.3-2.js ecma/Expressions/11.1.1.js ecma/Expressions/11.10-1.js ecma/Expressions/11.10-2.js ecma/Expressions/11.10-3.js ecma/Expressions/11.12-1.js ecma/Expressions/11.12-2-n.js ecma/Expressions/11.12-3.js ecma/Expressions/11.12-4.js ecma/Expressions/11.13.1.js ecma/Expressions/11.13.2-1.js ecma/Expressions/11.13.2-2.js ecma/Expressions/11.13.2-3.js ecma/Expressions/11.13.2-4.js ecma/Expressions/11.13.2-5.js ecma/Expressions/11.14-1.js ecma/Expressions/11.2.1-1.js ecma/Expressions/11.2.1-2.js ecma/Expressions/11.2.1-3-n.js ecma/Expressions/11.2.1-4-n.js ecma/Expressions/11.2.1-5.js ecma/Expressions/11.2.2-1-n.js ecma/Expressions/11.2.2-1.js ecma/Expressions/11.2.2-10-n.js ecma/Expressions/11.2.2-11.js ecma/Expressions/11.2.2-2-n.js ecma/Expressions/11.2.2-3-n.js ecma/Expressions/11.2.2-4-n.js ecma/Expressions/11.2.2-5-n.js ecma/Expressions/11.2.2-6-n.js ecma/Expressions/11.2.2-7-n.js ecma/Expressions/11.2.2-8-n.js ecma/Expressions/11.2.2-9-n.js ecma/Expressions/11.2.3-1.js ecma/Expressions/11.2.3-2-n.js ecma/Expressions/11.2.3-3-n.js ecma/Expressions/11.2.3-4-n.js ecma/Expressions/11.2.3-5.js ecma/Expressions/11.3.1.js ecma/Expressions/11.3.2.js ecma/Expressions/11.4.2.js ecma/Expressions/11.4.3.js ecma/Expressions/11.4.4.js ecma/Expressions/11.4.5.js ecma/Expressions/11.4.6.js ecma/Expressions/11.4.8.js ecma/Expressions/11.4.9.js ecma/Expressions/11.5.1.js ecma/Expressions/11.5.2.js ecma/Expressions/11.5.3.js ecma/Expressions/11.6.1-1.js ecma/Expressions/11.6.1-2.js ecma/Expressions/11.6.1-3.js ecma/Expressions/11.6.2-1.js ecma/Expressions/11.6.3.js ecma/Expressions/11.7.1.js ecma/Expressions/11.7.2.js ecma/Expressions/11.8.1.js ecma/Expressions/11.8.2.js ecma/Expressions/11.8.3.js ecma/Expressions/11.9.2.js ecma/Expressions/11.9.3.js ecma/FunctionObjects/15.3.1.1-1.js ecma/FunctionObjects/15.3.1.1-2.js ecma/FunctionObjects/15.3.1.1-3.js ecma/FunctionObjects/15.3.2.1-1.js ecma/FunctionObjects/15.3.2.1-2.js ecma/FunctionObjects/15.3.2.1-3.js ecma/FunctionObjects/15.3.3.1-2.js ecma/FunctionObjects/15.3.3.1-3.js ecma/FunctionObjects/15.3.3.1-4.js ecma/FunctionObjects/15.3.3.2.js ecma/FunctionObjects/15.3.4-1.js ecma/FunctionObjects/15.3.4.1.js ecma/FunctionObjects/15.3.4.js ecma/FunctionObjects/15.3.5-1.js ecma/FunctionObjects/15.3.5-2.js ecma/FunctionObjects/15.3.5.1.js ecma/FunctionObjects/15.3.5.3.js ecma/GlobalObject/15.1-1-n.js ecma/GlobalObject/15.1-2-n.js ecma/GlobalObject/15.1.1.1.js ecma/GlobalObject/15.1.1.2.js ecma/GlobalObject/15.1.2.1-2.js ecma/GlobalObject/15.1.2.2-2.js ecma/GlobalObject/15.1.2.3-2.js ecma/GlobalObject/15.1.2.5-2.js ecma/GlobalObject/15.1.2.5-3.js ecma/LexicalConventions/7.1-1.js ecma/LexicalConventions/7.1-2.js ecma/LexicalConventions/7.1-3.js ecma/LexicalConventions/7.2-1.js ecma/LexicalConventions/7.2-2-n.js ecma/LexicalConventions/7.2-3-n.js ecma/LexicalConventions/7.2-4-n.js ecma/LexicalConventions/7.2-5-n.js ecma/LexicalConventions/7.2-6.js ecma/LexicalConventions/7.3-1.js ecma/LexicalConventions/7.3-10.js ecma/LexicalConventions/7.3-11.js ecma/LexicalConventions/7.3-12.js ecma/LexicalConventions/7.3-13-n.js ecma/LexicalConventions/7.3-2.js ecma/LexicalConventions/7.3-3.js ecma/LexicalConventions/7.3-4.js ecma/LexicalConventions/7.3-5.js ecma/LexicalConventions/7.3-6.js ecma/LexicalConventions/7.3-8.js ecma/LexicalConventions/7.3-9.js ecma/LexicalConventions/7.4.1-1-n.js ecma/LexicalConventions/7.4.1-2-n.js ecma/LexicalConventions/7.4.1-3-n.js ecma/LexicalConventions/7.4.2-1-n.js ecma/LexicalConventions/7.4.2-10-n.js ecma/LexicalConventions/7.4.2-11-n.js ecma/LexicalConventions/7.4.2-12-n.js ecma/LexicalConventions/7.4.2-13-n.js ecma/LexicalConventions/7.4.2-14-n.js ecma/LexicalConventions/7.4.2-15-n.js ecma/LexicalConventions/7.4.2-16-n.js ecma/LexicalConventions/7.4.2-2-n.js ecma/LexicalConventions/7.4.2-3-n.js ecma/LexicalConventions/7.4.2-4-n.js ecma/LexicalConventions/7.4.2-5-n.js ecma/LexicalConventions/7.4.2-6-n.js ecma/LexicalConventions/7.4.2-7-n.js ecma/LexicalConventions/7.4.2-8-n.js ecma/LexicalConventions/7.4.3-1-n.js ecma/LexicalConventions/7.4.3-10-n.js ecma/LexicalConventions/7.4.3-11-n.js ecma/LexicalConventions/7.4.3-13-n.js ecma/LexicalConventions/7.4.3-15-n.js ecma/LexicalConventions/7.4.3-16-n.js ecma/LexicalConventions/7.4.3-2-n.js ecma/LexicalConventions/7.4.3-3-n.js ecma/LexicalConventions/7.4.3-4-n.js ecma/LexicalConventions/7.4.3-5-n.js ecma/LexicalConventions/7.4.3-6-n.js ecma/LexicalConventions/7.4.3-7-n.js ecma/LexicalConventions/7.4.3-8-n.js ecma/LexicalConventions/7.4.3-9-n.js ecma/LexicalConventions/7.5-1.js ecma/LexicalConventions/7.5-10-n.js ecma/LexicalConventions/7.5-2-n.js ecma/LexicalConventions/7.5-3-n.js ecma/LexicalConventions/7.5-4-n.js ecma/LexicalConventions/7.5-5-n.js ecma/LexicalConventions/7.5-6.js ecma/LexicalConventions/7.5-7.js ecma/LexicalConventions/7.5-8-n.js ecma/LexicalConventions/7.5-9-n.js ecma/LexicalConventions/7.6.js ecma/LexicalConventions/7.7.1.js ecma/LexicalConventions/7.7.2.js ecma/LexicalConventions/7.7.3-1.js ecma/LexicalConventions/7.7.3-2.js ecma/LexicalConventions/7.7.3.js ecma/LexicalConventions/7.7.4.js ecma/LexicalConventions/7.8.2-n.js ecma/Math/15.8-2-n.js ecma/Math/15.8-3-n.js ecma/Math/15.8.1.1-1.js ecma/Math/15.8.1.1-2.js ecma/Math/15.8.1.2-1.js ecma/Math/15.8.1.3-1.js ecma/Math/15.8.1.3-2.js ecma/Math/15.8.1.4-1.js ecma/Math/15.8.1.4-2.js ecma/Math/15.8.1.5-1.js ecma/Math/15.8.1.5-2.js ecma/Math/15.8.1.6-1.js ecma/Math/15.8.1.6-2.js ecma/Math/15.8.1.7-1.js ecma/Math/15.8.1.7-2.js ecma/Math/15.8.1.8-1.js ecma/Math/15.8.1.8-2.js ecma/Math/15.8.1.8-3.js ecma/Math/15.8.2.1.js ecma/Math/15.8.2.10.js ecma/Math/15.8.2.12.js ecma/Math/15.8.2.13.js ecma/Math/15.8.2.14.js ecma/Math/15.8.2.15.js ecma/Math/15.8.2.16.js ecma/Math/15.8.2.17.js ecma/Math/15.8.2.18.js ecma/Math/15.8.2.2.js ecma/Math/15.8.2.3.js ecma/Math/15.8.2.4.js ecma/Math/15.8.2.5.js ecma/Math/15.8.2.6.js ecma/Math/15.8.2.7.js ecma/Math/15.8.2.8.js ecma/Math/15.8.2.9.js ecma/Number/15.7.2.js ecma/Number/15.7.3.1-1.js ecma/Number/15.7.3.1-2.js ecma/Number/15.7.3.1-3.js ecma/Number/15.7.3.2-1.js ecma/Number/15.7.3.2-2.js ecma/Number/15.7.3.2-3.js ecma/Number/15.7.3.3-1.js ecma/Number/15.7.3.3-2.js ecma/Number/15.7.3.3-3.js ecma/Number/15.7.3.4-1.js ecma/Number/15.7.3.4-2.js ecma/Number/15.7.3.4-3.js ecma/Number/15.7.3.4-4.js ecma/Number/15.7.3.5-1.js ecma/Number/15.7.3.5-2.js ecma/Number/15.7.3.5-3.js ecma/Number/15.7.3.5-4.js ecma/Number/15.7.3.6-1.js ecma/Number/15.7.3.6-4.js ecma/Number/15.7.3.js ecma/Number/15.7.4-1.js ecma/Number/15.7.4.1.js ecma/Number/15.7.4.2-1.js ecma/Number/15.7.4.2-2-n.js ecma/Number/15.7.4.2-3-n.js ecma/Number/15.7.4.2-4.js ecma/Number/15.7.4.3-1.js ecma/Number/15.7.4.3-2.js ecma/ObjectObjects/15.2.1.2.js ecma/ObjectObjects/15.2.2.1.js ecma/ObjectObjects/15.2.2.2.js ecma/ObjectObjects/15.2.3.1-1.js ecma/ObjectObjects/15.2.3.1-2.js ecma/ObjectObjects/15.2.3.1-3.js ecma/ObjectObjects/15.2.3.1-4.js ecma/ObjectObjects/15.2.3.js ecma/ObjectObjects/15.2.4.1.js ecma/ObjectObjects/15.2.4.2.js ecma/ObjectObjects/15.2.4.3.js ecma/SourceText/6-1.js ecma/SourceText/6-2.js ecma/Statements/12.10-1.js ecma/Statements/12.10.js ecma/Statements/12.5-1.js ecma/Statements/12.5-2.js ecma/Statements/12.6.2-1.js ecma/Statements/12.6.2-2.js ecma/Statements/12.6.2-4.js ecma/Statements/12.6.2-5.js ecma/Statements/12.6.2-6.js ecma/Statements/12.6.2-7.js ecma/Statements/12.6.2-8.js ecma/Statements/12.6.2-9-n.js ecma/Statements/12.6.3-1.js ecma/Statements/12.6.3-10.js ecma/Statements/12.6.3-11.js ecma/Statements/12.6.3-12.js ecma/Statements/12.6.3-19.js ecma/Statements/12.6.3-2.js ecma/Statements/12.6.3-3.js ecma/Statements/12.6.3-4.js ecma/Statements/12.6.3-5-n.js ecma/Statements/12.6.3-6-n.js ecma/Statements/12.6.3-7-n.js ecma/Statements/12.6.3-9-n.js ecma/Statements/12.7-1-n.js ecma/Statements/12.8-1-n.js ecma/Statements/12.9-1-n.js ecma/String/15.5.1.js ecma/String/15.5.2.js ecma/String/15.5.3.1-1.js ecma/String/15.5.3.1-2.js ecma/String/15.5.3.1-3.js ecma/String/15.5.3.1-4.js ecma/String/15.5.3.2-1.js ecma/String/15.5.3.2-2.js ecma/String/15.5.3.2-3.js ecma/String/15.5.3.js ecma/String/15.5.4.1.js ecma/String/15.5.4.10-1.js ecma/String/15.5.4.11-1.js ecma/String/15.5.4.11-3.js ecma/String/15.5.4.11-4.js ecma/String/15.5.4.11-6.js ecma/String/15.5.4.12-2.js ecma/String/15.5.4.12-3.js ecma/String/15.5.4.2-1.js ecma/String/15.5.4.2-2-n.js ecma/String/15.5.4.2-3.js ecma/String/15.5.4.2.js ecma/String/15.5.4.3-1.js ecma/String/15.5.4.3-2.js ecma/String/15.5.4.3-3-n.js ecma/String/15.5.4.4-1.js ecma/String/15.5.4.4-2.js ecma/String/15.5.4.4-3.js ecma/String/15.5.4.4-4.js ecma/String/15.5.4.5-1.js ecma/String/15.5.4.5-2.js ecma/String/15.5.4.5-3.js ecma/String/15.5.4.5-4.js ecma/String/15.5.4.5-5.js ecma/String/15.5.4.6-1.js ecma/String/15.5.4.7-2.js ecma/String/15.5.4.8-1.js ecma/String/15.5.4.8-3.js ecma/String/15.5.4.9-1.js ecma/String/15.5.4.js ecma/String/15.5.5.1.js ecma/TypeConversion/9.2.js ecma/TypeConversion/9.3-1.js ecma/TypeConversion/9.3.1-1.js ecma/TypeConversion/9.3.1-2.js ecma/TypeConversion/9.3.1-3.js ecma/TypeConversion/9.3.js ecma/TypeConversion/9.4-1.js ecma/TypeConversion/9.4-2.js ecma/TypeConversion/9.5-2.js ecma/TypeConversion/9.6.js ecma/TypeConversion/9.7.js ecma/TypeConversion/9.8.1.js ecma/TypeConversion/9.9-1.js ecma/Types/8.1.js ecma/Types/8.4.js ecma/Types/8.6.2.1-1.js ecma/extensions/10.1.4-9.js ecma/extensions/10.1.6.js ecma/extensions/10.1.8-1.js ecma/extensions/11.6.1-1.js ecma/extensions/11.6.1-2.js ecma/extensions/11.6.1-3.js ecma/extensions/11.6.2-1.js ecma/extensions/15-2.js ecma/extensions/15.2.1.1.js ecma/extensions/15.2.3-1.js ecma/extensions/15.2.4.js ecma/extensions/15.3.1.1-2.js ecma/extensions/15.3.2.1-1.js ecma/extensions/15.3.2.1-2.js ecma/extensions/15.4.3.js ecma/extensions/15.5.3.js ecma/extensions/15.5.4.2.js ecma/extensions/15.5.4.4-4.js ecma/extensions/15.5.4.5-6.js ecma/extensions/15.5.4.7-3.js ecma/extensions/15.6.3.1-5.js ecma/extensions/15.6.3.js ecma/extensions/15.6.4-2.js ecma/extensions/15.7.3.js ecma/extensions/15.7.4.js ecma/extensions/15.8-1.js ecma/extensions/15.9.5.js ecma/extensions/8.6.2.1-1.js ecma/extensions/9.9-1.js ecma/jsref.js ecma_2/Exceptions/boolean-001.js ecma_2/Exceptions/date-001.js ecma_2/Exceptions/date-002.js ecma_2/Exceptions/date-004.js ecma_2/Exceptions/exception-001.js ecma_2/Exceptions/exception-002.js ecma_2/Exceptions/exception-004.js ecma_2/Exceptions/exception-005.js ecma_2/Exceptions/exception-006.js ecma_2/Exceptions/exception-007.js ecma_2/Exceptions/exception-008.js ecma_2/Exceptions/exception-009.js ecma_2/Exceptions/exception-010-n.js ecma_2/Exceptions/exception-011-n.js ecma_2/Exceptions/expression-002.js ecma_2/Exceptions/expression-004.js ecma_2/Exceptions/expression-005.js ecma_2/Exceptions/expression-006.js ecma_2/Exceptions/expression-007.js ecma_2/Exceptions/expression-008.js ecma_2/Exceptions/expression-009.js ecma_2/Exceptions/expression-010.js ecma_2/Exceptions/expression-011.js ecma_2/Exceptions/expression-012.js ecma_2/Exceptions/expression-013.js ecma_2/Exceptions/expression-014.js ecma_2/Exceptions/expression-015.js ecma_2/Exceptions/expression-016.js ecma_2/Exceptions/expression-017.js ecma_2/Exceptions/global-001.js ecma_2/Exceptions/global-002.js ecma_2/Exceptions/lexical-001.js ecma_2/Exceptions/lexical-002.js ecma_2/Exceptions/lexical-003.js ecma_2/Exceptions/lexical-004.js ecma_2/Exceptions/lexical-005.js ecma_2/Exceptions/lexical-006.js ecma_2/Exceptions/lexical-007.js ecma_2/Exceptions/lexical-009.js ecma_2/Exceptions/lexical-010.js ecma_2/Exceptions/lexical-011.js ecma_2/Exceptions/lexical-012.js ecma_2/Exceptions/lexical-013.js ecma_2/Exceptions/lexical-014.js ecma_2/Exceptions/lexical-015.js ecma_2/Exceptions/lexical-016.js ecma_2/Exceptions/lexical-017.js ecma_2/Exceptions/lexical-018.js ecma_2/Exceptions/lexical-019.js ecma_2/Exceptions/lexical-020.js ecma_2/Exceptions/lexical-022.js ecma_2/Exceptions/lexical-023.js ecma_2/Exceptions/lexical-024.js ecma_2/Exceptions/lexical-025.js ecma_2/Exceptions/lexical-026.js ecma_2/Exceptions/lexical-027.js ecma_2/Exceptions/lexical-028.js ecma_2/Exceptions/lexical-029.js ecma_2/Exceptions/lexical-030.js ecma_2/Exceptions/lexical-031.js ecma_2/Exceptions/lexical-032.js ecma_2/Exceptions/lexical-033.js ecma_2/Exceptions/lexical-034.js ecma_2/Exceptions/lexical-035.js ecma_2/Exceptions/lexical-036.js ecma_2/Exceptions/lexical-037.js ecma_2/Exceptions/lexical-038.js ecma_2/Exceptions/lexical-039.js ecma_2/Exceptions/lexical-040.js ecma_2/Exceptions/lexical-041.js ecma_2/Exceptions/lexical-042.js ecma_2/Exceptions/lexical-047.js ecma_2/Exceptions/lexical-048.js ecma_2/Exceptions/lexical-049.js ecma_2/Exceptions/lexical-050.js ecma_2/Exceptions/lexical-051.js ecma_2/Exceptions/lexical-053.js ecma_2/Exceptions/lexical-054.js ecma_2/Exceptions/number-002.js ecma_2/Exceptions/number-003.js ecma_2/Exceptions/statement-001.js ecma_2/Exceptions/statement-002.js ecma_2/Exceptions/statement-003.js ecma_2/Exceptions/statement-004.js ecma_2/Exceptions/statement-005.js ecma_2/Exceptions/statement-006.js ecma_2/Exceptions/statement-007.js ecma_2/Exceptions/statement-008.js ecma_2/Exceptions/string-001.js ecma_2/Exceptions/string-002.js ecma_2/Expressions/StrictEquality-001.js ecma_2/FunctionObjects/apply-001-n.js ecma_2/FunctionObjects/call-1.js ecma_2/LexicalConventions/keywords-001.js ecma_2/LexicalConventions/regexp-literals-001.js ecma_2/LexicalConventions/regexp-literals-002.js ecma_2/RegExp/constructor-001.js ecma_2/RegExp/exec-002.js ecma_2/RegExp/function-001.js ecma_2/RegExp/hex-001.js ecma_2/RegExp/multiline-001.js ecma_2/RegExp/octal-001.js ecma_2/RegExp/octal-002.js ecma_2/RegExp/octal-003.js ecma_2/RegExp/properties-001.js ecma_2/RegExp/properties-002.js ecma_2/RegExp/regress-001.js ecma_2/RegExp/unicode-001.js ecma_2/Statements/dowhile-001.js ecma_2/Statements/dowhile-002.js ecma_2/Statements/dowhile-003.js ecma_2/Statements/dowhile-004.js ecma_2/Statements/dowhile-005.js ecma_2/Statements/dowhile-006.js ecma_2/Statements/dowhile-007.js ecma_2/Statements/forin-001.js ecma_2/Statements/forin-002.js ecma_2/Statements/if-001.js ecma_2/Statements/label-001.js ecma_2/Statements/label-002.js ecma_2/Statements/switch-002.js ecma_2/Statements/switch-003.js ecma_2/Statements/switch-004.js ecma_2/Statements/try-001.js ecma_2/Statements/try-003.js ecma_2/Statements/try-004.js ecma_2/Statements/try-005.js ecma_2/Statements/try-007.js ecma_2/Statements/try-008.js ecma_2/Statements/try-009.js ecma_2/Statements/try-012.js ecma_2/Statements/while-001.js ecma_2/Statements/while-002.js ecma_2/Statements/while-003.js ecma_2/Statements/while-004.js ecma_2/String/match-001.js ecma_2/String/match-002.js ecma_2/String/match-003.js ecma_2/String/match-004.js ecma_2/String/split-001.js ecma_2/String/split-002.js ecma_2/String/split-003.js ecma_2/extensions/constructor-001.js ecma_2/extensions/function-001.js ecma_2/extensions/instanceof-001.js ecma_2/extensions/instanceof-002.js ecma_2/extensions/instanceof-006.js ecma_2/instanceof/instanceof-001.js ecma_2/instanceof/instanceof-002.js ecma_2/instanceof/regress-7635.js ecma_2/jsref.js ecma_3/Array/15.4.4.11-01.js ecma_3/Array/15.4.4.3-1.js ecma_3/Array/15.4.4.4-001.js ecma_3/Array/regress-101488.js ecma_3/Array/regress-130451.js ecma_3/Array/regress-322135-01.js ecma_3/Date/15.9.4.3.js ecma_3/Date/15.9.5.3.js ecma_3/Date/15.9.5.4.js ecma_3/Date/15.9.5.5.js ecma_3/Date/15.9.5.6.js ecma_3/Date/15.9.5.7.js ecma_3/Exceptions/15.11.1.1.js ecma_3/Exceptions/15.11.4.4-1.js ecma_3/Exceptions/15.11.7.6-001.js ecma_3/Exceptions/15.11.7.6-002.js ecma_3/Exceptions/15.11.7.6-003.js ecma_3/Exceptions/binding-001.js ecma_3/Exceptions/regress-95101.js ecma_3/ExecutionContexts/10.1.3-1.js ecma_3/ExecutionContexts/10.1.3-2.js ecma_3/ExecutionContexts/10.1.3.js ecma_3/ExecutionContexts/10.1.4-1.js ecma_3/ExecutionContexts/10.6.1-01.js ecma_3/ExecutionContexts/regress-23346.js ecma_3/Expressions/11.10-01.js ecma_3/Expressions/11.10-03.js ecma_3/Expressions/11.6.1-1.js ecma_3/Expressions/11.7.1-01.js ecma_3/Expressions/11.7.2-01.js ecma_3/Expressions/11.7.3-01.js ecma_3/Expressions/11.9.6-1.js ecma_3/FunExpr/fe-001-n.js ecma_3/FunExpr/fe-001.js ecma_3/FunExpr/fe-002.js ecma_3/Function/15.3.4.3-1.js ecma_3/Function/15.3.4.4-1.js ecma_3/Function/arguments-002.js ecma_3/Function/call-001.js ecma_3/Function/regress-131964.js ecma_3/Function/regress-137181.js ecma_3/Function/regress-193555.js ecma_3/Function/regress-313570.js ecma_3/Function/regress-49286.js ecma_3/Function/regress-58274.js ecma_3/Function/regress-85880.js ecma_3/Function/regress-94506.js ecma_3/Function/regress-97921.js ecma_3/Function/scope-001.js ecma_3/Function/scope-002.js ecma_3/Number/15.7.4.5-1.js ecma_3/Number/15.7.4.6-1.js ecma_3/Number/15.7.4.7-1.js ecma_3/Number/15.7.4.7-2.js ecma_3/NumberFormatting/tostring-001.js ecma_3/Object/8.6.2.6-001.js ecma_3/Object/class-001.js ecma_3/Object/class-002.js ecma_3/Object/class-003.js ecma_3/Object/class-004.js ecma_3/Object/class-005.js ecma_3/Object/regress-361274.js ecma_3/Object/regress-385393-07.js ecma_3/Object/regress-72773.js ecma_3/Object/regress-79129-001.js ecma_3/Operators/11.13.1-001.js ecma_3/Operators/11.13.1-002.js ecma_3/Operators/11.4.1-001.js ecma_3/RegExp/15.10.2-1.js ecma_3/RegExp/15.10.2.12.js ecma_3/RegExp/15.10.3.1-1.js ecma_3/RegExp/15.10.3.1-2.js ecma_3/RegExp/15.10.4.1-1.js ecma_3/RegExp/15.10.4.1-2.js ecma_3/RegExp/15.10.4.1-3.js ecma_3/RegExp/15.10.4.1-4.js ecma_3/RegExp/15.10.4.1-5-n.js ecma_3/RegExp/15.10.6.2-1.js ecma_3/RegExp/15.10.6.2-2.js ecma_3/RegExp/octal-001.js ecma_3/RegExp/octal-002.js ecma_3/RegExp/perlstress-001.js ecma_3/RegExp/perlstress-002.js ecma_3/RegExp/regress-100199.js ecma_3/RegExp/regress-105972.js ecma_3/RegExp/regress-122076.js ecma_3/RegExp/regress-123437.js ecma_3/RegExp/regress-165353.js ecma_3/RegExp/regress-169497.js ecma_3/RegExp/regress-169534.js ecma_3/RegExp/regress-187133.js ecma_3/RegExp/regress-191479.js ecma_3/RegExp/regress-202564.js ecma_3/RegExp/regress-209067.js ecma_3/RegExp/regress-209919.js ecma_3/RegExp/regress-216591.js ecma_3/RegExp/regress-220367-001.js ecma_3/RegExp/regress-223273.js ecma_3/RegExp/regress-223535.js ecma_3/RegExp/regress-224676.js ecma_3/RegExp/regress-225289.js ecma_3/RegExp/regress-225343.js ecma_3/RegExp/regress-24712.js ecma_3/RegExp/regress-28686.js ecma_3/RegExp/regress-309840.js ecma_3/RegExp/regress-312351.js ecma_3/RegExp/regress-31316.js ecma_3/RegExp/regress-334158.js ecma_3/RegExp/regress-346090.js ecma_3/RegExp/regress-367888.js: ecma_3/RegExp/regress-375642.js: ecma_3/RegExp/regress-375715-02.js ecma_3/RegExp/regress-375715-03.js ecma_3/RegExp/regress-57572.js ecma_3/RegExp/regress-57631.js ecma_3/RegExp/regress-67773.js ecma_3/RegExp/regress-76683.js ecma_3/RegExp/regress-78156.js ecma_3/RegExp/regress-85721.js ecma_3/RegExp/regress-87231.js ecma_3/RegExp/regress-98306.js ecma_3/Statements/12.6.3.js ecma_3/Statements/regress-131348.js ecma_3/Statements/regress-157509.js ecma_3/Statements/regress-194364.js ecma_3/Statements/regress-226517.js ecma_3/Statements/regress-74474-001.js ecma_3/Statements/regress-83532-001.js ecma_3/Statements/regress-83532-002.js ecma_3/Statements/switch-001.js ecma_3/String/regress-104375.js ecma_3/String/regress-189898.js ecma_3/String/regress-313567.js ecma_3/String/regress-83293.js ecma_3/Unicode/uc-001-n.js ecma_3/Unicode/uc-002-n.js ecma_3/Unicode/uc-002.js ecma_3/Unicode/uc-003.js ecma_3/Unicode/uc-004.js ecma_3/Unicode/uc-005.js ecma_3/extensions/regress-103087.js ecma_3/extensions/regress-188206-01.js ecma_3/extensions/regress-188206-02.js ecma_3/extensions/regress-220367-002.js ecma_3/extensions/regress-228087.js ecma_3/extensions/regress-320854.js ecma_3/extensions/regress-327170.js ecma_3/extensions/regress-385393-03.js js-test-driver-begin.js js-test-driver-end.js js1_1/jsref.js js1_2/Array/array_split_1.js js1_2/Array/general1.js js1_2/Array/general2.js js1_2/Array/slice.js js1_2/Array/splice1.js js1_2/Array/splice2.js js1_2/Array/tostring_1.js js1_2/Array/tostring_2.js js1_2/Objects/toString-001.js js1_2/String/charCodeAt.js js1_2/String/concat.js js1_2/String/match.js js1_2/String/slice.js js1_2/function/Number.js js1_2/function/String.js js1_2/function/definition-1.js js1_2/function/length.js js1_2/function/nesting-1.js js1_2/function/nesting.js js1_2/function/regexparg-2-n.js js1_2/jsref.js js1_2/operator/strictEquality.js js1_2/regexp/RegExp_dollar_number.js js1_2/regexp/RegExp_input.js js1_2/regexp/RegExp_input_as_array.js js1_2/regexp/RegExp_lastIndex.js js1_2/regexp/RegExp_lastMatch.js js1_2/regexp/RegExp_lastMatch_as_array.js js1_2/regexp/RegExp_lastParen.js js1_2/regexp/RegExp_lastParen_as_array.js js1_2/regexp/RegExp_leftContext.js js1_2/regexp/RegExp_leftContext_as_array.js js1_2/regexp/RegExp_multiline.js js1_2/regexp/RegExp_multiline_as_array.js js1_2/regexp/RegExp_object.js js1_2/regexp/RegExp_rightContext.js js1_2/regexp/RegExp_rightContext_as_array.js js1_2/regexp/alphanumeric.js js1_2/regexp/asterisk.js js1_2/regexp/backslash.js js1_2/regexp/backspace.js js1_2/regexp/beginLine.js js1_2/regexp/character_class.js js1_2/regexp/compile.js js1_2/regexp/control_characters.js js1_2/regexp/digit.js js1_2/regexp/dot.js js1_2/regexp/endLine.js js1_2/regexp/everything.js js1_2/regexp/exec.js js1_2/regexp/flags.js js1_2/regexp/global.js js1_2/regexp/hexadecimal.js js1_2/regexp/ignoreCase.js js1_2/regexp/interval.js js1_2/regexp/octal.js js1_2/regexp/parentheses.js js1_2/regexp/regress-6359.js js1_2/regexp/regress-9141.js js1_2/regexp/simple_form.js js1_2/regexp/source.js js1_2/regexp/special_characters.js js1_2/regexp/string_replace.js js1_2/regexp/string_search.js js1_2/regexp/string_split.js js1_2/regexp/test.js js1_2/regexp/toString.js js1_2/regexp/vertical_bar.js js1_2/regexp/whitespace.js js1_2/regexp/word_boundary.js js1_2/regress/regress-144834.js js1_2/regress/regress-7703.js js1_2/statements/break.js js1_2/statements/do_while.js js1_2/statements/switch.js js1_2/statements/switch2.js js1_2/version120/boolean-001.js js1_3/Boolean/boolean-001.js js1_3/Script/delete-001.js js1_3/Script/function-002.js js1_3/Script/new-001.js js1_3/Script/switch-001.js js1_3/extensions/proto_10.js js1_3/extensions/proto_2.js js1_3/extensions/proto_5.js js1_3/inherit/proto_1.js js1_3/inherit/proto_10.js js1_3/inherit/proto_11.js js1_3/inherit/proto_12.js js1_3/inherit/proto_3.js js1_3/inherit/proto_4.js js1_3/inherit/proto_6.js js1_3/inherit/proto_7.js js1_3/inherit/proto_8.js js1_3/inherit/proto_9.js js1_3/jsref.js js1_3/regress/delete-001.js js1_3/regress/function-002.js js1_3/regress/new-001.js js1_3/regress/switch-001.js js1_4/Eval/eval-001.js js1_4/Eval/eval-002.js js1_4/Eval/eval-003.js js1_4/Functions/function-001.js js1_4/Regress/date-001-n.js js1_4/Regress/function-001.js js1_4/Regress/function-002.js js1_4/Regress/function-003.js js1_4/Regress/function-004-n.js js1_4/Regress/regress-7224.js js1_4/Regress/toString-001-n.js js1_4/jsref.js js1_5/Array/11.1.4.js js1_5/Array/array-001.js js1_5/Array/regress-101964.js js1_5/Array/regress-107138.js js1_5/Array/regress-108440.js js1_5/Array/regress-154338.js js1_5/Array/regress-178722.js js1_5/Array/regress-255555.js js1_5/Array/regress-299644.js js1_5/Array/regress-300858.js js1_5/Array/regress-310351.js js1_5/Array/regress-311515.js js1_5/Array/regress-313153.js js1_5/Array/regress-315509-01.js js1_5/Array/regress-345961.js js1_5/Array/regress-348810.js js1_5/Array/regress-350256-01.js js1_5/Array/regress-350256-02.js js1_5/Array/regress-360681-01.js js1_5/Array/regress-360681-02.js js1_5/Array/regress-364104.js js1_5/Array/regress-94257.js js1_5/Date/regress-188211.js js1_5/Date/regress-301738-01.js js1_5/Date/regress-309925-01.js js1_5/Date/regress-346027.js js1_5/Exceptions/catchguard-002-n.js js1_5/Exceptions/catchguard-003-n.js js1_5/Exceptions/regress-123002.js js1_5/Exceptions/regress-232182.js js1_5/Exceptions/regress-273931.js js1_5/Exceptions/regress-347674.js js1_5/Exceptions/regress-350837.js js1_5/Expressions/regress-192288.js js1_5/Expressions/regress-96526-argsub.js js1_5/Expressions/regress-96526-noargsub.js js1_5/Function/10.1.6.js js1_5/Function/15.3.4.4.js js1_5/Function/regress-123371.js js1_5/Function/regress-178389.js js1_5/Function/regress-292215.js js1_5/Function/regress-344052.js js1_5/GetSet/regress-375976.js js1_5/LexicalConventions/lexical-001.js js1_5/LexicalConventions/regress-177314.js js1_5/Object/regress-137000.js js1_5/Object/regress-192105.js js1_5/Object/regress-338709.js js1_5/Object/regress-382503.js js1_5/Object/regress-382532.js js1_5/Object/regress-90596-003.js js1_5/Regress/regress-104077.js js1_5/Regress/regress-110286.js js1_5/Regress/regress-114491.js js1_5/Regress/regress-114493.js js1_5/Regress/regress-115436.js js1_5/Regress/regress-116228.js js1_5/Regress/regress-118849.js js1_5/Regress/regress-127243.js js1_5/Regress/regress-127557.js js1_5/Regress/regress-131510-001.js js1_5/Regress/regress-140852.js js1_5/Regress/regress-140974.js js1_5/Regress/regress-146596.js js1_5/Regress/regress-152646.js js1_5/Regress/regress-159334.js js1_5/Regress/regress-162392.js js1_5/Regress/regress-165201.js js1_5/Regress/regress-167658.js js1_5/Regress/regress-168347.js js1_5/Regress/regress-170193.js js1_5/Regress/regress-174709.js js1_5/Regress/regress-176125.js js1_5/Regress/regress-185165.js js1_5/Regress/regress-191633.js js1_5/Regress/regress-192414.js js1_5/Regress/regress-193418.js js1_5/Regress/regress-203402.js js1_5/Regress/regress-203841.js js1_5/Regress/regress-204210.js js1_5/Regress/regress-210682.js js1_5/Regress/regress-211590.js js1_5/Regress/regress-214761.js js1_5/Regress/regress-216320.js js1_5/Regress/regress-224956.js js1_5/Regress/regress-229006.js js1_5/Regress/regress-230216-1.js js1_5/Regress/regress-230216-2.js js1_5/Regress/regress-230216-3.js js1_5/Regress/regress-233483-2.js js1_5/Regress/regress-233483.js js1_5/Regress/regress-238881.js js1_5/Regress/regress-238945.js js1_5/Regress/regress-243174.js js1_5/Regress/regress-243389-n.js js1_5/Regress/regress-243869.js js1_5/Regress/regress-244619.js js1_5/Regress/regress-245113.js js1_5/Regress/regress-245308.js js1_5/Regress/regress-246911.js js1_5/Regress/regress-246964.js js1_5/Regress/regress-247179.js js1_5/Regress/regress-253150.js js1_5/Regress/regress-254296.js js1_5/Regress/regress-254974.js js1_5/Regress/regress-256501.js js1_5/Regress/regress-256617.js js1_5/Regress/regress-256798.js js1_5/Regress/regress-260541.js js1_5/Regress/regress-261887.js js1_5/Regress/regress-274888.js js1_5/Regress/regress-275378.js js1_5/Regress/regress-276103.js js1_5/Regress/regress-278873.js js1_5/Regress/regress-280769-3.js js1_5/Regress/regress-280769-4.js js1_5/Regress/regress-281487.js js1_5/Regress/regress-281930.js js1_5/Regress/regress-283477.js js1_5/Regress/regress-286216.js js1_5/Regress/regress-288688.js js1_5/Regress/regress-289094.js js1_5/Regress/regress-290656.js js1_5/Regress/regress-294191.js js1_5/Regress/regress-294195-01.js js1_5/Regress/regress-294195-02.js js1_5/Regress/regress-295052.js js1_5/Regress/regress-295666.js js1_5/Regress/regress-306633.js js1_5/Regress/regress-306727.js js1_5/Regress/regress-306794.js js1_5/Regress/regress-308566.js js1_5/Regress/regress-310295.js js1_5/Regress/regress-310607.js js1_5/Regress/regress-310993.js js1_5/Regress/regress-311071.js js1_5/Regress/regress-311629.js js1_5/Regress/regress-312260.js js1_5/Regress/regress-31255.js js1_5/Regress/regress-314401.js js1_5/Regress/regress-315990.js js1_5/Regress/regress-317476.js js1_5/Regress/regress-317714-02.js js1_5/Regress/regress-319384.js js1_5/Regress/regress-320032.js js1_5/Regress/regress-321757.js js1_5/Regress/regress-321874.js js1_5/Regress/regress-322430.js js1_5/Regress/regress-326467.js js1_5/Regress/regress-328012.js js1_5/Regress/regress-328897.js js1_5/Regress/regress-329383.js js1_5/Regress/regress-330951.js js1_5/Regress/regress-334807-05.js js1_5/Regress/regress-334807-06.js js1_5/Regress/regress-338307.js js1_5/Regress/regress-340369.js js1_5/Regress/regress-341360.js js1_5/Regress/regress-343966.js js1_5/Regress/regress-344804.js js1_5/Regress/regress-344959.js js1_5/Regress/regress-346801.js js1_5/Regress/regress-349482-02.js js1_5/Regress/regress-349592.js js1_5/Regress/regress-350253.js js1_5/Regress/regress-350312.js js1_5/Regress/regress-350415.js js1_5/Regress/regress-351116.js js1_5/Regress/regress-351515.js js1_5/Regress/regress-352009.js js1_5/Regress/regress-352208.js js1_5/Regress/regress-360969-01.js js1_5/Regress/regress-360969-02.js js1_5/Regress/regress-360969-03.js js1_5/Regress/regress-360969-04.js js1_5/Regress/regress-366468.js js1_5/Regress/regress-367561-01.js js1_5/Regress/regress-379245.js js1_5/Regress/regress-39309.js js1_5/Regress/regress-398609.js js1_5/Regress/regress-406769.js js1_5/Regress/regress-407024.js js1_5/Regress/regress-407323.js js1_5/Regress/regress-407957.js js1_5/Regress/regress-57043.js js1_5/Regress/regress-68498-001.js js1_5/Regress/regress-68498-002.js js1_5/Regress/regress-68498-004.js js1_5/Regress/regress-69607.js js1_5/Regress/regress-71107.js js1_5/Regress/regress-76054.js js1_5/Regress/regress-82306.js js1_5/Regress/regress-90445.js js1_5/Regress/regress-96526-001.js js1_5/Scope/regress-154693.js js1_5/Scope/regress-184107.js js1_5/Scope/regress-185485.js js1_5/Scope/regress-191276.js js1_5/Scope/regress-192226.js js1_5/Scope/regress-202678-001.js js1_5/Scope/regress-202678-002.js js1_5/Scope/regress-208496-001.js js1_5/Scope/regress-208496-002.js js1_5/Scope/regress-220362.js js1_5/Scope/regress-77578-001.js js1_5/Scope/scope-002.js js1_5/Scope/scope-003.js js1_5/String/regress-107771.js js1_5/String/regress-112626.js js1_5/String/regress-179068.js js1_5/decompilation/regress-344120.js js1_5/decompilation/regress-349489.js js1_5/decompilation/regress-349663.js js1_5/decompilation/regress-350670.js js1_5/decompilation/regress-351625.js js1_5/decompilation/regress-351626.js js1_5/decompilation/regress-352022.js js1_5/decompilation/regress-352360.js js1_5/decompilation/regress-352873-01.js js1_5/decompilation/regress-352873-02.js js1_5/decompilation/regress-353120.js js1_5/decompilation/regress-354878.js js1_5/decompilation/regress-354910.js js1_5/decompilation/regress-371692.js js1_5/decompilation/regress-373678.js js1_5/decompilation/regress-375639.js js1_5/decompilation/regress-383721.js js1_5/decompilation/regress-406555.js js1_5/extensions/catchguard-001.js js1_5/extensions/catchguard-002.js js1_5/extensions/catchguard-003.js js1_5/extensions/getset-004.js js1_5/extensions/getset-005.js js1_5/extensions/getset-006.js js1_5/extensions/no-such-method.js js1_5/extensions/regress-104077.js js1_5/extensions/regress-178722.js js1_5/extensions/regress-220584.js js1_5/extensions/regress-225831.js js1_5/extensions/regress-226078.js js1_5/extensions/regress-237461.js js1_5/extensions/regress-245795.js js1_5/extensions/regress-255245.js js1_5/extensions/regress-291213.js js1_5/extensions/regress-311161.js js1_5/extensions/regress-311583.js js1_5/extensions/regress-311792-01.js js1_5/extensions/regress-311792-02.js js1_5/extensions/regress-312278.js js1_5/extensions/regress-313500.js js1_5/extensions/regress-313630.js js1_5/extensions/regress-313763.js js1_5/extensions/regress-313803.js js1_5/extensions/regress-313938.js js1_5/extensions/regress-314874.js js1_5/extensions/regress-319683.js js1_5/extensions/regress-322957.js js1_5/extensions/regress-325269.js js1_5/extensions/regress-327608.js js1_5/extensions/regress-328556.js js1_5/extensions/regress-338804-01.js js1_5/extensions/regress-338804-03.js js1_5/extensions/regress-339685.js js1_5/extensions/regress-340199.js js1_5/extensions/regress-341956-02.js js1_5/extensions/regress-341956-03.js js1_5/extensions/regress-346494-01.js js1_5/extensions/regress-350312-01.js js1_5/extensions/regress-350312-02.js js1_5/extensions/regress-350312-03.js js1_5/extensions/regress-351102-01.js js1_5/extensions/regress-351102-02.js js1_5/extensions/regress-351102-06.js js1_5/extensions/regress-351973.js js1_5/extensions/regress-352261.js js1_5/extensions/regress-352281.js js1_5/extensions/regress-354297.js js1_5/extensions/regress-354541-01.js js1_5/extensions/regress-354541-03.js js1_5/extensions/regress-355982.js js1_5/extensions/regress-356402.js js1_5/extensions/regress-363988.js js1_5/extensions/regress-365527.js js1_5/extensions/regress-365692.js js1_5/extensions/regress-366288.js js1_5/extensions/regress-366292.js js1_5/extensions/regress-366396.js js1_5/extensions/regress-367118-01.js js1_5/extensions/regress-367118-02.js js1_5/extensions/regress-367120-01.js js1_5/extensions/regress-367120-02.js js1_5/extensions/regress-367121.js js1_5/extensions/regress-367501-01.js js1_5/extensions/regress-367501-02.js js1_5/extensions/regress-367501-03.js js1_5/extensions/regress-367589.js js1_5/extensions/regress-369404.js js1_5/extensions/regress-374589.js js1_5/extensions/regress-375183.js js1_5/extensions/regress-380889.js js1_5/extensions/regress-385134.js js1_5/extensions/regress-394967.js js1_5/extensions/regress-396326.js js1_5/extensions/regress-407501.js js1_5/extensions/regress-44009.js js1_5/extensions/regress-90596-001.js js1_5/extensions/regress-90596-002.js js1_5/extensions/regress-96284-001.js js1_5/extensions/regress-96284-002.js js1_5/extensions/scope-001.js js1_6/Array/filter.js js1_6/Array/regress-304828.js js1_6/Array/regress-305002.js js1_6/Array/regress-310425-01.js js1_6/Array/regress-310425-02.js js1_6/Array/regress-320887.js js1_6/Array/regress-352742-01.js js1_6/Array/regress-352742-02.js js1_6/Array/regress-415451.js js1_6/Array/regress-415540.js js1_6/Regress/regress-301574.js js1_6/Regress/regress-311157-01.js js1_6/Regress/regress-311157-02.js js1_6/Regress/regress-314887.js js1_6/Regress/regress-351795.js js1_6/Regress/regress-352271.js js1_6/Regress/regress-378492.js js1_6/decompilation/regress-352084.js js1_6/extensions/regress-385393-08.js js1_7/GC/regress-341675.js js1_7/block/order-of-operation.js js1_7/block/regress-341939.js js1_7/block/regress-344139.js js1_7/block/regress-344370.js js1_7/block/regress-345542.js js1_7/block/regress-348685.js js1_7/block/regress-349283.js js1_7/block/regress-349298.js js1_7/block/regress-349507.js js1_7/block/regress-349653.js js1_7/block/regress-349962.js js1_7/block/regress-350279.js js1_7/block/regress-350730.js js1_7/block/regress-350793-01.js js1_7/block/regress-351497.js js1_7/block/regress-351606.js js1_7/block/regress-352092.js js1_7/block/regress-352185.js js1_7/block/regress-352212.js js1_7/block/regress-352267.js js1_7/block/regress-352616.js js1_7/block/regress-352624.js js1_7/block/regress-352907.js js1_7/block/regress-357754.js js1_7/block/regress-376410.js js1_7/block/regress-396900.js js1_7/block/regress-411279.js js1_7/decompilation/regress-349633.js js1_7/decompilation/regress-350810.js js1_7/decompilation/regress-352015.js js1_7/decompilation/regress-352025.js js1_7/decompilation/regress-352269.js js1_7/decompilation/regress-352272.js js1_7/decompilation/regress-352283.js js1_7/decompilation/regress-352732.js js1_7/decompilation/regress-355635.js js1_7/decompilation/regress-355786.js js1_7/decompilation/regress-375794.js js1_7/decompilation/regress-380506.js js1_7/expressions/destructuring-scope.js js1_7/expressions/regress-346203.js js1_7/expressions/regress-346645-01.js js1_7/expressions/regress-346645-02.js js1_7/expressions/regress-346645-03.js js1_7/expressions/regress-349624.js js1_7/expressions/regress-349818.js js1_7/extensions/basic-Iterator.js js1_7/extensions/basic-for-in.js js1_7/extensions/destructuring-order.js js1_7/extensions/iterator-ctor.js js1_7/extensions/regress-346021.js js1_7/extensions/regress-346642-02.js js1_7/extensions/regress-346773.js js1_7/extensions/regress-349619.js js1_7/extensions/regress-350312.js js1_7/extensions/regress-351070-02.js js1_7/extensions/regress-352797-01.js js1_7/extensions/regress-352885-01.js js1_7/extensions/regress-352885-02.js js1_7/extensions/regress-353214-02.js js1_7/extensions/regress-354499-01.js js1_7/extensions/regress-354499-02.js js1_7/extensions/regress-354945-01.js js1_7/extensions/regress-355052-01.js js1_7/extensions/regress-355052-02.js js1_7/extensions/regress-355052-03.js js1_7/extensions/regress-355410.js js1_7/extensions/regress-355512.js js1_7/extensions/regress-355578.js js1_7/extensions/regress-355583.js js1_7/extensions/regress-363040-01.js js1_7/extensions/regress-363040-02.js js1_7/extensions/regress-366668-01.js js1_7/extensions/regress-366668-02.js js1_7/extensions/regress-387955-01.js js1_7/extensions/regress-392308.js js1_7/extensions/regress-396326.js js1_7/geniter/326466-01.js js1_7/geniter/builtin-Iterator-function.js js1_7/geniter/evens.js js1_7/geniter/fibonacci-matrix-generator.js js1_7/geniter/iterator-toString.js js1_7/geniter/message-value-passing.js js1_7/geniter/multiple-close.js js1_7/geniter/nested-yield.js js1_7/geniter/pi-generator.js js1_7/geniter/regress-345736.js js1_7/geniter/regress-345855.js js1_7/geniter/regress-345879-01.js js1_7/geniter/regress-347593.js js1_7/geniter/regress-349012-02.js js1_7/geniter/regress-349012-03.js js1_7/geniter/regress-349012-04.js js1_7/geniter/regress-349012-05.js js1_7/geniter/regress-349023-01.js js1_7/geniter/regress-349023-02.js js1_7/geniter/regress-349023-03.js js1_7/geniter/regress-349362.js js1_7/geniter/regress-349851.js js1_7/geniter/regress-350621.js js1_7/geniter/regress-350809.js js1_7/geniter/regress-351120.js js1_7/geniter/regress-352197.js js1_7/geniter/regress-352876.js js1_7/geniter/regress-355834.js js1_7/geniter/regress-359062.js js1_7/geniter/regress-366941.js js1_7/geniter/regress-382335.js js1_7/geniter/regress-390918.js js1_7/geniter/send-no-rhs.js js1_7/geniter/sequential-yields.js js1_7/geniter/throw-after-close.js js1_7/geniter/throw-forever.js js1_7/geniter/unreachable-yield.js js1_7/geniter/yield-undefined.js js1_7/iterable/regress-341499.js js1_7/iterable/regress-341510.js js1_7/iterable/regress-341815.js js1_7/iterable/regress-341821.js js1_7/iterable/regress-354750-01.js js1_7/iterable/regress-355025.js js1_7/iterable/regress-355075-01.js js1_7/iterable/regress-355090.js js1_7/iterable/regress-412467.js js1_7/lexical/regress-346642-04.js js1_7/regress/regress-352640-01.js js1_7/regress/regress-352640-02.js js1_7/regress/regress-352640-03.js js1_7/regress/regress-352640-04.js js1_7/regress/regress-352797-02.js js1_7/regress/regress-352870-03.js js1_7/regress/regress-353079.js js1_7/regress/regress-355023.js js1_7/regress/regress-355832-01.js js1_7/regress/regress-361566.js js1_7/regress/regress-369666-01.js js1_7/regress/regress-369666-02.js js1_7/regress/regress-372331.js js1_7/regress/regress-373827-01.js js1_7/regress/regress-373827-02.js js1_7/regress/regress-373828.js js1_7/regress/regress-379442.js js1_7/regress/regress-385393-05.js js1_7/regress/regress-407727-01.js js1_7/regress/regress-407727-02.js js1_7/regress/regress-407957.js js1_7/regress/regress-414553.js lc2/Arrays/array-001.js lc2/Arrays/array-002.js lc2/Arrays/array-003.js lc2/Arrays/array-004.js lc2/Arrays/array-005.js lc2/Arrays/array-006-n.js lc2/Arrays/array-007-n.js lc2/Classes/class-001.js lc2/Classes/class-002.js lc2/JSToJava/character-001.js lc2/JSToJava/double-001.js lc2/JSToJava/double-002.js lc2/JSToJava/float-001.js lc2/JSToJava/float-002.js lc2/JSToJava/integer-001.js lc2/JSToJava/integer-002.js lc2/JSToJava/long-001.js lc2/JSToJava/long-002.js lc2/JSToJava/long-003-n.js lc2/JSToJava/short-001.js lc2/JSToJava/short-002.js lc2/JSToJava/short-003-n.js lc2/JavaToJS/String-001.js lc2/JavaToJS/boolean-001.js lc2/JavaToJS/boolean-003.js lc2/JavaToJS/boolean-004.js lc2/JavaToJS/boolean-005.js lc2/JavaToJS/char-001.js lc2/JavaToJS/char-002.js lc2/JavaToJS/enum-001.js lc2/JavaToJS/enum-002.js lc2/JavaToJS/null-001.js lc2/JavaToJS/number-001.js lc2/JavaToJS/number-002.js lc2/Methods/method-001.js lc2/Methods/method-002.js lc2/Methods/method-003.js lc2/Methods/method-004-n.js lc2/Methods/method-005.js lc2/Methods/method-006-n.js lc2/Methods/println-001.js lc2/Objects/object-001.js lc2/Objects/object-002.js lc2/Objects/object-003.js lc2/Objects/object-004.js lc2/Objects/object-005.js lc2/Objects/object-006.js lc2/Packages/package-001.js lc2/Packages/package-002.js lc2/Packages/package-003.js lc2/Packages/package-005.js lc2/Packages/package-006.js lc2/Packages/package-007-n.js lc2/Packages/package-008-n.js lc2/misc/constructor.js lc3/ArrayMethods/byte-002.js lc3/ConvertBoolean/boolean-005-n.js lc3/ConvertBoolean/boolean-006-n.js lc3/ConvertBoolean/boolean-007-n.js lc3/ConvertBoolean/boolean-008-n.js lc3/ConvertBoolean/boolean-009-n.js lc3/ConvertBoolean/boolean-010-n.js lc3/ConvertBoolean/boolean-011-n.js lc3/ConvertBoolean/boolean-012-n.js lc3/ConvertBoolean/boolean-013-n.js lc3/ConvertNull/null-002.js lc3/ConvertNull/null-003-n.js lc3/ConvertNull/null-004-n.js lc3/ConvertNull/null-006-n.js lc3/ConvertString/string-004-n.js lc3/ConvertString/string-005-n.js lc3/ConvertString/string-007-n.js lc3/ConvertUndefined/undefined-001-n.js lc3/JSBoolean/boolean-002-n.js lc3/JSBoolean/boolean-003-n.js lc3/JSBoolean/boolean-004-n.js lc3/JSBoolean/boolean-005-n.js lc3/JSBoolean/boolean-006-n.js lc3/JSBoolean/boolean-007-n.js lc3/JSBoolean/boolean-008-n.js lc3/JSNull/ToBoolean-001-n.js lc3/JSNull/ToLong-001-n.js lc3/JSNull/ToNumber-001-n.js lc3/JSNumber/ToByte-002-n.js lc3/JSNumber/ToByte-003-n.js lc3/JSNumber/ToByte-005-n.js lc3/JSNumber/ToChar-002-n.js lc3/JSNumber/ToChar-003-n.js lc3/JSNumber/ToChar-005-n.js lc3/JSNumber/ToChar-006-n.js lc3/JSNumber/ToInt-002-n.js lc3/JSNumber/ToInt-003-n.js lc3/JSNumber/ToLong-002-n.js lc3/JSNumber/ToLong-003-n.js lc3/JSNumber/ToLong-004-n.js lc3/JSNumber/ToLong-005-n.js lc3/JSNumber/ToLong-006-n.js lc3/JSNumber/ToLong-007-n.js lc3/JSNumber/ToLong-008-n.js lc3/JSNumber/ToLong-009-n.js lc3/JSNumber/ToLong-010-n.js lc3/JSNumber/ToLong-011-n.js lc3/JSNumber/ToShort-003-n.js lc3/JSNumber/ToShort-005-n.js lc3/JSObject/ToDouble-002-n.js lc3/JSObject/ToDouble-003-n.js lc3/JSObject/ToFloat-002-n.js lc3/JSObject/ToFloat-003-n.js lc3/JSUndefined/undefined-002-n.js lc3/JSUndefined/undefined-003-n.js lc3/JSUndefined/undefined-004-n.js lc3/JSUndefined/undefined-005-n.js lc3/JSUndefined/undefined-006-n.js lc3/JSUndefined/undefined-008-n.js lc3/JSUndefined/undefined-009-n.js lc3/JSUndefined/undefined-010-n.js lc3/JavaArray/ToArray-002-n.js lc3/JavaArray/ToBoolean-001-n.js lc3/JavaObject/JavaObjectToBoolean-002-n.js lc3/JavaObject/JavaObjectToByte-002-n.js lc3/JavaObject/JavaObjectToByte-007-n.js lc3/JavaObject/JavaObjectToByte-008-n.js lc3/JavaObject/JavaObjectToChar-003-n.js lc3/JavaObject/JavaObjectToChar-005-n.js lc3/JavaObject/JavaObjectToChar-006-n.js lc3/JavaObject/JavaObjectToInt-002-n.js lc3/JavaObject/JavaObjectToInt-003-n.js lc3/JavaObject/JavaObjectToInt-004-n.js lc3/JavaObject/JavaObjectToLong-002-n.js lc3/JavaObject/JavaObjectToLong-003-n.js lc3/JavaObject/JavaObjectToLong-004-n.js lc3/JavaObject/JavaObjectToLong-006-n.js lc3/JavaObject/JavaObjectToShort-002-n.js lc3/JavaObject/JavaObjectToShort-003-n.js lc3/JavaObject/JavaObjectToShort-004-n.js lc3/StringMethods/string-001.js lc3/StringMethods/string-001.js rhino-1.7R4/testsrc/org/000077500000000000000000000000001176760007500151755ustar00rootroot00000000000000rhino-1.7R4/testsrc/org/mozilla/000077500000000000000000000000001176760007500166445ustar00rootroot00000000000000rhino-1.7R4/testsrc/org/mozilla/javascript/000077500000000000000000000000001176760007500210125ustar00rootroot00000000000000rhino-1.7R4/testsrc/org/mozilla/javascript/drivers/000077500000000000000000000000001176760007500224705ustar00rootroot00000000000000rhino-1.7R4/testsrc/org/mozilla/javascript/drivers/JsDriver.java000066400000000000000000000675621176760007500251030ustar00rootroot00000000000000/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.javascript.drivers; import java.io.*; import java.util.*; import org.w3c.dom.*; import org.mozilla.javascript.tools.shell.*; /** * @version $Id: JsDriver.java,v 1.10 2009/05/15 12:30:45 nboyd%atg.com Exp $ */ public class JsDriver { private JsDriver() { } private static String join(String[] list) { String rv = ""; for (int i=0; i list = new ArrayList(); for (int i=0; i < tests.length; i++) { if (tests[i].startsWith("@")) TestUtils.addTestsFromFile(tests[i].substring(1), list); else list.add(tests[i]); } return list.toArray(new String[0]); } private boolean matches(String path) { if (list.length == 0) return true; return TestUtils.matches(list, path); } private boolean excluded(String path) { if (skip.length == 0) return false; return TestUtils.matches(skip, path); } private void addFiles(List