Source Code Cross Referenced for ScriptableObject.java in  » Scripting » rhino » org » mozilla » javascript » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » rhino » org.mozilla.javascript 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
0002:         *
0003:         * ***** BEGIN LICENSE BLOCK *****
0004:         * Version: MPL 1.1/GPL 2.0
0005:         *
0006:         * The contents of this file are subject to the Mozilla Public License Version
0007:         * 1.1 (the "License"); you may not use this file except in compliance with
0008:         * the License. You may obtain a copy of the License at
0009:         * http://www.mozilla.org/MPL/
0010:         *
0011:         * Software distributed under the License is distributed on an "AS IS" basis,
0012:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013:         * for the specific language governing rights and limitations under the
0014:         * License.
0015:         *
0016:         * The Original Code is Rhino code, released
0017:         * May 6, 1999.
0018:         *
0019:         * The Initial Developer of the Original Code is
0020:         * Netscape Communications Corporation.
0021:         * Portions created by the Initial Developer are Copyright (C) 1997-1999
0022:         * the Initial Developer. All Rights Reserved.
0023:         *
0024:         * Contributor(s):
0025:         *   Norris Boyd
0026:         *   Igor Bukanov
0027:         *   Bob Jervis
0028:         *   Roger Lawrence
0029:         *   Steve Weiss
0030:         *
0031:         * Alternatively, the contents of this file may be used under the terms of
0032:         * the GNU General Public License Version 2 or later (the "GPL"), in which
0033:         * case the provisions of the GPL are applicable instead of those above. If
0034:         * you wish to allow use of your version of this file only under the terms of
0035:         * the GPL and not to allow others to use your version of this file under the
0036:         * MPL, indicate your decision by deleting the provisions above and replacing
0037:         * them with the notice and other provisions required by the GPL. If you do
0038:         * not delete the provisions above, a recipient may use your version of this
0039:         * file under either the MPL or the GPL.
0040:         *
0041:         * ***** END LICENSE BLOCK ***** */
0042:
0043:        // API class
0044:        package org.mozilla.javascript;
0045:
0046:        import java.lang.reflect.*;
0047:        import java.util.Hashtable;
0048:        import java.io.*;
0049:        import org.mozilla.javascript.debug.DebuggableObject;
0050:
0051:        /**
0052:         * This is the default implementation of the Scriptable interface. This
0053:         * class provides convenient default behavior that makes it easier to
0054:         * define host objects.
0055:         * <p>
0056:         * Various properties and methods of JavaScript objects can be conveniently
0057:         * defined using methods of ScriptableObject.
0058:         * <p>
0059:         * Classes extending ScriptableObject must define the getClassName method.
0060:         *
0061:         * @see org.mozilla.javascript.Scriptable
0062:         * @author Norris Boyd
0063:         */
0064:
0065:        public abstract class ScriptableObject implements  Scriptable,
0066:                Serializable, DebuggableObject, ConstProperties {
0067:
0068:            /**
0069:             * The empty property attribute.
0070:             *
0071:             * Used by getAttributes() and setAttributes().
0072:             *
0073:             * @see org.mozilla.javascript.ScriptableObject#getAttributes(String)
0074:             * @see org.mozilla.javascript.ScriptableObject#setAttributes(String, int)
0075:             */
0076:            public static final int EMPTY = 0x00;
0077:
0078:            /**
0079:             * Property attribute indicating assignment to this property is ignored.
0080:             *
0081:             * @see org.mozilla.javascript.ScriptableObject
0082:             *      #put(String, Scriptable, Object)
0083:             * @see org.mozilla.javascript.ScriptableObject#getAttributes(String)
0084:             * @see org.mozilla.javascript.ScriptableObject#setAttributes(String, int)
0085:             */
0086:            public static final int READONLY = 0x01;
0087:
0088:            /**
0089:             * Property attribute indicating property is not enumerated.
0090:             *
0091:             * Only enumerated properties will be returned by getIds().
0092:             *
0093:             * @see org.mozilla.javascript.ScriptableObject#getIds()
0094:             * @see org.mozilla.javascript.ScriptableObject#getAttributes(String)
0095:             * @see org.mozilla.javascript.ScriptableObject#setAttributes(String, int)
0096:             */
0097:            public static final int DONTENUM = 0x02;
0098:
0099:            /**
0100:             * Property attribute indicating property cannot be deleted.
0101:             *
0102:             * @see org.mozilla.javascript.ScriptableObject#delete(String)
0103:             * @see org.mozilla.javascript.ScriptableObject#getAttributes(String)
0104:             * @see org.mozilla.javascript.ScriptableObject#setAttributes(String, int)
0105:             */
0106:            public static final int PERMANENT = 0x04;
0107:
0108:            /**
0109:             * Property attribute indicating that this is a const property that has not
0110:             * been assigned yet.  The first 'const' assignment to the property will
0111:             * clear this bit.
0112:             */
0113:            public static final int UNINITIALIZED_CONST = 0x08;
0114:
0115:            public static final int CONST = PERMANENT | READONLY
0116:                    | UNINITIALIZED_CONST;
0117:            /**
0118:             * The prototype of this object.
0119:             */
0120:            private Scriptable prototypeObject;
0121:
0122:            /**
0123:             * The parent scope of this object.
0124:             */
0125:            private Scriptable parentScopeObject;
0126:
0127:            private static final Slot REMOVED = new Slot(null, 0, READONLY);
0128:
0129:            static {
0130:                REMOVED.wasDeleted = 1;
0131:            }
0132:
0133:            private transient Slot[] slots;
0134:            // If count >= 0, it gives number of keys or if count < 0,
0135:            // it indicates sealed object where ~count gives number of keys
0136:            private int count;
0137:
0138:            // cache; may be removed for smaller memory footprint
0139:            private transient Slot lastAccess = REMOVED;
0140:
0141:            // associated values are not serialized
0142:            private transient volatile Hashtable associatedValues;
0143:
0144:            private static final int SLOT_QUERY = 1;
0145:            private static final int SLOT_MODIFY = 2;
0146:            private static final int SLOT_REMOVE = 3;
0147:            private static final int SLOT_MODIFY_GETTER_SETTER = 4;
0148:            private static final int SLOT_MODIFY_CONST = 5;
0149:
0150:            private static class Slot implements  Serializable {
0151:                static final long serialVersionUID = -3539051633409902634L;
0152:
0153:                String name; // This can change due to caching
0154:                int indexOrHash;
0155:                private volatile short attributes;
0156:                transient volatile byte wasDeleted;
0157:                volatile Object value;
0158:                transient volatile Slot next;
0159:
0160:                Slot(String name, int indexOrHash, int attributes) {
0161:                    this .name = name;
0162:                    this .indexOrHash = indexOrHash;
0163:                    this .attributes = (short) attributes;
0164:                }
0165:
0166:                private void readObject(ObjectInputStream in)
0167:                        throws IOException, ClassNotFoundException {
0168:                    in.defaultReadObject();
0169:                    if (name != null) {
0170:                        indexOrHash = name.hashCode();
0171:                    }
0172:                }
0173:
0174:                final int getAttributes() {
0175:                    return attributes;
0176:                }
0177:
0178:                final synchronized void setAttributes(int value) {
0179:                    checkValidAttributes(value);
0180:                    attributes = (short) value;
0181:                }
0182:
0183:                final void checkNotReadonly() {
0184:                    if ((attributes & READONLY) != 0) {
0185:                        String str = (name != null ? name : Integer
0186:                                .toString(indexOrHash));
0187:                        throw Context.reportRuntimeError1(
0188:                                "msg.modify.readonly", str);
0189:                    }
0190:                }
0191:
0192:            }
0193:
0194:            private static final class GetterSlot extends Slot {
0195:                static final long serialVersionUID = -4900574849788797588L;
0196:
0197:                Object getter;
0198:                Object setter;
0199:
0200:                GetterSlot(String name, int indexOrHash, int attributes) {
0201:                    super (name, indexOrHash, attributes);
0202:                }
0203:            }
0204:
0205:            static void checkValidAttributes(int attributes) {
0206:                final int mask = READONLY | DONTENUM | PERMANENT
0207:                        | UNINITIALIZED_CONST;
0208:                if ((attributes & ~mask) != 0) {
0209:                    throw new IllegalArgumentException(String
0210:                            .valueOf(attributes));
0211:                }
0212:            }
0213:
0214:            public ScriptableObject() {
0215:            }
0216:
0217:            public ScriptableObject(Scriptable scope, Scriptable prototype) {
0218:                if (scope == null)
0219:                    throw new IllegalArgumentException();
0220:
0221:                parentScopeObject = scope;
0222:                prototypeObject = prototype;
0223:            }
0224:
0225:            /**
0226:             * Return the name of the class.
0227:             *
0228:             * This is typically the same name as the constructor.
0229:             * Classes extending ScriptableObject must implement this abstract
0230:             * method.
0231:             */
0232:            public abstract String getClassName();
0233:
0234:            /**
0235:             * Returns true if the named property is defined.
0236:             *
0237:             * @param name the name of the property
0238:             * @param start the object in which the lookup began
0239:             * @return true if and only if the property was found in the object
0240:             */
0241:            public boolean has(String name, Scriptable start) {
0242:                return null != getSlot(name, 0, SLOT_QUERY);
0243:            }
0244:
0245:            /**
0246:             * Returns true if the property index is defined.
0247:             *
0248:             * @param index the numeric index for the property
0249:             * @param start the object in which the lookup began
0250:             * @return true if and only if the property was found in the object
0251:             */
0252:            public boolean has(int index, Scriptable start) {
0253:                return null != getSlot(null, index, SLOT_QUERY);
0254:            }
0255:
0256:            /**
0257:             * Returns the value of the named property or NOT_FOUND.
0258:             *
0259:             * If the property was created using defineProperty, the
0260:             * appropriate getter method is called.
0261:             *
0262:             * @param name the name of the property
0263:             * @param start the object in which the lookup began
0264:             * @return the value of the property (may be null), or NOT_FOUND
0265:             */
0266:            public Object get(String name, Scriptable start) {
0267:                return getImpl(name, 0, start);
0268:            }
0269:
0270:            /**
0271:             * Returns the value of the indexed property or NOT_FOUND.
0272:             *
0273:             * @param index the numeric index for the property
0274:             * @param start the object in which the lookup began
0275:             * @return the value of the property (may be null), or NOT_FOUND
0276:             */
0277:            public Object get(int index, Scriptable start) {
0278:                return getImpl(null, index, start);
0279:            }
0280:
0281:            /**
0282:             * Sets the value of the named property, creating it if need be.
0283:             *
0284:             * If the property was created using defineProperty, the
0285:             * appropriate setter method is called. <p>
0286:             *
0287:             * If the property's attributes include READONLY, no action is
0288:             * taken.
0289:             * This method will actually set the property in the start
0290:             * object.
0291:             *
0292:             * @param name the name of the property
0293:             * @param start the object whose property is being set
0294:             * @param value value to set the property to
0295:             */
0296:            public void put(String name, Scriptable start, Object value) {
0297:                if (putImpl(name, 0, start, value, EMPTY))
0298:                    return;
0299:
0300:                if (start == this )
0301:                    throw Kit.codeBug();
0302:                start.put(name, start, value);
0303:            }
0304:
0305:            /**
0306:             * Sets the value of the indexed property, creating it if need be.
0307:             *
0308:             * @param index the numeric index for the property
0309:             * @param start the object whose property is being set
0310:             * @param value value to set the property to
0311:             */
0312:            public void put(int index, Scriptable start, Object value) {
0313:                if (putImpl(null, index, start, value, EMPTY))
0314:                    return;
0315:
0316:                if (start == this )
0317:                    throw Kit.codeBug();
0318:                start.put(index, start, value);
0319:            }
0320:
0321:            /**
0322:             * Removes a named property from the object.
0323:             *
0324:             * If the property is not found, or it has the PERMANENT attribute,
0325:             * no action is taken.
0326:             *
0327:             * @param name the name of the property
0328:             */
0329:            public void delete(String name) {
0330:                checkNotSealed(name, 0);
0331:                accessSlot(name, 0, SLOT_REMOVE);
0332:            }
0333:
0334:            /**
0335:             * Removes the indexed property from the object.
0336:             *
0337:             * If the property is not found, or it has the PERMANENT attribute,
0338:             * no action is taken.
0339:             *
0340:             * @param index the numeric index for the property
0341:             */
0342:            public void delete(int index) {
0343:                checkNotSealed(null, index);
0344:                accessSlot(null, index, SLOT_REMOVE);
0345:            }
0346:
0347:            /**
0348:             * Sets the value of the named const property, creating it if need be.
0349:             *
0350:             * If the property was created using defineProperty, the
0351:             * appropriate setter method is called. <p>
0352:             *
0353:             * If the property's attributes include READONLY, no action is
0354:             * taken.
0355:             * This method will actually set the property in the start
0356:             * object.
0357:             *
0358:             * @param name the name of the property
0359:             * @param start the object whose property is being set
0360:             * @param value value to set the property to
0361:             */
0362:            public void putConst(String name, Scriptable start, Object value) {
0363:                if (putImpl(name, 0, start, value, READONLY))
0364:                    return;
0365:
0366:                if (start == this )
0367:                    throw Kit.codeBug();
0368:                if (start instanceof  ConstProperties)
0369:                    ((ConstProperties) start).putConst(name, start, value);
0370:                else
0371:                    start.put(name, start, value);
0372:            }
0373:
0374:            public void defineConst(String name, Scriptable start) {
0375:                if (putImpl(name, 0, start, Undefined.instance,
0376:                        UNINITIALIZED_CONST))
0377:                    return;
0378:
0379:                if (start == this )
0380:                    throw Kit.codeBug();
0381:                if (start instanceof  ConstProperties)
0382:                    ((ConstProperties) start).defineConst(name, start);
0383:            }
0384:
0385:            /**
0386:             * Returns true if the named property is defined as a const on this object.
0387:             * @param name
0388:             * @return true if the named property is defined as a const, false
0389:             * otherwise.
0390:             */
0391:            public boolean isConst(String name) {
0392:                Slot slot = getSlot(name, 0, SLOT_QUERY);
0393:                if (slot == null) {
0394:                    return false;
0395:                }
0396:                return (slot.getAttributes() & (PERMANENT | READONLY)) == (PERMANENT | READONLY);
0397:
0398:            }
0399:
0400:            /**
0401:             * @deprecated Use {@link #getAttributes(String name)}. The engine always
0402:             * ignored the start argument.
0403:             */
0404:            public final int getAttributes(String name, Scriptable start) {
0405:                return getAttributes(name);
0406:            }
0407:
0408:            /**
0409:             * @deprecated Use {@link #getAttributes(int index)}. The engine always
0410:             * ignored the start argument.
0411:             */
0412:            public final int getAttributes(int index, Scriptable start) {
0413:                return getAttributes(index);
0414:            }
0415:
0416:            /**
0417:             * @deprecated Use {@link #setAttributes(String name, int attributes)}.
0418:             * The engine always ignored the start argument.
0419:             */
0420:            public final void setAttributes(String name, Scriptable start,
0421:                    int attributes) {
0422:                setAttributes(name, attributes);
0423:            }
0424:
0425:            /**
0426:             * @deprecated Use {@link #setAttributes(int index, int attributes)}.
0427:             * The engine always ignored the start argument.
0428:             */
0429:            public void setAttributes(int index, Scriptable start,
0430:                    int attributes) {
0431:                setAttributes(index, attributes);
0432:            }
0433:
0434:            /**
0435:             * Get the attributes of a named property.
0436:             *
0437:             * The property is specified by <code>name</code>
0438:             * as defined for <code>has</code>.<p>
0439:             *
0440:             * @param name the identifier for the property
0441:             * @return the bitset of attributes
0442:             * @exception EvaluatorException if the named property is not found
0443:             * @see org.mozilla.javascript.ScriptableObject#has(String, Scriptable)
0444:             * @see org.mozilla.javascript.ScriptableObject#READONLY
0445:             * @see org.mozilla.javascript.ScriptableObject#DONTENUM
0446:             * @see org.mozilla.javascript.ScriptableObject#PERMANENT
0447:             * @see org.mozilla.javascript.ScriptableObject#EMPTY
0448:             */
0449:            public int getAttributes(String name) {
0450:                return findAttributeSlot(name, 0, SLOT_QUERY).getAttributes();
0451:            }
0452:
0453:            /**
0454:             * Get the attributes of an indexed property.
0455:             *
0456:             * @param index the numeric index for the property
0457:             * @exception EvaluatorException if the named property is not found
0458:             *            is not found
0459:             * @return the bitset of attributes
0460:             * @see org.mozilla.javascript.ScriptableObject#has(String, Scriptable)
0461:             * @see org.mozilla.javascript.ScriptableObject#READONLY
0462:             * @see org.mozilla.javascript.ScriptableObject#DONTENUM
0463:             * @see org.mozilla.javascript.ScriptableObject#PERMANENT
0464:             * @see org.mozilla.javascript.ScriptableObject#EMPTY
0465:             */
0466:            public int getAttributes(int index) {
0467:                return findAttributeSlot(null, index, SLOT_QUERY)
0468:                        .getAttributes();
0469:            }
0470:
0471:            /**
0472:             * Set the attributes of a named property.
0473:             *
0474:             * The property is specified by <code>name</code>
0475:             * as defined for <code>has</code>.<p>
0476:             *
0477:             * The possible attributes are READONLY, DONTENUM,
0478:             * and PERMANENT. Combinations of attributes
0479:             * are expressed by the bitwise OR of attributes.
0480:             * EMPTY is the state of no attributes set. Any unused
0481:             * bits are reserved for future use.
0482:             *
0483:             * @param name the name of the property
0484:             * @param attributes the bitset of attributes
0485:             * @exception EvaluatorException if the named property is not found
0486:             * @see org.mozilla.javascript.Scriptable#has(String, Scriptable)
0487:             * @see org.mozilla.javascript.ScriptableObject#READONLY
0488:             * @see org.mozilla.javascript.ScriptableObject#DONTENUM
0489:             * @see org.mozilla.javascript.ScriptableObject#PERMANENT
0490:             * @see org.mozilla.javascript.ScriptableObject#EMPTY
0491:             */
0492:            public void setAttributes(String name, int attributes) {
0493:                checkNotSealed(name, 0);
0494:                findAttributeSlot(name, 0, SLOT_MODIFY).setAttributes(
0495:                        attributes);
0496:            }
0497:
0498:            /**
0499:             * Set the attributes of an indexed property.
0500:             *
0501:             * @param index the numeric index for the property
0502:             * @param attributes the bitset of attributes
0503:             * @exception EvaluatorException if the named property is not found
0504:             * @see org.mozilla.javascript.Scriptable#has(String, Scriptable)
0505:             * @see org.mozilla.javascript.ScriptableObject#READONLY
0506:             * @see org.mozilla.javascript.ScriptableObject#DONTENUM
0507:             * @see org.mozilla.javascript.ScriptableObject#PERMANENT
0508:             * @see org.mozilla.javascript.ScriptableObject#EMPTY
0509:             */
0510:            public void setAttributes(int index, int attributes) {
0511:                checkNotSealed(null, index);
0512:                findAttributeSlot(null, index, SLOT_MODIFY).setAttributes(
0513:                        attributes);
0514:            }
0515:
0516:            /**
0517:             * XXX: write docs.
0518:             */
0519:            public void setGetterOrSetter(String name, int index,
0520:                    Callable getterOrSeter, boolean isSetter) {
0521:                if (name != null && index != 0)
0522:                    throw new IllegalArgumentException(name);
0523:
0524:                checkNotSealed(name, index);
0525:                GetterSlot gslot = (GetterSlot) getSlot(name, index,
0526:                        SLOT_MODIFY_GETTER_SETTER);
0527:                gslot.checkNotReadonly();
0528:                if (isSetter) {
0529:                    gslot.setter = getterOrSeter;
0530:                } else {
0531:                    gslot.getter = getterOrSeter;
0532:                }
0533:                gslot.value = Undefined.instance;
0534:            }
0535:
0536:            /**
0537:             * Get the getter or setter for a given property. Used by __lookupGetter__
0538:             * and __lookupSetter__.
0539:             * 
0540:             * @param name Name of the object. If nonnull, index must be 0.
0541:             * @param index Index of the object. If nonzero, name must be null.
0542:             * @param isSetter If true, return the setter, otherwise return the getter.
0543:             * @exception IllegalArgumentException if both name and index are nonnull
0544:             *            and nonzero respectively.
0545:             * @return Null if the property does not exist. Otherwise returns either 
0546:             *         the getter or the setter for the property, depending on 
0547:             *         the value of isSetter (may be undefined if unset).
0548:             */
0549:            public Object getGetterOrSetter(String name, int index,
0550:                    boolean isSetter) {
0551:                if (name != null && index != 0)
0552:                    throw new IllegalArgumentException(name);
0553:                Slot slot = getSlot(name, index, SLOT_QUERY);
0554:                if (slot == null)
0555:                    return null;
0556:                if (slot instanceof  GetterSlot) {
0557:                    GetterSlot gslot = (GetterSlot) slot;
0558:                    Object result = isSetter ? gslot.setter : gslot.getter;
0559:                    return result != null ? result : Undefined.instance;
0560:                } else
0561:                    return Undefined.instance;
0562:            }
0563:
0564:            /**
0565:             * Returns whether a property is a getter or a setter
0566:             * @param name property name
0567:             * @param index property index
0568:             * @param setter true to check for a setter, false for a getter
0569:             * @return whether the property is a getter or a setter
0570:             */
0571:            protected boolean isGetterOrSetter(String name, int index,
0572:                    boolean setter) {
0573:                Slot slot = getSlot(name, index, SLOT_QUERY);
0574:                if (slot instanceof  GetterSlot) {
0575:                    if (setter && ((GetterSlot) slot).setter != null)
0576:                        return true;
0577:                    if (!setter && ((GetterSlot) slot).getter != null)
0578:                        return true;
0579:                }
0580:                return false;
0581:            }
0582:
0583:            void addLazilyInitializedValue(String name, int index,
0584:                    LazilyLoadedCtor init, int attributes) {
0585:                if (name != null && index != 0)
0586:                    throw new IllegalArgumentException(name);
0587:                checkNotSealed(name, index);
0588:                GetterSlot gslot = (GetterSlot) getSlot(name, index,
0589:                        SLOT_MODIFY_GETTER_SETTER);
0590:                gslot.setAttributes(attributes);
0591:                gslot.getter = null;
0592:                gslot.setter = null;
0593:                gslot.value = init;
0594:            }
0595:
0596:            /**
0597:             * Returns the prototype of the object.
0598:             */
0599:            public Scriptable getPrototype() {
0600:                return prototypeObject;
0601:            }
0602:
0603:            /**
0604:             * Sets the prototype of the object.
0605:             */
0606:            public void setPrototype(Scriptable m) {
0607:                prototypeObject = m;
0608:            }
0609:
0610:            /**
0611:             * Returns the parent (enclosing) scope of the object.
0612:             */
0613:            public Scriptable getParentScope() {
0614:                return parentScopeObject;
0615:            }
0616:
0617:            /**
0618:             * Sets the parent (enclosing) scope of the object.
0619:             */
0620:            public void setParentScope(Scriptable m) {
0621:                parentScopeObject = m;
0622:            }
0623:
0624:            /**
0625:             * Returns an array of ids for the properties of the object.
0626:             *
0627:             * <p>Any properties with the attribute DONTENUM are not listed. <p>
0628:             *
0629:             * @return an array of java.lang.Objects with an entry for every
0630:             * listed property. Properties accessed via an integer index will
0631:             * have a corresponding
0632:             * Integer entry in the returned array. Properties accessed by
0633:             * a String will have a String entry in the returned array.
0634:             */
0635:            public Object[] getIds() {
0636:                return getIds(false);
0637:            }
0638:
0639:            /**
0640:             * Returns an array of ids for the properties of the object.
0641:             *
0642:             * <p>All properties, even those with attribute DONTENUM, are listed. <p>
0643:             *
0644:             * @return an array of java.lang.Objects with an entry for every
0645:             * listed property. Properties accessed via an integer index will
0646:             * have a corresponding
0647:             * Integer entry in the returned array. Properties accessed by
0648:             * a String will have a String entry in the returned array.
0649:             */
0650:            public Object[] getAllIds() {
0651:                return getIds(true);
0652:            }
0653:
0654:            /**
0655:             * Implements the [[DefaultValue]] internal method.
0656:             *
0657:             * <p>Note that the toPrimitive conversion is a no-op for
0658:             * every type other than Object, for which [[DefaultValue]]
0659:             * is called. See ECMA 9.1.<p>
0660:             *
0661:             * A <code>hint</code> of null means "no hint".
0662:             *
0663:             * @param typeHint the type hint
0664:             * @return the default value for the object
0665:             *
0666:             * See ECMA 8.6.2.6.
0667:             */
0668:            public Object getDefaultValue(Class typeHint) {
0669:                return getDefaultValue(this , typeHint);
0670:            }
0671:
0672:            public static Object getDefaultValue(Scriptable object,
0673:                    Class typeHint) {
0674:                Context cx = null;
0675:                for (int i = 0; i < 2; i++) {
0676:                    boolean tryToString;
0677:                    if (typeHint == ScriptRuntime.StringClass) {
0678:                        tryToString = (i == 0);
0679:                    } else {
0680:                        tryToString = (i == 1);
0681:                    }
0682:
0683:                    String methodName;
0684:                    Object[] args;
0685:                    if (tryToString) {
0686:                        methodName = "toString";
0687:                        args = ScriptRuntime.emptyArgs;
0688:                    } else {
0689:                        methodName = "valueOf";
0690:                        args = new Object[1];
0691:                        String hint;
0692:                        if (typeHint == null) {
0693:                            hint = "undefined";
0694:                        } else if (typeHint == ScriptRuntime.StringClass) {
0695:                            hint = "string";
0696:                        } else if (typeHint == ScriptRuntime.ScriptableClass) {
0697:                            hint = "object";
0698:                        } else if (typeHint == ScriptRuntime.FunctionClass) {
0699:                            hint = "function";
0700:                        } else if (typeHint == ScriptRuntime.BooleanClass
0701:                                || typeHint == Boolean.TYPE) {
0702:                            hint = "boolean";
0703:                        } else if (typeHint == ScriptRuntime.NumberClass
0704:                                || typeHint == ScriptRuntime.ByteClass
0705:                                || typeHint == Byte.TYPE
0706:                                || typeHint == ScriptRuntime.ShortClass
0707:                                || typeHint == Short.TYPE
0708:                                || typeHint == ScriptRuntime.IntegerClass
0709:                                || typeHint == Integer.TYPE
0710:                                || typeHint == ScriptRuntime.FloatClass
0711:                                || typeHint == Float.TYPE
0712:                                || typeHint == ScriptRuntime.DoubleClass
0713:                                || typeHint == Double.TYPE) {
0714:                            hint = "number";
0715:                        } else {
0716:                            throw Context.reportRuntimeError1(
0717:                                    "msg.invalid.type", typeHint.toString());
0718:                        }
0719:                        args[0] = hint;
0720:                    }
0721:                    Object v = getProperty(object, methodName);
0722:                    if (!(v instanceof  Function))
0723:                        continue;
0724:                    Function fun = (Function) v;
0725:                    if (cx == null)
0726:                        cx = Context.getContext();
0727:                    v = fun.call(cx, fun.getParentScope(), object, args);
0728:                    if (v != null) {
0729:                        if (!(v instanceof  Scriptable)) {
0730:                            return v;
0731:                        }
0732:                        if (typeHint == ScriptRuntime.ScriptableClass
0733:                                || typeHint == ScriptRuntime.FunctionClass) {
0734:                            return v;
0735:                        }
0736:                        if (tryToString && v instanceof  Wrapper) {
0737:                            // Let a wrapped java.lang.String pass for a primitive
0738:                            // string.
0739:                            Object u = ((Wrapper) v).unwrap();
0740:                            if (u instanceof  String)
0741:                                return u;
0742:                        }
0743:                    }
0744:                }
0745:                // fall through to error
0746:                String arg = (typeHint == null) ? "undefined" : typeHint
0747:                        .getName();
0748:                throw ScriptRuntime.typeError1("msg.default.value", arg);
0749:            }
0750:
0751:            /**
0752:             * Implements the instanceof operator.
0753:             *
0754:             * <p>This operator has been proposed to ECMA.
0755:             *
0756:             * @param instance The value that appeared on the LHS of the instanceof
0757:             *              operator
0758:             * @return true if "this" appears in value's prototype chain
0759:             *
0760:             */
0761:            public boolean hasInstance(Scriptable instance) {
0762:                // Default for JS objects (other than Function) is to do prototype
0763:                // chasing.  This will be overridden in NativeFunction and non-JS
0764:                // objects.
0765:
0766:                return ScriptRuntime.jsDelegatesTo(instance, this );
0767:            }
0768:
0769:            /**
0770:             * Emulate the SpiderMonkey (and Firefox) feature of allowing
0771:             * custom objects to avoid detection by normal "object detection"
0772:             * code patterns. This is used to implement document.all.
0773:             * See https://bugzilla.mozilla.org/show_bug.cgi?id=412247.
0774:             * This is an analog to JOF_DETECTING from SpiderMonkey; see
0775:             * https://bugzilla.mozilla.org/show_bug.cgi?id=248549.
0776:             * Other than this special case, embeddings should return false.
0777:             * @return true if this object should avoid object detection
0778:             * @since 1.7R1
0779:             */
0780:            public boolean avoidObjectDetection() {
0781:                return false;
0782:            }
0783:
0784:            /**
0785:             * Custom <tt>==</tt> operator.
0786:             * Must return {@link Scriptable#NOT_FOUND} if this object does not
0787:             * have custom equality operator for the given value,
0788:             * <tt>Boolean.TRUE</tt> if this object is equivalent to <tt>value</tt>,
0789:             * <tt>Boolean.FALSE</tt> if this object is not equivalent to
0790:             * <tt>value</tt>.
0791:             * <p>
0792:             * The default implementation returns Boolean.TRUE
0793:             * if <tt>this == value</tt> or {@link Scriptable#NOT_FOUND} otherwise.
0794:             * It indicates that by default custom equality is available only if
0795:             * <tt>value</tt> is <tt>this</tt> in which case true is returned.
0796:             */
0797:            protected Object equivalentValues(Object value) {
0798:                return (this  == value) ? Boolean.TRUE : Scriptable.NOT_FOUND;
0799:            }
0800:
0801:            /**
0802:             * Defines JavaScript objects from a Java class that implements Scriptable.
0803:             *
0804:             * If the given class has a method
0805:             * <pre>
0806:             * static void init(Context cx, Scriptable scope, boolean sealed);</pre>
0807:             *
0808:             * or its compatibility form
0809:             * <pre>
0810:             * static void init(Scriptable scope);</pre>
0811:             *
0812:             * then it is invoked and no further initialization is done.<p>
0813:             *
0814:             * However, if no such a method is found, then the class's constructors and
0815:             * methods are used to initialize a class in the following manner.<p>
0816:             *
0817:             * First, the zero-parameter constructor of the class is called to
0818:             * create the prototype. If no such constructor exists,
0819:             * a {@link EvaluatorException} is thrown. <p>
0820:             *
0821:             * Next, all methods are scanned for special prefixes that indicate that they
0822:             * have special meaning for defining JavaScript objects.
0823:             * These special prefixes are
0824:             * <ul>
0825:             * <li><code>jsFunction_</code> for a JavaScript function
0826:             * <li><code>jsStaticFunction_</code> for a JavaScript function that
0827:             *           is a property of the constructor
0828:             * <li><code>jsGet_</code> for a getter of a JavaScript property
0829:             * <li><code>jsSet_</code> for a setter of a JavaScript property
0830:             * <li><code>jsConstructor</code> for a JavaScript function that
0831:             *           is the constructor
0832:             * </ul><p>
0833:             *
0834:             * If the method's name begins with "jsFunction_", a JavaScript function
0835:             * is created with a name formed from the rest of the Java method name
0836:             * following "jsFunction_". So a Java method named "jsFunction_foo" will
0837:             * define a JavaScript method "foo". Calling this JavaScript function
0838:             * will cause the Java method to be called. The parameters of the method
0839:             * must be of number and types as defined by the FunctionObject class.
0840:             * The JavaScript function is then added as a property
0841:             * of the prototype. <p>
0842:             *
0843:             * If the method's name begins with "jsStaticFunction_", it is handled
0844:             * similarly except that the resulting JavaScript function is added as a
0845:             * property of the constructor object. The Java method must be static.
0846:             *
0847:             * If the method's name begins with "jsGet_" or "jsSet_", the method is
0848:             * considered to define a property. Accesses to the defined property
0849:             * will result in calls to these getter and setter methods. If no
0850:             * setter is defined, the property is defined as READONLY.<p>
0851:             *
0852:             * If the method's name is "jsConstructor", the method is
0853:             * considered to define the body of the constructor. Only one
0854:             * method of this name may be defined.
0855:             * If no method is found that can serve as constructor, a Java
0856:             * constructor will be selected to serve as the JavaScript
0857:             * constructor in the following manner. If the class has only one
0858:             * Java constructor, that constructor is used to define
0859:             * the JavaScript constructor. If the the class has two constructors,
0860:             * one must be the zero-argument constructor (otherwise an
0861:             * {@link EvaluatorException} would have already been thrown
0862:             * when the prototype was to be created). In this case
0863:             * the Java constructor with one or more parameters will be used
0864:             * to define the JavaScript constructor. If the class has three
0865:             * or more constructors, an {@link EvaluatorException}
0866:             * will be thrown.<p>
0867:             *
0868:             * Finally, if there is a method
0869:             * <pre>
0870:             * static void finishInit(Scriptable scope, FunctionObject constructor,
0871:             *                        Scriptable prototype)</pre>
0872:             *
0873:             * it will be called to finish any initialization. The <code>scope</code>
0874:             * argument will be passed, along with the newly created constructor and
0875:             * the newly created prototype.<p>
0876:             *
0877:             * @param scope The scope in which to define the constructor.
0878:             * @param clazz The Java class to use to define the JavaScript objects
0879:             *              and properties.
0880:             * @exception IllegalAccessException if access is not available
0881:             *            to a reflected class member
0882:             * @exception InstantiationException if unable to instantiate
0883:             *            the named class
0884:             * @exception InvocationTargetException if an exception is thrown
0885:             *            during execution of methods of the named class
0886:             * @see org.mozilla.javascript.Function
0887:             * @see org.mozilla.javascript.FunctionObject
0888:             * @see org.mozilla.javascript.ScriptableObject#READONLY
0889:             * @see org.mozilla.javascript.ScriptableObject
0890:             *      #defineProperty(String, Class, int)
0891:             */
0892:            public static void defineClass(Scriptable scope, Class clazz)
0893:                    throws IllegalAccessException, InstantiationException,
0894:                    InvocationTargetException {
0895:                defineClass(scope, clazz, false, false);
0896:            }
0897:
0898:            /**
0899:             * Defines JavaScript objects from a Java class, optionally
0900:             * allowing sealing.
0901:             *
0902:             * Similar to <code>defineClass(Scriptable scope, Class clazz)</code>
0903:             * except that sealing is allowed. An object that is sealed cannot have
0904:             * properties added or removed. Note that sealing is not allowed in
0905:             * the current ECMA/ISO language specification, but is likely for
0906:             * the next version.
0907:             *
0908:             * @param scope The scope in which to define the constructor.
0909:             * @param clazz The Java class to use to define the JavaScript objects
0910:             *              and properties. The class must implement Scriptable.
0911:             * @param sealed Whether or not to create sealed standard objects that
0912:             *               cannot be modified.
0913:             * @exception IllegalAccessException if access is not available
0914:             *            to a reflected class member
0915:             * @exception InstantiationException if unable to instantiate
0916:             *            the named class
0917:             * @exception InvocationTargetException if an exception is thrown
0918:             *            during execution of methods of the named class
0919:             * @since 1.4R3
0920:             */
0921:            public static void defineClass(Scriptable scope, Class clazz,
0922:                    boolean sealed) throws IllegalAccessException,
0923:                    InstantiationException, InvocationTargetException {
0924:                defineClass(scope, clazz, sealed, false);
0925:            }
0926:
0927:            /**
0928:             * Defines JavaScript objects from a Java class, optionally
0929:             * allowing sealing and mapping of Java inheritance to JavaScript
0930:             * prototype-based inheritance.
0931:             *
0932:             * Similar to <code>defineClass(Scriptable scope, Class clazz)</code>
0933:             * except that sealing and inheritance mapping are allowed. An object
0934:             * that is sealed cannot have properties added or removed. Note that
0935:             * sealing is not allowed in the current ECMA/ISO language specification,
0936:             * but is likely for the next version.
0937:             *
0938:             * @param scope The scope in which to define the constructor.
0939:             * @param clazz The Java class to use to define the JavaScript objects
0940:             *              and properties. The class must implement Scriptable.
0941:             * @param sealed Whether or not to create sealed standard objects that
0942:             *               cannot be modified.
0943:             * @param mapInheritance Whether or not to map Java inheritance to
0944:             *                       JavaScript prototype-based inheritance.
0945:             * @return the class name for the prototype of the specified class
0946:             * @exception IllegalAccessException if access is not available
0947:             *            to a reflected class member
0948:             * @exception InstantiationException if unable to instantiate
0949:             *            the named class
0950:             * @exception InvocationTargetException if an exception is thrown
0951:             *            during execution of methods of the named class
0952:             * @since 1.6R2
0953:             */
0954:            public static String defineClass(Scriptable scope, Class clazz,
0955:                    boolean sealed, boolean mapInheritance)
0956:                    throws IllegalAccessException, InstantiationException,
0957:                    InvocationTargetException {
0958:                BaseFunction ctor = buildClassCtor(scope, clazz, sealed,
0959:                        mapInheritance);
0960:                if (ctor == null)
0961:                    return null;
0962:                String name = ctor.getClassPrototype().getClassName();
0963:                defineProperty(scope, name, ctor, ScriptableObject.DONTENUM);
0964:                return name;
0965:            }
0966:
0967:            static BaseFunction buildClassCtor(Scriptable scope, Class clazz,
0968:                    boolean sealed, boolean mapInheritance)
0969:                    throws IllegalAccessException, InstantiationException,
0970:                    InvocationTargetException {
0971:                Method[] methods = FunctionObject.getMethodList(clazz);
0972:                for (int i = 0; i < methods.length; i++) {
0973:                    Method method = methods[i];
0974:                    if (!method.getName().equals("init"))
0975:                        continue;
0976:                    Class[] parmTypes = method.getParameterTypes();
0977:                    if (parmTypes.length == 3
0978:                            && parmTypes[0] == ScriptRuntime.ContextClass
0979:                            && parmTypes[1] == ScriptRuntime.ScriptableClass
0980:                            && parmTypes[2] == Boolean.TYPE
0981:                            && Modifier.isStatic(method.getModifiers())) {
0982:                        Object args[] = { Context.getContext(), scope,
0983:                                sealed ? Boolean.TRUE : Boolean.FALSE };
0984:                        method.invoke(null, args);
0985:                        return null;
0986:                    }
0987:                    if (parmTypes.length == 1
0988:                            && parmTypes[0] == ScriptRuntime.ScriptableClass
0989:                            && Modifier.isStatic(method.getModifiers())) {
0990:                        Object args[] = { scope };
0991:                        method.invoke(null, args);
0992:                        return null;
0993:                    }
0994:
0995:                }
0996:
0997:                // If we got here, there isn't an "init" method with the right
0998:                // parameter types.
0999:
1000:                Constructor[] ctors = clazz.getConstructors();
1001:                Constructor protoCtor = null;
1002:                for (int i = 0; i < ctors.length; i++) {
1003:                    if (ctors[i].getParameterTypes().length == 0) {
1004:                        protoCtor = ctors[i];
1005:                        break;
1006:                    }
1007:                }
1008:                if (protoCtor == null) {
1009:                    throw Context.reportRuntimeError1("msg.zero.arg.ctor",
1010:                            clazz.getName());
1011:                }
1012:
1013:                Scriptable proto = (Scriptable) protoCtor
1014:                        .newInstance(ScriptRuntime.emptyArgs);
1015:                String className = proto.getClassName();
1016:
1017:                // Set the prototype's prototype, trying to map Java inheritance to JS
1018:                // prototype-based inheritance if requested to do so.
1019:                Scriptable super Proto = null;
1020:                if (mapInheritance) {
1021:                    Class super Class = clazz.getSuperclass();
1022:                    if (ScriptRuntime.ScriptableClass
1023:                            .isAssignableFrom(super Class)
1024:                            && !Modifier.isAbstract(super Class.getModifiers())) {
1025:                        String name = ScriptableObject.defineClass(scope,
1026:                                super Class, sealed, mapInheritance);
1027:                        if (name != null) {
1028:                            super Proto = ScriptableObject.getClassPrototype(
1029:                                    scope, name);
1030:                        }
1031:                    }
1032:                }
1033:                if (super Proto == null) {
1034:                    super Proto = ScriptableObject.getObjectPrototype(scope);
1035:                }
1036:                proto.setPrototype(super Proto);
1037:
1038:                // Find out whether there are any methods that begin with
1039:                // "js". If so, then only methods that begin with special
1040:                // prefixes will be defined as JavaScript entities.
1041:                final String functionPrefix = "jsFunction_";
1042:                final String staticFunctionPrefix = "jsStaticFunction_";
1043:                final String getterPrefix = "jsGet_";
1044:                final String setterPrefix = "jsSet_";
1045:                final String ctorName = "jsConstructor";
1046:
1047:                Member ctorMember = FunctionObject.findSingleMethod(methods,
1048:                        ctorName);
1049:
1050:                if (ctorMember == null) {
1051:                    if (ctors.length == 1) {
1052:                        ctorMember = ctors[0];
1053:                    } else if (ctors.length == 2) {
1054:                        if (ctors[0].getParameterTypes().length == 0)
1055:                            ctorMember = ctors[1];
1056:                        else if (ctors[1].getParameterTypes().length == 0)
1057:                            ctorMember = ctors[0];
1058:                    }
1059:                    if (ctorMember == null) {
1060:                        throw Context.reportRuntimeError1(
1061:                                "msg.ctor.multiple.parms", clazz.getName());
1062:                    }
1063:                }
1064:
1065:                FunctionObject ctor = new FunctionObject(className, ctorMember,
1066:                        scope);
1067:                if (ctor.isVarArgsMethod()) {
1068:                    throw Context.reportRuntimeError1("msg.varargs.ctor",
1069:                            ctorMember.getName());
1070:                }
1071:                ctor.initAsConstructor(scope, proto);
1072:
1073:                Method finishInit = null;
1074:                for (int i = 0; i < methods.length; i++) {
1075:                    if (methods[i] == ctorMember) {
1076:                        continue;
1077:                    }
1078:                    String name = methods[i].getName();
1079:                    if (name.equals("finishInit")) {
1080:                        Class[] parmTypes = methods[i].getParameterTypes();
1081:                        if (parmTypes.length == 3
1082:                                && parmTypes[0] == ScriptRuntime.ScriptableClass
1083:                                && parmTypes[1] == FunctionObject.class
1084:                                && parmTypes[2] == ScriptRuntime.ScriptableClass
1085:                                && Modifier.isStatic(methods[i].getModifiers())) {
1086:                            finishInit = methods[i];
1087:                            continue;
1088:                        }
1089:                    }
1090:                    // ignore any compiler generated methods.
1091:                    if (name.indexOf('$') != -1)
1092:                        continue;
1093:                    if (name.equals(ctorName))
1094:                        continue;
1095:
1096:                    String prefix = null;
1097:                    if (name.startsWith(functionPrefix)) {
1098:                        prefix = functionPrefix;
1099:                    } else if (name.startsWith(staticFunctionPrefix)) {
1100:                        prefix = staticFunctionPrefix;
1101:                        if (!Modifier.isStatic(methods[i].getModifiers())) {
1102:                            throw Context
1103:                                    .reportRuntimeError("jsStaticFunction must be used with static method.");
1104:                        }
1105:                    } else if (name.startsWith(getterPrefix)) {
1106:                        prefix = getterPrefix;
1107:                    } else if (name.startsWith(setterPrefix)) {
1108:                        prefix = setterPrefix;
1109:                    } else {
1110:                        continue;
1111:                    }
1112:                    name = name.substring(prefix.length());
1113:                    if (prefix == setterPrefix)
1114:                        continue; // deal with set when we see get
1115:                    if (prefix == getterPrefix) {
1116:                        if (!(proto instanceof  ScriptableObject)) {
1117:                            throw Context.reportRuntimeError2(
1118:                                    "msg.extend.scriptable", proto.getClass()
1119:                                            .toString(), name);
1120:                        }
1121:                        Method setter = FunctionObject.findSingleMethod(
1122:                                methods, setterPrefix + name);
1123:                        int attr = ScriptableObject.PERMANENT
1124:                                | ScriptableObject.DONTENUM
1125:                                | (setter != null ? 0
1126:                                        : ScriptableObject.READONLY);
1127:                        ((ScriptableObject) proto).defineProperty(name, null,
1128:                                methods[i], setter, attr);
1129:                        continue;
1130:                    }
1131:
1132:                    FunctionObject f = new FunctionObject(name, methods[i],
1133:                            proto);
1134:                    if (f.isVarArgsConstructor()) {
1135:                        throw Context.reportRuntimeError1("msg.varargs.fun",
1136:                                ctorMember.getName());
1137:                    }
1138:                    Scriptable dest = prefix == staticFunctionPrefix ? ctor
1139:                            : proto;
1140:                    defineProperty(dest, name, f, DONTENUM);
1141:                    if (sealed) {
1142:                        f.sealObject();
1143:                    }
1144:                }
1145:
1146:                // Call user code to complete initialization if necessary.
1147:                if (finishInit != null) {
1148:                    Object[] finishArgs = { scope, ctor, proto };
1149:                    finishInit.invoke(null, finishArgs);
1150:                }
1151:
1152:                // Seal the object if necessary.
1153:                if (sealed) {
1154:                    ctor.sealObject();
1155:                    if (proto instanceof  ScriptableObject) {
1156:                        ((ScriptableObject) proto).sealObject();
1157:                    }
1158:                }
1159:
1160:                return ctor;
1161:            }
1162:
1163:            /**
1164:             * Define a JavaScript property.
1165:             *
1166:             * Creates the property with an initial value and sets its attributes.
1167:             *
1168:             * @param propertyName the name of the property to define.
1169:             * @param value the initial value of the property
1170:             * @param attributes the attributes of the JavaScript property
1171:             * @see org.mozilla.javascript.Scriptable#put(String, Scriptable, Object)
1172:             */
1173:            public void defineProperty(String propertyName, Object value,
1174:                    int attributes) {
1175:                checkNotSealed(propertyName, 0);
1176:                put(propertyName, this , value);
1177:                setAttributes(propertyName, attributes);
1178:            }
1179:
1180:            /**
1181:             * Utility method to add properties to arbitrary Scriptable object.
1182:             * If destination is instance of ScriptableObject, calls
1183:             * defineProperty there, otherwise calls put in destination
1184:             * ignoring attributes
1185:             */
1186:            public static void defineProperty(Scriptable destination,
1187:                    String propertyName, Object value, int attributes) {
1188:                if (!(destination instanceof  ScriptableObject)) {
1189:                    destination.put(propertyName, destination, value);
1190:                    return;
1191:                }
1192:                ScriptableObject so = (ScriptableObject) destination;
1193:                so.defineProperty(propertyName, value, attributes);
1194:            }
1195:
1196:            /**
1197:             * Utility method to add properties to arbitrary Scriptable object.
1198:             * If destination is instance of ScriptableObject, calls
1199:             * defineProperty there, otherwise calls put in destination
1200:             * ignoring attributes
1201:             */
1202:            public static void defineConstProperty(Scriptable destination,
1203:                    String propertyName) {
1204:                if (destination instanceof  ConstProperties) {
1205:                    ConstProperties cp = (ConstProperties) destination;
1206:                    cp.defineConst(propertyName, destination);
1207:                } else
1208:                    defineProperty(destination, propertyName,
1209:                            Undefined.instance, CONST);
1210:            }
1211:
1212:            /**
1213:             * Define a JavaScript property with getter and setter side effects.
1214:             *
1215:             * If the setter is not found, the attribute READONLY is added to
1216:             * the given attributes. <p>
1217:             *
1218:             * The getter must be a method with zero parameters, and the setter, if
1219:             * found, must be a method with one parameter.<p>
1220:             *
1221:             * @param propertyName the name of the property to define. This name
1222:             *                    also affects the name of the setter and getter
1223:             *                    to search for. If the propertyId is "foo", then
1224:             *                    <code>clazz</code> will be searched for "getFoo"
1225:             *                    and "setFoo" methods.
1226:             * @param clazz the Java class to search for the getter and setter
1227:             * @param attributes the attributes of the JavaScript property
1228:             * @see org.mozilla.javascript.Scriptable#put(String, Scriptable, Object)
1229:             */
1230:            public void defineProperty(String propertyName, Class clazz,
1231:                    int attributes) {
1232:                int length = propertyName.length();
1233:                if (length == 0)
1234:                    throw new IllegalArgumentException();
1235:                char[] buf = new char[3 + length];
1236:                propertyName.getChars(0, length, buf, 3);
1237:                buf[3] = Character.toUpperCase(buf[3]);
1238:                buf[0] = 'g';
1239:                buf[1] = 'e';
1240:                buf[2] = 't';
1241:                String getterName = new String(buf);
1242:                buf[0] = 's';
1243:                String setterName = new String(buf);
1244:
1245:                Method[] methods = FunctionObject.getMethodList(clazz);
1246:                Method getter = FunctionObject.findSingleMethod(methods,
1247:                        getterName);
1248:                Method setter = FunctionObject.findSingleMethod(methods,
1249:                        setterName);
1250:                if (setter == null)
1251:                    attributes |= ScriptableObject.READONLY;
1252:                defineProperty(propertyName, null, getter,
1253:                        setter == null ? null : setter, attributes);
1254:            }
1255:
1256:            /**
1257:             * Define a JavaScript property.
1258:             *
1259:             * Use this method only if you wish to define getters and setters for
1260:             * a given property in a ScriptableObject. To create a property without
1261:             * special getter or setter side effects, use
1262:             * <code>defineProperty(String,int)</code>.
1263:             *
1264:             * If <code>setter</code> is null, the attribute READONLY is added to
1265:             * the given attributes.<p>
1266:             *
1267:             * Several forms of getters or setters are allowed. In all cases the
1268:             * type of the value parameter can be any one of the following types:
1269:             * Object, String, boolean, Scriptable, byte, short, int, long, float,
1270:             * or double. The runtime will perform appropriate conversions based
1271:             * upon the type of the parameter (see description in FunctionObject).
1272:             * The first forms are nonstatic methods of the class referred to
1273:             * by 'this':
1274:             * <pre>
1275:             * Object getFoo();
1276:             * void setFoo(SomeType value);</pre>
1277:             * Next are static methods that may be of any class; the object whose
1278:             * property is being accessed is passed in as an extra argument:
1279:             * <pre>
1280:             * static Object getFoo(Scriptable obj);
1281:             * static void setFoo(Scriptable obj, SomeType value);</pre>
1282:             * Finally, it is possible to delegate to another object entirely using
1283:             * the <code>delegateTo</code> parameter. In this case the methods are
1284:             * nonstatic methods of the class delegated to, and the object whose
1285:             * property is being accessed is passed in as an extra argument:
1286:             * <pre>
1287:             * Object getFoo(Scriptable obj);
1288:             * void setFoo(Scriptable obj, SomeType value);</pre>
1289:             *
1290:             * @param propertyName the name of the property to define.
1291:             * @param delegateTo an object to call the getter and setter methods on,
1292:             *                   or null, depending on the form used above.
1293:             * @param getter the method to invoke to get the value of the property
1294:             * @param setter the method to invoke to set the value of the property
1295:             * @param attributes the attributes of the JavaScript property
1296:             */
1297:            public void defineProperty(String propertyName, Object delegateTo,
1298:                    Method getter, Method setter, int attributes) {
1299:                MemberBox getterBox = null;
1300:                if (getter != null) {
1301:                    getterBox = new MemberBox(getter);
1302:
1303:                    boolean delegatedForm;
1304:                    if (!Modifier.isStatic(getter.getModifiers())) {
1305:                        delegatedForm = (delegateTo != null);
1306:                        getterBox.delegateTo = delegateTo;
1307:                    } else {
1308:                        delegatedForm = true;
1309:                        // Ignore delegateTo for static getter but store
1310:                        // non-null delegateTo indicator.
1311:                        getterBox.delegateTo = Void.TYPE;
1312:                    }
1313:
1314:                    String errorId = null;
1315:                    Class[] parmTypes = getter.getParameterTypes();
1316:                    if (parmTypes.length == 0) {
1317:                        if (delegatedForm) {
1318:                            errorId = "msg.obj.getter.parms";
1319:                        }
1320:                    } else if (parmTypes.length == 1) {
1321:                        Object argType = parmTypes[0];
1322:                        // Allow ScriptableObject for compatibility
1323:                        if (!(argType == ScriptRuntime.ScriptableClass || argType == ScriptRuntime.ScriptableObjectClass)) {
1324:                            errorId = "msg.bad.getter.parms";
1325:                        } else if (!delegatedForm) {
1326:                            errorId = "msg.bad.getter.parms";
1327:                        }
1328:                    } else {
1329:                        errorId = "msg.bad.getter.parms";
1330:                    }
1331:                    if (errorId != null) {
1332:                        throw Context.reportRuntimeError1(errorId, getter
1333:                                .toString());
1334:                    }
1335:                }
1336:
1337:                MemberBox setterBox = null;
1338:                if (setter != null) {
1339:                    if (setter.getReturnType() != Void.TYPE)
1340:                        throw Context.reportRuntimeError1("msg.setter.return",
1341:                                setter.toString());
1342:
1343:                    setterBox = new MemberBox(setter);
1344:
1345:                    boolean delegatedForm;
1346:                    if (!Modifier.isStatic(setter.getModifiers())) {
1347:                        delegatedForm = (delegateTo != null);
1348:                        setterBox.delegateTo = delegateTo;
1349:                    } else {
1350:                        delegatedForm = true;
1351:                        // Ignore delegateTo for static setter but store
1352:                        // non-null delegateTo indicator.
1353:                        setterBox.delegateTo = Void.TYPE;
1354:                    }
1355:
1356:                    String errorId = null;
1357:                    Class[] parmTypes = setter.getParameterTypes();
1358:                    if (parmTypes.length == 1) {
1359:                        if (delegatedForm) {
1360:                            errorId = "msg.setter2.expected";
1361:                        }
1362:                    } else if (parmTypes.length == 2) {
1363:                        Object argType = parmTypes[0];
1364:                        // Allow ScriptableObject for compatibility
1365:                        if (!(argType == ScriptRuntime.ScriptableClass || argType == ScriptRuntime.ScriptableObjectClass)) {
1366:                            errorId = "msg.setter2.parms";
1367:                        } else if (!delegatedForm) {
1368:                            errorId = "msg.setter1.parms";
1369:                        }
1370:                    } else {
1371:                        errorId = "msg.setter.parms";
1372:                    }
1373:                    if (errorId != null) {
1374:                        throw Context.reportRuntimeError1(errorId, setter
1375:                                .toString());
1376:                    }
1377:                }
1378:
1379:                GetterSlot gslot = (GetterSlot) getSlot(propertyName, 0,
1380:                        SLOT_MODIFY_GETTER_SETTER);
1381:                gslot.setAttributes(attributes);
1382:                gslot.getter = getterBox;
1383:                gslot.setter = setterBox;
1384:            }
1385:
1386:            /**
1387:             * Search for names in a class, adding the resulting methods
1388:             * as properties.
1389:             *
1390:             * <p> Uses reflection to find the methods of the given names. Then
1391:             * FunctionObjects are constructed from the methods found, and
1392:             * are added to this object as properties with the given names.
1393:             *
1394:             * @param names the names of the Methods to add as function properties
1395:             * @param clazz the class to search for the Methods
1396:             * @param attributes the attributes of the new properties
1397:             * @see org.mozilla.javascript.FunctionObject
1398:             */
1399:            public void defineFunctionProperties(String[] names, Class clazz,
1400:                    int attributes) {
1401:                Method[] methods = FunctionObject.getMethodList(clazz);
1402:                for (int i = 0; i < names.length; i++) {
1403:                    String name = names[i];
1404:                    Method m = FunctionObject.findSingleMethod(methods, name);
1405:                    if (m == null) {
1406:                        throw Context.reportRuntimeError2(
1407:                                "msg.method.not.found", name, clazz.getName());
1408:                    }
1409:                    FunctionObject f = new FunctionObject(name, m, this );
1410:                    defineProperty(name, f, attributes);
1411:                }
1412:            }
1413:
1414:            /**
1415:             * Get the Object.prototype property.
1416:             * See ECMA 15.2.4.
1417:             */
1418:            public static Scriptable getObjectPrototype(Scriptable scope) {
1419:                return getClassPrototype(scope, "Object");
1420:            }
1421:
1422:            /**
1423:             * Get the Function.prototype property.
1424:             * See ECMA 15.3.4.
1425:             */
1426:            public static Scriptable getFunctionPrototype(Scriptable scope) {
1427:                return getClassPrototype(scope, "Function");
1428:            }
1429:
1430:            /**
1431:             * Get the prototype for the named class.
1432:             *
1433:             * For example, <code>getClassPrototype(s, "Date")</code> will first
1434:             * walk up the parent chain to find the outermost scope, then will
1435:             * search that scope for the Date constructor, and then will
1436:             * return Date.prototype. If any of the lookups fail, or
1437:             * the prototype is not a JavaScript object, then null will
1438:             * be returned.
1439:             *
1440:             * @param scope an object in the scope chain
1441:             * @param className the name of the constructor
1442:             * @return the prototype for the named class, or null if it
1443:             *         cannot be found.
1444:             */
1445:            public static Scriptable getClassPrototype(Scriptable scope,
1446:                    String className) {
1447:                scope = getTopLevelScope(scope);
1448:                Object ctor = getProperty(scope, className);
1449:                Object proto;
1450:                if (ctor instanceof  BaseFunction) {
1451:                    proto = ((BaseFunction) ctor).getPrototypeProperty();
1452:                } else if (ctor instanceof  Scriptable) {
1453:                    Scriptable ctorObj = (Scriptable) ctor;
1454:                    proto = ctorObj.get("prototype", ctorObj);
1455:                } else {
1456:                    return null;
1457:                }
1458:                if (proto instanceof  Scriptable) {
1459:                    return (Scriptable) proto;
1460:                }
1461:                return null;
1462:            }
1463:
1464:            /**
1465:             * Get the global scope.
1466:             *
1467:             * <p>Walks the parent scope chain to find an object with a null
1468:             * parent scope (the global object).
1469:             *
1470:             * @param obj a JavaScript object
1471:             * @return the corresponding global scope
1472:             */
1473:            public static Scriptable getTopLevelScope(Scriptable obj) {
1474:                for (;;) {
1475:                    Scriptable parent = obj.getParentScope();
1476:                    if (parent == null) {
1477:                        return obj;
1478:                    }
1479:                    obj = parent;
1480:                }
1481:            }
1482:
1483:            /**
1484:             * Seal this object.
1485:             *
1486:             * A sealed object may not have properties added or removed. Once
1487:             * an object is sealed it may not be unsealed.
1488:             *
1489:             * @since 1.4R3
1490:             */
1491:            public synchronized void sealObject() {
1492:                if (count >= 0) {
1493:                    count = ~count;
1494:                }
1495:            }
1496:
1497:            /**
1498:             * Return true if this object is sealed.
1499:             *
1500:             * It is an error to attempt to add or remove properties to
1501:             * a sealed object.
1502:             *
1503:             * @return true if sealed, false otherwise.
1504:             * @since 1.4R3
1505:             */
1506:            public final boolean isSealed() {
1507:                return count < 0;
1508:            }
1509:
1510:            private void checkNotSealed(String name, int index) {
1511:                if (!isSealed())
1512:                    return;
1513:
1514:                String str = (name != null) ? name : Integer.toString(index);
1515:                throw Context.reportRuntimeError1("msg.modify.sealed", str);
1516:            }
1517:
1518:            /**
1519:             * Gets a named property from an object or any object in its prototype chain.
1520:             * <p>
1521:             * Searches the prototype chain for a property named <code>name</code>.
1522:             * <p>
1523:             * @param obj a JavaScript object
1524:             * @param name a property name
1525:             * @return the value of a property with name <code>name</code> found in
1526:             *         <code>obj</code> or any object in its prototype chain, or
1527:             *         <code>Scriptable.NOT_FOUND</code> if not found
1528:             * @since 1.5R2
1529:             */
1530:            public static Object getProperty(Scriptable obj, String name) {
1531:                Scriptable start = obj;
1532:                Object result;
1533:                do {
1534:                    result = obj.get(name, start);
1535:                    if (result != Scriptable.NOT_FOUND)
1536:                        break;
1537:                    obj = obj.getPrototype();
1538:                } while (obj != null);
1539:                return result;
1540:            }
1541:
1542:            /**
1543:             * Gets an indexed property from an object or any object in its prototype chain.
1544:             * <p>
1545:             * Searches the prototype chain for a property with integral index
1546:             * <code>index</code>. Note that if you wish to look for properties with numerical
1547:             * but non-integral indicies, you should use getProperty(Scriptable,String) with
1548:             * the string value of the index.
1549:             * <p>
1550:             * @param obj a JavaScript object
1551:             * @param index an integral index
1552:             * @return the value of a property with index <code>index</code> found in
1553:             *         <code>obj</code> or any object in its prototype chain, or
1554:             *         <code>Scriptable.NOT_FOUND</code> if not found
1555:             * @since 1.5R2
1556:             */
1557:            public static Object getProperty(Scriptable obj, int index) {
1558:                Scriptable start = obj;
1559:                Object result;
1560:                do {
1561:                    result = obj.get(index, start);
1562:                    if (result != Scriptable.NOT_FOUND)
1563:                        break;
1564:                    obj = obj.getPrototype();
1565:                } while (obj != null);
1566:                return result;
1567:            }
1568:
1569:            /**
1570:             * Returns whether a named property is defined in an object or any object
1571:             * in its prototype chain.
1572:             * <p>
1573:             * Searches the prototype chain for a property named <code>name</code>.
1574:             * <p>
1575:             * @param obj a JavaScript object
1576:             * @param name a property name
1577:             * @return the true if property was found
1578:             * @since 1.5R2
1579:             */
1580:            public static boolean hasProperty(Scriptable obj, String name) {
1581:                return null != getBase(obj, name);
1582:            }
1583:
1584:            /**
1585:             * If hasProperty(obj, name) would return true, then if the property that
1586:             * was found is compatible with the new property, this method just returns.
1587:             * If the property is not compatible, then an exception is thrown.
1588:             *
1589:             * A property redefinition is incompatible if the first definition was a
1590:             * const declaration or if this one is.  They are compatible only if neither
1591:             * was const.
1592:             */
1593:            public static void redefineProperty(Scriptable obj, String name,
1594:                    boolean isConst) {
1595:                Scriptable base = getBase(obj, name);
1596:                if (base == null)
1597:                    return;
1598:                if (base instanceof  ConstProperties) {
1599:                    ConstProperties cp = (ConstProperties) base;
1600:
1601:                    if (cp.isConst(name))
1602:                        throw Context.reportRuntimeError1("msg.const.redecl",
1603:                                name);
1604:                }
1605:                if (isConst)
1606:                    throw Context.reportRuntimeError1("msg.var.redecl", name);
1607:            }
1608:
1609:            /**
1610:             * Returns whether an indexed property is defined in an object or any object
1611:             * in its prototype chain.
1612:             * <p>
1613:             * Searches the prototype chain for a property with index <code>index</code>.
1614:             * <p>
1615:             * @param obj a JavaScript object
1616:             * @param index a property index
1617:             * @return the true if property was found
1618:             * @since 1.5R2
1619:             */
1620:            public static boolean hasProperty(Scriptable obj, int index) {
1621:                return null != getBase(obj, index);
1622:            }
1623:
1624:            /**
1625:             * Puts a named property in an object or in an object in its prototype chain.
1626:             * <p>
1627:             * Searches for the named property in the prototype chain. If it is found,
1628:             * the value of the property in <code>obj</code> is changed through a call
1629:             * to {@link Scriptable#put(String, Scriptable, Object)} on the
1630:             * prototype passing <code>obj</code> as the <code>start</code> argument.
1631:             * This allows the prototype to veto the property setting in case the
1632:             * prototype defines the property with [[ReadOnly]] attribute. If the
1633:             * property is not found, it is added in <code>obj</code>.
1634:             * @param obj a JavaScript object
1635:             * @param name a property name
1636:             * @param value any JavaScript value accepted by Scriptable.put
1637:             * @since 1.5R2
1638:             */
1639:            public static void putProperty(Scriptable obj, String name,
1640:                    Object value) {
1641:                Scriptable base = getBase(obj, name);
1642:                if (base == null)
1643:                    base = obj;
1644:                base.put(name, obj, value);
1645:            }
1646:
1647:            /**
1648:             * Puts a named property in an object or in an object in its prototype chain.
1649:             * <p>
1650:             * Searches for the named property in the prototype chain. If it is found,
1651:             * the value of the property in <code>obj</code> is changed through a call
1652:             * to {@link Scriptable#put(String, Scriptable, Object)} on the
1653:             * prototype passing <code>obj</code> as the <code>start</code> argument.
1654:             * This allows the prototype to veto the property setting in case the
1655:             * prototype defines the property with [[ReadOnly]] attribute. If the
1656:             * property is not found, it is added in <code>obj</code>.
1657:             * @param obj a JavaScript object
1658:             * @param name a property name
1659:             * @param value any JavaScript value accepted by Scriptable.put
1660:             * @since 1.5R2
1661:             */
1662:            public static void putConstProperty(Scriptable obj, String name,
1663:                    Object value) {
1664:                Scriptable base = getBase(obj, name);
1665:                if (base == null)
1666:                    base = obj;
1667:                if (base instanceof  ConstProperties)
1668:                    ((ConstProperties) base).putConst(name, obj, value);
1669:            }
1670:
1671:            /**
1672:             * Puts an indexed property in an object or in an object in its prototype chain.
1673:             * <p>
1674:             * Searches for the indexed property in the prototype chain. If it is found,
1675:             * the value of the property in <code>obj</code> is changed through a call
1676:             * to {@link Scriptable#put(int, Scriptable, Object)} on the prototype
1677:             * passing <code>obj</code> as the <code>start</code> argument. This allows
1678:             * the prototype to veto the property setting in case the prototype defines
1679:             * the property with [[ReadOnly]] attribute. If the property is not found, 
1680:             * it is added in <code>obj</code>.
1681:             * @param obj a JavaScript object
1682:             * @param index a property index
1683:             * @param value any JavaScript value accepted by Scriptable.put
1684:             * @since 1.5R2
1685:             */
1686:            public static void putProperty(Scriptable obj, int index,
1687:                    Object value) {
1688:                Scriptable base = getBase(obj, index);
1689:                if (base == null)
1690:                    base = obj;
1691:                base.put(index, obj, value);
1692:            }
1693:
1694:            /**
1695:             * Removes the property from an object or its prototype chain.
1696:             * <p>
1697:             * Searches for a property with <code>name</code> in obj or
1698:             * its prototype chain. If it is found, the object's delete
1699:             * method is called.
1700:             * @param obj a JavaScript object
1701:             * @param name a property name
1702:             * @return true if the property doesn't exist or was successfully removed
1703:             * @since 1.5R2
1704:             */
1705:            public static boolean deleteProperty(Scriptable obj, String name) {
1706:                Scriptable base = getBase(obj, name);
1707:                if (base == null)
1708:                    return true;
1709:                base.delete(name);
1710:                return !base.has(name, obj);
1711:            }
1712:
1713:            /**
1714:             * Removes the property from an object or its prototype chain.
1715:             * <p>
1716:             * Searches for a property with <code>index</code> in obj or
1717:             * its prototype chain. If it is found, the object's delete
1718:             * method is called.
1719:             * @param obj a JavaScript object
1720:             * @param index a property index
1721:             * @return true if the property doesn't exist or was successfully removed
1722:             * @since 1.5R2
1723:             */
1724:            public static boolean deleteProperty(Scriptable obj, int index) {
1725:                Scriptable base = getBase(obj, index);
1726:                if (base == null)
1727:                    return true;
1728:                base.delete(index);
1729:                return !base.has(index, obj);
1730:            }
1731:
1732:            /**
1733:             * Returns an array of all ids from an object and its prototypes.
1734:             * <p>
1735:             * @param obj a JavaScript object
1736:             * @return an array of all ids from all object in the prototype chain.
1737:             *         If a given id occurs multiple times in the prototype chain,
1738:             *         it will occur only once in this list.
1739:             * @since 1.5R2
1740:             */
1741:            public static Object[] getPropertyIds(Scriptable obj) {
1742:                if (obj == null) {
1743:                    return ScriptRuntime.emptyArgs;
1744:                }
1745:                Object[] result = obj.getIds();
1746:                ObjToIntMap map = null;
1747:                for (;;) {
1748:                    obj = obj.getPrototype();
1749:                    if (obj == null) {
1750:                        break;
1751:                    }
1752:                    Object[] ids = obj.getIds();
1753:                    if (ids.length == 0) {
1754:                        continue;
1755:                    }
1756:                    if (map == null) {
1757:                        if (result.length == 0) {
1758:                            result = ids;
1759:                            continue;
1760:                        }
1761:                        map = new ObjToIntMap(result.length + ids.length);
1762:                        for (int i = 0; i != result.length; ++i) {
1763:                            map.intern(result[i]);
1764:                        }
1765:                        result = null; // Allow to GC the result
1766:                    }
1767:                    for (int i = 0; i != ids.length; ++i) {
1768:                        map.intern(ids[i]);
1769:                    }
1770:                }
1771:                if (map != null) {
1772:                    result = map.getKeys();
1773:                }
1774:                return result;
1775:            }
1776:
1777:            /**
1778:             * Call a method of an object.
1779:             * @param obj the JavaScript object
1780:             * @param methodName the name of the function property
1781:             * @param args the arguments for the call
1782:             *
1783:             * @see Context#getCurrentContext()
1784:             */
1785:            public static Object callMethod(Scriptable obj, String methodName,
1786:                    Object[] args) {
1787:                return callMethod(null, obj, methodName, args);
1788:            }
1789:
1790:            /**
1791:             * Call a method of an object.
1792:             * @param cx the Context object associated with the current thread.
1793:             * @param obj the JavaScript object
1794:             * @param methodName the name of the function property
1795:             * @param args the arguments for the call
1796:             */
1797:            public static Object callMethod(Context cx, Scriptable obj,
1798:                    String methodName, Object[] args) {
1799:                Object funObj = getProperty(obj, methodName);
1800:                if (!(funObj instanceof  Function)) {
1801:                    throw ScriptRuntime.notFunctionError(obj, methodName);
1802:                }
1803:                Function fun = (Function) funObj;
1804:                // XXX: What should be the scope when calling funObj?
1805:                // The following favor scope stored in the object on the assumption
1806:                // that is more useful especially under dynamic scope setup.
1807:                // An alternative is to check for dynamic scope flag
1808:                // and use ScriptableObject.getTopLevelScope(fun) if the flag is not
1809:                // set. But that require access to Context and messy code
1810:                // so for now it is not checked.
1811:                Scriptable scope = ScriptableObject.getTopLevelScope(obj);
1812:                if (cx != null) {
1813:                    return fun.call(cx, scope, obj, args);
1814:                } else {
1815:                    return Context.call(null, fun, scope, obj, args);
1816:                }
1817:            }
1818:
1819:            private static Scriptable getBase(Scriptable obj, String name) {
1820:                do {
1821:                    if (obj.has(name, obj))
1822:                        break;
1823:                    obj = obj.getPrototype();
1824:                } while (obj != null);
1825:                return obj;
1826:            }
1827:
1828:            private static Scriptable getBase(Scriptable obj, int index) {
1829:                do {
1830:                    if (obj.has(index, obj))
1831:                        break;
1832:                    obj = obj.getPrototype();
1833:                } while (obj != null);
1834:                return obj;
1835:            }
1836:
1837:            /**
1838:             * Get arbitrary application-specific value associated with this object.
1839:             * @param key key object to select particular value.
1840:             * @see #associateValue(Object key, Object value)
1841:             */
1842:            public final Object getAssociatedValue(Object key) {
1843:                Hashtable h = associatedValues;
1844:                if (h == null)
1845:                    return null;
1846:                return h.get(key);
1847:            }
1848:
1849:            /**
1850:             * Get arbitrary application-specific value associated with the top scope
1851:             * of the given scope.
1852:             * The method first calls {@link #getTopLevelScope(Scriptable scope)}
1853:             * and then searches the prototype chain of the top scope for the first
1854:             * object containing the associated value with the given key.
1855:             *
1856:             * @param scope the starting scope.
1857:             * @param key key object to select particular value.
1858:             * @see #getAssociatedValue(Object key)
1859:             */
1860:            public static Object getTopScopeValue(Scriptable scope, Object key) {
1861:                scope = ScriptableObject.getTopLevelScope(scope);
1862:                for (;;) {
1863:                    if (scope instanceof  ScriptableObject) {
1864:                        ScriptableObject so = (ScriptableObject) scope;
1865:                        Object value = so.getAssociatedValue(key);
1866:                        if (value != null) {
1867:                            return value;
1868:                        }
1869:                    }
1870:                    scope = scope.getPrototype();
1871:                    if (scope == null) {
1872:                        return null;
1873:                    }
1874:                }
1875:            }
1876:
1877:            /**
1878:             * Associate arbitrary application-specific value with this object.
1879:             * Value can only be associated with the given object and key only once.
1880:             * The method ignores any subsequent attempts to change the already
1881:             * associated value.
1882:             * <p> The associated values are not serialized.
1883:             * @param key key object to select particular value.
1884:             * @param value the value to associate
1885:             * @return the passed value if the method is called first time for the
1886:             * given key or old value for any subsequent calls.
1887:             * @see #getAssociatedValue(Object key)
1888:             */
1889:            public final Object associateValue(Object key, Object value) {
1890:                if (value == null)
1891:                    throw new IllegalArgumentException();
1892:                Hashtable h = associatedValues;
1893:                if (h == null) {
1894:                    synchronized (this ) {
1895:                        h = associatedValues;
1896:                        if (h == null) {
1897:                            h = new Hashtable();
1898:                            associatedValues = h;
1899:                        }
1900:                    }
1901:                }
1902:                return Kit.initHash(h, key, value);
1903:            }
1904:
1905:            private Object getImpl(String name, int index, Scriptable start) {
1906:                Slot slot = getSlot(name, index, SLOT_QUERY);
1907:                if (slot == null) {
1908:                    return Scriptable.NOT_FOUND;
1909:                }
1910:                if (!(slot instanceof  GetterSlot)) {
1911:                    return slot.value;
1912:                }
1913:                Object getterObj = ((GetterSlot) slot).getter;
1914:                if (getterObj != null) {
1915:                    if (getterObj instanceof  MemberBox) {
1916:                        MemberBox nativeGetter = (MemberBox) getterObj;
1917:                        Object getterThis;
1918:                        Object[] args;
1919:                        if (nativeGetter.delegateTo == null) {
1920:                            getterThis = start;
1921:                            args = ScriptRuntime.emptyArgs;
1922:                        } else {
1923:                            getterThis = nativeGetter.delegateTo;
1924:                            args = new Object[] { start };
1925:                        }
1926:                        return nativeGetter.invoke(getterThis, args);
1927:                    } else {
1928:                        Function f = (Function) getterObj;
1929:                        Context cx = Context.getContext();
1930:                        return f.call(cx, f.getParentScope(), start,
1931:                                ScriptRuntime.emptyArgs);
1932:                    }
1933:                }
1934:                Object value = slot.value;
1935:                if (value instanceof  LazilyLoadedCtor) {
1936:                    LazilyLoadedCtor initializer = (LazilyLoadedCtor) value;
1937:                    try {
1938:                        initializer.init();
1939:                    } finally {
1940:                        value = initializer.getValue();
1941:                        slot.value = value;
1942:                    }
1943:                }
1944:                return value;
1945:            }
1946:
1947:            /**
1948:             *
1949:             * @param name
1950:             * @param index
1951:             * @param start
1952:             * @param value
1953:             * @param constFlag EMPTY means normal put.  UNINITIALIZED_CONST means
1954:             * defineConstProperty.  READONLY means const initialization expression.
1955:             * @return false if this != start and no slot was found.  true if this == start
1956:             * or this != start and a READONLY slot was found.
1957:             */
1958:            private boolean putImpl(String name, int index, Scriptable start,
1959:                    Object value, int constFlag) {
1960:                Slot slot;
1961:                if (this  != start) {
1962:                    slot = getSlot(name, index, SLOT_QUERY);
1963:                    if (slot == null) {
1964:                        return false;
1965:                    }
1966:                } else {
1967:                    checkNotSealed(name, index);
1968:                    // either const hoisted declaration or initialization
1969:                    if (constFlag != EMPTY) {
1970:                        slot = getSlot(name, index, SLOT_MODIFY_CONST);
1971:                        int attr = slot.getAttributes();
1972:                        if ((attr & READONLY) == 0)
1973:                            throw Context.reportRuntimeError1("msg.var.redecl",
1974:                                    name);
1975:                        if ((attr & UNINITIALIZED_CONST) != 0) {
1976:                            slot.value = value;
1977:                            // clear the bit on const initialization
1978:                            if (constFlag != UNINITIALIZED_CONST)
1979:                                slot.setAttributes(attr & ~UNINITIALIZED_CONST);
1980:                        }
1981:                        return true;
1982:                    }
1983:                    slot = getSlot(name, index, SLOT_MODIFY);
1984:                }
1985:                if ((slot.getAttributes() & READONLY) != 0)
1986:                    return true;
1987:                if (slot instanceof  GetterSlot) {
1988:                    Object setterObj = ((GetterSlot) slot).setter;
1989:                    if (setterObj != null) {
1990:                        Context cx = Context.getContext();
1991:                        if (setterObj instanceof  MemberBox) {
1992:                            MemberBox nativeSetter = (MemberBox) setterObj;
1993:                            Class pTypes[] = nativeSetter.argTypes;
1994:                            // XXX: cache tag since it is already calculated in
1995:                            // defineProperty ?
1996:                            Class valueType = pTypes[pTypes.length - 1];
1997:                            int tag = FunctionObject.getTypeTag(valueType);
1998:                            Object actualArg = FunctionObject.convertArg(cx,
1999:                                    start, value, tag);
2000:                            Object setterThis;
2001:                            Object[] args;
2002:                            if (nativeSetter.delegateTo == null) {
2003:                                setterThis = start;
2004:                                args = new Object[] { actualArg };
2005:                            } else {
2006:                                setterThis = nativeSetter.delegateTo;
2007:                                args = new Object[] { start, actualArg };
2008:                            }
2009:                            nativeSetter.invoke(setterThis, args);
2010:                        } else {
2011:                            Function f = (Function) setterObj;
2012:                            f.call(cx, f.getParentScope(), start,
2013:                                    new Object[] { value });
2014:                        }
2015:                        return true;
2016:                    }
2017:                }
2018:                if (this  == start) {
2019:                    slot.value = value;
2020:                    return true;
2021:                } else {
2022:                    return false;
2023:                }
2024:            }
2025:
2026:            private Slot findAttributeSlot(String name, int index,
2027:                    int accessType) {
2028:                Slot slot = getSlot(name, index, accessType);
2029:                if (slot == null) {
2030:                    String str = (name != null ? name : Integer.toString(index));
2031:                    throw Context
2032:                            .reportRuntimeError1("msg.prop.not.found", str);
2033:                }
2034:                return slot;
2035:            }
2036:
2037:            /**
2038:             * Locate the slot with given name or index.
2039:             *
2040:             * @param name property name or null if slot holds spare array index.
2041:             * @param index index or 0 if slot holds property name.
2042:             */
2043:            private Slot getSlot(String name, int index, int accessType) {
2044:                Slot slot;
2045:
2046:                // Query last access cache and check that it was not deleted.
2047:                lastAccessCheck: {
2048:                    slot = lastAccess;
2049:                    if (name != null) {
2050:                        if (name != slot.name)
2051:                            break lastAccessCheck;
2052:                        // No String.equals here as successful slot search update
2053:                        // name object with fresh reference of the same string.
2054:                    } else {
2055:                        if (slot.name != null || index != slot.indexOrHash)
2056:                            break lastAccessCheck;
2057:                    }
2058:
2059:                    if (slot.wasDeleted != 0)
2060:                        break lastAccessCheck;
2061:
2062:                    if (accessType == SLOT_MODIFY_GETTER_SETTER
2063:                            && !(slot instanceof  GetterSlot))
2064:                        break lastAccessCheck;
2065:
2066:                    return slot;
2067:                }
2068:
2069:                slot = accessSlot(name, index, accessType);
2070:                if (slot != null) {
2071:                    // Update the cache
2072:                    lastAccess = slot;
2073:                }
2074:                return slot;
2075:            }
2076:
2077:            private Slot accessSlot(String name, int index, int accessType) {
2078:                int indexOrHash = (name != null ? name.hashCode() : index);
2079:
2080:                if (accessType == SLOT_QUERY || accessType == SLOT_MODIFY
2081:                        || accessType == SLOT_MODIFY_CONST
2082:                        || accessType == SLOT_MODIFY_GETTER_SETTER) {
2083:                    // Check the hashtable without using synchronization
2084:
2085:                    Slot[] slotsLocalRef = slots; // Get stable local reference
2086:                    if (slotsLocalRef == null) {
2087:                        if (accessType == SLOT_QUERY)
2088:                            return null;
2089:                    } else {
2090:                        int tableSize = slotsLocalRef.length;
2091:                        int slotIndex = getSlotIndex(tableSize, indexOrHash);
2092:                        Slot slot = slotsLocalRef[slotIndex];
2093:                        while (slot != null) {
2094:                            String sname = slot.name;
2095:                            if (sname != null) {
2096:                                if (sname == name)
2097:                                    break;
2098:                                if (name != null
2099:                                        && indexOrHash == slot.indexOrHash) {
2100:                                    if (name.equals(sname)) {
2101:                                        // This will avoid calling String.equals when
2102:                                        // slot is accessed with same string object
2103:                                        // next time.
2104:                                        slot.name = name;
2105:                                        break;
2106:                                    }
2107:                                }
2108:                            } else if (name == null
2109:                                    && indexOrHash == slot.indexOrHash) {
2110:                                break;
2111:                            }
2112:                            slot = slot.next;
2113:                        }
2114:                        if (accessType == SLOT_QUERY) {
2115:                            return slot;
2116:                        } else if (accessType == SLOT_MODIFY) {
2117:                            if (slot != null)
2118:                                return slot;
2119:                        } else if (accessType == SLOT_MODIFY_GETTER_SETTER) {
2120:                            if (slot instanceof  GetterSlot)
2121:                                return slot;
2122:                        } else if (accessType == SLOT_MODIFY_CONST) {
2123:                            if (slot != null)
2124:                                return slot;
2125:                        }
2126:                    }
2127:
2128:                    // A new slot has to be inserted or the old has to be replaced
2129:                    // by GetterSlot. Time to synchronize.
2130:
2131:                    synchronized (this ) {
2132:                        // Refresh local ref if another thread triggered grow
2133:                        slotsLocalRef = slots;
2134:                        int insertPos;
2135:                        if (count == 0) {
2136:                            // Always throw away old slots if any on empty insert
2137:                            slotsLocalRef = new Slot[5];
2138:                            slots = slotsLocalRef;
2139:                            insertPos = getSlotIndex(slotsLocalRef.length,
2140:                                    indexOrHash);
2141:                        } else {
2142:                            int tableSize = slotsLocalRef.length;
2143:                            insertPos = getSlotIndex(tableSize, indexOrHash);
2144:                            Slot prev = slotsLocalRef[insertPos];
2145:                            Slot slot = prev;
2146:                            while (slot != null) {
2147:                                if (slot.indexOrHash == indexOrHash
2148:                                        && (slot.name == name || (name != null && name
2149:                                                .equals(slot.name)))) {
2150:                                    break;
2151:                                }
2152:                                prev = slot;
2153:                                slot = slot.next;
2154:                            }
2155:
2156:                            if (slot != null) {
2157:                                // Another thread just added a slot with same
2158:                                // name/index before this one entered synchronized
2159:                                // block. This is a race in application code and
2160:                                // probably indicates bug there. But for the hashtable
2161:                                // implementation it is harmless with the only
2162:                                // complication is the need to replace the added slot
2163:                                // if we need GetterSlot and the old one is not.
2164:                                if (accessType == SLOT_MODIFY_GETTER_SETTER
2165:                                        && !(slot instanceof  GetterSlot)) {
2166:                                    GetterSlot newSlot = new GetterSlot(name,
2167:                                            indexOrHash, slot.getAttributes());
2168:                                    newSlot.value = slot.value;
2169:                                    newSlot.next = slot.next;
2170:                                    if (prev == slot) {
2171:                                        slotsLocalRef[insertPos] = newSlot;
2172:                                    } else {
2173:                                        prev.next = newSlot;
2174:                                    }
2175:                                    slot.wasDeleted = (byte) 1;
2176:                                    if (slot == lastAccess) {
2177:                                        lastAccess = REMOVED;
2178:                                    }
2179:                                    slot = newSlot;
2180:                                } else if (accessType == SLOT_MODIFY_CONST) {
2181:                                    return null;
2182:                                }
2183:                                return slot;
2184:                            }
2185:
2186:                            // Check if the table is not too full before inserting.
2187:                            if (4 * (count + 1) > 3 * slotsLocalRef.length) {
2188:                                slotsLocalRef = new Slot[slotsLocalRef.length * 2 + 1];
2189:                                copyTable(slots, slotsLocalRef, count);
2190:                                slots = slotsLocalRef;
2191:                                insertPos = getSlotIndex(slotsLocalRef.length,
2192:                                        indexOrHash);
2193:                            }
2194:                        }
2195:
2196:                        Slot newSlot = (accessType == SLOT_MODIFY_GETTER_SETTER ? new GetterSlot(
2197:                                name, indexOrHash, 0)
2198:                                : new Slot(name, indexOrHash, 0));
2199:                        if (accessType == SLOT_MODIFY_CONST)
2200:                            newSlot.setAttributes(CONST);
2201:                        ++count;
2202:                        addKnownAbsentSlot(slotsLocalRef, newSlot, insertPos);
2203:                        return newSlot;
2204:                    }
2205:
2206:                } else if (accessType == SLOT_REMOVE) {
2207:                    synchronized (this ) {
2208:                        Slot[] slotsLocalRef = slots;
2209:                        if (count != 0) {
2210:                            int tableSize = slots.length;
2211:                            int slotIndex = getSlotIndex(tableSize, indexOrHash);
2212:                            Slot prev = slotsLocalRef[slotIndex];
2213:                            Slot slot = prev;
2214:                            while (slot != null) {
2215:                                if (slot.indexOrHash == indexOrHash
2216:                                        && (slot.name == name || (name != null && name
2217:                                                .equals(slot.name)))) {
2218:                                    break;
2219:                                }
2220:                                prev = slot;
2221:                                slot = slot.next;
2222:                            }
2223:                            if (slot != null
2224:                                    && (slot.getAttributes() & PERMANENT) == 0) {
2225:                                count--;
2226:                                if (prev == slot) {
2227:                                    slotsLocalRef[slotIndex] = slot.next;
2228:                                } else {
2229:                                    prev.next = slot.next;
2230:                                }
2231:                                // Mark the slot as removed to handle a case when
2232:                                // another thread manages to put just removed slot
2233:                                // into lastAccess cache.
2234:                                slot.wasDeleted = (byte) 1;
2235:                                if (slot == lastAccess) {
2236:                                    lastAccess = REMOVED;
2237:                                }
2238:                            }
2239:                        }
2240:                    }
2241:                    return null;
2242:
2243:                } else {
2244:                    throw Kit.codeBug();
2245:                }
2246:            }
2247:
2248:            private static int getSlotIndex(int tableSize, int indexOrHash) {
2249:                return (indexOrHash & 0x7fffffff) % tableSize;
2250:            }
2251:
2252:            // Must be inside synchronized (this)
2253:            private static void copyTable(Slot[] slots, Slot[] newSlots,
2254:                    int count) {
2255:                if (count == 0)
2256:                    throw Kit.codeBug();
2257:
2258:                int tableSize = newSlots.length;
2259:                int i = slots.length;
2260:                for (;;) {
2261:                    --i;
2262:                    Slot slot = slots[i];
2263:                    while (slot != null) {
2264:                        int insertPos = getSlotIndex(tableSize,
2265:                                slot.indexOrHash);
2266:                        Slot next = slot.next;
2267:                        addKnownAbsentSlot(newSlots, slot, insertPos);
2268:                        slot.next = null;
2269:                        slot = next;
2270:                        if (--count == 0)
2271:                            return;
2272:                    }
2273:                }
2274:            }
2275:
2276:            /**
2277:             * Add slot with keys that are known to absent from the table.
2278:             * This is an optimization to use when inserting into empty table,
2279:             * after table growth or during deserialization.
2280:             */
2281:            private static void addKnownAbsentSlot(Slot[] slots, Slot slot,
2282:                    int insertPos) {
2283:                if (slots[insertPos] == null) {
2284:                    slots[insertPos] = slot;
2285:                } else {
2286:                    Slot prev = slots[insertPos];
2287:                    while (prev.next != null) {
2288:                        prev = prev.next;
2289:                    }
2290:                    prev.next = slot;
2291:                }
2292:            }
2293:
2294:            Object[] getIds(boolean getAll) {
2295:                Slot[] s = slots;
2296:                Object[] a = ScriptRuntime.emptyArgs;
2297:                if (s == null)
2298:                    return a;
2299:                int c = 0;
2300:                for (int i = 0; i < s.length; i++) {
2301:                    Slot slot = s[i];
2302:                    while (slot != null) {
2303:                        if (getAll || (slot.getAttributes() & DONTENUM) == 0) {
2304:                            if (c == 0)
2305:                                a = new Object[s.length];
2306:                            a[c++] = (slot.name != null ? (Object) slot.name
2307:                                    : new Integer(slot.indexOrHash));
2308:                        }
2309:                        slot = slot.next;
2310:                    }
2311:                }
2312:                if (c == a.length)
2313:                    return a;
2314:                Object[] result = new Object[c];
2315:                System.arraycopy(a, 0, result, 0, c);
2316:                return result;
2317:            }
2318:
2319:            private synchronized void writeObject(ObjectOutputStream out)
2320:                    throws IOException {
2321:                out.defaultWriteObject();
2322:                int objectsCount = count;
2323:                if (objectsCount < 0) {
2324:                    // "this" was sealed
2325:                    objectsCount = ~objectsCount;
2326:                }
2327:                if (objectsCount == 0) {
2328:                    out.writeInt(0);
2329:                } else {
2330:                    out.writeInt(slots.length);
2331:                    for (int i = 0; i < slots.length; ++i) {
2332:                        Slot slot = slots[i];
2333:                        while (slot != null) {
2334:                            out.writeObject(slot);
2335:                            slot = slot.next;
2336:                            if (--objectsCount == 0)
2337:                                return;
2338:                        }
2339:                    }
2340:                }
2341:            }
2342:
2343:            private void readObject(ObjectInputStream in) throws IOException,
2344:                    ClassNotFoundException {
2345:                in.defaultReadObject();
2346:                lastAccess = REMOVED;
2347:
2348:                int tableSize = in.readInt();
2349:                if (tableSize != 0) {
2350:                    slots = new Slot[tableSize];
2351:                    int objectsCount = count;
2352:                    if (objectsCount < 0) {
2353:                        // "this" was sealed
2354:                        objectsCount = ~objectsCount;
2355:                    }
2356:                    for (int i = 0; i != objectsCount; ++i) {
2357:                        Slot slot = (Slot) in.readObject();
2358:                        int slotIndex = getSlotIndex(tableSize,
2359:                                slot.indexOrHash);
2360:                        addKnownAbsentSlot(slots, slot, slotIndex);
2361:                    }
2362:                }
2363:            }
2364:
2365:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.