~ubuntu-branches/ubuntu/karmic/rhino/karmic

« back to all changes in this revision

Viewing changes to src/org/mozilla/javascript/IdScriptableObject.java

  • Committer: Bazaar Package Importer
  • Author(s): Jerry Haltom
  • Date: 2005-03-19 16:56:07 UTC
  • mto: (11.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20050319165607-geu3j3fnqlkpqkh1
Tags: upstream-1.6.R1
ImportĀ upstreamĀ versionĀ 1.6.R1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
 
2
 *
 
3
 * The contents of this file are subject to the Netscape Public
 
4
 * License Version 1.1 (the "License"); you may not use this file
 
5
 * except in compliance with the License. You may obtain a copy of
 
6
 * the License at http://www.mozilla.org/NPL/
 
7
 *
 
8
 * Software distributed under the License is distributed on an "AS
 
9
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
10
 * implied. See the License for the specific language governing
 
11
 * rights and limitations under the License.
 
12
 *
 
13
 * The Original Code is Rhino code, released
 
14
 * May 6, 1999.
 
15
 *
 
16
 * The Initial Developer of the Original Code is Netscape
 
17
 * Communications Corporation.  Portions created by Netscape are
 
18
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 
19
 * Rights Reserved.
 
20
 *
 
21
 * Contributor(s):
 
22
 * Igor Bukanov
 
23
 *
 
24
 * Alternatively, the contents of this file may be used under the
 
25
 * terms of the GNU Public License (the "GPL"), in which case the
 
26
 * provisions of the GPL are applicable instead of those above.
 
27
 * If you wish to allow use of your version of this file only
 
28
 * under the terms of the GPL and not to allow others to use your
 
29
 * version of this file under the NPL, indicate your decision by
 
30
 * deleting the provisions above and replace them with the notice
 
31
 * and other provisions required by the GPL.  If you do not delete
 
32
 * the provisions above, a recipient may use your version of this
 
33
 * file under either the NPL or the GPL.
 
34
 */
 
35
 
 
36
package org.mozilla.javascript;
 
37
 
 
38
import java.io.*;
 
39
 
 
40
/**
 
41
Base class for native object implementation that uses IdFunctionObject to export its methods to script via <class-name>.prototype object.
 
42
 
 
43
Any descendant should implement at least the following methods:
 
44
    findInstanceIdInfo
 
45
    getInstanceIdName
 
46
    execIdCall
 
47
    methodArity
 
48
 
 
49
To define non-function properties, the descendant should override
 
50
    getInstanceIdValue
 
51
    setInstanceIdValue
 
52
to get/set property value and provide its default attributes.
 
53
 
 
54
 
 
55
To customize initializition of constructor and protype objects, descendant
 
56
may override scopeInit or fillConstructorProperties methods.
 
57
 
 
58
*/
 
59
public abstract class IdScriptableObject extends ScriptableObject
 
60
    implements IdFunctionCall
 
61
{
 
62
    private transient volatile PrototypeValues prototypeValues;
 
63
 
 
64
    private static final class PrototypeValues implements Serializable
 
65
    {
 
66
        private static final int VALUE_SLOT = 0;
 
67
        private static final int NAME_SLOT = 1;
 
68
        private static final int SLOT_SPAN = 2;
 
69
 
 
70
        private IdScriptableObject obj;
 
71
        private Object tag;
 
72
        private int maxId;
 
73
        private volatile Object[] valueArray;
 
74
        private volatile short[] attributeArray;
 
75
        private volatile int lastFoundId = 1;
 
76
 
 
77
        // The following helps to avoid creation of valueArray during runtime
 
78
        // initialization for common case of "constructor" property
 
79
        int constructorId;
 
80
        private IdFunctionObject constructor;
 
81
        private short constructorAttrs;
 
82
 
 
83
        PrototypeValues(IdScriptableObject obj, int maxId)
 
84
        {
 
85
            if (obj == null) throw new IllegalArgumentException();
 
86
            if (maxId < 1) throw new IllegalArgumentException();
 
87
            this.obj = obj;
 
88
            this.maxId = maxId;
 
89
        }
 
90
 
 
91
        final int getMaxId()
 
92
        {
 
93
            return maxId;
 
94
        }
 
95
 
 
96
        final void initValue(int id, String name, Object value, int attributes)
 
97
        {
 
98
            if (!(1 <= id && id <= maxId))
 
99
                throw new IllegalArgumentException();
 
100
            if (name == null)
 
101
                throw new IllegalArgumentException();
 
102
            if (value == NOT_FOUND)
 
103
                throw new IllegalArgumentException();
 
104
            ScriptableObject.checkValidAttributes(attributes);
 
105
            if (obj.findPrototypeId(name) != id)
 
106
                throw new IllegalArgumentException(name);
 
107
 
 
108
            if (id == constructorId) {
 
109
                if (!(value instanceof IdFunctionObject)) {
 
110
                    throw new IllegalArgumentException("consructor should be initialized with IdFunctionObject");
 
111
                }
 
112
                constructor = (IdFunctionObject)value;
 
113
                constructorAttrs = (short)attributes;
 
114
                return;
 
115
            }
 
116
 
 
117
            initSlot(id, name, value, attributes);
 
118
        }
 
119
 
 
120
        private void initSlot(int id, String name, Object value,
 
121
                              int attributes)
 
122
        {
 
123
            Object[] array = valueArray;
 
124
            if (array == null)
 
125
                throw new IllegalStateException();
 
126
 
 
127
            if (value == null) {
 
128
                value = UniqueTag.NULL_VALUE;
 
129
            }
 
130
            int index = (id - 1) * SLOT_SPAN;
 
131
            synchronized (this) {
 
132
                Object value2 = array[index + VALUE_SLOT];
 
133
                if (value2 == null) {
 
134
                    array[index + VALUE_SLOT] = value;
 
135
                    array[index + NAME_SLOT] = name;
 
136
                    attributeArray[id - 1] = (short)attributes;
 
137
                } else {
 
138
                    if (!name.equals(array[index + NAME_SLOT]))
 
139
                         throw new IllegalStateException();
 
140
                }
 
141
            }
 
142
        }
 
143
 
 
144
        final IdFunctionObject createPrecachedConstructor()
 
145
        {
 
146
            if (constructorId != 0) throw new IllegalStateException();
 
147
            constructorId = obj.findPrototypeId("constructor");
 
148
            if (constructorId == 0) {
 
149
                throw new IllegalStateException(
 
150
                    "No id for constructor property");
 
151
            }
 
152
            obj.initPrototypeId(constructorId);
 
153
            if (constructor == null) {
 
154
                throw new IllegalStateException(
 
155
                    obj.getClass().getName()+".initPrototypeId() did not "
 
156
                    +"initialize id="+constructorId);
 
157
            }
 
158
            constructor.initFunction(obj.getClassName(),
 
159
                                     ScriptableObject.getTopLevelScope(obj));
 
160
            constructor.markAsConstructor(obj);
 
161
            return constructor;
 
162
        }
 
163
 
 
164
        final int findId(String name)
 
165
        {
 
166
            Object[] array = valueArray;
 
167
            if (array == null) {
 
168
                return obj.findPrototypeId(name);
 
169
            }
 
170
            int id = lastFoundId;
 
171
            if (name == array[(id - 1) * SLOT_SPAN + NAME_SLOT]) {
 
172
                return id;
 
173
            }
 
174
            id = obj.findPrototypeId(name);
 
175
            if (id != 0) {
 
176
                int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
 
177
                // Make cache to work!
 
178
                array[nameSlot] = name;
 
179
                lastFoundId = id;
 
180
            }
 
181
            return id;
 
182
        }
 
183
 
 
184
        final boolean has(int id)
 
185
        {
 
186
            Object[] array = valueArray;
 
187
            if (array == null) {
 
188
                // Not yet initialized, assume all exists
 
189
                return true;
 
190
            }
 
191
            int valueSlot = (id  - 1) * SLOT_SPAN + VALUE_SLOT;
 
192
            Object value = array[valueSlot];
 
193
            if (value == null) {
 
194
                // The particular entry has not been yet initialized
 
195
                return true;
 
196
            }
 
197
            return value != NOT_FOUND;
 
198
        }
 
199
 
 
200
        final Object get(int id)
 
201
        {
 
202
            Object value = ensureId(id);
 
203
            if (value == UniqueTag.NULL_VALUE) {
 
204
                value = null;
 
205
            }
 
206
            return value;
 
207
        }
 
208
 
 
209
        final void set(int id, Scriptable start, Object value)
 
210
        {
 
211
            if (value == NOT_FOUND) throw new IllegalArgumentException();
 
212
            ensureId(id);
 
213
            int attr = attributeArray[id - 1];
 
214
            if ((attr & READONLY) == 0) {
 
215
                if (start == obj) {
 
216
                    if (value == null) {
 
217
                        value = UniqueTag.NULL_VALUE;
 
218
                    }
 
219
                    int valueSlot = (id  - 1) * SLOT_SPAN + VALUE_SLOT;
 
220
                    synchronized (this) {
 
221
                        valueArray[valueSlot] = value;
 
222
                    }
 
223
                }
 
224
                else {
 
225
                    int nameSlot = (id  - 1) * SLOT_SPAN + NAME_SLOT;
 
226
                    String name = (String)valueArray[nameSlot];
 
227
                    start.put(name, start, value);
 
228
                }
 
229
            }
 
230
        }
 
231
 
 
232
        final void delete(int id)
 
233
        {
 
234
            ensureId(id);
 
235
            int attr = attributeArray[id - 1];
 
236
            if ((attr & PERMANENT) == 0) {
 
237
                int valueSlot = (id  - 1) * SLOT_SPAN + VALUE_SLOT;
 
238
                synchronized (this) {
 
239
                    valueArray[valueSlot] = NOT_FOUND;
 
240
                    attributeArray[id - 1] = EMPTY;
 
241
                }
 
242
            }
 
243
        }
 
244
 
 
245
        final int getAttributes(int id)
 
246
        {
 
247
            ensureId(id);
 
248
            return attributeArray[id - 1];
 
249
        }
 
250
 
 
251
        final void setAttributes(int id, int attributes)
 
252
        {
 
253
            ScriptableObject.checkValidAttributes(attributes);
 
254
            ensureId(id);
 
255
            synchronized (this) {
 
256
                attributeArray[id - 1] = (short)attributes;
 
257
            }
 
258
        }
 
259
 
 
260
        final Object[] getNames(boolean getAll, Object[] extraEntries)
 
261
        {
 
262
            Object[] names = null;
 
263
            int count = 0;
 
264
            for (int id = 1; id <= maxId; ++id) {
 
265
                Object value = ensureId(id);
 
266
                if (getAll || (attributeArray[id - 1] & DONTENUM) == 0) {
 
267
                    if (value != NOT_FOUND) {
 
268
                        int nameSlot = (id  - 1) * SLOT_SPAN + NAME_SLOT;
 
269
                        String name = (String)valueArray[nameSlot];
 
270
                        if (names == null) {
 
271
                            names = new Object[maxId];
 
272
                        }
 
273
                        names[count++] = name;
 
274
                    }
 
275
                }
 
276
            }
 
277
            if (count == 0) {
 
278
                return extraEntries;
 
279
            } else if (extraEntries == null || extraEntries.length == 0) {
 
280
                if (count != names.length) {
 
281
                    Object[] tmp = new Object[count];
 
282
                    System.arraycopy(names, 0, tmp, 0, count);
 
283
                    names = tmp;
 
284
                }
 
285
                return names;
 
286
            } else {
 
287
                int extra = extraEntries.length;
 
288
                Object[] tmp = new Object[extra + count];
 
289
                System.arraycopy(extraEntries, 0, tmp, 0, extra);
 
290
                System.arraycopy(names, 0, tmp, extra, count);
 
291
                return tmp;
 
292
            }
 
293
        }
 
294
 
 
295
        private Object ensureId(int id)
 
296
        {
 
297
            Object[] array = valueArray;
 
298
            if (array == null) {
 
299
                synchronized (this) {
 
300
                    array = valueArray;
 
301
                    if (array == null) {
 
302
                        array = new Object[maxId * SLOT_SPAN];
 
303
                        valueArray = array;
 
304
                        attributeArray = new short[maxId];
 
305
                    }
 
306
                }
 
307
            }
 
308
            int valueSlot = (id  - 1) * SLOT_SPAN + VALUE_SLOT;
 
309
            Object value = array[valueSlot];
 
310
            if (value == null) {
 
311
                if (id == constructorId) {
 
312
                    initSlot(constructorId, "constructor",
 
313
                             constructor, constructorAttrs);
 
314
                    constructor = null; // no need to refer it any longer
 
315
                } else {
 
316
                    obj.initPrototypeId(id);
 
317
                }
 
318
                value = array[valueSlot];
 
319
                if (value == null) {
 
320
                    throw new IllegalStateException(
 
321
                        obj.getClass().getName()+".initPrototypeId(int id) "
 
322
                        +"did not initialize id="+id);
 
323
                }
 
324
            }
 
325
            return value;
 
326
        }
 
327
    }
 
328
 
 
329
    public IdScriptableObject()
 
330
    {
 
331
    }
 
332
 
 
333
    public IdScriptableObject(Scriptable scope, Scriptable prototype)
 
334
    {
 
335
        super(scope, prototype);
 
336
    }
 
337
 
 
338
    protected final Object defaultGet(String name)
 
339
    {
 
340
        return super.get(name, this);
 
341
    }
 
342
 
 
343
    protected final void defaultPut(String name, Object value)
 
344
    {
 
345
        super.put(name, this, value);
 
346
    }
 
347
 
 
348
    public boolean has(String name, Scriptable start)
 
349
    {
 
350
        int info = findInstanceIdInfo(name);
 
351
        if (info != 0) {
 
352
            int attr = (info >>> 16);
 
353
            if ((attr & PERMANENT) != 0) {
 
354
                return true;
 
355
            }
 
356
            int id = (info & 0xFFFF);
 
357
            return NOT_FOUND != getInstanceIdValue(id);
 
358
        }
 
359
        if (prototypeValues != null) {
 
360
            int id = prototypeValues.findId(name);
 
361
            if (id != 0) {
 
362
                return prototypeValues.has(id);
 
363
            }
 
364
        }
 
365
        return super.has(name, start);
 
366
    }
 
367
 
 
368
    public Object get(String name, Scriptable start)
 
369
    {
 
370
        int info = findInstanceIdInfo(name);
 
371
        if (info != 0) {
 
372
            int id = (info & 0xFFFF);
 
373
            return getInstanceIdValue(id);
 
374
        }
 
375
        if (prototypeValues != null) {
 
376
            int id = prototypeValues.findId(name);
 
377
            if (id != 0) {
 
378
                return prototypeValues.get(id);
 
379
            }
 
380
        }
 
381
        return super.get(name, start);
 
382
    }
 
383
 
 
384
    public void put(String name, Scriptable start, Object value)
 
385
    {
 
386
        int info = findInstanceIdInfo(name);
 
387
        if (info != 0) {
 
388
            if (start == this && isSealed()) {
 
389
                throw Context.reportRuntimeError1("msg.modify.sealed",
 
390
                                                  name);
 
391
            }
 
392
            int attr = (info >>> 16);
 
393
            if ((attr & READONLY) == 0) {
 
394
                if (start == this) {
 
395
                    int id = (info & 0xFFFF);
 
396
                    setInstanceIdValue(id, value);
 
397
                }
 
398
                else {
 
399
                    start.put(name, start, value);
 
400
                }
 
401
            }
 
402
            return;
 
403
        }
 
404
        if (prototypeValues != null) {
 
405
            int id = prototypeValues.findId(name);
 
406
            if (id != 0) {
 
407
                if (start == this && isSealed()) {
 
408
                    throw Context.reportRuntimeError1("msg.modify.sealed",
 
409
                                                      name);
 
410
                }
 
411
                prototypeValues.set(id, start, value);
 
412
                return;
 
413
            }
 
414
        }
 
415
        super.put(name, start, value);
 
416
    }
 
417
 
 
418
    public void delete(String name)
 
419
    {
 
420
        int info = findInstanceIdInfo(name);
 
421
        if (info != 0) {
 
422
            // Let the super class to throw exceptions for sealed objects
 
423
            if (!isSealed()) {
 
424
                int attr = (info >>> 16);
 
425
                if ((attr & PERMANENT) == 0) {
 
426
                    int id = (info & 0xFFFF);
 
427
                    setInstanceIdValue(id, NOT_FOUND);
 
428
                }
 
429
                return;
 
430
            }
 
431
        }
 
432
        if (prototypeValues != null) {
 
433
            int id = prototypeValues.findId(name);
 
434
            if (id != 0) {
 
435
                if (!isSealed()) {
 
436
                    prototypeValues.delete(id);
 
437
                }
 
438
                return;
 
439
            }
 
440
        }
 
441
        super.delete(name);
 
442
    }
 
443
 
 
444
    public int getAttributes(String name)
 
445
    {
 
446
        int info = findInstanceIdInfo(name);
 
447
        if (info != 0) {
 
448
            int attr = (info >>> 16);
 
449
            return attr;
 
450
        }
 
451
        if (prototypeValues != null) {
 
452
            int id = prototypeValues.findId(name);
 
453
            if (id != 0) {
 
454
                return prototypeValues.getAttributes(id);
 
455
            }
 
456
        }
 
457
        return super.getAttributes(name);
 
458
    }
 
459
 
 
460
    public void setAttributes(String name, int attributes)
 
461
    {
 
462
        ScriptableObject.checkValidAttributes(attributes);
 
463
        int info = findInstanceIdInfo(name);
 
464
        if (info != 0) {
 
465
            int currentAttributes = (info >>> 16);
 
466
            if (attributes != currentAttributes) {
 
467
                throw new RuntimeException(
 
468
                    "Change of attributes for this id is not supported");
 
469
            }
 
470
            return;
 
471
        }
 
472
        if (prototypeValues != null) {
 
473
            int id = prototypeValues.findId(name);
 
474
            if (id != 0) {
 
475
                prototypeValues.setAttributes(id, attributes);
 
476
                return;
 
477
            }
 
478
        }
 
479
        super.setAttributes(name, attributes);
 
480
    }
 
481
 
 
482
    Object[] getIds(boolean getAll)
 
483
    {
 
484
        Object[] result = super.getIds(getAll);
 
485
 
 
486
        if (prototypeValues != null) {
 
487
            result = prototypeValues.getNames(getAll, result);
 
488
        }
 
489
 
 
490
        int maxInstanceId = getMaxInstanceId();
 
491
        if (maxInstanceId != 0) {
 
492
            Object[] ids = null;
 
493
            int count = 0;
 
494
 
 
495
            for (int id = maxInstanceId; id != 0; --id) {
 
496
                String name = getInstanceIdName(id);
 
497
                int info = findInstanceIdInfo(name);
 
498
                if (info != 0) {
 
499
                    int attr = (info >>> 16);
 
500
                    if ((attr & PERMANENT) == 0) {
 
501
                        if (NOT_FOUND == getInstanceIdValue(id)) {
 
502
                            continue;
 
503
                        }
 
504
                    }
 
505
                    if (getAll || (attr & DONTENUM) == 0) {
 
506
                        if (count == 0) {
 
507
                            // Need extra room for no more then [1..id] names
 
508
                            ids = new Object[id];
 
509
                        }
 
510
                        ids[count++] = name;
 
511
                    }
 
512
                }
 
513
            }
 
514
            if (count != 0) {
 
515
                if (result.length == 0 && ids.length == count) {
 
516
                    result = ids;
 
517
                }
 
518
                else {
 
519
                    Object[] tmp = new Object[result.length + count];
 
520
                    System.arraycopy(result, 0, tmp, 0, result.length);
 
521
                    System.arraycopy(ids, 0, tmp, result.length, count);
 
522
                    result = tmp;
 
523
                }
 
524
            }
 
525
        }
 
526
        return result;
 
527
    }
 
528
 
 
529
    /**
 
530
     * Get maximum id findInstanceIdInfo can generate.
 
531
     */
 
532
    protected int getMaxInstanceId()
 
533
    {
 
534
        return 0;
 
535
    }
 
536
 
 
537
    protected static int instanceIdInfo(int attributes, int id)
 
538
    {
 
539
        return (attributes << 16) | id;
 
540
    }
 
541
 
 
542
    /**
 
543
     * Map name to id of instance property.
 
544
     * Should return 0 if not found or the result of
 
545
     * {@link #instanceIdInfo(int, int)}.
 
546
     */
 
547
    protected int findInstanceIdInfo(String name)
 
548
    {
 
549
        return 0;
 
550
    }
 
551
 
 
552
    /** Map id back to property name it defines.
 
553
     */
 
554
    protected String getInstanceIdName(int id)
 
555
    {
 
556
        throw new IllegalArgumentException(String.valueOf(id));
 
557
    }
 
558
 
 
559
    /** Get id value.
 
560
     ** If id value is constant, descendant can call cacheIdValue to store
 
561
     ** value in the permanent cache.
 
562
     ** Default implementation creates IdFunctionObject instance for given id
 
563
     ** and cache its value
 
564
     */
 
565
    protected Object getInstanceIdValue(int id)
 
566
    {
 
567
        throw new IllegalStateException(String.valueOf(id));
 
568
    }
 
569
 
 
570
    /**
 
571
     * Set or delete id value. If value == NOT_FOUND , the implementation
 
572
     * should make sure that the following getInstanceIdValue return NOT_FOUND.
 
573
     */
 
574
    protected void setInstanceIdValue(int id, Object value)
 
575
    {
 
576
        throw new IllegalStateException(String.valueOf(id));
 
577
    }
 
578
 
 
579
    /** 'thisObj' will be null if invoked as constructor, in which case
 
580
     ** instance of Scriptable should be returned. */
 
581
    public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
 
582
                             Scriptable thisObj, Object[] args)
 
583
    {
 
584
        throw f.unknown();
 
585
    }
 
586
 
 
587
    public final IdFunctionObject exportAsJSClass(int maxPrototypeId,
 
588
                                                  Scriptable scope,
 
589
                                                  boolean sealed)
 
590
    {
 
591
        // Set scope and prototype unless this is top level scope itself
 
592
        if (scope != this && scope != null) {
 
593
            setParentScope(scope);
 
594
            setPrototype(getObjectPrototype(scope));
 
595
        }
 
596
 
 
597
        activatePrototypeMap(maxPrototypeId);
 
598
        IdFunctionObject ctor = prototypeValues.createPrecachedConstructor();
 
599
        if (sealed) {
 
600
            sealObject();
 
601
        }
 
602
        fillConstructorProperties(ctor);
 
603
        if (sealed) {
 
604
            ctor.sealObject();
 
605
        }
 
606
        ctor.exportAsScopeProperty();
 
607
        return ctor;
 
608
    }
 
609
 
 
610
    public final boolean hasPrototypeMap()
 
611
    {
 
612
        return prototypeValues != null;
 
613
    }
 
614
 
 
615
    public final void activatePrototypeMap(int maxPrototypeId)
 
616
    {
 
617
        PrototypeValues values = new PrototypeValues(this, maxPrototypeId);
 
618
        synchronized (this) {
 
619
            if (prototypeValues != null)
 
620
                throw new IllegalStateException();
 
621
            prototypeValues = values;
 
622
        }
 
623
    }
 
624
 
 
625
    public final void initPrototypeMethod(Object tag, int id, String name,
 
626
                                          int arity)
 
627
    {
 
628
        Scriptable scope = ScriptableObject.getTopLevelScope(this);
 
629
        IdFunctionObject f = newIdFunction(tag, id, name, arity, scope);
 
630
        prototypeValues.initValue(id, name, f, DONTENUM);
 
631
    }
 
632
 
 
633
    public final void initPrototypeConstructor(IdFunctionObject f)
 
634
    {
 
635
        int id = prototypeValues.constructorId;
 
636
        if (id == 0)
 
637
            throw new IllegalStateException();
 
638
        if (f.methodId() != id)
 
639
            throw new IllegalArgumentException();
 
640
        if (isSealed()) { f.sealObject(); }
 
641
        prototypeValues.initValue(id, "constructor", f, DONTENUM);
 
642
    }
 
643
 
 
644
    public final void initPrototypeValue(int id, String name, Object value,
 
645
                                         int attributes)
 
646
    {
 
647
        prototypeValues.initValue(id, name, value, attributes);
 
648
    }
 
649
 
 
650
    protected void initPrototypeId(int id)
 
651
    {
 
652
        throw new IllegalStateException(String.valueOf(id));
 
653
    }
 
654
 
 
655
    protected int findPrototypeId(String name)
 
656
    {
 
657
        throw new IllegalStateException(name);
 
658
    }
 
659
 
 
660
    protected void fillConstructorProperties(IdFunctionObject ctor)
 
661
    {
 
662
    }
 
663
 
 
664
    protected void addIdFunctionProperty(Scriptable obj, Object tag, int id,
 
665
                                         String name, int arity)
 
666
    {
 
667
        Scriptable scope = ScriptableObject.getTopLevelScope(obj);
 
668
        IdFunctionObject f = newIdFunction(tag, id, name, arity, scope);
 
669
        f.addAsProperty(obj);
 
670
    }
 
671
 
 
672
    /**
 
673
     * Utility method to construct type error to indicate incompatible call
 
674
     * when converting script thisObj to a particular type is not possible.
 
675
     * Possible usage would be to have a private function like realThis:
 
676
     * <pre>
 
677
     *  private static NativeSomething realThis(Scriptable thisObj,
 
678
     *                                          IdFunctionObject f)
 
679
     *  {
 
680
     *      if (!(thisObj instanceof NativeSomething))
 
681
     *          throw incompatibleCallError(f);
 
682
     *      return (NativeSomething)thisObj;
 
683
     * }
 
684
     * </pre>
 
685
     * Note that although such function can be implemented universally via
 
686
     * java.lang.Class.isInstance(), it would be much more slower.
 
687
     * @param readOnly specify if the function f does not change state of
 
688
     * object.
 
689
     * @return Scriptable object suitable for a check by the instanceof
 
690
     * operator.
 
691
     * @throws RuntimeException if no more instanceof target can be found
 
692
     */
 
693
    protected static EcmaError incompatibleCallError(IdFunctionObject f)
 
694
    {
 
695
        throw ScriptRuntime.typeError1("msg.incompat.call",
 
696
                                       f.getFunctionName());
 
697
    }
 
698
 
 
699
    private IdFunctionObject newIdFunction(Object tag, int id, String name,
 
700
                                           int arity, Scriptable scope)
 
701
    {
 
702
        IdFunctionObject f = new IdFunctionObject(this, tag, id, name, arity,
 
703
                                                  scope);
 
704
        if (isSealed()) { f.sealObject(); }
 
705
        return f;
 
706
    }
 
707
 
 
708
    private void readObject(ObjectInputStream stream)
 
709
        throws IOException, ClassNotFoundException
 
710
    {
 
711
        stream.defaultReadObject();
 
712
        int maxPrototypeId = stream.readInt();
 
713
        if (maxPrototypeId != 0) {
 
714
            activatePrototypeMap(maxPrototypeId);
 
715
        }
 
716
    }
 
717
 
 
718
    private void writeObject(ObjectOutputStream stream)
 
719
        throws IOException
 
720
    {
 
721
        stream.defaultWriteObject();
 
722
        int maxPrototypeId = 0;
 
723
        if (prototypeValues != null) {
 
724
            maxPrototypeId = prototypeValues.getMaxId();
 
725
        }
 
726
        stream.writeInt(maxPrototypeId);
 
727
    }
 
728
 
 
729
}
 
730