2003/05/12 05:31:48
[org.ibex.core.git] / src / org / mozilla / javascript / IdScriptable.java
diff --git a/src/org/mozilla/javascript/IdScriptable.java b/src/org/mozilla/javascript/IdScriptable.java
deleted file mode 100644 (file)
index 84fbc92..0000000
+++ /dev/null
@@ -1,577 +0,0 @@
-/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-\r
- *\r
- * The contents of this file are subject to the Netscape Public\r
- * License Version 1.1 (the "License"); you may not use this file\r
- * except in compliance with the License. You may obtain a copy of\r
- * the License at http://www.mozilla.org/NPL/\r
- *\r
- * Software distributed under the License is distributed on an "AS\r
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
- * implied. See the License for the specific language governing\r
- * rights and limitations under the License.\r
- *\r
- * The Original Code is Rhino code, released\r
- * May 6, 1999.\r
- *\r
- * The Initial Developer of the Original Code is Netscape\r
- * Communications Corporation.  Portions created by Netscape are\r
- * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
- * Rights Reserved.\r
- *\r
- * Contributor(s):\r
- * Igor Bukanov\r
- *\r
- * Alternatively, the contents of this file may be used under the\r
- * terms of the GNU Public License (the "GPL"), in which case the\r
- * provisions of the GPL are applicable instead of those above.\r
- * If you wish to allow use of your version of this file only\r
- * under the terms of the GPL and not to allow others to use your\r
- * version of this file under the NPL, indicate your decision by\r
- * deleting the provisions above and replace them with the notice\r
- * and other provisions required by the GPL.  If you do not delete\r
- * the provisions above, a recipient may use your version of this\r
- * file under either the NPL or the GPL.\r
- */\r
-\r
-package org.mozilla.javascript;\r
-\r
-/**\r
-Base class for native object implementation that uses IdFunction to export its methods to script via <class-name>.prototype object.\r
-\r
-Any descendant should implement at least the following methods:\r
-    mapNameToId\r
-    getIdName\r
-    execMethod\r
-    methodArity\r
-\r
-To define non-function properties, the descendant should customize\r
-    getIdValue\r
-    setIdValue\r
-    getIdDefaultAttributes\r
-    maxInstanceId\r
-to get/set property value and provide its default attributes.\r
-\r
-To customize initializition of constructor and protype objects, descendant\r
-may override scopeInit or fillConstructorProperties methods.\r
-\r
-*/\r
-public abstract class IdScriptable extends ScriptableObject\r
-    implements IdFunctionMaster\r
-{\r
-    /** NULL_TAG can be used to distinguish between uninitialized and null\r
-     ** values\r
-     */\r
-    protected static final Object NULL_TAG = new Object();\r
-\r
-    public IdScriptable() {\r
-        activateIdMap(maxInstanceId());\r
-    }\r
-    \r
-    public boolean has(String name, Scriptable start) {\r
-        if (maxId != 0) {\r
-            int id = mapNameToId(name);\r
-            if (id != 0) {\r
-                return hasValue(id);\r
-            }\r
-        }\r
-        return super.has(name, start);\r
-    }\r
-\r
-    public Object get(String name, Scriptable start) {\r
-        if (CACHE_NAMES) {\r
-            int maxId = this.maxId;\r
-            L:if (maxId != 0) {\r
-                Object[] data = idMapData;\r
-                if (data == null) { \r
-                    int id = mapNameToId(name);\r
-                    if (id != 0) {\r
-                        return getIdValue(id);\r
-                    }\r
-                }\r
-                else {\r
-                    int id = lastIdCache;\r
-                    if (data[id - 1 + maxId] != name) {\r
-                        id = mapNameToId(name);\r
-                        if (id == 0) { break L; }\r
-                           data[id - 1 + maxId] = name;\r
-                           lastIdCache = id;\r
-                    }\r
-                    Object value = data[id - 1];\r
-                    if (value == null) {\r
-                        value = getIdValue(id);\r
-                    }\r
-                    else if (value == NULL_TAG) {\r
-                        value = null;\r
-                    }\r
-                    return value;\r
-                }\r
-            }\r
-        }\r
-        else {\r
-            if (maxId != 0) {\r
-                int id = mapNameToId(name);\r
-                if (id != 0) {\r
-                    Object[] data = idMapData;\r
-                    if (data == null) { \r
-                        return getIdValue(id);\r
-                    }\r
-                    else {\r
-                        Object value = data[id - 1];\r
-                        if (value == null) {\r
-                            value = getIdValue(id);\r
-                        }\r
-                        else if (value == NULL_TAG) {\r
-                            value = null;\r
-                        }\r
-                        return value;\r
-                    }\r
-                }\r
-            }\r
-        }\r
-        return super.get(name, start);\r
-    }\r
-\r
-    public void put(String name, Scriptable start, Object value) {\r
-        if (maxId != 0) {\r
-            int id = mapNameToId(name);\r
-            if (id != 0) {\r
-                int attr = getAttributes(id);\r
-                if ((attr & READONLY) == 0) {\r
-                    if (start == this) {\r
-                        setIdValue(id, value);\r
-                    }\r
-                    else {\r
-                        start.put(name, start, value);\r
-                    }\r
-                }\r
-                return;\r
-            }\r
-        }\r
-        super.put(name, start, value);\r
-    }\r
-\r
-    public void delete(String name) {\r
-        if (maxId != 0) {\r
-            int id = mapNameToId(name);\r
-            if (id != 0) {\r
-                // Let the super class to throw exceptions for sealed objects\r
-                if (!isSealed()) {\r
-                    int attr = getAttributes(id);\r
-                    if ((attr & PERMANENT) == 0) {\r
-                        deleteIdValue(id);\r
-                    }\r
-                    return;\r
-                }\r
-            }\r
-        }\r
-        super.delete(name);\r
-    }\r
-\r
-    public int getAttributes(String name, Scriptable start)\r
-        throws PropertyException\r
-    {\r
-        if (maxId != 0) {\r
-            int id = mapNameToId(name);\r
-            if (id != 0) {\r
-                if (hasValue(id)) {\r
-                    return getAttributes(id);\r
-                }\r
-                // For ids with deleted values super will throw exceptions\r
-            }\r
-        }\r
-        return super.getAttributes(name, start);\r
-    }\r
-\r
-    public void setAttributes(String name, Scriptable start,\r
-                              int attributes)\r
-        throws PropertyException\r
-    {\r
-        if (maxId != 0) {\r
-            int id = mapNameToId(name);\r
-            if (id != 0) {\r
-                if (hasValue(id)) {\r
-                    synchronized (this) {\r
-                        setAttributes(id, attributes);\r
-                    }\r
-                    return;\r
-                }\r
-                // For ids with deleted values super will throw exceptions\r
-            }\r
-        }\r
-        super.setAttributes(name, start, attributes);\r
-    }\r
-\r
-    synchronized void addPropertyAttribute(int attribute) {\r
-        extraIdAttributes |= (byte)attribute;\r
-        super.addPropertyAttribute(attribute);\r
-    }\r
-\r
-    /**\r
-     * Redefine ScriptableObject.defineProperty to allow changing\r
-     * values/attributes of id-based properties unless \r
-     * getIdDefaultAttributes contains the READONLY attribute.\r
-     * @see #getIdDefaultAttributes\r
-     * @see org.mozilla.javascript.ScriptableObject#defineProperty\r
-     */\r
-    public void defineProperty(String propertyName, Object value,\r
-                               int attributes)\r
-    {\r
-        if (maxId != 0) {\r
-            int id = mapNameToId(propertyName);\r
-            if (id != 0) {\r
-                int default_attributes = getIdDefaultAttributes(id);\r
-                if ((default_attributes & READONLY) != 0) {\r
-                    // It is a bug to redefine id with readonly attributes\r
-                    throw new RuntimeException\r
-                        ("Attempt to redefine read-only id " + propertyName);\r
-                }\r
-                setAttributes(id, attributes);\r
-                setIdValue(id, value);\r
-                return;\r
-            }\r
-        }\r
-        super.defineProperty(propertyName, value, attributes);\r
-    }\r
-\r
-    Object[] getIds(boolean getAll) {\r
-        Object[] result = super.getIds(getAll);\r
-        \r
-        if (maxId != 0) {\r
-            Object[] ids = null;\r
-            int count = 0;\r
-            \r
-            for (int id = maxId; id != 0; --id) {\r
-                if (hasValue(id)) {\r
-                    if (getAll || (getAttributes(id) & DONTENUM) == 0) {\r
-                        if (count == 0) {\r
-                            // Need extra room for nor more then [1..id] names\r
-                            ids = new Object[id];\r
-                        }\r
-                        ids[count++] = getIdName(id);\r
-                    }\r
-                }\r
-            }\r
-            if (count != 0) {\r
-                if (result.length == 0 && ids.length == count) {\r
-                    result = ids;\r
-                }\r
-                else {\r
-                    Object[] tmp = new Object[result.length + count];\r
-                    System.arraycopy(result, 0, tmp, 0, result.length);\r
-                    System.arraycopy(ids, 0, tmp, result.length, count);\r
-                    result = tmp;\r
-                }\r
-            }\r
-        }\r
-        return result;\r
-    }\r
-\r
-    /** Return maximum id number that should be present in each instance. */\r
-    protected int maxInstanceId() { return 0; }\r
-\r
-    /**\r
-     * Map name to id of prototype or instance property.\r
-     * Should return 0 if not found\r
-     */\r
-    protected abstract int mapNameToId(String name);\r
-\r
-    /** Map id back to property name it defines.\r
-     */\r
-    protected abstract String getIdName(int id);\r
-\r
-    /** Get default attributes for id. \r
-     ** Default implementation return DONTENUM that is the standard attribute \r
-     ** for core EcmaScript function. Typically descendants need to overwrite\r
-     ** this for non-function attributes like length to return\r
-     ** DONTENUM | READONLY | PERMANENT or DONTENUM | PERMANENT\r
-     */\r
-    protected int getIdDefaultAttributes(int id) {\r
-        return DONTENUM;\r
-    }\r
-\r
-    /** Check if id value exists.\r
-     ** Default implementation always returns true */\r
-    protected boolean hasIdValue(int id) {\r
-        return true;\r
-    }\r
-\r
-    /** Get id value. \r
-     ** If id value is constant, descendant can call cacheIdValue to store\r
-     ** value in the permanent cache.\r
-     ** Default implementation creates IdFunction instance for given id\r
-     ** and cache its value\r
-     */\r
-    protected Object getIdValue(int id) {\r
-        IdFunction f = newIdFunction(id);\r
-        f.setParentScope(getParentScope());\r
-        return cacheIdValue(id, f);\r
-    }\r
-\r
-    /**\r
-     * Set id value. \r
-     * IdScriptable never calls this method if result of\r
-     * <code>getIdDefaultAttributes(id)</code> contains READONLY attribute.\r
-     * Descendants can overwrite this method to provide custom handler for\r
-     * property assignments.\r
-     */\r
-    protected void setIdValue(int id, Object value) {\r
-        synchronized (this) {\r
-            ensureIdData()[id - 1] = (value != null) ? value : NULL_TAG;\r
-        }\r
-    }\r
-    \r
-    /**\r
-     * Store value in permanent cache unless value was already assigned to id.\r
-     * After this call IdScriptable never calls hasIdValue and getIdValue \r
-     * for the given id.\r
-     */\r
-    protected Object cacheIdValue(int id, Object value) {\r
-        synchronized (this) {\r
-            Object[] data = ensureIdData();\r
-            Object curValue = data[id - 1];\r
-            if (curValue == null) {\r
-                data[id - 1] = (value != null) ? value : NULL_TAG;\r
-            }\r
-            else {\r
-                value = curValue;\r
-            }\r
-        }\r
-        return value;\r
-    }\r
-    \r
-    /**\r
-     * Delete value represented by id so hasIdValue return false. \r
-     * IdScriptable never calls this method if result of\r
-     * <code>getIdDefaultAttributes(id)</code> contains PERMANENT attribute.\r
-     * Descendants can overwrite this method to provide custom handler for\r
-     * property delete.\r
-     */\r
-    protected void deleteIdValue(int id) {\r
-        synchronized (this) {\r
-            ensureIdData()[id - 1] = NOT_FOUND;\r
-        }\r
-    }\r
-    \r
-    /** 'thisObj' will be null if invoked as constructor, in which case\r
-     ** instance of Scriptable should be returned. */\r
-    public Object execMethod(int methodId, IdFunction function,\r
-                             Context cx, Scriptable scope,\r
-                             Scriptable thisObj, Object[] args)\r
-        throws JavaScriptException\r
-    {\r
-        throw IdFunction.onBadMethodId(this, methodId);\r
-    }\r
-\r
-    /** Get arity or defined argument count for method with given id. \r
-     ** Should return -1 if methodId is not known or can not be used\r
-     ** with execMethod call. */\r
-    public int methodArity(int methodId) {\r
-        return -1;\r
-    }\r
-    \r
-    /** Activate id support with the given maximum id */\r
-    protected void activateIdMap(int maxId) {\r
-        this.maxId = maxId;\r
-    }\r
-    \r
-    /** Sets whether newly constructed function objects should be sealed */\r
-    protected void setSealFunctionsFlag(boolean sealed) {\r
-        setSetupFlag(SEAL_FUNCTIONS_FLAG, sealed);\r
-    }\r
-    \r
-    /** \r
-     * Set parameters of function properties. \r
-     * Currently only determines whether functions should use dynamic scope.\r
-     * @param cx context to read function parameters.\r
-     * \r
-     * @see org.mozilla.javascript.Context#hasCompileFunctionsWithDynamicScope\r
-     */\r
-    protected void setFunctionParametrs(Context cx) {\r
-        setSetupFlag(USE_DYNAMIC_SCOPE_FLAG,\r
-                     cx.hasCompileFunctionsWithDynamicScope());\r
-    }\r
-    \r
-    private void setSetupFlag(int flag, boolean value) {\r
-        setupFlags = (byte)(value ? setupFlags | flag : setupFlags & ~flag);\r
-    }\r
-\r
-    /** \r
-     * Prepare this object to serve as the prototype property of constructor \r
-     * object with name <code>getClassName()<code> defined in\r
-     * <code>scope</code>.\r
-     * @param maxId maximum id available in prototype object\r
-     * @param cx current context\r
-     * @param scope object to define constructor in.\r
-     * @param sealed indicates whether object and all its properties should \r
-     *        be sealed \r
-     */ \r
-    public void addAsPrototype(int maxId, Context cx, Scriptable scope, \r
-                               boolean sealed) \r
-    {\r
-        activateIdMap(maxId);\r
-\r
-        setSealFunctionsFlag(sealed);\r
-        setFunctionParametrs(cx);\r
-        \r
-        int constructorId = mapNameToId("constructor");\r
-        if (constructorId == 0) {\r
-            // It is a bug to call this function without id for constructor \r
-            throw new RuntimeException("No id for constructor property");\r
-        }\r
-\r
-        IdFunction ctor = newIdFunction(constructorId);\r
-        ctor.initAsConstructor(scope, this);\r
-        fillConstructorProperties(cx, ctor, sealed);\r
-        if (sealed) {\r
-            ctor.sealObject();\r
-            ctor.addPropertyAttribute(READONLY);\r
-        }\r
-\r
-        setParentScope(ctor);\r
-        setPrototype(getObjectPrototype(scope));\r
-        cacheIdValue(constructorId, ctor);\r
-\r
-        if (sealed) {\r
-            sealObject();\r
-        }\r
-\r
-        defineProperty(scope, getClassName(), ctor, ScriptableObject.DONTENUM);\r
-    }\r
-\r
-    protected void fillConstructorProperties\r
-        (Context cx, IdFunction ctor, boolean sealed)\r
-    {\r
-    }\r
-\r
-    protected void addIdFunctionProperty\r
-        (Scriptable obj, int id, boolean sealed)\r
-    {\r
-        IdFunction f = newIdFunction(id);\r
-        if (sealed) { f.sealObject(); }\r
-        defineProperty(obj, getIdName(id), f, DONTENUM);\r
-    }\r
-\r
-    /** \r
-     * Utility method for converting target object into native this.\r
-     * Possible usage would be to have a private function like realThis:\r
-     * <pre>\r
-       private NativeSomething realThis(Scriptable thisObj,\r
-                                        IdFunction f, boolean readOnly)\r
-       {\r
-           while (!(thisObj instanceof NativeSomething)) {\r
-               thisObj = nextInstanceCheck(thisObj, f, readOnly);\r
-           }\r
-           return (NativeSomething)thisObj;\r
-       }\r
-    * </pre>\r
-    * Note that although such function can be implemented universally via\r
-    * java.lang.Class.isInstance(), it would be much more slower.\r
-    * @param readOnly specify if the function f does not change state of object.\r
-    * @return Scriptable object suitable for a check by the instanceof operator.\r
-    * @throws RuntimeException if no more instanceof target can be found\r
-    */\r
-    protected Scriptable nextInstanceCheck(Scriptable thisObj,\r
-                                           IdFunction f,\r
-                                           boolean readOnly)\r
-    {\r
-        if (readOnly && 0 != (setupFlags & USE_DYNAMIC_SCOPE_FLAG)) {\r
-            // for read only functions under dynamic scope look prototype chain\r
-            thisObj = thisObj.getPrototype();\r
-            if (thisObj != null) { return thisObj; }\r
-        }\r
-        throw NativeGlobal.typeError1("msg.incompat.call", \r
-                                      f.getFunctionName(), f);\r
-    }\r
-\r
-    protected IdFunction newIdFunction(int id) {\r
-        IdFunction f = new IdFunction(this, getIdName(id), id);\r
-        if (0 != (setupFlags & SEAL_FUNCTIONS_FLAG)) { f.sealObject(); }\r
-        return f;\r
-    }\r
-\r
-    protected final Object wrap_double(double x) {\r
-        return (x == x) ? new Double(x) : ScriptRuntime.NaNobj;\r
-    }\r
-\r
-    protected final Object wrap_int(int x) {\r
-        byte b = (byte)x;\r
-        if (b == x) { return new Byte(b); }\r
-        return new Integer(x);\r
-    }\r
-\r
-    protected final Object wrap_long(long x) {\r
-        int i = (int)x;\r
-        if (i == x) { return wrap_int(i); }\r
-        return new Long(x);\r
-    }\r
-\r
-    protected final Object wrap_boolean(boolean x) {\r
-        return x ? Boolean.TRUE : Boolean.FALSE;\r
-    }\r
-    \r
-    private boolean hasValue(int id) {\r
-        Object value;\r
-        Object[] data = idMapData;\r
-        if (data == null || (value = data[id - 1]) == null) {\r
-            return hasIdValue(id);\r
-        }\r
-        else {\r
-            return value != NOT_FOUND;\r
-        }\r
-    }\r
-\r
-    // Must be called only from synchronized (this)\r
-    private Object[] ensureIdData() {\r
-        Object[] data = idMapData;\r
-        if (data == null) { \r
-            idMapData = data = new Object[CACHE_NAMES ? maxId * 2 : maxId];\r
-        }\r
-        return data;\r
-    }\r
-    \r
-    private int getAttributes(int id) {\r
-        int attributes = getIdDefaultAttributes(id) | extraIdAttributes;\r
-        byte[] array = attributesArray;\r
-        if (array != null) {\r
-            attributes |= 0xFF & array[id - 1];\r
-        }\r
-        return attributes;\r
-    }\r
-\r
-    private void setAttributes(int id, int attributes) {\r
-        int defaultAttrs = getIdDefaultAttributes(id);\r
-        if ((attributes & defaultAttrs) != defaultAttrs) {\r
-            // It is a bug to set attributes to less restrictive values \r
-            // then given by defaultAttrs\r
-            throw new RuntimeException("Attempt to unset default attributes");\r
-        }\r
-        // Store only additional bits\r
-        attributes &= ~defaultAttrs;\r
-        byte[] array = attributesArray;\r
-        if (array == null && attributes != 0) {\r
-            synchronized (this) {\r
-                array = attributesArray;\r
-                if (array == null) {\r
-                    attributesArray = array = new byte[maxId];\r
-                }\r
-            }\r
-        }\r
-        if (array != null) {\r
-            array[id - 1] = (byte)attributes;\r
-        }\r
-    }\r
-\r
-    private int maxId;\r
-    private Object[] idMapData;\r
-    private byte[] attributesArray;\r
-\r
-    private static final boolean CACHE_NAMES = true;\r
-    private int lastIdCache;\r
-\r
-    private static final int USE_DYNAMIC_SCOPE_FLAG = 1 << 0;\r
-    private static final int SEAL_FUNCTIONS_FLAG    = 1 << 1;\r
-    \r
-    private byte setupFlags;\r
-    private byte extraIdAttributes;\r
-}\r
-\r