This commit is contained in:
Lana Steuck 2014-11-13 09:38:35 -08:00
commit 30066363bb
44 changed files with 1729 additions and 627 deletions

View File

@ -156,6 +156,7 @@
<fileset dir="${src.dir}/jdk/nashorn/tools/resources/"/>
</copy>
<copy file="${src.dir}/jdk/internal/dynalink/support/messages.properties" todir="${build.classes.dir}/jdk/internal/dynalink/support"/>
<copy file="${src.dir}/jdk/nashorn/internal/codegen/anchor.properties" todir="${build.classes.dir}/jdk/nashorn/internal/codegen"/>
<echo message="full=${nashorn.fullversion}" file="${build.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties"/>
<echo file="${build.classes.dir}/jdk/nashorn/internal/runtime/resources/version.properties" append="true">${line.separator}</echo>

View File

@ -140,6 +140,11 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
private boolean hasApplies(final FunctionNode functionNode) {
try {
functionNode.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
@Override
public boolean enterFunctionNode(final FunctionNode fn) {
return fn == functionNode;
}
@Override
public boolean enterCallNode(final CallNode callNode) {
if (isApply(callNode)) {
@ -162,7 +167,7 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
* scope, thus we are conservative and treat any access to arguments outside the
* apply call as a case of "we cannot apply the optimization".
*/
private void checkValidTransform(final FunctionNode functionNode) {
private static void checkValidTransform(final FunctionNode functionNode) {
final Set<Expression> argumentsFound = new HashSet<>();
final Deque<Set<Expression>> stack = new ArrayDeque<>();

View File

@ -33,6 +33,8 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
@ -221,11 +223,37 @@ public final class OptimisticTypesPersistence {
private static void reportError(final String msg, final File file, final Exception e) {
final long now = System.currentTimeMillis();
if(now - lastReportedError > ERROR_REPORT_THRESHOLD) {
getLogger().warning(String.format("Failed to %s %s", msg, file), e);
reportError(String.format("Failed to %s %s", msg, file), e);
lastReportedError = now;
}
}
/**
* Logs an error message with warning severity (reasoning being that we're reporting an error that'll disable the
* type info cache, but it's only logged as a warning because that doesn't prevent Nashorn from running, it just
* disables a performance-enhancing cache).
* @param msg the message to log
* @param e the exception that represents the error.
*/
private static void reportError(final String msg, final Exception e) {
getLogger().warning(msg, "\n", exceptionToString(e));
}
/**
* A helper that prints an exception stack trace into a string. We have to do this as if we just pass the exception
* to {@link DebugLogger#warning(Object...)}, it will only log the exception message and not the stack, making
* problems harder to diagnose.
* @param e the exception
* @return the string representation of {@link Exception#printStackTrace()} output.
*/
private static String exceptionToString(final Exception e) {
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw, false);
e.printStackTrace(pw);
pw.flush();
return sw.toString();
}
private static File createBaseCacheDir() {
if(MAX_FILES == 0 || Options.getBooleanProperty("nashorn.typeInfo.disabled")) {
return null;
@ -233,7 +261,7 @@ public final class OptimisticTypesPersistence {
try {
return createBaseCacheDirPrivileged();
} catch(final Exception e) {
getLogger().warning("Failed to create cache dir", e);
reportError("Failed to create cache dir", e);
return null;
}
}
@ -267,7 +295,7 @@ public final class OptimisticTypesPersistence {
try {
return createCacheDirPrivileged(baseDir);
} catch(final Exception e) {
getLogger().warning("Failed to create cache dir", e);
reportError("Failed to create cache dir", e);
return null;
}
}
@ -280,7 +308,7 @@ public final class OptimisticTypesPersistence {
try {
versionDirName = getVersionDirName();
} catch(final Exception e) {
getLogger().warning("Failed to calculate version dir name", e);
reportError("Failed to calculate version dir name", e);
return null;
}
final File versionDir = new File(baseDir, versionDirName);
@ -328,7 +356,12 @@ public final class OptimisticTypesPersistence {
* @throws Exception if digest could not be created
*/
public static String getVersionDirName() throws Exception {
final URL url = OptimisticTypesPersistence.class.getResource("");
// NOTE: getResource("") won't work if the JAR file doesn't have directory entries (and JAR files in JDK distro
// don't, or at least it's a bad idea counting on it). Alternatively, we could've tried
// getResource("OptimisticTypesPersistence.class") but behavior of getResource with regard to its willingness
// to hand out URLs to .class files is also unspecified. Therefore, the most robust way to obtain an URL to our
// package is to have a small non-class anchor file and start out from its URL.
final URL url = OptimisticTypesPersistence.class.getResource("anchor.properties");
final String protocol = url.getProtocol();
if (protocol.equals("jar")) {
// Normal deployment: nashorn.jar

View File

@ -0,0 +1,27 @@
#
# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Oracle designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
# This file exists only so OptimisticTypesPersistence.getVersionDirName() can take its URL.

View File

@ -264,6 +264,10 @@ public final class BinaryNode extends Expression implements Assignment<Expressio
case COMMARIGHT: {
return rhs.getType(localVariableTypes);
}
case AND:
case OR:{
return Type.widestReturnType(lhs.getType(localVariableTypes), rhs.getType(localVariableTypes));
}
default:
if (isComparison()) {
return Type.BOOLEAN;

View File

@ -35,7 +35,6 @@ import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArray
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -93,17 +92,6 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
private static final Object CALL_CMP = new Object();
private static final Object TO_LOCALE_STRING = new Object();
private SwitchPoint lengthMadeNotWritableSwitchPoint;
private PushLinkLogic pushLinkLogic;
private PopLinkLogic popLinkLogic;
private ConcatLinkLogic concatLinkLogic;
/**
* Index for the modification SwitchPoint that triggers when length
* becomes not writable
*/
private static final int LENGTH_NOT_WRITABLE_SWITCHPOINT = 0;
/*
* Constructors.
*/
@ -271,12 +259,83 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
@Override
public Object getLength() {
final long length = JSType.toUint32(getArray().length());
if(length < Integer.MAX_VALUE) {
if (length < Integer.MAX_VALUE) {
return (int)length;
}
return length;
}
private boolean defineLength(final long oldLen, final PropertyDescriptor oldLenDesc, final PropertyDescriptor desc, final boolean reject) {
// Step 3a
if (!desc.has(VALUE)) {
return super.defineOwnProperty("length", desc, reject);
}
// Step 3b
final PropertyDescriptor newLenDesc = desc;
// Step 3c and 3d - get new length and convert to long
final long newLen = NativeArray.validLength(newLenDesc.getValue(), true);
// Step 3e
newLenDesc.setValue(newLen);
// Step 3f
// increasing array length - just need to set new length value (and attributes if any) and return
if (newLen >= oldLen) {
return super.defineOwnProperty("length", newLenDesc, reject);
}
// Step 3g
if (!oldLenDesc.isWritable()) {
if (reject) {
throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this));
}
return false;
}
// Step 3h and 3i
final boolean newWritable = !newLenDesc.has(WRITABLE) || newLenDesc.isWritable();
if (!newWritable) {
newLenDesc.setWritable(true);
}
// Step 3j and 3k
final boolean succeeded = super.defineOwnProperty("length", newLenDesc, reject);
if (!succeeded) {
return false;
}
// Step 3l
// make sure that length is set till the point we can delete the old elements
long o = oldLen;
while (newLen < o) {
o--;
final boolean deleteSucceeded = delete(o, false);
if (!deleteSucceeded) {
newLenDesc.setValue(o + 1);
if (!newWritable) {
newLenDesc.setWritable(false);
}
super.defineOwnProperty("length", newLenDesc, false);
if (reject) {
throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this));
}
return false;
}
}
// Step 3m
if (!newWritable) {
// make 'length' property not writable
final ScriptObject newDesc = Global.newEmptyInstance();
newDesc.set(WRITABLE, false, 0);
return super.defineOwnProperty("length", newDesc, false);
}
return true;
}
/**
* ECMA 15.4.5.1 [[DefineOwnProperty]] ( P, Desc, Throw )
*/
@ -290,82 +349,16 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
// Step 2
// get old length and convert to long
long oldLen = NativeArray.validLength(oldLenDesc.getValue(), true);
final long oldLen = NativeArray.validLength(oldLenDesc.getValue(), true);
// Step 3
if ("length".equals(key)) {
// check for length being made non-writable
final boolean result = defineLength(oldLen, oldLenDesc, desc, reject);
if (desc.has(WRITABLE) && !desc.isWritable()) {
setIsLengthNotWritable();
}
// Step 3a
if (!desc.has(VALUE)) {
return super.defineOwnProperty("length", desc, reject);
}
// Step 3b
final PropertyDescriptor newLenDesc = desc;
// Step 3c and 3d - get new length and convert to long
final long newLen = NativeArray.validLength(newLenDesc.getValue(), true);
// Step 3e
newLenDesc.setValue(newLen);
// Step 3f
// increasing array length - just need to set new length value (and attributes if any) and return
if (newLen >= oldLen) {
return super.defineOwnProperty("length", newLenDesc, reject);
}
// Step 3g
if (!oldLenDesc.isWritable()) {
if (reject) {
throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this));
}
return false;
}
// Step 3h and 3i
final boolean newWritable = !newLenDesc.has(WRITABLE) || newLenDesc.isWritable();
if (!newWritable) {
newLenDesc.setWritable(true);
}
// Step 3j and 3k
final boolean succeeded = super.defineOwnProperty("length", newLenDesc, reject);
if (!succeeded) {
return false;
}
// Step 3l
// make sure that length is set till the point we can delete the old elements
while (newLen < oldLen) {
oldLen--;
final boolean deleteSucceeded = delete(oldLen, false);
if (!deleteSucceeded) {
newLenDesc.setValue(oldLen + 1);
if (!newWritable) {
newLenDesc.setWritable(false);
}
super.defineOwnProperty("length", newLenDesc, false);
if (reject) {
throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this));
}
return false;
}
}
// Step 3m
if (!newWritable) {
// make 'length' property not writable
final ScriptObject newDesc = Global.newEmptyInstance();
newDesc.set(WRITABLE, false, 0);
return super.defineOwnProperty("length", newDesc, false);
}
return true;
return result;
}
// Step 4a
@ -441,23 +434,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
@Override
public void setIsLengthNotWritable() {
super.setIsLengthNotWritable();
/*
* Switchpoints are created lazily. If we link any push or pop site,
* we need to create the "length made not writable" switchpoint, if it
* doesn't exist.
*
* If the switchpoint already exists, we will find it here, and invalidate
* it, invalidating all previous callsites that use it.
*
* If the switchpoint doesn't exist, no push/pop has been linked so far,
* because that would create it too. We invalidate it immediately and the
* check link logic for all future callsites will fail immediately at link
* time
*/
if (lengthMadeNotWritableSwitchPoint == null) {
lengthMadeNotWritableSwitchPoint = new SwitchPoint();
}
SwitchPoint.invalidateAll(new SwitchPoint[] { lengthMadeNotWritableSwitchPoint });
setArray(ArrayData.setIsLengthNotWritable(getArray()));
}
/**
@ -494,7 +471,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
@Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static void length(final Object self, final Object length) {
if (isArray(self)) {
((ScriptObject) self).setLength(validLength(length, true));
((ScriptObject)self).setLength(validLength(length, true));
}
}
@ -1306,10 +1283,13 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
// Get only non-missing elements. Missing elements go at the end
// of the sorted array. So, just don't copy these to sort input.
final ArrayList<Object> src = new ArrayList<>();
for (long i = 0; i < len; i = array.nextIndex(i)) {
if (array.has((int) i)) {
src.add(array.getObject((int) i));
for (final Iterator<Long> iter = array.indexIterator(); iter.hasNext(); ) {
final long index = iter.next();
if (index >= len) {
break;
}
src.add(array.getObject((int)index));
}
final Object[] sorted = sort(src.toArray(), comparefn);
@ -1767,11 +1747,11 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
@Override
public SpecializedFunction.LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz) {
if (clazz == PushLinkLogic.class) {
return pushLinkLogic == null ? new PushLinkLogic(this) : pushLinkLogic;
return PushLinkLogic.INSTANCE;
} else if (clazz == PopLinkLogic.class) {
return popLinkLogic == null ? new PopLinkLogic(this) : pushLinkLogic;
return PopLinkLogic.INSTANCE;
} else if (clazz == ConcatLinkLogic.class) {
return concatLinkLogic == null ? new ConcatLinkLogic(this) : concatLinkLogic;
return ConcatLinkLogic.INSTANCE;
}
return null;
}
@ -1787,21 +1767,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
* modification switchpoint which is touched when length is written.
*/
private static abstract class ArrayLinkLogic extends SpecializedFunction.LinkLogic {
private final NativeArray array;
protected ArrayLinkLogic(final NativeArray array) {
this.array = array;
}
private SwitchPoint getSwitchPoint() {
return array.lengthMadeNotWritableSwitchPoint;
}
private SwitchPoint newSwitchPoint() {
assert array.lengthMadeNotWritableSwitchPoint == null;
final SwitchPoint sp = new SwitchPoint();
array.lengthMadeNotWritableSwitchPoint = sp;
return sp;
protected ArrayLinkLogic() {
}
protected static ContinuousArrayData getContinuousArrayData(final Object self) {
@ -1822,68 +1788,13 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
public Class<? extends Throwable> getRelinkException() {
return ClassCastException.class;
}
@Override
public boolean hasModificationSwitchPoints() {
return getSwitchPoint() != null;
}
@Override
public boolean hasModificationSwitchPoint(final int index) {
assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
return hasModificationSwitchPoints();
}
@Override
public SwitchPoint getOrCreateModificationSwitchPoint(final int index) {
assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
SwitchPoint sp = getSwitchPoint();
if (sp == null) {
sp = newSwitchPoint();
}
return sp;
}
@Override
public SwitchPoint[] getOrCreateModificationSwitchPoints() {
return new SwitchPoint[] { getOrCreateModificationSwitchPoint(LENGTH_NOT_WRITABLE_SWITCHPOINT) };
}
@Override
public void invalidateModificationSwitchPoint(final int index) {
assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
invalidateModificationSwitchPoints();
}
@Override
public void invalidateModificationSwitchPoints() {
final SwitchPoint sp = getSwitchPoint();
assert sp != null : "trying to invalidate non-existant modified SwitchPoint";
if (!sp.hasBeenInvalidated()) {
SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
}
}
@Override
public boolean hasInvalidatedModificationSwitchPoint(final int index) {
assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
return hasInvalidatedModificationSwitchPoints();
}
@Override
public boolean hasInvalidatedModificationSwitchPoints() {
final SwitchPoint sp = getSwitchPoint();
return sp != null && !sp.hasBeenInvalidated();
}
}
/**
* This is linker logic for optimistic concatenations
*/
private static final class ConcatLinkLogic extends ArrayLinkLogic {
private ConcatLinkLogic(final NativeArray array) {
super(array);
}
private static final LinkLogic INSTANCE = new ConcatLinkLogic();
@Override
public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
@ -1915,9 +1826,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
* This is linker logic for optimistic pushes
*/
private static final class PushLinkLogic extends ArrayLinkLogic {
private PushLinkLogic(final NativeArray array) {
super(array);
}
private static final LinkLogic INSTANCE = new PushLinkLogic();
@Override
public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
@ -1929,9 +1838,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
* This is linker logic for optimistic pops
*/
private static final class PopLinkLogic extends ArrayLinkLogic {
private PopLinkLogic(final NativeArray array) {
super(array);
}
private static final LinkLogic INSTANCE = new PopLinkLogic();
/**
* We need to check if we are dealing with a continuous non empty array data here,

View File

@ -39,6 +39,7 @@ import jdk.nashorn.internal.runtime.PropertyListeners;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.events.RuntimeEvent;
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
@ -65,6 +66,36 @@ public final class NativeDebug extends ScriptObject {
return "Debug";
}
/**
* Return the ArrayData class for this ScriptObject
* @param self self
* @param obj script object to check
* @return ArrayData class, or undefined if no ArrayData is present
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object getArrayDataClass(final Object self, final Object obj) {
try {
return ((ScriptObject)obj).getArray().getClass();
} catch (final ClassCastException e) {
return ScriptRuntime.UNDEFINED;
}
}
/**
* Return the ArrayData for this ScriptObject
* @param self self
* @param obj script object to check
* @return ArrayData, ArrayDatas have toString methods, return Undefined if data missing
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object getArrayData(final Object self, final Object obj) {
try {
return ((ScriptObject)obj).getArray();
} catch (final ClassCastException e) {
return ScriptRuntime.UNDEFINED;
}
}
/**
* Nashorn extension: get context, context utility
*

View File

@ -30,7 +30,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.runtime.ScriptFunction;
@ -62,10 +61,6 @@ public @interface SpecializedFunction {
*/
public static final LinkLogic EMPTY_INSTANCE = new Empty();
private static final SwitchPoint[] INVALIDATED_SWITCHPOINTS = new SwitchPoint[0];
private SwitchPoint[] modificationSwitchPoints; //cache
/** Empty link logic class - allow all linking, no guards */
private static final class Empty extends LinkLogic {
@Override
@ -166,92 +161,6 @@ public @interface SpecializedFunction {
return null;
}
/**
* Return the modification SwitchPoint of a particular index from this OptimisticBuiltins
* If none exists, one is created and that one is return.
*
* The implementor must map indexes to specific SwitchPoints for specific events and keep
* track of what they mean, for example NativeArray.LENGTH_NOT_WRITABLE_SWITCHPOINT
* might be a useful index mapping
*
* @param index index for SwitchPoint to get or create
* @return modification SwitchPoint of particular index for the receiver
*/
public SwitchPoint getOrCreateModificationSwitchPoint(final int index) {
return null;
}
/**
* Return the modification SwitchPoint from this OptimisticBuiltins. If none
* exists, one is created and that one is return.
*
* @return modification SwitchPoint for the receiver
*/
public SwitchPoint[] getOrCreateModificationSwitchPoints() {
return null;
}
/**
* Hook to invalidate a modification SwitchPoint by index.
*
* @param index index for SwitchPoint to invalidate
*/
public void invalidateModificationSwitchPoint(final int index) {
//empty
}
/**
* Hook to invalidate all modification SwitchPoints for a receiver
*/
public void invalidateModificationSwitchPoints() {
//empty
}
/**
* Check whether the receiver has an invalidated modification SwitchPoint.
*
* @param index index for the modification SwitchPoint
* @return true if the particular SwitchPoint at the index is invalidated
*/
public boolean hasInvalidatedModificationSwitchPoint(final int index) {
return false;
}
/**
* Check whether at least one of the modification SwitchPoints has been
* invalidated
* @return true if one of the SwitchPoints has been invalidated
*/
public boolean hasInvalidatedModificationSwitchPoints() {
return false;
}
/**
* Check whether this OptimisticBuiltins has a SwitchPoints of particular
* index.
*
* As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of,
* e.g. in the constructor of every subclass.
*
* @param index index for the modification SwitchPoint
* @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not
*/
public boolean hasModificationSwitchPoint(final int index) {
return false;
}
/**
* Check whether this OptimisticBuiltins has SwitchPoints.
*
* As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of,
* e.g. in the constructor of every subclass.
*
* @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not
*/
public boolean hasModificationSwitchPoints() {
return false;
}
/**
* Check, given a link request and a receiver, if this specialization
* fits This is used by the linker in {@link ScriptFunction} to figure
@ -265,47 +174,9 @@ public @interface SpecializedFunction {
* pick a non specialized target
*/
public boolean checkLinkable(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
// no matter what the modification switchpoints are, if any of them are invalidated,
// we can't link. Side effect is that if it's the first time we see this callsite,
// we have to create the SwitchPoint(s) so future modification switchpoint invalidations
// relink it
final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(self);
if (sps == INVALIDATED_SWITCHPOINTS) {
// nope, can't do the fast link as this assumption
// has been invalidated already, e.g. length of an
// array set to not writable
return false;
}
modificationSwitchPoints = sps; //cache
// check the link guard, if it says we can link, go ahead
return canLink(self, desc, request);
}
private SwitchPoint[] getOrCreateModificationSwitchPoints(final Object self) {
final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(); //ask for all my switchpoints
if (sps != null) { //switchpoint exists, but some may be invalidated
for (final SwitchPoint sp : sps) {
if (sp.hasBeenInvalidated()) {
return INVALIDATED_SWITCHPOINTS;
}
}
}
return sps;
}
/**
* Get the cached modification switchpoints. Only possible to do after a link
* check call has been performed, one that has answered "true", or you will get the
* wrong information.
*
* Should be used only from {@link ScriptFunction#findCallMethod}
*
* @return cached modification switchpoints for this callsite, null if none
*/
public SwitchPoint[] getModificationSwitchPoints() {
return modificationSwitchPoints == null ? null : modificationSwitchPoints.clone();
}
}
/**

View File

@ -82,10 +82,9 @@ public abstract class CodeStore implements Loggable {
* Returns a new code store instance.
*
* @param context the current context
* @return The instance
* @throws IOException If an error occurs
* @return The instance, or null if code store could not be created
*/
public static CodeStore newCodeStore(final Context context) throws IOException {
public static CodeStore newCodeStore(final Context context) {
final Class<CodeStore> baseClass = CodeStore.class;
try {
// security check first
@ -103,9 +102,14 @@ public abstract class CodeStore implements Loggable {
} catch (final AccessControlException e) {
context.getLogger(CodeStore.class).warning("failed to load code store provider ", e);
}
final CodeStore store = new DirectoryCodeStore(context);
store.initLogger(context);
return store;
try {
final CodeStore store = new DirectoryCodeStore(context);
store.initLogger(context);
return store;
} catch (final IOException e) {
context.getLogger(CodeStore.class).warning("failed to create cache directory ", e);
return null;
}
}

View File

@ -33,9 +33,11 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.lang.invoke.SwitchPoint;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Supplier;
@ -726,34 +728,58 @@ final class CompiledFunction {
* @param ipp
* @return string describing the ipp map
*/
private static String toStringInvalidations(final Map<Integer, Type> ipp) {
private static List<String> toStringInvalidations(final Map<Integer, Type> ipp) {
if (ipp == null) {
return "";
return Collections.emptyList();
}
final StringBuilder sb = new StringBuilder();
final List<String> list = new ArrayList<>();
for (final Iterator<Map.Entry<Integer, Type>> iter = ipp.entrySet().iterator(); iter.hasNext(); ) {
final Map.Entry<Integer, Type> entry = iter.next();
final char bct = entry.getValue().getBytecodeStackType();
final String type;
switch (entry.getValue().getBytecodeStackType()) {
case 'A':
type = "object";
break;
case 'I':
type = "int";
break;
case 'J':
type = "long";
break;
case 'D':
type = "double";
break;
default:
type = String.valueOf(bct);
break;
}
final StringBuilder sb = new StringBuilder();
sb.append('[').
append("program point: ").
append(entry.getKey()).
append("->").
append(bct == 'A' ? 'O' : bct).
append(" -> ").
append(type).
append(']');
if (iter.hasNext()) {
sb.append(' ');
}
list.add(sb.toString());
}
return sb.toString();
return list;
}
private void logRecompile(final String reason, final FunctionNode fn, final MethodType type, final Map<Integer, Type> ipp) {
if (log.isEnabled()) {
log.info(reason, DebugLogger.quote(fn.getName()), " signature: ", type, " ", toStringInvalidations(ipp));
log.info(reason, DebugLogger.quote(fn.getName()), " signature: ", type);
log.indent();
for (final String str : toStringInvalidations(ipp)) {
log.fine(str);
}
log.unindent();
}
}
@ -769,7 +795,14 @@ final class CompiledFunction {
*/
private synchronized MethodHandle handleRewriteException(final OptimismInfo oldOptInfo, final RewriteException re) {
if (log.isEnabled()) {
log.info(new RecompilationEvent(Level.INFO, re, re.getReturnValueNonDestructive()), "RewriteException ", re.getMessageShort());
log.info(
new RecompilationEvent(
Level.INFO,
re,
re.getReturnValueNonDestructive()),
"caught RewriteException ",
re.getMessageShort());
log.indent();
}
final MethodType type = type();
@ -799,7 +832,7 @@ final class CompiledFunction {
logRecompile("Deoptimizing recompilation (up to bytecode) ", fn, ct, effectiveOptInfo.invalidatedProgramPoints);
fn = compiler.compile(fn, serialized ? CompilationPhases.RECOMPILE_SERIALIZED_UPTO_BYTECODE : CompilationPhases.COMPILE_UPTO_BYTECODE);
log.info("Reusable IR generated");
log.fine("Reusable IR generated");
// compile the rest of the function, and install it
log.info("Generating and installing bytecode from reusable IR...");
@ -815,15 +848,15 @@ final class CompiledFunction {
compiler.persistClassInfo(cacheKey, normalFn);
}
log.info("Done.");
final boolean canBeDeoptimized = normalFn.canBeDeoptimized();
if (log.isEnabled()) {
log.info("Recompiled '", fn.getName(), "' (", Debug.id(this), ") ", canBeDeoptimized ? " can still be deoptimized." : " is completely deoptimized.");
}
log.unindent();
log.info("Done.");
log.info("Looking up invoker...");
log.info("Recompiled '", fn.getName(), "' (", Debug.id(this), ") ", canBeDeoptimized ? "can still be deoptimized." : " is completely deoptimized.");
log.finest("Looking up invoker...");
}
final MethodHandle newInvoker = effectiveOptInfo.data.lookup(fn);
invoker = newInvoker.asType(type.changeReturnType(newInvoker.type().returnType()));
@ -870,7 +903,6 @@ final class CompiledFunction {
private SwitchPoint optimisticAssumptions;
private final DebugLogger log;
@SuppressWarnings("unused")
OptimismInfo(final RecompilableScriptFunctionData data, final Map<Integer, Type> invalidatedProgramPoints) {
this.data = data;
this.log = data.getLogger();

View File

@ -509,11 +509,7 @@ public final class Context {
}
if (env._persistent_cache) {
try {
codeStore = newCodeStore(this);
} catch (final IOException e) {
throw new RuntimeException("Error initializing code cache", e);
}
codeStore = newCodeStore(this);
}
// print version info if asked.
@ -1200,7 +1196,7 @@ public final class Context {
FunctionNode functionNode = null;
// We only use the code store here if optimistic types are disabled. With optimistic types, initial compilation
// just creates a thin wrapper, and actual code is stored per function in RecompilableScriptFunctionData.
final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types;
final boolean useCodeStore = codeStore != null && !env._parse_only && !env._optimistic_types;
final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null;
if (useCodeStore) {

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@ -620,20 +619,25 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return f;
}
MethodHandle lookup(final FunctionInitializer fnInit) {
private void logLookup(final boolean shouldLog, final MethodType targetType) {
if (shouldLog && log.isEnabled()) {
log.info("Looking up ", DebugLogger.quote(functionName), " type=", targetType);
}
}
private MethodHandle lookup(final FunctionInitializer fnInit, final boolean shouldLog) {
final MethodType type = fnInit.getMethodType();
logLookup(shouldLog, type);
return lookupCodeMethod(fnInit.getCode(), type);
}
MethodHandle lookup(final FunctionNode fn) {
final MethodType type = new FunctionSignature(fn).getMethodType();
logLookup(true, type);
return lookupCodeMethod(fn.getCompileUnit().getCode(), type);
}
MethodHandle lookupCodeMethod(final Class<?> codeClass, final MethodType targetType) {
if (log.isEnabled()) {
log.info("Looking up ", DebugLogger.quote(functionName), " type=", targetType);
}
return MH.findStatic(LOOKUP, codeClass, functionName, targetType);
}
@ -649,7 +653,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
if(!code.isEmpty()) {
throw new IllegalStateException(name);
}
addCode(lookup(initializer), null, null, initializer.getFlags());
addCode(lookup(initializer, true), null, null, initializer.getFlags());
}
private CompiledFunction addCode(final MethodHandle target, final Map<Integer, Type> invalidatedProgramPoints,
@ -671,10 +675,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
*/
private CompiledFunction addCode(final FunctionInitializer fnInit, final MethodType callSiteType) {
if (isVariableArity()) {
return addCode(lookup(fnInit), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags());
return addCode(lookup(fnInit, true), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags());
}
final MethodHandle handle = lookup(fnInit);
final MethodHandle handle = lookup(fnInit, true);
final MethodType fromType = handle.type();
MethodType toType = needsCallee(fromType) ? callSiteType.changeParameterType(0, ScriptFunction.class) : callSiteType.dropParameterTypes(0, 1);
toType = toType.changeReturnType(fromType.returnType());
@ -699,7 +703,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
toType = toType.dropParameterTypes(fromCount, toCount);
}
return addCode(lookup(fnInit).asType(toType), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags());
return addCode(lookup(fnInit, false).asType(toType), fnInit.getInvalidatedProgramPoints(), callSiteType, fnInit.getFlags());
}
/**

View File

@ -603,16 +603,6 @@ public abstract class ScriptFunction extends ScriptObject {
log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc);
}
final SwitchPoint[] msps = linkLogic.getModificationSwitchPoints();
if (msps != null) {
for (final SwitchPoint sp : msps) {
if (sp != null) {
assert !sp.hasBeenInvalidated();
sps.add(sp);
}
}
}
exceptionGuard = linkLogic.getRelinkException();
break;

View File

@ -510,6 +510,13 @@ public abstract class ScriptObject implements PropertyAccess {
}
}
private void invalidateGlobalConstant(final String key) {
final GlobalConstants globalConstants = getGlobalConstants();
if (globalConstants != null) {
globalConstants.delete(key);
}
}
/**
* ECMA 8.12.9 [[DefineOwnProperty]] (P, Desc, Throw)
*
@ -525,6 +532,8 @@ public abstract class ScriptObject implements PropertyAccess {
final Object current = getOwnPropertyDescriptor(key);
final String name = JSType.toString(key);
invalidateGlobalConstant(key);
if (current == UNDEFINED) {
if (isExtensible()) {
// add a new own property
@ -923,10 +932,8 @@ public abstract class ScriptObject implements PropertyAccess {
if (property instanceof UserAccessorProperty) {
((UserAccessorProperty)property).setAccessors(this, getMap(), null);
}
final GlobalConstants globalConstants = getGlobalConstants();
if (globalConstants != null) {
globalConstants.delete(property.getKey());
}
invalidateGlobalConstant(property.getKey());
return true;
}
}
@ -1352,12 +1359,9 @@ public abstract class ScriptObject implements PropertyAccess {
final PropertyMap selfMap = this.getMap();
final ArrayData array = getArray();
final long length = array.length();
for (long i = 0; i < length; i = array.nextIndex(i)) {
if (array.has((int)i)) {
keys.add(JSType.toString(i));
}
for (final Iterator<Long> iter = array.indexIterator(); iter.hasNext(); ) {
keys.add(JSType.toString(iter.next().longValue()));
}
for (final Property property : selfMap.getProperties()) {
@ -1516,12 +1520,12 @@ public abstract class ScriptObject implements PropertyAccess {
*
* @return {@code true} if 'length' property is non-writable
*/
public final boolean isLengthNotWritable() {
public boolean isLengthNotWritable() {
return (flags & IS_LENGTH_NOT_WRITABLE) != 0;
}
/**
* Flag this object as having non-writable length property
* Flag this object as having non-writable length property.
*/
public void setIsLengthNotWritable() {
flags |= IS_LENGTH_NOT_WRITABLE;
@ -3152,6 +3156,8 @@ public abstract class ScriptObject implements PropertyAccess {
public final void setObject(final FindProperty find, final int callSiteFlags, final String key, final Object value) {
FindProperty f = find;
invalidateGlobalConstant(key);
if (f != null && f.isInherited() && !(f.getProperty() instanceof UserAccessorProperty)) {
final boolean isScope = NashornCallSiteDescriptor.isScopeFlag(callSiteFlags);
// If the start object of the find is not this object it means the property was found inside a
@ -3177,7 +3183,6 @@ public abstract class ScriptObject implements PropertyAccess {
if (NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)) {
throw typeError("property.not.writable", key, ScriptRuntime.safeToString(this));
}
return;
}
@ -3588,7 +3593,6 @@ public abstract class ScriptObject implements PropertyAccess {
}
return false;
}
return deleteObject(JSType.toObject(key), strict);
}

View File

@ -30,6 +30,9 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@ -55,6 +58,21 @@ public abstract class ArrayData {
* a proper ArrayData when we try to write to it */
public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData();
/**
* Length of the array data. Not necessarily length of the wrapped array.
* This is private to ensure that no one in a subclass is able to touch the length
* without going through {@link setLength}. This is used to implement
* {@link LengthNotWritableFilter}s, ensuring that there are no ways past
* a {@link setLength} function replaced by a nop
*/
private long length;
/**
* Method handle to throw an {@link UnwarrantedOptimismException} when getting an element
* of the wrong type
*/
protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class);
/**
* Immutable empty array to get ScriptObjects started.
* Use the same array and convert it to mutable as soon as it is modified
@ -82,7 +100,7 @@ public abstract class ArrayData {
@Override
public ContinuousArrayData copy() {
return new UntouchedArrayData((int)length);
return new UntouchedArrayData((int)length());
}
@Override
@ -112,6 +130,16 @@ public abstract class ArrayData {
return toRealArrayData(0).convert(type);
}
@Override
public ArrayData delete(final int index) {
return new DeletedRangeArrayFilter(this, index, index);
}
@Override
public ArrayData delete(final long fromIndex, final long toIndex) {
return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
}
@Override
public void shiftLeft(final int by) {
//nop, always empty or we wouldn't be of this class
@ -172,16 +200,6 @@ public abstract class ArrayData {
return false; //empty
}
@Override
public ArrayData delete(final int index) {
return new DeletedRangeArrayFilter(this, index, index);
}
@Override
public ArrayData delete(final long fromIndex, final long toIndex) {
return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
}
@Override
public Object pop() {
return ScriptRuntime.UNDEFINED;
@ -230,17 +248,6 @@ public abstract class ArrayData {
}
};
/**
* Length of the array data. Not necessarily length of the wrapped array.
*/
protected long length;
/**
* Method handle to throw an {@link UnwarrantedOptimismException} when getting an element
* of the wrong type
*/
protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class);
/**
* Constructor
* @param length Virtual length of the array.
@ -393,6 +400,16 @@ public abstract class ArrayData {
return new NonExtensibleArrayFilter(underlying);
}
/**
* Prevent this array from having its length reset
*
* @param underlying the underlying ArrayDAta to wrap in the non extensible filter
* @return new array data, filtered
*/
public static final ArrayData setIsLengthNotWritable(final ArrayData underlying) {
return new LengthNotWritableFilter(underlying);
}
/**
* Return the length of the array data. This may differ from the actual
* length of the array this wraps as length may be set or gotten as any
@ -445,6 +462,22 @@ public abstract class ArrayData {
this.length = length;
}
/**
* Increase length by 1
* @return the new length, not the old one (i.e. pre-increment)
*/
protected final long increaseLength() {
return ++this.length;
}
/**
* Decrease length by 1.
* @return the new length, not the old one (i.e. pre-decrement)
*/
protected final long decreaseLength() {
return --this.length;
}
/**
* Shift the array data left
*
@ -454,7 +487,7 @@ public abstract class ArrayData {
*
* @param by offset to shift
*/
public abstract void shiftLeft(int by);
public abstract void shiftLeft(final int by);
/**
* Shift the array right
@ -463,7 +496,7 @@ public abstract class ArrayData {
* @return New arraydata (or same)
*/
public abstract ArrayData shiftRight(int by);
public abstract ArrayData shiftRight(final int by);
/**
* Ensure that the given index exists and won't fail subsequent
@ -471,7 +504,7 @@ public abstract class ArrayData {
* @param safeIndex the index to ensure wont go out of bounds
* @return new array data (or same)
*/
public abstract ArrayData ensure(long safeIndex);
public abstract ArrayData ensure(final long safeIndex);
/**
* Shrink the array to a new length, may or may not retain the
@ -481,7 +514,7 @@ public abstract class ArrayData {
*
* @return new array data (or same)
*/
public abstract ArrayData shrink(long newLength);
public abstract ArrayData shrink(final long newLength);
/**
* Set an object value at a given index
@ -491,7 +524,7 @@ public abstract class ArrayData {
* @param strict are we in strict mode
* @return new array data (or same)
*/
public abstract ArrayData set(int index, Object value, boolean strict);
public abstract ArrayData set(final int index, final Object value, final boolean strict);
/**
* Set an int value at a given index
@ -501,7 +534,7 @@ public abstract class ArrayData {
* @param strict are we in strict mode
* @return new array data (or same)
*/
public abstract ArrayData set(int index, int value, boolean strict);
public abstract ArrayData set(final int index, final int value, final boolean strict);
/**
* Set a long value at a given index
@ -511,7 +544,7 @@ public abstract class ArrayData {
* @param strict are we in strict mode
* @return new array data (or same)
*/
public abstract ArrayData set(int index, long value, boolean strict);
public abstract ArrayData set(final int index, final long value, final boolean strict);
/**
* Set an double value at a given index
@ -521,7 +554,7 @@ public abstract class ArrayData {
* @param strict are we in strict mode
* @return new array data (or same)
*/
public abstract ArrayData set(int index, double value, boolean strict);
public abstract ArrayData set(final int index, final double value, final boolean strict);
/**
* Set an empty value at a given index. Should only affect Object array.
@ -552,7 +585,7 @@ public abstract class ArrayData {
* @param index the index
* @return the value
*/
public abstract int getInt(int index);
public abstract int getInt(final int index);
/**
* Returns the optimistic type of this array data. Basically, when an array data object needs to throw an
@ -581,7 +614,7 @@ public abstract class ArrayData {
* @param index the index
* @return the value
*/
public abstract long getLong(int index);
public abstract long getLong(final int index);
/**
* Get optimistic long - default is that it's impossible. Overridden
@ -601,7 +634,7 @@ public abstract class ArrayData {
* @param index the index
* @return the value
*/
public abstract double getDouble(int index);
public abstract double getDouble(final int index);
/**
* Get optimistic double - default is that it's impossible. Overridden
@ -621,14 +654,14 @@ public abstract class ArrayData {
* @param index the index
* @return the value
*/
public abstract Object getObject(int index);
public abstract Object getObject(final int index);
/**
* Tests to see if an entry exists (avoids boxing.)
* @param index the index
* @return true if entry exists
*/
public abstract boolean has(int index);
public abstract boolean has(final int index);
/**
* Returns if element at specific index can be deleted or not.
@ -674,7 +707,7 @@ public abstract class ArrayData {
* @param index the index
* @return new array data (or same)
*/
public abstract ArrayData delete(int index);
public abstract ArrayData delete(final int index);
/**
* Delete a given range from this array;
@ -684,7 +717,7 @@ public abstract class ArrayData {
*
* @return new ArrayData after deletion
*/
public abstract ArrayData delete(long fromIndex, long toIndex);
public abstract ArrayData delete(final long fromIndex, final long toIndex);
/**
* Convert the ArrayData to one with a different element type
@ -694,7 +727,7 @@ public abstract class ArrayData {
* @param type new element type
* @return new array data
*/
public abstract ArrayData convert(Class<?> type);
public abstract ArrayData convert(final Class<?> type);
/**
* Push an array of items to the end of the array
@ -778,7 +811,7 @@ public abstract class ArrayData {
* @param to end index + 1
* @return new array data
*/
public abstract ArrayData slice(long from, long to);
public abstract ArrayData slice(final long from, final long to);
/**
* Fast splice operation. This just modifies the array according to the number of
@ -822,6 +855,34 @@ public abstract class ArrayData {
return widest;
}
/**
* Return a list of keys in the array for the iterators
* @return iterator key list
*/
protected List<Long> computeIteratorKeys() {
final List<Long> keys = new ArrayList<>();
final long len = length();
for (long i = 0L; i < len; i = nextIndex(i)) {
if (has((int)i)) {
keys.add(i);
}
}
return keys;
}
/**
* Return an iterator that goes through all indexes of elements
* in this array. This includes those after array.length if
* they exist
*
* @return iterator
*/
public Iterator<Long> indexIterator() {
return computeIteratorKeys().iterator();
}
/**
* Exponential growth function for array size when in
* need of resizing.
@ -841,7 +902,7 @@ public abstract class ArrayData {
*
* @return the next index
*/
public long nextIndex(final long index) {
long nextIndex(final long index) {
return index + 1;
}

View File

@ -39,7 +39,7 @@ abstract class ArrayFilter extends ArrayData {
protected ArrayData underlying;
ArrayFilter(final ArrayData underlying) {
super(underlying.length);
super(underlying.length());
this.underlying = underlying;
}
@ -70,62 +70,55 @@ abstract class ArrayFilter extends ArrayData {
@Override
public void shiftLeft(final int by) {
underlying.shiftLeft(by);
setLength(underlying.length);
setLength(underlying.length());
}
@Override
public ArrayData shiftRight(final int by) {
underlying = underlying.shiftRight(by);
setLength(underlying.length);
setLength(underlying.length());
return this;
}
@Override
public ArrayData ensure(final long safeIndex) {
underlying = underlying.ensure(safeIndex);
setLength(underlying.length);
setLength(underlying.length());
return this;
}
@Override
public ArrayData shrink(final long newLength) {
underlying = underlying.shrink(newLength);
setLength(underlying.length);
setLength(underlying.length());
return this;
}
@Override
public ArrayData set(final int index, final Object value, final boolean strict) {
underlying = underlying.set(index, value, strict);
setLength(underlying.length);
setLength(underlying.length());
return this;
}
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
underlying = underlying.set(index, value, strict);
setLength(underlying.length);
setLength(underlying.length());
return this;
}
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
underlying = underlying.set(index, value, strict);
setLength(underlying.length);
setLength(underlying.length());
return this;
}
@Override
public ArrayData set(final int index, final double value, final boolean strict) {
underlying = underlying.set(index, value, strict);
setLength(underlying.length);
setLength(underlying.length());
return this;
}
@ -189,29 +182,28 @@ abstract class ArrayFilter extends ArrayData {
@Override
public ArrayData delete(final int index) {
underlying = underlying.delete(index);
setLength(underlying.length);
setLength(underlying.length());
return this;
}
@Override
public ArrayData delete(final long from, final long to) {
underlying = underlying.delete(from, to);
setLength(underlying.length);
setLength(underlying.length());
return this;
}
@Override
public ArrayData convert(final Class<?> type) {
underlying = underlying.convert(type);
setLength(underlying.length);
setLength(underlying.length());
return this;
}
@Override
public Object pop() {
final Object value = underlying.pop();
setLength(underlying.length);
setLength(underlying.length());
return value;
}

View File

@ -65,7 +65,7 @@ public abstract class ContinuousArrayData extends ArrayData {
* @return true if we don't need to do any array reallocation to fit an element at index
*/
public final boolean hasRoomFor(final int index) {
return has(index) || (index == length && ensure(index) == this);
return has(index) || (index == length() && ensure(index) == this);
}
/**
@ -73,7 +73,7 @@ public abstract class ContinuousArrayData extends ArrayData {
* @return true if empty
*/
public boolean isEmpty() {
return length == 0L;
return length() == 0L;
}
/**

View File

@ -38,8 +38,7 @@ final class DeletedArrayFilter extends ArrayFilter {
DeletedArrayFilter(final ArrayData underlying) {
super(underlying);
this.deleted = new BitVector(underlying.length);
this.deleted = new BitVector(underlying.length());
}
@Override
@ -79,25 +78,24 @@ final class DeletedArrayFilter extends ArrayFilter {
@Override
public void shiftLeft(final int by) {
super.shiftLeft(by);
deleted.shiftLeft(by, length);
deleted.shiftLeft(by, length());
}
@Override
public ArrayData shiftRight(final int by) {
super.shiftRight(by);
deleted.shiftRight(by, length);
deleted.shiftRight(by, length());
return this;
}
@Override
public ArrayData ensure(final long safeIndex) {
if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
return new SparseArrayData(this, safeIndex + 1);
}
super.ensure(safeIndex);
deleted.resize(length);
deleted.resize(length());
return this;
}
@ -105,36 +103,31 @@ final class DeletedArrayFilter extends ArrayFilter {
@Override
public ArrayData shrink(final long newLength) {
super.shrink(newLength);
deleted.resize(length);
deleted.resize(length());
return this;
}
@Override
public ArrayData set(final int index, final Object value, final boolean strict) {
deleted.clear(ArrayIndex.toLongIndex(index));
return super.set(index, value, strict);
}
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
deleted.clear(ArrayIndex.toLongIndex(index));
return super.set(index, value, strict);
}
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
deleted.clear(ArrayIndex.toLongIndex(index));
return super.set(index, value, strict);
}
@Override
public ArrayData set(final int index, final double value, final boolean strict) {
deleted.clear(ArrayIndex.toLongIndex(index));
return super.set(index, value, strict);
}
@ -146,7 +139,7 @@ final class DeletedArrayFilter extends ArrayFilter {
@Override
public ArrayData delete(final int index) {
final long longIndex = ArrayIndex.toLongIndex(index);
assert longIndex >= 0 && longIndex < length;
assert longIndex >= 0 && longIndex < length();
deleted.set(longIndex);
underlying.setEmpty(index);
return this;
@ -154,7 +147,7 @@ final class DeletedArrayFilter extends ArrayFilter {
@Override
public ArrayData delete(final long fromIndex, final long toIndex) {
assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length;
assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length();
deleted.setRange(fromIndex, toIndex + 1);
underlying.setEmpty(fromIndex, toIndex);
return this;
@ -162,7 +155,7 @@ final class DeletedArrayFilter extends ArrayFilter {
@Override
public Object pop() {
final long index = length - 1;
final long index = length() - 1;
if (super.has((int)index)) {
final boolean isDeleted = deleted.isSet(index);
@ -179,7 +172,7 @@ final class DeletedArrayFilter extends ArrayFilter {
final ArrayData newArray = underlying.slice(from, to);
final DeletedArrayFilter newFilter = new DeletedArrayFilter(newArray);
newFilter.getDeleted().copy(deleted);
newFilter.getDeleted().shiftLeft(from, newFilter.length);
newFilter.getDeleted().shiftLeft(from, newFilter.length());
return newFilter;
}

View File

@ -42,10 +42,10 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
}
private static ArrayData maybeSparse(final ArrayData underlying, final long hi) {
if(hi < SparseArrayData.MAX_DENSE_LENGTH || underlying instanceof SparseArrayData) {
if (hi < SparseArrayData.MAX_DENSE_LENGTH || underlying instanceof SparseArrayData) {
return underlying;
}
return new SparseArrayData(underlying, underlying.length);
return new SparseArrayData(underlying, underlying.length());
}
private boolean isEmpty() {
@ -93,7 +93,7 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
@Override
public ArrayData ensure(final long safeIndex) {
if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
return new SparseArrayData(this, safeIndex + 1);
}
@ -110,7 +110,7 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
@Override
public ArrayData shiftRight(final int by) {
super.shiftRight(by);
final long len = length;
final long len = length();
lo = Math.min(len, lo + by);
hi = Math.min(len - 1, hi + by);
@ -238,7 +238,7 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
@Override
public Object pop() {
final int index = (int)length - 1;
final int index = (int)length() - 1;
if (super.has(index)) {
final boolean isDeleted = isDeleted(index);
final Object value = super.pop();

View File

@ -26,9 +26,9 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
* ArrayData after the array has been frozen by Object.freeze call.
@ -79,4 +79,15 @@ final class FrozenArrayFilter extends SealedArrayFilter {
}
return this;
}
@Override
public ArrayData push(final boolean strict, final Object... items) {
return this; //nop
}
@Override
public Object pop() {
final int len = (int)underlying.length();
return len == 0 ? ScriptRuntime.UNDEFINED : underlying.getObject(len - 1);
}
}

View File

@ -119,22 +119,24 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public IntArrayData copy() {
return new IntArrayData(array.clone(), (int)length);
return new IntArrayData(array.clone(), (int)length());
}
@Override
public Object asArrayOfType(final Class<?> componentType) {
if (componentType == int.class) {
return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
final int len = (int)length();
return array.length == len ? array.clone() : Arrays.copyOf(array, len);
}
return super.asArrayOfType(componentType);
}
private Object[] toObjectArray(final boolean trim) {
assert length <= array.length : "length exceeds internal array size";
final Object[] oarray = new Object[trim ? (int)length : array.length];
assert length() <= array.length : "length exceeds internal array size";
final int len = (int)length();
final Object[] oarray = new Object[trim ? len : array.length];
for (int index = 0; index < length; index++) {
for (int index = 0; index < len; index++) {
oarray[index] = Integer.valueOf(array[index]);
}
@ -142,10 +144,11 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
}
private double[] toDoubleArray() {
assert length <= array.length : "length exceeds internal array size";
assert length() <= array.length : "length exceeds internal array size";
final int len = (int)length();
final double[] darray = new double[array.length];
for (int index = 0; index < length; index++) {
for (int index = 0; index < len; index++) {
darray[index] = array[index];
}
@ -153,10 +156,11 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
}
private long[] toLongArray() {
assert length <= array.length : "length exceeds internal array size";
assert length() <= array.length : "length exceeds internal array size";
final int len = (int)length();
final long[] larray = new long[array.length];
for (int index = 0; index < length; index++) {
for (int index = 0; index < len; index++) {
larray[index] = array[index];
}
@ -164,15 +168,15 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
}
private LongArrayData convertToLong() {
return new LongArrayData(toLongArray(), (int)length);
return new LongArrayData(toLongArray(), (int)length());
}
private NumberArrayData convertToDouble() {
return new NumberArrayData(toDoubleArray(), (int)length);
return new NumberArrayData(toDoubleArray(), (int)length());
}
private ObjectArrayData convertToObject() {
return new ObjectArrayData(toObjectArray(false), (int)length);
return new ObjectArrayData(toObjectArray(false), (int)length());
}
@Override
@ -196,7 +200,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public ArrayData shiftRight(final int by) {
final ArrayData newData = ensure(by + length - 1);
final ArrayData newData = ensure(by + length() - 1);
if (newData != this) {
newData.shiftRight(by);
return newData;
@ -241,7 +245,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@ -250,7 +254,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
public ArrayData set(final int index, final long value, final boolean strict) {
if (JSType.isRepresentableAsInt(value)) {
array[index] = JSType.toInt32(value);
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@ -261,7 +265,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
public ArrayData set(final int index, final double value, final boolean strict) {
if (JSType.isRepresentableAsInt(value)) {
array[index] = (int)(long)value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@ -305,7 +309,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public boolean has(final int index) {
return 0 <= index && index < length;
return 0 <= index && index < length();
}
@Override
@ -320,11 +324,12 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public Object pop() {
if (length == 0) {
final int len = (int)length();
if (len == 0) {
return ScriptRuntime.UNDEFINED;
}
final int newLength = (int)length - 1;
final int newLength = len - 1;
final int elem = array[newLength];
array[newLength] = 0;
setLength(newLength);
@ -334,12 +339,12 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public ArrayData slice(final long from, final long to) {
return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length : from)));
return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length() : from)));
}
@Override
public final ArrayData push(final boolean strict, final int item) {
final long len = length;
final long len = length();
final ArrayData newData = ensure(len);
if (newData == this) {
array[(int)len] = item;
@ -350,7 +355,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
final long oldLength = length;
final long oldLength = length();
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
@ -384,21 +389,21 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public long fastPush(final int arg) {
final int len = (int)length;
final int len = (int)length();
if (len == array.length) {
array = Arrays.copyOf(array, nextSize(len));
}
array[len] = arg;
return ++length;
return increaseLength();
}
//length must not be zero
@Override
public int fastPopInt() {
if (length == 0) {
if (length() == 0) {
throw new ClassCastException(); //relink
}
final int newLength = (int)--length;
final int newLength = (int)decreaseLength();
final int elem = array[newLength];
array[newLength] = 0;
return elem;
@ -421,8 +426,8 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
final int otherLength = (int)otherData.length;
final int thisLength = (int)length;
final int otherLength = (int)otherData.length();
final int thisLength = (int)length();
assert otherLength > 0 && thisLength > 0;
final int[] otherArray = ((IntArrayData)otherData).array;
@ -437,7 +442,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public String toString() {
assert length <= array.length : length + " > " + array.length;
return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
assert length() <= array.length : length() + " > " + array.length;
return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length()));
}
}

View File

@ -0,0 +1,198 @@
package jdk.nashorn.internal.runtime.arrays;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
* Filter to use for ArrayData where the length is not writable.
* The default behavior is just to ignore {@link ArrayData#setLength}
*/
final class LengthNotWritableFilter extends ArrayFilter {
private final SortedMap<Long, Object> extraElements; //elements with index >= length
/**
* Constructor
* @param underlying array
*/
LengthNotWritableFilter(final ArrayData underlying) {
this(underlying, new TreeMap<Long, Object>());
}
private LengthNotWritableFilter(final ArrayData underlying, final SortedMap<Long, Object> extraElements) {
super(underlying);
this.extraElements = extraElements;
}
@Override
public ArrayData copy() {
return new LengthNotWritableFilter(underlying.copy(), new TreeMap<>(extraElements));
}
@Override
public boolean has(final int index) {
return super.has(index) || extraElements.containsKey((long)index);
}
/**
* Set the length of the data array
*
* @param length the new length for the data array
*/
@Override
public void setLength(final long length) {
//empty - setting length for a LengthNotWritableFilter is always a nop
}
@Override
public ArrayData ensure(final long index) {
return this;
}
@Override
public ArrayData slice(final long from, final long to) {
//return array[from...to), or array[from...length] if undefined, in this case not as we are an ArrayData
return new LengthNotWritableFilter(underlying.slice(from, to), extraElements.subMap(from, to));
}
private boolean checkAdd(final long index, final Object value) {
if (index >= length()) {
extraElements.put(index, value);
return true;
}
return false;
}
private Object get(final long index) {
final Object obj = extraElements.get(index);
if (obj == null) {
return ScriptRuntime.UNDEFINED;
}
return obj;
}
@Override
public int getInt(final int index) {
if (index >= length()) {
return JSType.toInt32(get(index));
}
return underlying.getInt(index);
}
@Override
public int getIntOptimistic(final int index, final int programPoint) {
if (index >= length()) {
return JSType.toInt32Optimistic(get(index), programPoint);
}
return underlying.getIntOptimistic(index, programPoint);
}
@Override
public long getLong(final int index) {
if (index >= length()) {
return JSType.toLong(get(index));
}
return underlying.getLong(index);
}
@Override
public long getLongOptimistic(final int index, final int programPoint) {
if (index >= length()) {
return JSType.toLongOptimistic(get(index), programPoint);
}
return underlying.getLongOptimistic(index, programPoint);
}
@Override
public double getDouble(final int index) {
if (index >= length()) {
return JSType.toNumber(get(index));
}
return underlying.getDouble(index);
}
@Override
public double getDoubleOptimistic(final int index, final int programPoint) {
if (index >= length()) {
return JSType.toNumberOptimistic(get(index), programPoint);
}
return underlying.getDoubleOptimistic(index, programPoint);
}
@Override
public Object getObject(final int index) {
if (index >= length()) {
return get(index);
}
return underlying.getObject(index);
}
@Override
public ArrayData set(final int index, final Object value, final boolean strict) {
if (checkAdd(index, value)) {
return this;
}
underlying = underlying.set(index, value, strict);
return this;
}
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
if (checkAdd(index, value)) {
return this;
}
underlying = underlying.set(index, value, strict);
return this;
}
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
if (checkAdd(index, value)) {
return this;
}
underlying = underlying.set(index, value, strict);
return this;
}
@Override
public ArrayData set(final int index, final double value, final boolean strict) {
if (checkAdd(index, value)) {
return this;
}
underlying = underlying.set(index, value, strict);
return this;
}
@Override
public ArrayData delete(final int index) {
extraElements.remove(index);
underlying = underlying.delete(index);
return this;
}
@Override
public ArrayData delete(final long fromIndex, final long toIndex) {
for (final Iterator<Long> iter = extraElements.keySet().iterator(); iter.hasNext();) {
final long next = iter.next();
if (next >= fromIndex && next <= toIndex) {
iter.remove();
}
if (next > toIndex) { //ordering guaranteed because TreeSet
break;
}
}
underlying = underlying.delete(fromIndex, toIndex);
return this;
}
@Override
public Iterator<Long> indexIterator() {
final List<Long> keys = computeIteratorKeys();
keys.addAll(extraElements.keySet()); //even if they are outside length this is fine
return keys.iterator();
}
}

View File

@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@ -77,7 +76,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public LongArrayData copy() {
return new LongArrayData(array.clone(), (int)length);
return new LongArrayData(array.clone(), (int)length());
}
@Override
@ -86,10 +85,11 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
}
private Object[] toObjectArray(final boolean trim) {
assert length <= array.length : "length exceeds internal array size";
final Object[] oarray = new Object[trim ? (int)length : array.length];
assert length() <= array.length : "length exceeds internal array size";
final int len = (int)length();
final Object[] oarray = new Object[trim ? len : array.length];
for (int index = 0; index < length; index++) {
for (int index = 0; index < len; index++) {
oarray[index] = Long.valueOf(array[index]);
}
@ -99,16 +99,18 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public Object asArrayOfType(final Class<?> componentType) {
if (componentType == long.class) {
return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
final int len = (int)length();
return array.length == len ? array.clone() : Arrays.copyOf(array, len);
}
return super.asArrayOfType(componentType);
}
private double[] toDoubleArray() {
assert length <= array.length : "length exceeds internal array size";
assert length() <= array.length : "length exceeds internal array size";
final int len = (int)length();
final double[] darray = new double[array.length];
for (int index = 0; index < length; index++) {
for (int index = 0; index < len; index++) {
darray[index] = array[index];
}
@ -120,7 +122,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
if (type == Integer.class || type == Long.class) {
return this;
}
final int len = (int)length;
final int len = (int)length();
if (type == Double.class) {
return new NumberArrayData(toDoubleArray(), len);
}
@ -134,7 +136,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public ArrayData shiftRight(final int by) {
final ArrayData newData = ensure(by + length - 1);
final ArrayData newData = ensure(by + length() - 1);
if (newData != this) {
newData.shiftRight(by);
return newData;
@ -179,14 +181,14 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@ -194,7 +196,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
public ArrayData set(final int index, final double value, final boolean strict) {
if (JSType.isRepresentableAsLong(value)) {
array[index] = (long)value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
return convert(Double.class).set(index, value, strict);
@ -265,7 +267,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public boolean has(final int index) {
return 0 <= index && index < length;
return 0 <= index && index < length();
}
@Override
@ -280,11 +282,12 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public Object pop() {
if (length == 0) {
final int len = (int)length();
if (len == 0) {
return ScriptRuntime.UNDEFINED;
}
final int newLength = (int)length - 1;
final int newLength = len - 1;
final long elem = array[newLength];
array[newLength] = 0;
setLength(newLength);
@ -294,14 +297,14 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public ArrayData slice(final long from, final long to) {
final long start = from < 0 ? from + length : from;
final long start = from < 0 ? from + length() : from;
final long newLength = to - start;
return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
@Override
public final ArrayData push(final boolean strict, final long item) {
final long len = length;
final long len = length();
final ArrayData newData = ensure(len);
if (newData == this) {
array[(int)len] = item;
@ -312,7 +315,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
final long oldLength = length;
final long oldLength = length();
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
@ -345,20 +348,20 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public long fastPush(final long arg) {
final int len = (int)length;
final int len = (int)length();
if (len == array.length) {
array = Arrays.copyOf(array, nextSize(len));
}
array[len] = arg;
return ++length;
return increaseLength();
}
@Override
public long fastPopLong() {
if (length == 0) {
throw new ClassCastException();
if (length() == 0) {
throw new ClassCastException(); //undefined result
}
final int newLength = (int)--length;
final int newLength = (int)decreaseLength();
final long elem = array[newLength];
array[newLength] = 0;
return elem;
@ -376,8 +379,8 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
final int otherLength = (int)otherData.length;
final int thisLength = (int)length;
final int otherLength = (int)otherData.length();
final int thisLength = (int)length();
assert otherLength > 0 && thisLength > 0;
final long[] otherArray = ((LongArrayData)otherData).array;
@ -392,13 +395,14 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public String toString() {
assert length <= array.length : length + " > " + array.length;
assert length() <= array.length : length() + " > " + array.length;
final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).
append(": [");
for (int i = 0; i < length; i++) {
final int len = (int)length();
for (int i = 0; i < len; i++) {
sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString()
if (i + 1 < length) {
if (i + 1 < len) {
sb.append(", ");
}
}

View File

@ -7,13 +7,13 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
/**
* Filter class that wrap arrays that have been tagged non extensible
*/
public class NonExtensibleArrayFilter extends ArrayFilter {
final class NonExtensibleArrayFilter extends ArrayFilter {
/**
* Constructor
* @param underlying array
*/
public NonExtensibleArrayFilter(final ArrayData underlying) {
NonExtensibleArrayFilter(final ArrayData underlying) {
super(underlying);
}

View File

@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@ -76,7 +75,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public NumberArrayData copy() {
return new NumberArrayData(array.clone(), (int)length);
return new NumberArrayData(array.clone(), (int)length());
}
@Override
@ -85,10 +84,11 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
}
private Object[] toObjectArray(final boolean trim) {
assert length <= array.length : "length exceeds internal array size";
final Object[] oarray = new Object[trim ? (int)length : array.length];
assert length() <= array.length : "length exceeds internal array size";
final int len = (int)length();
final Object[] oarray = new Object[trim ? len : array.length];
for (int index = 0; index < length; index++) {
for (int index = 0; index < len; index++) {
oarray[index] = Double.valueOf(array[index]);
}
return oarray;
@ -96,8 +96,9 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public Object asArrayOfType(final Class<?> componentType) {
if(componentType == double.class) {
return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
if (componentType == double.class) {
final int len = (int)length();
return array.length == len ? array.clone() : Arrays.copyOf(array, len);
}
return super.asArrayOfType(componentType);
}
@ -105,7 +106,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public ContinuousArrayData convert(final Class<?> type) {
if (type != Double.class && type != Integer.class && type != Long.class) {
final int len = (int)length;
final int len = (int)length();
return new ObjectArrayData(toObjectArray(false), len);
}
return this;
@ -118,7 +119,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public ArrayData shiftRight(final int by) {
final ArrayData newData = ensure(by + length - 1);
final ArrayData newData = ensure(by + length() - 1);
if (newData != this) {
newData.shiftRight(by);
return newData;
@ -163,21 +164,21 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@Override
public ArrayData set(final int index, final double value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@ -241,7 +242,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public boolean has(final int index) {
return 0 <= index && index < length;
return 0 <= index && index < length();
}
@Override
@ -256,11 +257,12 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public Object pop() {
if (length == 0) {
final int len = (int)length();
if (len == 0) {
return UNDEFINED;
}
final int newLength = (int)length - 1;
final int newLength = len - 1;
final double elem = array[newLength];
array[newLength] = 0;
setLength(newLength);
@ -269,14 +271,14 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public ArrayData slice(final long from, final long to) {
final long start = from < 0 ? from + length : from;
final long start = from < 0 ? from + length() : from;
final long newLength = to - start;
return new NumberArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
@Override
public final ArrayData push(final boolean strict, final double item) {
final long len = length;
final long len = length();
final ArrayData newData = ensure(len);
if (newData == this) {
array[(int)len] = item;
@ -287,7 +289,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
final long oldLength = length;
final long oldLength = length();
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
@ -325,21 +327,21 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public long fastPush(final double arg) {
final int len = (int)length;
final int len = (int)length();
if (len == array.length) {
//note that fastpush never creates spares arrays, there is nothing to gain by that - it will just use even more memory
array = Arrays.copyOf(array, nextSize(len));
}
array[len] = arg;
return ++length;
return increaseLength();
}
@Override
public double fastPopDouble() {
if (length == 0) {
if (length() == 0) {
throw new ClassCastException();
}
final int newLength = (int)--length;
final int newLength = (int)decreaseLength();
final double elem = array[newLength];
array[newLength] = 0;
return elem;
@ -352,8 +354,8 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
final int otherLength = (int)otherData.length;
final int thisLength = (int)length;
final int otherLength = (int)otherData.length();
final int thisLength = (int)length();
assert otherLength > 0 && thisLength > 0;
final double[] otherArray = ((NumberArrayData)otherData).array;
@ -368,7 +370,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public String toString() {
assert length <= array.length : length + " > " + array.length;
return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
assert length() <= array.length : length() + " > " + array.length;
return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length()));
}
}

View File

@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@ -77,16 +76,16 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
@Override
public ObjectArrayData copy() {
return new ObjectArrayData(array.clone(), (int)length);
return new ObjectArrayData(array.clone(), (int)length());
}
@Override
public Object[] asObjectArray() {
return array.length == length ? array.clone() : asObjectArrayCopy();
return array.length == length() ? array.clone() : asObjectArrayCopy();
}
private Object[] asObjectArrayCopy() {
final long len = length;
final long len = length();
assert len <= Integer.MAX_VALUE;
final Object[] copy = new Object[(int)len];
System.arraycopy(array, 0, copy, 0, (int)len);
@ -105,7 +104,7 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
@Override
public ArrayData shiftRight(final int by) {
final ArrayData newData = ensure(by + length - 1);
final ArrayData newData = ensure(by + length() - 1);
if (newData != this) {
newData.shiftRight(by);
return newData;
@ -137,28 +136,28 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
@Override
public ArrayData set(final int index, final Object value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@Override
public ArrayData set(final int index, final double value, final boolean strict) {
array[index] = value;
setLength(Math.max(index + 1, length));
setLength(Math.max(index + 1, length()));
return this;
}
@ -231,7 +230,7 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
@Override
public boolean has(final int index) {
return 0 <= index && index < length;
return 0 <= index && index < length();
}
@Override
@ -263,20 +262,20 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
@Override
public long fastPush(final Object arg) {
final int len = (int)length;
final int len = (int)length();
if (len == array.length) {
array = Arrays.copyOf(array, nextSize(len));
}
array[len] = arg;
return ++length;
return increaseLength();
}
@Override
public Object fastPopObject() {
if (length == 0) {
if (length() == 0) {
return ScriptRuntime.UNDEFINED;
}
final int newLength = (int)--length;
final int newLength = (int)decreaseLength();
final Object elem = array[newLength];
array[newLength] = ScriptRuntime.EMPTY;
return elem;
@ -284,11 +283,11 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
@Override
public Object pop() {
if (length == 0) {
if (length() == 0) {
return ScriptRuntime.UNDEFINED;
}
final int newLength = (int)length - 1;
final int newLength = (int)length() - 1;
final Object elem = array[newLength];
setEmpty(newLength);
setLength(newLength);
@ -297,14 +296,14 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
@Override
public ArrayData slice(final long from, final long to) {
final long start = from < 0 ? from + length : from;
final long start = from < 0 ? from + length() : from;
final long newLength = to - start;
return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
@Override
public ArrayData push(final boolean strict, final Object item) {
final long len = length;
final long len = length();
final ArrayData newData = ensure(len);
if (newData == this) {
array[(int)len] = item;
@ -315,7 +314,7 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
@Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
final long oldLength = length;
final long oldLength = length();
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
@ -343,8 +342,8 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
@Override
public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
final int otherLength = (int)otherData.length;
final int thisLength = (int)length;
final int otherLength = (int)otherData.length();
final int thisLength = (int)length();
assert otherLength > 0 && thisLength > 0;
final Object[] otherArray = ((ObjectArrayData)otherData).array;
@ -359,7 +358,7 @@ final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
@Override
public String toString() {
assert length <= array.length : length + " > " + array.length;
return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
assert length() <= array.length : length() + " > " + array.length;
return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length()));
}
}

View File

@ -53,21 +53,21 @@ class SparseArrayData extends ArrayData {
SparseArrayData(final ArrayData underlying, final long length, final TreeMap<Long, Object> sparseMap) {
super(length);
assert underlying.length <= length;
assert underlying.length() <= length;
this.underlying = underlying;
this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length);
this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length());
this.sparseMap = sparseMap;
}
@Override
public ArrayData copy() {
return new SparseArrayData(underlying.copy(), length, new TreeMap<>(sparseMap));
return new SparseArrayData(underlying.copy(), length(), new TreeMap<>(sparseMap));
}
@Override
public Object[] asObjectArray() {
final int len = (int)Math.min(length, Integer.MAX_VALUE);
final int underlyingLength = (int)Math.min(len, underlying.length);
final int len = (int)Math.min(length(), Integer.MAX_VALUE);
final int underlyingLength = (int)Math.min(len, underlying.length());
final Object[] objArray = new Object[len];
for (int i = 0; i < underlyingLength; i++) {
@ -104,14 +104,15 @@ class SparseArrayData extends ArrayData {
}
sparseMap = newSparseMap;
setLength(Math.max(length - by, 0));
setLength(Math.max(length() - by, 0));
}
@Override
public ArrayData shiftRight(final int by) {
final TreeMap<Long, Object> newSparseMap = new TreeMap<>();
if (underlying.length + by > maxDenseLength) {
for (long i = maxDenseLength - by; i < underlying.length; i++) {
final long len = underlying.length();
if (len + by > maxDenseLength) {
for (long i = maxDenseLength - by; i < len; i++) {
if (underlying.has((int) i)) {
newSparseMap.put(Long.valueOf(i + by), underlying.getObject((int) i));
}
@ -127,23 +128,23 @@ class SparseArrayData extends ArrayData {
}
sparseMap = newSparseMap;
setLength(length + by);
setLength(length() + by);
return this;
}
@Override
public ArrayData ensure(final long safeIndex) {
if (safeIndex < maxDenseLength && underlying.length <= safeIndex) {
if (safeIndex < maxDenseLength && underlying.length() <= safeIndex) {
underlying = underlying.ensure(safeIndex);
}
setLength(Math.max(safeIndex + 1, length));
setLength(Math.max(safeIndex + 1, length()));
return this;
}
@Override
public ArrayData shrink(final long newLength) {
if (newLength < underlying.length) {
if (newLength < underlying.length()) {
underlying = underlying.shrink(newLength);
underlying.setLength(newLength);
sparseMap.clear();
@ -160,11 +161,11 @@ class SparseArrayData extends ArrayData {
if (index >= 0 && index < maxDenseLength) {
ensure(index);
underlying = underlying.set(index, value, strict);
setLength(Math.max(underlying.length, length));
setLength(Math.max(underlying.length(), length()));
} else {
final Long longIndex = indexToKey(index);
sparseMap.put(longIndex, value);
setLength(Math.max(longIndex + 1, length));
setLength(Math.max(longIndex + 1, length()));
}
return this;
@ -175,11 +176,11 @@ class SparseArrayData extends ArrayData {
if (index >= 0 && index < maxDenseLength) {
ensure(index);
underlying = underlying.set(index, value, strict);
setLength(Math.max(underlying.length, length));
setLength(Math.max(underlying.length(), length()));
} else {
final Long longIndex = indexToKey(index);
sparseMap.put(longIndex, value);
setLength(Math.max(longIndex + 1, length));
setLength(Math.max(longIndex + 1, length()));
}
return this;
}
@ -189,11 +190,11 @@ class SparseArrayData extends ArrayData {
if (index >= 0 && index < maxDenseLength) {
ensure(index);
underlying = underlying.set(index, value, strict);
setLength(Math.max(underlying.length, length));
setLength(Math.max(underlying.length(), length()));
} else {
final Long longIndex = indexToKey(index);
sparseMap.put(longIndex, value);
setLength(Math.max(longIndex + 1, length));
setLength(Math.max(longIndex + 1, length()));
}
return this;
}
@ -203,11 +204,11 @@ class SparseArrayData extends ArrayData {
if (index >= 0 && index < maxDenseLength) {
ensure(index);
underlying = underlying.set(index, value, strict);
setLength(Math.max(underlying.length, length));
setLength(Math.max(underlying.length(), length()));
} else {
final Long longIndex = indexToKey(index);
sparseMap.put(longIndex, value);
setLength(Math.max(longIndex + 1, length));
setLength(Math.max(longIndex + 1, length()));
}
return this;
}
@ -294,7 +295,7 @@ class SparseArrayData extends ArrayData {
@Override
public boolean has(final int index) {
if (index >= 0 && index < maxDenseLength) {
return index < underlying.length && underlying.has(index);
return index < underlying.length() && underlying.has(index);
}
return sparseMap.containsKey(indexToKey(index));
@ -303,7 +304,7 @@ class SparseArrayData extends ArrayData {
@Override
public ArrayData delete(final int index) {
if (index >= 0 && index < maxDenseLength) {
if (index < underlying.length) {
if (index < underlying.length()) {
underlying = underlying.delete(index);
}
} else {
@ -315,8 +316,8 @@ class SparseArrayData extends ArrayData {
@Override
public ArrayData delete(final long fromIndex, final long toIndex) {
if (fromIndex < maxDenseLength && fromIndex < underlying.length) {
underlying = underlying.delete(fromIndex, Math.min(toIndex, underlying.length - 1));
if (fromIndex < maxDenseLength && fromIndex < underlying.length()) {
underlying = underlying.delete(fromIndex, Math.min(toIndex, underlying.length() - 1));
}
if (toIndex >= maxDenseLength) {
sparseMap.subMap(fromIndex, true, toIndex, true).clear();
@ -336,30 +337,34 @@ class SparseArrayData extends ArrayData {
@Override
public Object pop() {
if (length == 0) {
final long len = length();
final long underlyingLen = underlying.length();
if (len == 0) {
return ScriptRuntime.UNDEFINED;
}
if (length == underlying.length) {
if (len == underlyingLen) {
final Object result = underlying.pop();
setLength(underlying.length);
setLength(underlying.length());
return result;
}
setLength(length - 1);
final Long key = Long.valueOf(length);
setLength(len - 1);
final Long key = Long.valueOf(len - 1);
return sparseMap.containsKey(key) ? sparseMap.remove(key) : ScriptRuntime.UNDEFINED;
}
@Override
public ArrayData slice(final long from, final long to) {
assert to <= length;
final long start = from < 0 ? (from + length) : from;
assert to <= length();
final long start = from < 0 ? (from + length()) : from;
final long newLength = to - start;
final long underlyingLength = underlying.length();
if (start >= 0 && to <= maxDenseLength) {
if (newLength <= underlying.length) {
if (newLength <= underlyingLength) {
return underlying.slice(from, to);
}
return underlying.slice(from, to).ensure(newLength - 1).delete(underlying.length, newLength);
return underlying.slice(from, to).ensure(newLength - 1).delete(underlyingLength, newLength);
}
ArrayData sliced = EMPTY_ARRAY;
@ -369,13 +374,13 @@ class SparseArrayData extends ArrayData {
sliced = sliced.set((int)(i - start), getObject((int)i), false);
}
}
assert sliced.length == newLength;
assert sliced.length() == newLength;
return sliced;
}
@Override
public long nextIndex(final long index) {
if (index < underlying.length - 1) {
if (index < underlying.length() - 1) {
return underlying.nextIndex(index);
}
@ -383,6 +388,7 @@ class SparseArrayData extends ArrayData {
if (nextKey != null) {
return nextKey;
}
return length;
return length();
}
}

View File

@ -58,7 +58,7 @@ public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayDa
* @return element length
*/
public final int getElementLength() {
return (int)length;
return (int)length();
}
/**
@ -119,7 +119,7 @@ public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayDa
@Override
public final boolean has(final int index) {
return 0 <= index && index < length;
return 0 <= index && index < length();
}
@Override

View File

@ -39,8 +39,7 @@ final class UndefinedArrayFilter extends ArrayFilter {
UndefinedArrayFilter(final ArrayData underlying) {
super(underlying);
this.undefined = new BitVector(underlying.length);
this.undefined = new BitVector(underlying.length());
}
@Override
@ -80,25 +79,24 @@ final class UndefinedArrayFilter extends ArrayFilter {
@Override
public void shiftLeft(final int by) {
super.shiftLeft(by);
undefined.shiftLeft(by, length);
undefined.shiftLeft(by, length());
}
@Override
public ArrayData shiftRight(final int by) {
super.shiftRight(by);
undefined.shiftRight(by, length);
undefined.shiftRight(by, length());
return this;
}
@Override
public ArrayData ensure(final long safeIndex) {
if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
return new SparseArrayData(this, safeIndex + 1);
}
super.ensure(safeIndex);
undefined.resize(length);
undefined.resize(length());
return this;
}
@ -106,8 +104,7 @@ final class UndefinedArrayFilter extends ArrayFilter {
@Override
public ArrayData shrink(final long newLength) {
super.shrink(newLength);
undefined.resize(length);
undefined.resize(length());
return this;
}
@ -216,7 +213,7 @@ final class UndefinedArrayFilter extends ArrayFilter {
@Override
public Object pop() {
final long index = length - 1;
final long index = length() - 1;
if (super.has((int)index)) {
final boolean isUndefined = undefined.isSet(index);
@ -233,7 +230,7 @@ final class UndefinedArrayFilter extends ArrayFilter {
final ArrayData newArray = underlying.slice(from, to);
final UndefinedArrayFilter newFilter = new UndefinedArrayFilter(newArray);
newFilter.getUndefined().copy(undefined);
newFilter.getUndefined().shiftLeft(from, newFilter.length);
newFilter.getUndefined().shiftLeft(from, newFilter.length());
return newFilter;
}

View File

@ -0,0 +1,225 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8035312 push to frozen array must not increase length property
*
* @test
* @run
* @fork
* @option -Dnashorn.debug=true
*/
function printArrayDataClass(x) {
if (typeof Debug !== 'undefined') {
print(Debug.getArrayDataClass(x));
}
}
function gpush(x, elem) {
try {
print("Pushing " + elem + " to " + x);
x.push(elem);
} catch (e) {
print("caught error" + e);
}
print("\tarray is now [" + x + "] length is = " + x.length);
print();
printArrayDataClass(x);
}
function gpop(x) {
try {
print("Popping from " + x);
x.pop();
} catch (e) {
if (!(e instanceof TypeError)) {
print("e of wrong type " + e);
}
}
print("\tarray is now [" + x + "] length is = " + x.length);
print();
printArrayDataClass(x);
}
function checkArray(x) {
print();
print(">>> Push test");
var olen = x.length;
gpush(x, 0);
print("x.length === " + x.length + " (should be " + olen + ")");
print("x[3] === " + x[3] + " (should be 0)");
print("x[4] === " + x[4] + " (should be undefined)");
print();
print(">>> Pop test");
gpop(x);
gpop(x);
print("x.length === " + x.length + " (should be " + olen + ")");
print("x === " + x);
for (var i = 0 ; i < 5; i++) {
gpop(x);
}
print("x.length === " + x.length + " (should be " + olen + ")");
print("x === " + x);
}
print("*** Freezing");
var frozen = [1,2,3];
Object.freeze(frozen);
checkArray(frozen);
printArrayDataClass(frozen);
//so far so good
print();
print("*** Other length not writable issues");
var lengthNotWritable = [1,2,3];
Object.defineProperty(lengthNotWritable, "length", { writable: false });
checkArray(lengthNotWritable);
printArrayDataClass(lengthNotWritable);
function set(array, from, to, stride) {
//add three elements
for (var i = from; i < to; i+=stride) {
try {
print("Writing " + i);
array[i] = i;
printArrayDataClass(array);
} catch (e) {
print(e instanceof TypeError);
}
}
}
//define empty array with non writable length
var arr = [1];
Object.defineProperty(arr, "length", { writable: false });
var olen2 = arr.length;
set(arr, 0, 3, 1);
if (arr.length != olen2) {
throw new ("error: " + arr.length + " != " + olen2);
}
print();
print("array writing 0-3, with 1 stride, array = " + arr);
print("length = " + arr.length + ", but elements are: " + arr[0] + " " + arr[1] + " " + arr[2]);
print();
//do the same but sparse/deleted range
var arr2 = [1];
Object.defineProperty(arr2, "length", { writable: false });
print("initial length = " + arr2.length);
var olen3 = arr2.length;
set(arr2, 0, 30, 3);
if (arr2.length != olen3) {
throw new ("error: " + arr2.length + " != " + olen3);
}
print();
var larger = 20;
print("array writing 0-" + larger + ", with 3 stride, array = " + arr2);
print("length = " + arr2.length + ", but elements are: " + arr2[0] + " " + arr2[1] + " " + arr2[2]);
for (var i = 0; i < larger; i++) {
if (arr2[i] === undefined) {
continue;
}
print(arr2[i] + " has length " + arr2.length);
}
print();
var elem = 0x7fffffff - 10;
printArrayDataClass(arr2);
print("adding a new element high up in the array");
print("length before element was added " + arr2.length);
print("putting sparse at " + elem);
arr2[elem] = "sparse";
print("length after element was added " + arr2.length + " should be the same");
printArrayDataClass(arr2);
print();
print("Printing arr2 - this will fail if length is > 28 and it is " + arr2.length);
print("arr2 = [" + arr2 + "]");
print("new length that should not be writable = " + arr2.length);
print(arr2[elem] === "sparse");
print(arr2[elem]);
for (var i = 0; i < larger; i++) {
print(arr2[i]);
}
for (var key in arr2) {
print(key + ":" + arr2[key]);
}
//issues reported by sundar - generic setter doesn't go through push/pop bulkable
function sundarExample2(arr, _writable) {
print("Checking if push works for bulkable non bulkable arrays - Setting length property not allowed");
arr[0] = "bar";
print(arr.length + " should be 1"); // should be 1
print(arr[0] + " should be bar");
print("["+ arr + "] should be [bar]");
// Object.defineProperty(arr, "length", { configurable: _writable });
Object.defineProperty(arr, "length", { writable: _writable });
arr[1] = "baz";
if (_writable) {
print(arr.length + " should be 2");
print(arr[0] + " should be bar");
print(arr[1] + " should be baz");
print("["+ arr + "] should be [bar,baz]");
} else {
print(arr.length + " should STILL be 1");
print(arr[0] + " should be bar");
print(arr[1] + " should be baz");
print("["+ arr + "] should be [bar]");
}
}
var newArr1 = [];
sundarExample2(newArr1, false);
print();
try {
sundarExample2(newArr1, true);
print("should not get here");
} catch (e) {
if (!(e instanceof TypeError)) {
print("Wrong exception");
}
print("got TypeError when redefining length, as expected")
}
print();
sundarExample2([], true);
print("Done");

View File

@ -0,0 +1,186 @@
*** Freezing
>>> Push test
Pushing 0 to 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
x.length === 3 (should be 3)
x[3] === undefined (should be 0)
x[4] === undefined (should be undefined)
>>> Pop test
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
x.length === 3 (should be 3)
x === 1,2,3
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
x.length === 3 (should be 3)
x === 1,2,3
class jdk.nashorn.internal.runtime.arrays.FrozenArrayFilter
*** Other length not writable issues
>>> Push test
Pushing 0 to 1,2,3
caught errorTypeError: "length" is not a writable property of [object Array]
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
x.length === 3 (should be 3)
x[3] === 0 (should be 0)
x[4] === undefined (should be undefined)
>>> Pop test
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
x.length === 3 (should be 3)
x === 1,2,3
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Popping from 1,2,3
array is now [1,2,3] length is = 3
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
x.length === 3 (should be 3)
x === 1,2,3
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 0
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 1
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 2
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
array writing 0-3, with 1 stride, array = 0
length = 1, but elements are: 0 undefined 2
initial length = 1
Writing 0
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 3
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 6
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 9
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 12
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 15
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 18
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 21
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 24
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Writing 27
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
array writing 0-20, with 3 stride, array = 0
length = 1, but elements are: 0 undefined undefined
0 has length 1
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
adding a new element high up in the array
length before element was added 1
putting sparse at 2147483637
length after element was added 1 should be the same
class jdk.nashorn.internal.runtime.arrays.LengthNotWritableFilter
Printing arr2 - this will fail if length is > 28 and it is 1
arr2 = [0]
new length that should not be writable = 1
true
sparse
0
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
undefined
0:0
2147483637:sparse
Checking if push works for bulkable non bulkable arrays - Setting length property not allowed
1 should be 1
bar should be bar
[bar] should be [bar]
1 should STILL be 1
bar should be bar
baz should be baz
[bar] should be [bar]
Checking if push works for bulkable non bulkable arrays - Setting length property not allowed
1 should be 1
bar should be bar
[bar] should be [bar]
got TypeError when redefining length, as expected
Checking if push works for bulkable non bulkable arrays - Setting length property not allowed
1 should be 1
bar should be bar
[bar] should be [bar]
2 should be 2
bar should be bar
baz should be baz
[bar,baz] should be [bar,baz]
Done

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8035312_2 - length setter and iterators
*
* @test
* @run
*/
"use strict"
function printArray(a,n) {
print("PRINT_ARRAY CALLED: length = " + a.length);
print();
print("INDEXED");
for (var x = 0; x<n; x++) {
print("\t" + x + ":"+a[x]);
}
print("KEYS");
for (var key in a) {
print("\t" + key + ";" + a[key]);
}
}
var b = [1,2,3];
Object.defineProperty(b, "length", { writable: false });
var high = 8;
b[high] = high;
printArray(b, high + 5);
var c = [1,2,3];
c[high] = high;
print();
print("element[" + high + "]: " + c.length + " " + c[high]);
print("Resetting length");
c.length = 3;
print("element[" + high + "]: " + c.length + " " + c[high]);
print();
printArray(c, high + 5);
print();

View File

@ -0,0 +1,47 @@
PRINT_ARRAY CALLED: length = 3
INDEXED
0:1
1:2
2:3
3:undefined
4:undefined
5:undefined
6:undefined
7:undefined
8:8
9:undefined
10:undefined
11:undefined
12:undefined
KEYS
0;1
1;2
2;3
8;8
element[8]: 9 8
Resetting length
element[8]: 3 undefined
PRINT_ARRAY CALLED: length = 3
INDEXED
0:1
1:2
2:3
3:undefined
4:undefined
5:undefined
6:undefined
7:undefined
8:undefined
9:undefined
10:undefined
11:undefined
12:undefined
KEYS
0;1
1;2
2;3

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8035312_3 - sparse array, non writable length
*
* @test
* @run
*/
var b = [1,2,3];
Object.defineProperty(b, "length", { writable: false });
var high = 23534343;
b[high-10] = high-10;
print(b[high-10]);
var c = [1,2,3];
c[high-10] = high-10;
c.length = 3;
print(c);
print(c[high-10]);

View File

@ -0,0 +1,3 @@
23534333
1,2,3
undefined

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8035312_4 - pushes and pops for non writable length
*
* @test
* @run
*/
var b = [1,2,3];
Object.defineProperty(b, "length", { writable: false });
try {
b.push(4);
} catch (e) {
print("length = " + b.length);
print("i caught an error");
}
print(b);
print(b[3]);
print("length = " + b.length);
var c = [1,2,3];
Object.defineProperty(c, "length", { writable: false });
for (var i = 0; i < 5; i++) {
try {
c.pop();
} catch (e) {
print("length = " + c.length);
print("I caught an error");
print(c);
}
}
print(c);
print(c[3]);
print("length = " + b.length);

View File

@ -0,0 +1,23 @@
length = 3
i caught an error
1,2,3
4
length = 3
length = 3
I caught an error
1,2,
length = 3
I caught an error
1,2,
length = 3
I caught an error
1,2,
length = 3
I caught an error
1,2,
length = 3
I caught an error
1,2,
1,2,
undefined
length = 3

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8035312_5 - pushes and pops for frozen array
*
* @test
* @run
*/
var b = [1,2,3];
Object.freeze(b);
try {
b.push(4);
} catch (e) {
print("length = " + b.length);
print("i caught an error");
}
print(b);
print(b[3]);
print("length = " + b.length);
var c = [1,2,3];
Object.freeze(c);
for (var i = 0; i < 5; i++) {
try {
c.pop();
} catch (e) {
print("length = " + c.length);
print("I caught an error");
print(c);
}
}
print(c);
print(c[3]);
print("length = " + b.length);

View File

@ -0,0 +1,6 @@
1,2,3
undefined
length = 3
1,2,3
undefined
length = 3

View File

@ -0,0 +1,103 @@
/*
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8062799: Binary logical expressions can have numeric types
*
* @test
* @run
*/
(function() {
var inspect = Java.type("jdk.nashorn.test.tools.StaticTypeInspector").inspect;
var b = true;
var i = 1;
var l = 4294967296;
var d = 2.1;
var o = "foo";
print(inspect(b || b, "b || b"));
print(inspect(b || i, "b || i"));
print(inspect(b || l, "b || l"));
print(inspect(b || d, "b || d"));
print(inspect(b || o, "b || o"));
print(inspect(i || b, "i || b"));
print(inspect(i || i, "i || i"));
print(inspect(i || l, "i || l"));
print(inspect(i || d, "i || d"));
print(inspect(i || o, "i || o"));
print(inspect(l || b, "l || b"));
print(inspect(l || i, "l || i"));
print(inspect(l || l, "l || l"));
print(inspect(l || d, "l || d"));
print(inspect(l || o, "l || o"));
print(inspect(d || b, "d || b"));
print(inspect(d || i, "d || i"));
print(inspect(d || l, "d || l"));
print(inspect(d || d, "d || d"));
print(inspect(d || o, "d || o"));
print(inspect(o || b, "o || b"));
print(inspect(o || i, "o || i"));
print(inspect(o || l, "o || l"));
print(inspect(o || d, "o || d"));
print(inspect(o || o, "o || o"));
print(inspect(b && b, "b && b"));
print(inspect(b && i, "b && i"));
print(inspect(b && l, "b && l"));
print(inspect(b && d, "b && d"));
print(inspect(b && o, "b && o"));
print(inspect(i && b, "i && b"));
print(inspect(i && i, "i && i"));
print(inspect(i && l, "i && l"));
print(inspect(i && d, "i && d"));
print(inspect(i && o, "i && o"));
print(inspect(l && b, "l && b"));
print(inspect(l && i, "l && i"));
print(inspect(l && l, "l && l"));
print(inspect(l && d, "l && d"));
print(inspect(l && o, "l && o"));
print(inspect(d && b, "d && b"));
print(inspect(d && i, "d && i"));
print(inspect(d && l, "d && l"));
print(inspect(d && d, "d && d"));
print(inspect(d && o, "d && o"));
print(inspect(o && b, "o && b"));
print(inspect(o && i, "o && i"));
print(inspect(o && l, "o && l"));
print(inspect(o && d, "o && d"));
print(inspect(o && o, "o && o"));
})();

View File

@ -0,0 +1,50 @@
b || b: boolean
b || i: boolean
b || l: boolean
b || d: boolean
b || o: boolean
i || b: int
i || i: int
i || l: long
i || d: double
i || o: int
l || b: long
l || i: long
l || l: long
l || d: double
l || o: long
d || b: double
d || i: double
d || l: double
d || d: double
d || o: double
o || b: object
o || i: object
o || l: object
o || d: object
o || o: object
b && b: boolean
b && i: int
b && l: long
b && d: double
b && o: object
i && b: boolean
i && i: int
i && l: long
i && d: double
i && o: object
l && b: boolean
l && i: long
l && l: long
l && d: double
l && o: object
d && b: boolean
d && i: double
d && l: double
d && d: double
d && o: object
o && b: boolean
o && i: int
o && l: long
o && d: double
o && o: object

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8062937 - GlobalConstants produces wrong result with defineProperty and index setters
*
* @test
* @run
*/
var x = 1;
for (var i = 2; i < 5; i++) {
print(x);
Object.defineProperty(this, "x", {value: i});
}
print(x);
print();
var name = "y";
var y = 1;
for (var i = 2; i < 5; i++) {
print(y);
this[name] = i;
}
print(y);

View File

@ -0,0 +1,9 @@
1
2
3
4
1
2
3
4

View File

@ -1,6 +1,6 @@
1,2,3,4,5,6
first: true
1,2,3,4,5,6,7
1,2,3,4,5,6
1,2,3,,,,4711.17,dingo!,4,5,6
second: true
1,2,3,,,,4711.17,dingo!,4,5,6,7
1,2,3,,,,4711.17,dingo!,4,5,6