зеркало из https://github.com/mozilla/pjs.git
Fixing under allocation of ids array while enumerating properties.
This commit is contained in:
Родитель
80101fd2cf
Коммит
f8d44cc5d9
|
@ -1,741 +0,0 @@
|
|||
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
|
||||
*
|
||||
* The contents of this file are subject to the Netscape Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/NPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is Rhino code, released
|
||||
* May 6, 1999.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Igor Bukanov
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU Public License (the "GPL"), in which case the
|
||||
* provisions of the GPL are applicable instead of those above.
|
||||
* If you wish to allow use of your version of this file only
|
||||
* under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the NPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this
|
||||
* file under either the NPL or the GPL.
|
||||
*/
|
||||
|
||||
package org.mozilla.javascript;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
Base class for native object implementation that uses IdFunction to export its methods to script via <class-name>.prototype object.
|
||||
|
||||
Any descendant should implement at least the following methods:
|
||||
findInstanceIdInfo
|
||||
getInstanceIdName
|
||||
execMethod
|
||||
methodArity
|
||||
|
||||
To define non-function properties, the descendant should override
|
||||
getInstanceIdValue
|
||||
setInstanceIdValue
|
||||
to get/set property value and provide its default attributes.
|
||||
|
||||
|
||||
To customize initializition of constructor and protype objects, descendant
|
||||
may override scopeInit or fillConstructorProperties methods.
|
||||
|
||||
*/
|
||||
public abstract class IdScriptable extends ScriptableObject
|
||||
implements IdFunctionMaster
|
||||
{
|
||||
private static final class PrototypeValues implements Serializable
|
||||
{
|
||||
private static final int VALUE_SLOT = 0;
|
||||
private static final int NAME_SLOT = 1;
|
||||
private static final int SLOT_SPAN = 2;
|
||||
|
||||
private IdScriptable obj;
|
||||
private Object tag;
|
||||
private int maxId;
|
||||
private volatile Object[] valueArray;
|
||||
private volatile short[] attributeArray;
|
||||
private volatile int lastFoundId = 1;
|
||||
|
||||
// The following helps to avoid creation of valueArray during runtime
|
||||
// initialization for common case of "constructor" property
|
||||
int constructorId;
|
||||
private IdFunction constructor;
|
||||
private short constructorAttrs;
|
||||
|
||||
PrototypeValues(IdScriptable obj, int maxId)
|
||||
{
|
||||
if (obj == null) throw new IllegalArgumentException();
|
||||
if (maxId < 1) throw new IllegalArgumentException();
|
||||
this.obj = obj;
|
||||
this.maxId = maxId;
|
||||
}
|
||||
|
||||
final void initValue(int id, String name, Object value, int attributes)
|
||||
{
|
||||
if (!(1 <= id && id <= maxId))
|
||||
throw new IllegalArgumentException();
|
||||
if (name == null)
|
||||
throw new IllegalArgumentException();
|
||||
if (value == NOT_FOUND)
|
||||
throw new IllegalArgumentException();
|
||||
ScriptableObject.checkValidAttributes(attributes);
|
||||
if (obj.findPrototypeId(name) != id)
|
||||
throw new IllegalArgumentException(name);
|
||||
|
||||
if (id == constructorId) {
|
||||
if (!(value instanceof IdFunction)) {
|
||||
throw new IllegalArgumentException(
|
||||
"consructor should be initialized with IdFunction");
|
||||
}
|
||||
constructor = (IdFunction)value;
|
||||
constructorAttrs = (short)attributes;
|
||||
return;
|
||||
}
|
||||
|
||||
initSlot(id, name, value, attributes);
|
||||
}
|
||||
|
||||
private void initSlot(int id, String name, Object value,
|
||||
int attributes)
|
||||
{
|
||||
Object[] array = valueArray;
|
||||
if (array == null)
|
||||
throw new IllegalStateException();
|
||||
|
||||
if (value == null) {
|
||||
value = UniqueTag.NULL_VALUE;
|
||||
}
|
||||
int index = (id - 1) * SLOT_SPAN;
|
||||
synchronized (this) {
|
||||
Object value2 = array[index + VALUE_SLOT];
|
||||
if (value2 == null) {
|
||||
array[index + VALUE_SLOT] = value;
|
||||
array[index + NAME_SLOT] = name;
|
||||
attributeArray[id - 1] = (short)attributes;
|
||||
} else {
|
||||
if (!name.equals(array[index + NAME_SLOT]))
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final IdFunction createPrecachedConstructor()
|
||||
{
|
||||
if (constructorId != 0) throw new IllegalStateException();
|
||||
constructorId = obj.findPrototypeId("constructor");
|
||||
if (constructorId == 0) {
|
||||
throw new IllegalStateException(
|
||||
"No id for constructor property");
|
||||
}
|
||||
obj.initPrototypeId(constructorId);
|
||||
if (constructor == null) {
|
||||
throw new IllegalStateException(
|
||||
obj.getClass().getName()+".initPrototypeId() did not "
|
||||
+"initialize id="+constructorId);
|
||||
}
|
||||
constructor.initFunction(obj.getClassName(),
|
||||
ScriptableObject.getTopLevelScope(obj));
|
||||
constructor.markAsConstructor(obj);
|
||||
return constructor;
|
||||
}
|
||||
|
||||
final int findId(String name)
|
||||
{
|
||||
Object[] array = valueArray;
|
||||
if (array == null) {
|
||||
return obj.findPrototypeId(name);
|
||||
}
|
||||
int id = lastFoundId;
|
||||
if (name == array[(id - 1) * SLOT_SPAN + NAME_SLOT]) {
|
||||
return id;
|
||||
}
|
||||
id = obj.findPrototypeId(name);
|
||||
if (id != 0) {
|
||||
int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
|
||||
// Make cache to work!
|
||||
array[nameSlot] = name;
|
||||
lastFoundId = id;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
final boolean has(int id)
|
||||
{
|
||||
Object[] array = valueArray;
|
||||
if (array == null) {
|
||||
// Not yet initialized, assume all exists
|
||||
return true;
|
||||
}
|
||||
int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
|
||||
Object value = array[valueSlot];
|
||||
if (value == null) {
|
||||
// The particular entry has not been yet initialized
|
||||
return true;
|
||||
}
|
||||
return value != NOT_FOUND;
|
||||
}
|
||||
|
||||
final Object get(int id)
|
||||
{
|
||||
Object value = ensureId(id);
|
||||
if (value == UniqueTag.NULL_VALUE) {
|
||||
value = null;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
final void set(int id, Scriptable start, Object value)
|
||||
{
|
||||
if (value == NOT_FOUND) throw new IllegalArgumentException();
|
||||
ensureId(id);
|
||||
int attr = attributeArray[id - 1];
|
||||
if ((attr & READONLY) == 0) {
|
||||
if (start == obj) {
|
||||
if (value == null) {
|
||||
value = UniqueTag.NULL_VALUE;
|
||||
}
|
||||
int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
|
||||
synchronized (this) {
|
||||
valueArray[valueSlot] = value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
|
||||
String name = (String)valueArray[nameSlot];
|
||||
start.put(name, start, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void delete(int id)
|
||||
{
|
||||
ensureId(id);
|
||||
int attr = attributeArray[id - 1];
|
||||
if ((attr & PERMANENT) == 0) {
|
||||
int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
|
||||
synchronized (this) {
|
||||
valueArray[valueSlot] = NOT_FOUND;
|
||||
attributeArray[id - 1] = EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final int getAttributes(int id)
|
||||
{
|
||||
ensureId(id);
|
||||
return attributeArray[id - 1];
|
||||
}
|
||||
|
||||
final void setAttributes(int id, int attributes)
|
||||
{
|
||||
ScriptableObject.checkValidAttributes(attributes);
|
||||
ensureId(id);
|
||||
synchronized (this) {
|
||||
attributeArray[id - 1] = (short)attributes;
|
||||
}
|
||||
}
|
||||
|
||||
final Object[] getNames(boolean getAll, Object[] extraEntries)
|
||||
{
|
||||
Object[] names = null;
|
||||
int count = 0;
|
||||
for (int id = 1; id <= maxId; ++id) {
|
||||
Object value = ensureId(id);
|
||||
if (getAll || (attributeArray[id - 1] & DONTENUM) == 0) {
|
||||
if (value != NOT_FOUND) {
|
||||
int nameSlot = (id - 1) * SLOT_SPAN + NAME_SLOT;
|
||||
String name = (String)valueArray[nameSlot];
|
||||
if (names == null) {
|
||||
names = new Object[maxId - 1];
|
||||
}
|
||||
names[count++] = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count == 0) {
|
||||
return extraEntries;
|
||||
} else if (extraEntries == null || extraEntries.length == 0) {
|
||||
if (count != names.length) {
|
||||
Object[] tmp = new Object[count];
|
||||
System.arraycopy(names, 0, tmp, 0, count);
|
||||
names = tmp;
|
||||
}
|
||||
return names;
|
||||
} else {
|
||||
int extra = extraEntries.length;
|
||||
Object[] tmp = new Object[extra + count];
|
||||
System.arraycopy(extraEntries, 0, tmp, 0, extra);
|
||||
System.arraycopy(names, 0, tmp, extra, count);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
private Object ensureId(int id)
|
||||
{
|
||||
Object[] array = valueArray;
|
||||
if (array == null) {
|
||||
synchronized (this) {
|
||||
array = valueArray;
|
||||
if (array == null) {
|
||||
array = new Object[maxId * SLOT_SPAN];
|
||||
valueArray = array;
|
||||
attributeArray = new short[maxId];
|
||||
}
|
||||
}
|
||||
}
|
||||
int valueSlot = (id - 1) * SLOT_SPAN + VALUE_SLOT;
|
||||
Object value = array[valueSlot];
|
||||
if (value == null) {
|
||||
if (id == constructorId) {
|
||||
initSlot(constructorId, "constructor",
|
||||
constructor, constructorAttrs);
|
||||
constructor = null; // no need to refer it any longer
|
||||
} else {
|
||||
obj.initPrototypeId(id);
|
||||
}
|
||||
value = array[valueSlot];
|
||||
if (value == null) {
|
||||
throw new IllegalStateException(
|
||||
obj.getClass().getName()+".initPrototypeId(int id) "
|
||||
+"did not initialize id="+id);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public IdScriptable()
|
||||
{
|
||||
}
|
||||
|
||||
public boolean has(String name, Scriptable start)
|
||||
{
|
||||
if (maxInstanceId != 0) {
|
||||
int info = findInstanceIdInfo(name);
|
||||
if (info != 0) {
|
||||
int attr = (info >>> 16);
|
||||
if ((attr & PERMANENT) != 0) {
|
||||
return true;
|
||||
}
|
||||
int id = (info & 0xFFFF);
|
||||
return NOT_FOUND != getInstanceIdValue(id);
|
||||
}
|
||||
}
|
||||
if (prototypeValues != null) {
|
||||
int id = prototypeValues.findId(name);
|
||||
if (id != 0) {
|
||||
return prototypeValues.has(id);
|
||||
}
|
||||
}
|
||||
return super.has(name, start);
|
||||
}
|
||||
|
||||
public Object get(String name, Scriptable start)
|
||||
{
|
||||
if (maxInstanceId != 0) {
|
||||
int info = findInstanceIdInfo(name);
|
||||
if (info != 0) {
|
||||
int id = (info & 0xFFFF);
|
||||
return getInstanceIdValue(id);
|
||||
}
|
||||
}
|
||||
if (prototypeValues != null) {
|
||||
int id = prototypeValues.findId(name);
|
||||
if (id != 0) {
|
||||
return prototypeValues.get(id);
|
||||
}
|
||||
}
|
||||
return super.get(name, start);
|
||||
}
|
||||
|
||||
public void put(String name, Scriptable start, Object value)
|
||||
{
|
||||
if (maxInstanceId != 0) {
|
||||
int info = findInstanceIdInfo(name);
|
||||
if (info != 0) {
|
||||
if (start == this && isSealed()) {
|
||||
throw Context.reportRuntimeError1("msg.modify.sealed",
|
||||
name);
|
||||
}
|
||||
int attr = (info >>> 16);
|
||||
if ((attr & READONLY) == 0) {
|
||||
if (start == this) {
|
||||
int id = (info & 0xFFFF);
|
||||
setInstanceIdValue(id, value);
|
||||
}
|
||||
else {
|
||||
start.put(name, start, value);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (prototypeValues != null) {
|
||||
int id = prototypeValues.findId(name);
|
||||
if (id != 0) {
|
||||
if (start == this && isSealed()) {
|
||||
throw Context.reportRuntimeError1("msg.modify.sealed",
|
||||
name);
|
||||
}
|
||||
prototypeValues.set(id, start, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.put(name, start, value);
|
||||
}
|
||||
|
||||
public void delete(String name)
|
||||
{
|
||||
if (maxInstanceId != 0) {
|
||||
int info = findInstanceIdInfo(name);
|
||||
if (info != 0) {
|
||||
// Let the super class to throw exceptions for sealed objects
|
||||
if (!isSealed()) {
|
||||
int attr = (info >>> 16);
|
||||
if ((attr & PERMANENT) == 0) {
|
||||
int id = (info & 0xFFFF);
|
||||
setInstanceIdValue(id, NOT_FOUND);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (prototypeValues != null) {
|
||||
int id = prototypeValues.findId(name);
|
||||
if (id != 0) {
|
||||
if (!isSealed()) {
|
||||
prototypeValues.delete(id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.delete(name);
|
||||
}
|
||||
|
||||
public int getAttributes(String name)
|
||||
{
|
||||
if (maxInstanceId != 0) {
|
||||
int info = findInstanceIdInfo(name);
|
||||
if (info != 0) {
|
||||
int attr = (info >>> 16);
|
||||
return attr;
|
||||
}
|
||||
}
|
||||
if (prototypeValues != null) {
|
||||
int id = prototypeValues.findId(name);
|
||||
if (id != 0) {
|
||||
return prototypeValues.getAttributes(id);
|
||||
}
|
||||
}
|
||||
return super.getAttributes(name);
|
||||
}
|
||||
|
||||
public void setAttributes(String name, int attributes)
|
||||
{
|
||||
ScriptableObject.checkValidAttributes(attributes);
|
||||
if (maxInstanceId != 0) {
|
||||
int info = findInstanceIdInfo(name);
|
||||
if (info != 0) {
|
||||
int currentAttributes = (info >>> 16);
|
||||
if (attributes != currentAttributes) {
|
||||
throw new RuntimeException(
|
||||
"Change of attributes for this id is not supported");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (prototypeValues != null) {
|
||||
int id = prototypeValues.findId(name);
|
||||
if (id != 0) {
|
||||
prototypeValues.setAttributes(id, attributes);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.setAttributes(name, attributes);
|
||||
}
|
||||
|
||||
Object[] getIds(boolean getAll)
|
||||
{
|
||||
Object[] result = super.getIds(getAll);
|
||||
|
||||
if (prototypeValues != null) {
|
||||
result = prototypeValues.getNames(getAll, result);
|
||||
}
|
||||
|
||||
if (maxInstanceId != 0) {
|
||||
Object[] ids = null;
|
||||
int count = 0;
|
||||
|
||||
for (int id = maxInstanceId; id != 0; --id) {
|
||||
String name = getInstanceIdName(id);
|
||||
int info = findInstanceIdInfo(name);
|
||||
if (info != 0) {
|
||||
int attr = (info >>> 16);
|
||||
if ((attr & PERMANENT) == 0) {
|
||||
if (NOT_FOUND == getInstanceIdValue(id)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (getAll || (attr & DONTENUM) == 0) {
|
||||
if (count == 0) {
|
||||
// Need extra room for no more then [1..id] names
|
||||
ids = new Object[id];
|
||||
}
|
||||
ids[count++] = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count != 0) {
|
||||
if (result.length == 0 && ids.length == count) {
|
||||
result = ids;
|
||||
}
|
||||
else {
|
||||
Object[] tmp = new Object[result.length + count];
|
||||
System.arraycopy(result, 0, tmp, 0, result.length);
|
||||
System.arraycopy(ids, 0, tmp, result.length, count);
|
||||
result = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Get maximum id findInstanceIdInfo can generate */
|
||||
protected final int getMaxInstanceId()
|
||||
{
|
||||
return maxInstanceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set maximum id findInstanceIdInfo can generate.
|
||||
*
|
||||
* @param maxInstanceId new value of maximum id.
|
||||
* @param prevMaxId the current result of {@link #getMaxInstanceId()}.
|
||||
* It is used for consitency checks.
|
||||
*/
|
||||
protected final void setMaxInstanceId(int prevMaxId, int maxInstanceId)
|
||||
{
|
||||
if (prevMaxId != this.maxInstanceId) {
|
||||
// Consitency check
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (this.maxInstanceId >= maxInstanceId) {
|
||||
// maxInstanceId can only go up
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.maxInstanceId = maxInstanceId;
|
||||
}
|
||||
|
||||
protected static int instanceIdInfo(int attributes, int id)
|
||||
{
|
||||
return (attributes << 16) | id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map name to id of instance property.
|
||||
* Should return 0 if not found or the result of
|
||||
* {@link #instanceIdInfo(int, int)}.
|
||||
*/
|
||||
protected int findInstanceIdInfo(String name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Map id back to property name it defines.
|
||||
*/
|
||||
protected String getInstanceIdName(int id)
|
||||
{
|
||||
throw new IllegalArgumentException(String.valueOf(id));
|
||||
}
|
||||
|
||||
/** Get id value.
|
||||
** If id value is constant, descendant can call cacheIdValue to store
|
||||
** value in the permanent cache.
|
||||
** Default implementation creates IdFunction instance for given id
|
||||
** and cache its value
|
||||
*/
|
||||
protected Object getInstanceIdValue(int id)
|
||||
{
|
||||
throw new IllegalStateException(String.valueOf(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set or delete id value. If value == NOT_FOUND , the implementation
|
||||
* should make sure that the following getInstanceIdValue return NOT_FOUND.
|
||||
*/
|
||||
protected void setInstanceIdValue(int id, Object value)
|
||||
{
|
||||
throw new IllegalStateException(String.valueOf(id));
|
||||
}
|
||||
|
||||
/** 'thisObj' will be null if invoked as constructor, in which case
|
||||
** instance of Scriptable should be returned. */
|
||||
public Object execMethod(IdFunction f, Context cx, Scriptable scope,
|
||||
Scriptable thisObj, Object[] args)
|
||||
{
|
||||
throw f.unknown();
|
||||
}
|
||||
|
||||
public final IdFunction exportAsJSClass(int maxPrototypeId,
|
||||
Scriptable scope,
|
||||
boolean sealed)
|
||||
{
|
||||
// Set scope and prototype unless IdScriptable is top level scope itself
|
||||
if (scope != this && scope != null) {
|
||||
setParentScope(scope);
|
||||
setPrototype(getObjectPrototype(scope));
|
||||
}
|
||||
|
||||
activatePrototypeMap(maxPrototypeId);
|
||||
IdFunction ctor = prototypeValues.createPrecachedConstructor();
|
||||
if (sealed) {
|
||||
sealObject();
|
||||
}
|
||||
fillConstructorProperties(ctor);
|
||||
if (sealed) {
|
||||
ctor.sealObject();
|
||||
}
|
||||
ctor.exportAsScopeProperty();
|
||||
return ctor;
|
||||
}
|
||||
|
||||
public final boolean hasPrototypeMap()
|
||||
{
|
||||
return prototypeValues != null;
|
||||
}
|
||||
|
||||
public final void activatePrototypeMap(int maxPrototypeId)
|
||||
{
|
||||
PrototypeValues values = new PrototypeValues(this, maxPrototypeId);
|
||||
synchronized (this) {
|
||||
if (prototypeValues != null)
|
||||
throw new IllegalStateException();
|
||||
prototypeValues = values;
|
||||
}
|
||||
}
|
||||
|
||||
public final void initPrototypeMethod(Object tag, int id, String name,
|
||||
int arity)
|
||||
{
|
||||
Scriptable scope = ScriptableObject.getTopLevelScope(this);
|
||||
IdFunction f = newIdFunction(tag, id, name, arity, scope);
|
||||
prototypeValues.initValue(id, name, f, DONTENUM);
|
||||
}
|
||||
|
||||
public final void initPrototypeConstructor(IdFunction f)
|
||||
{
|
||||
int id = prototypeValues.constructorId;
|
||||
if (id == 0)
|
||||
throw new IllegalStateException();
|
||||
if (f.methodId() != id)
|
||||
throw new IllegalArgumentException();
|
||||
if (isSealed()) { f.sealObject(); }
|
||||
prototypeValues.initValue(id, "constructor", f, DONTENUM);
|
||||
}
|
||||
|
||||
public final void initPrototypeValue(int id, String name, Object value,
|
||||
int attributes)
|
||||
{
|
||||
prototypeValues.initValue(id, name, value, attributes);
|
||||
}
|
||||
|
||||
protected void initPrototypeId(int id)
|
||||
{
|
||||
throw new IllegalStateException(String.valueOf(id));
|
||||
}
|
||||
|
||||
protected int findPrototypeId(String name)
|
||||
{
|
||||
throw new IllegalStateException(name);
|
||||
}
|
||||
|
||||
protected void fillConstructorProperties(IdFunction ctor)
|
||||
{
|
||||
}
|
||||
|
||||
protected void addIdFunctionProperty(Scriptable obj, Object tag, int id,
|
||||
String name, int arity)
|
||||
{
|
||||
Scriptable scope = ScriptableObject.getTopLevelScope(obj);
|
||||
IdFunction f = newIdFunction(tag, id, name, arity, scope);
|
||||
f.addAsProperty(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method to construct type error to indicate incompatible call
|
||||
* when converting script thisObj to a particular type is not possible.
|
||||
* Possible usage would be to have a private function like realThis:
|
||||
* <pre>
|
||||
* private static NativeSomething realThis(Scriptable thisObj,
|
||||
* IdFunction f)
|
||||
* {
|
||||
* if (!(thisObj instanceof NativeSomething))
|
||||
* throw incompatibleCallError(f);
|
||||
* return (NativeSomething)thisObj;
|
||||
* }
|
||||
* </pre>
|
||||
* Note that although such function can be implemented universally via
|
||||
* java.lang.Class.isInstance(), it would be much more slower.
|
||||
* @param readOnly specify if the function f does not change state of
|
||||
* object.
|
||||
* @return Scriptable object suitable for a check by the instanceof
|
||||
* operator.
|
||||
* @throws RuntimeException if no more instanceof target can be found
|
||||
*/
|
||||
protected static EcmaError incompatibleCallError(IdFunction f)
|
||||
{
|
||||
throw ScriptRuntime.typeError1("msg.incompat.call",
|
||||
f.getFunctionName());
|
||||
}
|
||||
|
||||
private IdFunction newIdFunction(Object tag, int id, String name,
|
||||
int arity, Scriptable scope)
|
||||
{
|
||||
IdFunction f = new IdFunction(this, tag, id, name, arity,
|
||||
scope);
|
||||
if (isSealed()) { f.sealObject(); }
|
||||
return f;
|
||||
}
|
||||
|
||||
protected final Object wrap_double(double x)
|
||||
{
|
||||
return (x == x) ? new Double(x) : ScriptRuntime.NaNobj;
|
||||
}
|
||||
|
||||
protected final Object wrap_int(int x)
|
||||
{
|
||||
return ScriptRuntime.wrapInt(x);
|
||||
}
|
||||
|
||||
protected final Object wrap_long(long x)
|
||||
{
|
||||
int i = (int)x;
|
||||
if (i == x) { return wrap_int(i); }
|
||||
return new Long(x);
|
||||
}
|
||||
|
||||
protected final Object wrap_boolean(boolean x)
|
||||
{
|
||||
return x ? Boolean.TRUE : Boolean.FALSE;
|
||||
}
|
||||
|
||||
private int maxInstanceId;
|
||||
private volatile PrototypeValues prototypeValues;
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче