@Override public void set(final int key, final int value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { if (getArray().has(index)) { final ArrayData data = getArray(); setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); }
NativeArray(final long[] array) { this(ArrayData.allocate(array.length)); ArrayData arrayData = this.getArray(); Class<?> widest = int.class; for (int index = 0; index < array.length; index++) { final long value = array[index]; if (widest == int.class && JSType.isRepresentableAsInt(value)) { arrayData = arrayData.set(index, (int) value, false); } else if (widest != Object.class && JSType.isRepresentableAsDouble(value)) { arrayData = arrayData.set(index, (double) value, false); widest = double.class; } else { arrayData = arrayData.set(index, (Object) value, false); widest = Object.class; } } this.setArray(arrayData); }
/** * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single object argument * * @param self self reference * @param arg argument to push * @return array after pushes */ @SpecializedFunction public static double push(final Object self, final Object arg) { try { final ScriptObject sobj = (ScriptObject)self; final ArrayData arrayData = sobj.getArray(); final long length = arrayData.length(); if (bulkable(sobj) && length < JSType.MAX_UINT) { sobj.setArray(arrayData.push(true, arg)); return length + 1; } long len = JSType.toUint32(sobj.getLength()); sobj.set(len++, arg, CALLSITE_STRICT); sobj.set("length", len, CALLSITE_STRICT); return len; } catch (final ClassCastException | NullPointerException e) { throw typeError("not.an.object", ScriptRuntime.safeToString(self)); } }
@Override public boolean delete(final Object key, final boolean strict) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); final ArrayData array = getArray(); if (array.has(index)) { if (array.canDelete(index, strict)) { setArray(array.delete(index)); return true; } return false; } return deleteObject(primitiveKey, strict); }
/** * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single object argument * * @param self self reference * @param arg argument to push * @return array after pushes */ @SpecializedFunction public static long push(final Object self, final Object arg) { try { final ScriptObject sobj = (ScriptObject)self; final ArrayData arrayData = sobj.getArray(); final long length = arrayData.length(); if (bulkable(sobj) && length < JSType.MAX_UINT) { sobj.setArray(arrayData.push(true, arg)); return length + 1; } long len = JSType.toUint32(sobj.getLength()); sobj.set(len++, arg, CALLSITE_STRICT); sobj.set("length", len, CALLSITE_STRICT); return len; } catch (final ClassCastException | NullPointerException e) { throw typeError("not.an.object", ScriptRuntime.safeToString(self)); } }
private void loadConstant(final Object object, final CompileUnit compileUnit, final MethodEmitter methodEmitter) { final String unitClassName = compileUnit.getUnitClassName(); final ClassEmitter classEmitter = compileUnit.getClassEmitter(); final int index = compiler.getConstantData().add(object); final Class<?> cls = object.getClass(); if (cls == PropertyMap.class) { methodEmitter.load(index); methodEmitter.invokestatic(unitClassName, GET_MAP.symbolName(), methodDescriptor(PropertyMap.class, int.class)); classEmitter.needGetConstantMethod(PropertyMap.class); } else if (cls.isArray()) { methodEmitter.load(index); final String methodName = ClassEmitter.getArrayMethodName(cls); methodEmitter.invokestatic(unitClassName, methodName, methodDescriptor(cls, int.class)); classEmitter.needGetConstantMethod(cls); } else { methodEmitter.loadConstants().load(index).arrayload(); if (object instanceof ArrayData) { // avoid cast to non-public ArrayData subclass methodEmitter.checkcast(ArrayData.class); methodEmitter.invoke(virtualCallNoLookup(ArrayData.class, "copy", ArrayData.class)); } else if (cls != Object.class) { methodEmitter.checkcast(cls); } } }
@Override public void set(final double key, final int value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); }
@Override public void set(final Object key, final double value, final int callSiteFlags) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } return; } final Object propName = JSType.toPropertyKey(primitiveKey); setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); }
NativeStrictArguments(final Object[] values, final int numParams,final ScriptObject proto, final PropertyMap map) { super(proto, map); setIsArguments(); final ScriptFunction func = Global.instance().getTypeErrorThrower(); // We have to fill user accessor functions late as these are stored // in this object rather than in the PropertyMap of this object. final int flags = Property.NOT_ENUMERABLE | Property.NOT_CONFIGURABLE; initUserAccessors("caller", flags, func, func); initUserAccessors("callee", flags, func, func); setArray(ArrayData.allocate(values)); this.length = values.length; // extend/truncate named arg array as needed and copy values this.namedArgs = new Object[numParams]; if (numParams > values.length) { Arrays.fill(namedArgs, UNDEFINED); } System.arraycopy(values, 0, namedArgs, 0, Math.min(namedArgs.length, values.length)); }
@Override public void set(final int key, final double value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); }
@Override public void set(final Object key, final int value, final int callSiteFlags) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(primitiveKey); setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); }
@Override public void set(final Object key, final double value, final int callSiteFlags) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(primitiveKey); setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); }
@Override public void set(final double key, final long value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); }
@Override public void set(final long key, final int value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); setObject(findProperty(propName, true), callSiteFlags, propName, JSType.toObject(value)); }
@Override public void set(final long key, final Object value, final int callSiteFlags) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { setArray(data.set(index, value, isStrictFlag(callSiteFlags))); } else { doesNotHave(index, value, callSiteFlags); } return; } final String propName = JSType.toString(key); setObject(findProperty(propName, true), callSiteFlags, propName, value); }
NativeArray(final Object[] array) { this(ArrayData.allocate(array.length)); ArrayData arrayData = this.getArray(); for (int index = 0; index < array.length; index++) { final Object value = array[index]; if (value == ScriptRuntime.EMPTY) { arrayData = arrayData.delete(index); } else { arrayData = arrayData.set(index, value, false); } } this.setArray(arrayData); }
/** * Nashorn extension: setIndexedPropertiesToExternalArrayData. * set indexed properties be exposed from a given nio ByteBuffer. * * @param buf external buffer - should be a nio ByteBuffer */ public void setIndexedPropertiesToExternalArrayData(final ByteBuffer buf) { inGlobal(new Callable<Void>() { @Override public Void call() { sobj.setArray(ArrayData.allocate(buf)); return null; } }); }
@Override public boolean delete(final long key, final boolean strict) { final int index = getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { if (array.canDelete(index, strict)) { setArray(array.delete(index)); return true; } return false; } return deleteObject(JSType.toObject(key), strict); }
@Override public boolean delete(final int key, final boolean strict) { final int index = getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { if (array.canDelete(index, strict)) { setArray(array.delete(index)); return true; } return false; } return deleteObject(JSType.toObject(key), strict); }
/** * Allocate a new object array. * * @param initial object values. * @return the new array */ public static NativeArray allocate(final Object[] initial) { ArrayData arrayData = ArrayData.allocate(initial); for (int index = 0; index < initial.length; index++) { final Object value = initial[index]; if (value == ScriptRuntime.EMPTY) { arrayData = arrayData.delete(index); } } return new NativeArray(arrayData); }
@Override public boolean delete(final double key, final boolean strict) { final int index = getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { if (array.canDelete(index, strict)) { setArray(array.delete(index)); return true; } return false; } return deleteObject(JSType.toObject(key), strict); }
private void checkIntegerKey(final Object key) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { setArray(data.delete(index)); } } }
@Override public Object get(final Object key) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); final ArrayData array = getArray(); if (array.has(index)) { return array.getObject(index); } return get(index, JSType.toPropertyKey(primitiveKey)); }
/** * ECMAScript 15.2.3.8 - seal implementation * @return the sealed ScriptObject */ public ScriptObject seal() { PropertyMap oldMap = getMap(); while (true) { final PropertyMap newMap = getMap().seal(); if (!compareAndSetMap(oldMap, newMap)) { oldMap = getMap(); } else { setArray(ArrayData.seal(getArray())); return this; } } }
NativeArguments(final Object[] arguments, final Object callee, final int numParams, final ScriptObject proto, final PropertyMap map) { super(proto, map); setIsArguments(); setArray(ArrayData.allocate(arguments)); this.length = arguments.length; this.callee = callee; this.numMapped = Math.min(numParams, arguments.length); this.numParams = numParams; }
/** * Nashorn extension: setIndexedPropertiesToExternalArrayData * * @param self self reference * @param obj object whose index properties are backed by buffer * @param buf external buffer - should be a nio ByteBuffer * @return the 'obj' object */ @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR) public static ScriptObject setIndexedPropertiesToExternalArrayData(final Object self, final Object obj, final Object buf) { Global.checkObject(obj); final ScriptObject sobj = (ScriptObject)obj; if (buf instanceof ByteBuffer) { sobj.setArray(ArrayData.allocate((ByteBuffer)buf)); } else { throw typeError("not.a.bytebuffer", "setIndexedPropertiesToExternalArrayData's buf argument"); } return sobj; }
private static ArrayData addArrayElement(final ArrayData arrayData, final int index, final Object value) { final long oldLength = arrayData.length(); final long longIndex = ArrayIndex.toLongIndex(index); ArrayData newArrayData = arrayData; if (longIndex >= oldLength) { newArrayData = newArrayData.ensure(longIndex); if (longIndex > oldLength) { newArrayData = newArrayData.delete(oldLength, longIndex - 1); } } return newArrayData.set(index, value, false); }
/** * ECMA 15.2.39 - freeze implementation. Freeze this ScriptObject * @return the frozen ScriptObject */ public ScriptObject freeze() { PropertyMap oldMap = getMap(); while (true) { final PropertyMap newMap = getMap().freeze(); if (!compareAndSetMap(oldMap, newMap)) { oldMap = getMap(); } else { setArray(ArrayData.freeze(getArray())); return this; } } }
/** * Constructor * * @param map {@link PropertyMap} used to create the initial object */ public ScriptObject(final PropertyMap map) { if (Context.DEBUG) { ScriptObject.count.increment(); } this.arrayData = ArrayData.EMPTY_ARRAY; this.setMap(map == null ? PropertyMap.newMap() : map); }
/** * Numeric length setter for length property * * @param newLength new length to set */ public final void setLength(final long newLength) { final ArrayData data = getArray(); final long arrayLength = data.length(); if (newLength == arrayLength) { return; } if (newLength > arrayLength) { setArray(data.ensure(newLength - 1).safeDelete(arrayLength, newLength - 1, false)); return; } if (newLength < arrayLength) { long actualLength = newLength; // Check for numeric keys in property map and delete them or adjust length, depending on whether // they're defined as configurable. See ES5 #15.4.5.2 if (getMap().containsArrayKeys()) { for (long l = arrayLength - 1; l >= newLength; l--) { final FindProperty find = findProperty(JSType.toString(l), false); if (find != null) { if (find.getProperty().isConfigurable()) { deleteOwnProperty(find.getProperty()); } else { actualLength = l + 1; break; } } } } setArray(data.shrink(actualLength)); data.setLength(actualLength); } }
/** * Constructor * * @param map {@link PropertyMap} used to create the initial object */ public ScriptObject(final PropertyMap map) { if (Context.DEBUG) { ScriptObject.count++; } this.arrayData = ArrayData.EMPTY_ARRAY; this.setMap(map == null ? PropertyMap.newMap() : map); }
/** * Get the {@link ArrayData}, for this ScriptObject, ensuring it is of a type * that can handle elementType * @param elementType elementType * @return array data */ public final ArrayData getArray(final Class<?> elementType) { if (elementType == null) { return arrayData; } final ArrayData newArrayData = arrayData.convert(elementType); if (newArrayData != arrayData) { arrayData = newArrayData; } return newArrayData; }
private void checkIntegerKey(final String key) { final int index = getArrayIndex(key); if (isValidArrayIndex(index)) { final ArrayData data = getArray(); if (data.has(index)) { setArray(data.delete(index)); } } }
@Override public Object get(final double key) { final int index = getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { return array.getObject(index); } return get(index, JSType.toString(key)); }
@Override public int getInt(final Object key, final int programPoint) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); final ArrayData array = getArray(); if (array.has(index)) { return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index); } return getInt(index, JSType.toString(primitiveKey), programPoint); }
@Override public int getInt(final double key, final int programPoint) { final int index = getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { return isValid(programPoint) ? array.getIntOptimistic(index, programPoint) : array.getInt(index); } return getInt(index, JSType.toString(key), programPoint); }
@Override public int getInt(final int key, final int programPoint) { final int index = getArrayIndex(key); final ArrayData array = getArray(); if (array.has(index)) { return isValid(programPoint) ? array.getIntOptimistic(key, programPoint) : array.getInt(key); } return getInt(index, JSType.toString(key), programPoint); }
@Override public long getLong(final Object key, final int programPoint) { final Object primitiveKey = JSType.toPrimitive(key, String.class); final int index = getArrayIndex(primitiveKey); final ArrayData array = getArray(); if (array.has(index)) { return isValid(programPoint) ? array.getLongOptimistic(index, programPoint) : array.getLong(index); } return getLong(index, JSType.toString(primitiveKey), programPoint); }