aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlana <none@none>2014-10-31 20:17:42 -0700
committerlana <none@none>2014-10-31 20:17:42 -0700
commit1c6a99aee9c9cac3a2bab08193cc9e63488670b4 (patch)
treeeadf4474090165b6da74666ee8c16a497afd6409
parent87575b6d0933a092cd4b23b5146d15b0cdd6cf5b (diff)
parent0a092721b45904be9916f3f2f23e949feb59fa53 (diff)
downloadnashorn-1c6a99aee9c9cac3a2bab08193cc9e63488670b4.tar.gz
Merge
-rw-r--r--bin/runopt.sh117
-rw-r--r--src/jdk/nashorn/internal/codegen/CodeGenerator.java33
-rw-r--r--src/jdk/nashorn/internal/codegen/FoldConstants.java2
-rw-r--r--src/jdk/nashorn/internal/codegen/SpillObjectCreator.java2
-rw-r--r--src/jdk/nashorn/internal/codegen/TypeEvaluator.java2
-rw-r--r--src/jdk/nashorn/internal/codegen/types/Type.java13
-rw-r--r--src/jdk/nashorn/internal/objects/NativeArray.java136
-rw-r--r--src/jdk/nashorn/internal/objects/NativeDataView.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeDate.java3
-rw-r--r--src/jdk/nashorn/internal/objects/NativeFloat32Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeFloat64Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeInt16Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeInt32Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeInt8Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeObject.java3
-rw-r--r--src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java2
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint16Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint32Array.java7
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint8Array.java5
-rw-r--r--src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java5
-rw-r--r--src/jdk/nashorn/internal/parser/JSONParser.java1
-rw-r--r--src/jdk/nashorn/internal/runtime/AccessorProperty.java56
-rw-r--r--src/jdk/nashorn/internal/runtime/ECMAException.java22
-rw-r--r--src/jdk/nashorn/internal/runtime/FindProperty.java10
-rw-r--r--src/jdk/nashorn/internal/runtime/JSType.java31
-rw-r--r--src/jdk/nashorn/internal/runtime/Property.java47
-rw-r--r--src/jdk/nashorn/internal/runtime/PropertyMap.java21
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptObject.java118
-rw-r--r--src/jdk/nashorn/internal/runtime/SpillProperty.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/UserAccessorProperty.java198
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/AnyElements.java38
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ArrayData.java226
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java8
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java67
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java65
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java59
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java186
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java68
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java49
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/NumericElements.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java47
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/Bootstrap.java14
-rw-r--r--test/examples/getter-setter-micro.js81
-rw-r--r--test/script/basic/JDK-8061391.js151
-rw-r--r--test/script/basic/JDK-8061391.js.EXPECTED138
-rw-r--r--test/script/basic/JDK-8061391_2.js52
-rw-r--r--test/script/basic/JDK-8061391_3.js44
-rw-r--r--test/script/basic/JDK-8061391_3.js.EXPECTED1
-rw-r--r--test/script/basic/JDK-8062024.js40
-rw-r--r--test/script/basic/JDK-8062024.js.EXPECTED4
-rw-r--r--test/script/basic/JDK-8062132.js80
-rw-r--r--test/script/basic/JDK-8062132.js.EXPECTED6
-rw-r--r--test/script/basic/JDK-8062583.js51
-rw-r--r--test/script/basic/JDK-8062583.js.EXPECTED8
55 files changed, 1821 insertions, 541 deletions
diff --git a/bin/runopt.sh b/bin/runopt.sh
index 6b26e287..5ec9046b 100644
--- a/bin/runopt.sh
+++ b/bin/runopt.sh
@@ -28,14 +28,35 @@
# known flags for performance for the current configration
###########################################################################################
+# Flags to enable assertions, we need the system assertions too, since
+# this script runs Nashorn in the BCP to override any nashorn.jar that might
+# reside in your $JAVA_HOME/jre/lib/ext/nashorn.jar
+#
+ENABLE_ASSERTIONS_FLAGS="-ea -esa"
+
# Flags to instrument lambdaform computation, caching, interpretation and compilation
# Default compile threshold for lambdaforms is 30
-#FLAGS="-Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
-
+#
+#LAMBDAFORM_FLAGS="\
+# -Djava.lang.invoke.MethodHandle.COMPILE_THRESHOLD=3 \
+# -Djava.lang.invoke.MethodHandle.DUMP_CLASS_FILES=true \
+# -Djava.lang.invoke.MethodHandle.TRACE_METHOD_LINKAGE=true \
+# -Djava.lang.invoke.MethodHandle.TRACE_INTERPRETER=true"
# Flags to run trusted tests from the Nashorn test suite
-#FLAGS="-Djava.security.manager -Djava.security.policy=../build/nashorn.policy -Dnashorn.debug"
+#
+#TRUSTED_TEST_FLAGS="\
+#-Djava.security.manager \
+#-Djava.security.policy=../build/nashorn.policy -Dnashorn.debug"
+# Testing out new code optimizations using the generic hotspot "new code" parameter
+#
+#USE_NEW_CODE_FLAGS=-XX:+UnlockDiagnosticVMOptions -XX:+UseNewCode
+
+#
+#-Dnashorn.typeInfo.disabled=false \
+# and for Nashorn options:
+# --class-cache-size=0 --persistent-code-cache=false
# Unique timestamped file name for JFR recordings. For JFR, we also have to
# crank up the stack cutoff depth to 1024, because of ridiculously long lambda form
@@ -46,8 +67,42 @@
# can go (10 ms on most platforms). The default is normally higher. The increased
# sampling overhead is usually negligible for Nashorn runs, but the data is better
-JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
+if [ -z $JFR_FILENAME ]; then
+ JFR_FILENAME="./nashorn_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
+fi
+
+# Flight recorder
+#
+# see above - already in place, copy the flags down here to disable
+ENABLE_FLIGHT_RECORDER_FLAGS="\
+ -XX:+UnlockCommercialFeatures \
+ -XX:+FlightRecorder \
+ -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$JFR_FILENAME,stackdepth=1024"
+
+# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine,
+# keeping this flag around for experimental reasons. Replace + with - to switch it off
+#
+#ENABLE_TYPE_SPECIALIZATION_FLAGS=-XX:+UseTypeSpeculation
+
+# Same with math intrinsics. They should be enabled by default in 8u20 and 9, so
+# this disables them if needed
+#
+#DISABLE_MATH_INTRINSICS_FLAGS=-XX:-UseMathExactIntrinsics
+
+# Add timing to time the compilation phases.
+#ENABLE_TIME_FLAGS=--log=time
+
+# Add ShowHiddenFrames to get lambda form internals on the stack traces
+#ENABLE_SHOW_HIDDEN_FRAMES_FLAGS=-XX:+ShowHiddenFrames
+
+# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product,
+# That tired compilation is switched off, for C2 only output and that the number of
+# compiler threads is set to 1 for determinsm.
+#
+#PRINT_ASM_FLAGS=-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \
+# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments)
+#TIER_COMPILATION_THRESHOLD_FLAGS=-XX:IncreaseFirstTierCompileThresholdAt=10
# Directory where to look for nashorn.jar in a dist folder. The default is "..", assuming
# that we run the script from the make dir
@@ -59,49 +114,23 @@ NASHORN_JAR=$DIR/dist/nashorn.jar
# nashorn.jar in $JAVA_HOME/jre/lib/ext. Thus, we also need -esa, as assertions in
# nashorn count as system assertions in this configuration
+# Type profiling default level is 111, 222 adds some compile time, but is faster
+
$JAVA_HOME/bin/java \
-$FLAGS \
--ea \
--esa \
+$ENABLE_ASSERTIONS_FLAGS \
+$LAMBDAFORM_FLAGS \
+$TRUSTED_FLAGS \
+$USE_NEW_CODE_FLAGS \
+$ENABLE_SHOW_HIDDEN_FRAMES_FLAGS \
+$ENABLE_FLIGHT_RECORDER_FLAGS \
+$ENABLE_TYPE_SPECIALIZATION_FLAGS \
+$TIERED_COMPILATION_THRESOLD_FLAGS \
+$DISABLE_MATH_INTRINSICS_FLAGS \
+$PRINT_ASM_FLAGS \
-Xbootclasspath/p:$NASHORN_JAR \
-Xms2G -Xmx2G \
+-XX:TypeProfileLevel=222 \
-cp $CLASSPATH:../build/test/classes/ \
-jdk.nashorn.tools.Shell ${@}
-
-# Below are flags that may come in handy, but aren't used for default runs
-
-
-# Type profiling default level is 111, 222 adds some compile time, but produces better code.
-# -XX:TypeProfileLevel=222 \
-
-
-# Testing out new code optimizations using the generic hotspot "new code" parameter
-#-XX:+UnlockDiagnosticVMOptions \
-#-XX:+UseNewCode \
-
-
-# Type specialization and math intrinsic replacement should be enabled by default in 8u20 and nine,
-# keeping this flag around for experimental reasons. Replace + with - to switch it off
-#-XX:+UseTypeSpeculation \
-
+jdk.nashorn.tools.Shell $ENABLE_TIME_FLAGS ${@}
-# Same with math intrinsics. They should be enabled by default in 8u20 and 9
-#-XX:+UseMathExactIntrinsics \
-
-
-# Add -Dnashorn.time to time the compilation phases.
-#-Dnashorn.time \
-
-
-# Add ShowHiddenFrames to get lambda form internals on the stack traces
-#-XX:+ShowHiddenFrames \
-
-
-# Add print optoassembly to get an asm dump. This requires 1) a debug build, not product,
-# That tired compilation is switched off, for C2 only output and that the number of
-# compiler threads is set to 1 for determinsm.
-#-XX:+PrintOptoAssembly -XX:-TieredCompilation -XX:CICompilerCount=1 \
-
-# Tier compile threasholds. Default value is 10. (1-100 is useful for experiments)
-# -XX:IncreaseFirstTierCompileThresholdAt=XX
diff --git a/src/jdk/nashorn/internal/codegen/CodeGenerator.java b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
index d6743631..f6b9001e 100644
--- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java
+++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java
@@ -208,6 +208,8 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private static final Type ITERATOR_TYPE = Type.typeFor(ITERATOR_CLASS);
private static final Type EXCEPTION_TYPE = Type.typeFor(CompilerConstants.EXCEPTION_PREFIX.type());
+ private static final Integer INT_ZERO = Integer.valueOf(0);
+
/** Constant data & installation. The only reason the compiler keeps this is because it is assigned
* by reflection in class installation */
private final Compiler compiler;
@@ -3817,7 +3819,12 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
private void doSHR() {
// TODO: make SHR optimistic
- method.shr().convert(Type.LONG).load(JSType.MAX_UINT).and();
+ method.shr();
+ toUint();
+ }
+
+ private void toUint() {
+ JSType.TO_UINT32_I.invoke(method);
}
private void loadASSIGN_SUB(final BinaryNode binaryNode) {
@@ -3879,8 +3886,18 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private void loadBIT_OR(final BinaryNode binaryNode) {
- loadBinaryOperands(binaryNode);
- method.or();
+ // Optimize x|0 to (int)x
+ if (isRhsZero(binaryNode)) {
+ loadExpressionAsType(binaryNode.lhs(), Type.INT);
+ } else {
+ loadBinaryOperands(binaryNode);
+ method.or();
+ }
+ }
+
+ private static boolean isRhsZero(final BinaryNode binaryNode) {
+ final Expression rhs = binaryNode.rhs();
+ return rhs instanceof LiteralNode && INT_ZERO.equals(((LiteralNode)rhs).getValue());
}
private void loadBIT_XOR(final BinaryNode binaryNode) {
@@ -3957,8 +3974,14 @@ final class CodeGenerator extends NodeOperatorVisitor<CodeGeneratorLexicalContex
}
private void loadSHR(final BinaryNode binaryNode) {
- loadBinaryOperands(binaryNode);
- doSHR();
+ // Optimize x >>> 0 to (uint)x
+ if (isRhsZero(binaryNode)) {
+ loadExpressionAsType(binaryNode.lhs(), Type.INT);
+ toUint();
+ } else {
+ loadBinaryOperands(binaryNode);
+ doSHR();
+ }
}
private void loadSUB(final BinaryNode binaryNode, final TypeBounds resultBounds) {
diff --git a/src/jdk/nashorn/internal/codegen/FoldConstants.java b/src/jdk/nashorn/internal/codegen/FoldConstants.java
index fe81b2b4..79d20ea1 100644
--- a/src/jdk/nashorn/internal/codegen/FoldConstants.java
+++ b/src/jdk/nashorn/internal/codegen/FoldConstants.java
@@ -291,7 +291,7 @@ final class FoldConstants extends NodeVisitor<LexicalContext> implements Loggabl
value = lhs.getNumber() - rhs.getNumber();
break;
case SHR:
- return LiteralNode.newInstance(token, finish, (lhs.getInt32() >>> rhs.getInt32()) & JSType.MAX_UINT);
+ return LiteralNode.newInstance(token, finish, JSType.toUint32(lhs.getInt32() >>> rhs.getInt32()));
case SAR:
return LiteralNode.newInstance(token, finish, lhs.getInt32() >> rhs.getInt32());
case SHL:
diff --git a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
index 4fa51091..40d12dfb 100644
--- a/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
+++ b/src/jdk/nashorn/internal/codegen/SpillObjectCreator.java
@@ -88,7 +88,7 @@ public final class SpillObjectCreator extends ObjectCreator<Expression> {
final Property property = propertyMap.findProperty(key);
if (property != null) {
// normal property key
- property.setCurrentType(JSType.unboxedFieldType(constantValue));
+ property.setType(JSType.unboxedFieldType(constantValue));
final int slot = property.getSlot();
if (!OBJECT_FIELDS_ONLY && constantValue instanceof Number) {
jpresetValues[slot] = ObjectClassGenerator.pack((Number)constantValue);
diff --git a/src/jdk/nashorn/internal/codegen/TypeEvaluator.java b/src/jdk/nashorn/internal/codegen/TypeEvaluator.java
index 4f3bc07f..d5282a8b 100644
--- a/src/jdk/nashorn/internal/codegen/TypeEvaluator.java
+++ b/src/jdk/nashorn/internal/codegen/TypeEvaluator.java
@@ -117,7 +117,7 @@ final class TypeEvaluator {
}
final Property property = find.getProperty();
- final Class<?> propertyClass = property.getCurrentType();
+ final Class<?> propertyClass = property.getType();
if (propertyClass == null) {
// propertyClass == null means its value is Undefined. It is probably not initialized yet, so we won't make
// a type assumption yet.
diff --git a/src/jdk/nashorn/internal/codegen/types/Type.java b/src/jdk/nashorn/internal/codegen/types/Type.java
index 332ee55e..b31b2503 100644
--- a/src/jdk/nashorn/internal/codegen/types/Type.java
+++ b/src/jdk/nashorn/internal/codegen/types/Type.java
@@ -586,6 +586,7 @@ public abstract class Type implements Comparable<Type>, BytecodeOps, Serializabl
public int getSlots() {
return slots;
}
+
/**
* Returns the widest or most common of two types
*
@@ -609,6 +610,18 @@ public abstract class Type implements Comparable<Type>, BytecodeOps, Serializabl
}
/**
+ * Returns the widest or most common of two types, given as classes
+ *
+ * @param type0 type one
+ * @param type1 type two
+ *
+ * @return the widest type
+ */
+ public static Class<?> widest(final Class<?> type0, final Class<?> type1) {
+ return widest(Type.typeFor(type0), Type.typeFor(type1)).getTypeClass();
+ }
+
+ /**
* When doing widening for return types of a function or a ternary operator, it is not valid to widen a boolean to
* anything other than object. Note that this wouldn't be necessary if {@code Type.widest} did not allow
* boolean-to-number widening. Eventually, we should address it there, but it affects too many other parts of the
diff --git a/src/jdk/nashorn/internal/objects/NativeArray.java b/src/jdk/nashorn/internal/objects/NativeArray.java
index c83e8883..da07432d 100644
--- a/src/jdk/nashorn/internal/objects/NativeArray.java
+++ b/src/jdk/nashorn/internal/objects/NativeArray.java
@@ -33,6 +33,7 @@ import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator;
import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
+
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
import java.util.ArrayList;
@@ -92,9 +93,10 @@ 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 SwitchPoint lengthMadeNotWritableSwitchPoint;
+ private PushLinkLogic pushLinkLogic;
+ private PopLinkLogic popLinkLogic;
+ private ConcatLinkLogic concatLinkLogic;
/**
* Index for the modification SwitchPoint that triggers when length
@@ -130,7 +132,9 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
this(ArrayData.allocate(array.length));
ArrayData arrayData = this.getArray();
- arrayData.ensure(array.length - 1);
+ if (array.length > 0) {
+ arrayData.ensure(array.length - 1);
+ }
for (int index = 0; index < array.length; index++) {
final Object value = array[index];
@@ -266,7 +270,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
@Override
public Object getLength() {
- final long length = getArray().length() & JSType.MAX_UINT;
+ final long length = JSType.toUint32(getArray().length());
if(length < Integer.MAX_VALUE) {
return (int)length;
}
@@ -476,7 +480,7 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static Object length(final Object self) {
if (isArray(self)) {
- return ((ScriptObject) self).getArray().length() & JSType.MAX_UINT;
+ return JSType.toUint32(((ScriptObject) self).getArray().length());
}
return 0;
@@ -757,12 +761,86 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
* ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
*
* @param self self reference
+ * @param arg argument
+ * @return resulting NativeArray
+ */
+ @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+ public static NativeArray concat(final Object self, final int arg) {
+ final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Integer.class).copy(); //get at least an integer data copy of this data
+ newData.fastPush(arg); //add an integer to its end
+ return new NativeArray(newData);
+ }
+
+ /**
+ * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+ *
+ * @param self self reference
+ * @param arg argument
+ * @return resulting NativeArray
+ */
+ @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+ public static NativeArray concat(final Object self, final long arg) {
+ final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Long.class).copy(); //get at least a long array data copy of this data
+ newData.fastPush(arg); //add a long at the end
+ return new NativeArray(newData);
+ }
+
+ /**
+ * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+ *
+ * @param self self reference
+ * @param arg argument
+ * @return resulting NativeArray
+ */
+ @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+ public static NativeArray concat(final Object self, final double arg) {
+ final ContinuousArrayData newData = getContinuousArrayDataCCE(self, Double.class).copy(); //get at least a number array data copy of this data
+ newData.fastPush(arg); //add a double at the end
+ return new NativeArray(newData);
+ }
+
+ /**
+ * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+ *
+ * @param self self reference
+ * @param arg argument
+ * @return resulting NativeArray
+ */
+ @SpecializedFunction(linkLogic=ConcatLinkLogic.class)
+ public static NativeArray concat(final Object self, final Object arg) {
+ //arg is [NativeArray] of same type.
+ final ContinuousArrayData selfData = getContinuousArrayDataCCE(self);
+ final ContinuousArrayData newData;
+
+ if (arg instanceof NativeArray) {
+ final ContinuousArrayData argData = (ContinuousArrayData)((NativeArray)arg).getArray();
+ if (argData.isEmpty()) {
+ newData = selfData.copy();
+ } else if (selfData.isEmpty()) {
+ newData = argData.copy();
+ } else {
+ final Class<?> widestElementType = selfData.widest(argData).getBoxedElementType();
+ newData = ((ContinuousArrayData)selfData.convert(widestElementType)).fastConcat((ContinuousArrayData)argData.convert(widestElementType));
+ }
+ } else {
+ newData = getContinuousArrayDataCCE(self, Object.class).copy();
+ newData.fastPush(arg);
+ }
+
+ return new NativeArray(newData);
+ }
+
+ /**
+ * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
+ *
+ * @param self self reference
* @param args arguments
* @return resulting NativeArray
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
public static NativeArray concat(final Object self, final Object... args) {
final ArrayList<Object> list = new ArrayList<>();
+
concatToList(list, Global.toObject(self));
for (final Object obj : args) {
@@ -1692,13 +1770,15 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
return pushLinkLogic == null ? new PushLinkLogic(this) : pushLinkLogic;
} else if (clazz == PopLinkLogic.class) {
return popLinkLogic == null ? new PopLinkLogic(this) : pushLinkLogic;
+ } else if (clazz == ConcatLinkLogic.class) {
+ return concatLinkLogic == null ? new ConcatLinkLogic(this) : concatLinkLogic;
}
return null;
}
@Override
public boolean hasPerInstanceAssumptions() {
- return true; //length switchpoint
+ return true; //length writable switchpoint
}
/**
@@ -1798,6 +1878,40 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
}
/**
+ * This is linker logic for optimistic concatenations
+ */
+ private static final class ConcatLinkLogic extends ArrayLinkLogic {
+ private ConcatLinkLogic(final NativeArray array) {
+ super(array);
+ }
+
+ @Override
+ public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+ final Object[] args = request.getArguments();
+
+ if (args.length != 3) { //single argument check
+ return false;
+ }
+
+ final ContinuousArrayData selfData = getContinuousArrayData(self);
+ if (selfData == null) {
+ return false;
+ }
+
+ final Object arg = args[2];
+ //args[2] continuousarray or non arraydata, let past non array datas
+ if (arg instanceof NativeArray) {
+ final ContinuousArrayData argData = getContinuousArrayData(arg);
+ if (argData == null) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ }
+
+ /**
* This is linker logic for optimistic pushes
*/
private static final class PushLinkLogic extends ArrayLinkLogic {
@@ -1864,6 +1978,14 @@ public final class NativeArray extends ScriptObject implements OptimisticBuiltin
throw new ClassCastException();
}
+ private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self) {
+ try {
+ return (ContinuousArrayData)((NativeArray)self).getArray();
+ } catch (final NullPointerException e) {
+ throw new ClassCastException();
+ }
+ }
+
private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class<?> elementType) {
try {
return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType"
diff --git a/src/jdk/nashorn/internal/objects/NativeDataView.java b/src/jdk/nashorn/internal/objects/NativeDataView.java
index 0adde064..fb502771 100644
--- a/src/jdk/nashorn/internal/objects/NativeDataView.java
+++ b/src/jdk/nashorn/internal/objects/NativeDataView.java
@@ -27,6 +27,7 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.nashorn.internal.objects.annotations.Attribute;
@@ -432,7 +433,7 @@ public class NativeDataView extends ScriptObject {
@SpecializedFunction
public static long getUint32(final Object self, final int byteOffset) {
try {
- return JSType.MAX_UINT & getBuffer(self, false).getInt(JSType.toInt32(byteOffset));
+ return JSType.toUint32(getBuffer(self, false).getInt(JSType.toInt32(byteOffset)));
} catch (final IllegalArgumentException iae) {
throw rangeError(iae, "dataview.offset");
}
@@ -449,7 +450,7 @@ public class NativeDataView extends ScriptObject {
@SpecializedFunction
public static long getUint32(final Object self, final int byteOffset, final boolean littleEndian) {
try {
- return JSType.MAX_UINT & getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset));
+ return JSType.toUint32(getBuffer(self, littleEndian).getInt(JSType.toInt32(byteOffset)));
} catch (final IllegalArgumentException iae) {
throw rangeError(iae, "dataview.offset");
}
diff --git a/src/jdk/nashorn/internal/objects/NativeDate.java b/src/jdk/nashorn/internal/objects/NativeDate.java
index c85016a5..bb499c26 100644
--- a/src/jdk/nashorn/internal/objects/NativeDate.java
+++ b/src/jdk/nashorn/internal/objects/NativeDate.java
@@ -1045,7 +1045,8 @@ public final class NativeDate extends ScriptObject {
// ECMA 15.9.1.2 TimeWithinDay (t)
private static double timeWithinDay(final double t) {
- return t % msPerDay;
+ final double val = t % msPerDay;
+ return val < 0? val + msPerDay : val;
}
// ECMA 15.9.1.3 InLeapYear (t)
diff --git a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java
index e5ef0b5a..ef7a1ff8 100644
--- a/src/jdk/nashorn/internal/objects/NativeFloat32Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeFloat32Array.java
@@ -90,6 +90,11 @@ public final class NativeFloat32Array extends ArrayBufferView {
}
@Override
+ public Class<?> getBoxedElementType() {
+ return Double.class;
+ }
+
+ @Override
protected MethodHandle getGetElem() {
return GET_ELEM;
}
diff --git a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java
index 1ad61b27..d0413d08 100644
--- a/src/jdk/nashorn/internal/objects/NativeFloat64Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeFloat64Array.java
@@ -99,6 +99,11 @@ public final class NativeFloat64Array extends ArrayBufferView {
return double.class;
}
+ @Override
+ public Class<?> getBoxedElementType() {
+ return Double.class;
+ }
+
private double getElem(final int index) {
try {
return nb.get(index);
diff --git a/src/jdk/nashorn/internal/objects/NativeInt16Array.java b/src/jdk/nashorn/internal/objects/NativeInt16Array.java
index 06148848..e4cdce51 100644
--- a/src/jdk/nashorn/internal/objects/NativeInt16Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeInt16Array.java
@@ -100,6 +100,11 @@ public final class NativeInt16Array extends ArrayBufferView {
return int.class;
}
+ @Override
+ public Class<?> getBoxedElementType() {
+ return Integer.class;
+ }
+
private int getElem(final int index) {
try {
return nb.get(index);
diff --git a/src/jdk/nashorn/internal/objects/NativeInt32Array.java b/src/jdk/nashorn/internal/objects/NativeInt32Array.java
index 5074dc68..9e664ed7 100644
--- a/src/jdk/nashorn/internal/objects/NativeInt32Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeInt32Array.java
@@ -118,6 +118,11 @@ public final class NativeInt32Array extends ArrayBufferView {
}
@Override
+ public Class<?> getBoxedElementType() {
+ return Integer.class;
+ }
+
+ @Override
public int getInt(final int index) {
return getElem(index);
}
diff --git a/src/jdk/nashorn/internal/objects/NativeInt8Array.java b/src/jdk/nashorn/internal/objects/NativeInt8Array.java
index 319168c0..c336d274 100644
--- a/src/jdk/nashorn/internal/objects/NativeInt8Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeInt8Array.java
@@ -98,6 +98,11 @@ public final class NativeInt8Array extends ArrayBufferView {
return int.class;
}
+ @Override
+ public Class<?> getBoxedElementType() {
+ return Integer.class;
+ }
+
private int getElem(final int index) {
try {
return nb.get(index);
diff --git a/src/jdk/nashorn/internal/objects/NativeObject.java b/src/jdk/nashorn/internal/objects/NativeObject.java
index 5667e6ac..7a1375d3 100644
--- a/src/jdk/nashorn/internal/objects/NativeObject.java
+++ b/src/jdk/nashorn/internal/objects/NativeObject.java
@@ -28,7 +28,6 @@ package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -673,7 +672,7 @@ public final class NativeObject {
for (final Property prop : properties) {
if (prop.isEnumerable()) {
final Object value = sourceObj.get(prop.getKey());
- prop.setCurrentType(Object.class);
+ prop.setType(Object.class);
prop.setValue(sourceObj, sourceObj, value, false);
propList.add(prop);
}
diff --git a/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java b/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java
index ffd6055b..467399ae 100644
--- a/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java
+++ b/src/jdk/nashorn/internal/objects/NativeRegExpExecResult.java
@@ -74,7 +74,7 @@ public final class NativeRegExpExecResult extends ScriptObject {
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static Object length(final Object self) {
if (self instanceof ScriptObject) {
- return ((ScriptObject)self).getArray().length() & JSType.MAX_UINT;
+ return JSType.toUint32(((ScriptObject)self).getArray().length());
}
return 0;
diff --git a/src/jdk/nashorn/internal/objects/NativeUint16Array.java b/src/jdk/nashorn/internal/objects/NativeUint16Array.java
index 7f8a1923..2fc2c51a 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint16Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint16Array.java
@@ -124,6 +124,11 @@ public final class NativeUint16Array extends ArrayBufferView {
}
@Override
+ public Class<?> getBoxedElementType() {
+ return Integer.class;
+ }
+
+ @Override
public int getInt(final int index) {
return getElem(index);
}
diff --git a/src/jdk/nashorn/internal/objects/NativeUint32Array.java b/src/jdk/nashorn/internal/objects/NativeUint32Array.java
index 4772b977..4c83cc01 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint32Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint32Array.java
@@ -105,7 +105,7 @@ public final class NativeUint32Array extends ArrayBufferView {
private long getElem(final int index) {
try {
- return nb.get(index) & JSType.MAX_UINT;
+ return JSType.toUint32(nb.get(index));
} catch (final IndexOutOfBoundsException e) {
throw new ClassCastException(); //force relink - this works for unoptimistic too
}
@@ -133,6 +133,11 @@ public final class NativeUint32Array extends ArrayBufferView {
}
@Override
+ public Class<?> getBoxedElementType() {
+ return Integer.class;
+ }
+
+ @Override
public int getInt(final int index) {
return (int)getLong(index);
}
diff --git a/src/jdk/nashorn/internal/objects/NativeUint8Array.java b/src/jdk/nashorn/internal/objects/NativeUint8Array.java
index be7eb368..6e69ebad 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint8Array.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint8Array.java
@@ -124,6 +124,11 @@ public final class NativeUint8Array extends ArrayBufferView {
}
@Override
+ public Class<?> getBoxedElementType() {
+ return Integer.class;
+ }
+
+ @Override
public int getInt(final int index) {
return getElem(index);
}
diff --git a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
index 125ac0a2..2dff2612 100644
--- a/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
+++ b/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java
@@ -103,6 +103,11 @@ public final class NativeUint8ClampedArray extends ArrayBufferView {
return int.class;
}
+ @Override
+ public Class<?> getBoxedElementType() {
+ return int.class;
+ }
+
private int getElem(final int index) {
try {
return nb.get(index) & 0xff;
diff --git a/src/jdk/nashorn/internal/parser/JSONParser.java b/src/jdk/nashorn/internal/parser/JSONParser.java
index a5cae0ed..7faf89a8 100644
--- a/src/jdk/nashorn/internal/parser/JSONParser.java
+++ b/src/jdk/nashorn/internal/parser/JSONParser.java
@@ -32,7 +32,6 @@ import static jdk.nashorn.internal.parser.TokenType.ESCSTRING;
import static jdk.nashorn.internal.parser.TokenType.RBRACE;
import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
import static jdk.nashorn.internal.parser.TokenType.STRING;
-
import java.util.ArrayList;
import java.util.List;
import jdk.nashorn.internal.ir.Expression;
diff --git a/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/src/jdk/nashorn/internal/runtime/AccessorProperty.java
index e2935368..a9afeb93 100644
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java
@@ -145,13 +145,6 @@ public class AccessorProperty extends Property {
transient MethodHandle objectSetter;
/**
- * Current type of this object, in object only mode, this is an Object.class. In dual-fields mode
- * null means undefined, and primitive types are allowed. The reason a special type is used for
- * undefined, is that are no bits left to represent it in primitive types
- */
- private Class<?> currentType;
-
- /**
* Delegate constructor for bound properties. This is used for properties created by
* {@link ScriptRuntime#mergeScope} and the Nashorn {@code Object.bindProperties} method.
* The former is used to add a script's defined globals to the current global scope while
@@ -171,7 +164,7 @@ public class AccessorProperty extends Property {
this.objectSetter = bindTo(property.objectSetter, delegate);
property.GETTER_CACHE = new MethodHandle[NOOF_TYPES];
// Properties created this way are bound to a delegate
- setCurrentType(property.getCurrentType());
+ setType(property.getType());
}
/**
@@ -248,7 +241,7 @@ public class AccessorProperty extends Property {
objectGetter = getter.type() != Lookup.GET_OBJECT_TYPE ? MH.asType(getter, Lookup.GET_OBJECT_TYPE) : getter;
objectSetter = setter != null && setter.type() != Lookup.SET_OBJECT_TYPE ? MH.asType(setter, Lookup.SET_OBJECT_TYPE) : setter;
- setCurrentType(OBJECT_FIELDS_ONLY ? Object.class : getterType);
+ setType(OBJECT_FIELDS_ONLY ? Object.class : getterType);
}
/**
@@ -317,7 +310,7 @@ public class AccessorProperty extends Property {
*/
public AccessorProperty(final String key, final int flags, final Class<?> structure, final int slot, final Class<?> initialType) {
this(key, flags, structure, slot);
- setCurrentType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
+ setType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
}
/**
@@ -330,13 +323,13 @@ public class AccessorProperty extends Property {
protected AccessorProperty(final AccessorProperty property, final Class<?> newType) {
super(property, property.getFlags());
- this.GETTER_CACHE = newType != property.getCurrentType() ? new MethodHandle[NOOF_TYPES] : property.GETTER_CACHE;
+ this.GETTER_CACHE = newType != property.getLocalType() ? new MethodHandle[NOOF_TYPES] : property.GETTER_CACHE;
this.primitiveGetter = property.primitiveGetter;
this.primitiveSetter = property.primitiveSetter;
this.objectGetter = property.objectGetter;
this.objectSetter = property.objectSetter;
- setCurrentType(newType);
+ setType(newType);
}
/**
@@ -345,7 +338,7 @@ public class AccessorProperty extends Property {
* @param property source property
*/
protected AccessorProperty(final AccessorProperty property) {
- this(property, property.getCurrentType());
+ this(property, property.getLocalType());
}
/**
@@ -354,7 +347,7 @@ public class AccessorProperty extends Property {
* @param initialValue initial value
*/
protected final void setInitialValue(final ScriptObject owner, final Object initialValue) {
- setCurrentType(JSType.unboxedFieldType(initialValue));
+ setType(JSType.unboxedFieldType(initialValue));
if (initialValue instanceof Integer) {
invokeSetter(owner, ((Integer)initialValue).intValue());
} else if (initialValue instanceof Long) {
@@ -370,7 +363,7 @@ public class AccessorProperty extends Property {
* Initialize the type of a property
*/
protected final void initializeType() {
- setCurrentType(OBJECT_FIELDS_ONLY ? Object.class : null);
+ setType(OBJECT_FIELDS_ONLY ? Object.class : null);
}
private void readObject(final ObjectInputStream s) throws IOException, ClassNotFoundException {
@@ -557,12 +550,12 @@ public class AccessorProperty extends Property {
} else {
getter = debug(
createGetter(
- getCurrentType(),
+ getLocalType(),
type,
primitiveGetter,
objectGetter,
INVALID_PROGRAM_POINT),
- getCurrentType(),
+ getLocalType(),
type,
"get");
getterCache[i] = getter;
@@ -582,18 +575,18 @@ public class AccessorProperty extends Property {
return debug(
createGetter(
- getCurrentType(),
+ getLocalType(),
type,
primitiveGetter,
objectGetter,
programPoint),
- getCurrentType(),
+ getLocalType(),
type,
"get");
}
private MethodHandle getOptimisticPrimitiveGetter(final Class<?> type, final int programPoint) {
- final MethodHandle g = getGetter(getCurrentType());
+ final MethodHandle g = getGetter(getLocalType());
return MH.asType(OptimisticReturnFilters.filterOptimisticReturnValue(g, type, programPoint), g.type().changeReturnType(type));
}
@@ -631,7 +624,7 @@ public class AccessorProperty extends Property {
}
private MethodHandle generateSetter(final Class<?> forType, final Class<?> type) {
- return debug(createSetter(forType, type, primitiveSetter, objectSetter), getCurrentType(), type, "set");
+ return debug(createSetter(forType, type, primitiveSetter, objectSetter), getLocalType(), type, "set");
}
/**
@@ -639,7 +632,7 @@ public class AccessorProperty extends Property {
* @return true if undefined
*/
protected final boolean isUndefined() {
- return getCurrentType() == null;
+ return getLocalType() == null;
}
@Override
@@ -647,7 +640,7 @@ public class AccessorProperty extends Property {
checkUndeclared();
final int typeIndex = getAccessorTypeIndex(type);
- final int currentTypeIndex = getAccessorTypeIndex(getCurrentType());
+ final int currentTypeIndex = getAccessorTypeIndex(getLocalType());
//if we are asking for an object setter, but are still a primitive type, we might try to box it
MethodHandle mh;
@@ -656,13 +649,13 @@ public class AccessorProperty extends Property {
final PropertyMap newMap = getWiderMap(currentMap, newProperty);
final MethodHandle widerSetter = newProperty.getSetter(type, newMap);
- final Class<?> ct = getCurrentType();
+ final Class<?> ct = getLocalType();
mh = MH.filterArguments(widerSetter, 0, MH.insertArguments(debugReplace(ct, type, currentMap, newMap) , 1, newMap));
if (ct != null && ct.isPrimitive() && !type.isPrimitive()) {
mh = ObjectClassGenerator.createGuardBoxedPrimitiveSetter(ct, generateSetter(ct, ct), mh);
}
} else {
- final Class<?> forType = isUndefined() ? type : getCurrentType();
+ final Class<?> forType = isUndefined() ? type : getLocalType();
mh = generateSetter(!forType.isPrimitive() ? Object.class : forType, type);
}
@@ -681,24 +674,13 @@ public class AccessorProperty extends Property {
return false;
}
// Return true for currently undefined even if non-writable/configurable to allow initialization of ES6 CONST.
- return getCurrentType() == null || (getCurrentType() != Object.class && (isConfigurable() || isWritable()));
+ return getLocalType() == null || (getLocalType() != Object.class && (isConfigurable() || isWritable()));
}
private boolean needsInvalidator(final int typeIndex, final int currentTypeIndex) {
return canChangeType() && typeIndex > currentTypeIndex;
}
- @Override
- public final void setCurrentType(final Class<?> currentType) {
- assert currentType != boolean.class : "no boolean storage support yet - fix this";
- this.currentType = currentType == null ? null : currentType.isPrimitive() ? currentType : Object.class;
- }
-
- @Override
- public Class<?> getCurrentType() {
- return currentType;
- }
-
private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) {
if (!Context.DEBUG || !Global.hasInstance()) {
return mh;
diff --git a/src/jdk/nashorn/internal/runtime/ECMAException.java b/src/jdk/nashorn/internal/runtime/ECMAException.java
index 954a1707..f906e18f 100644
--- a/src/jdk/nashorn/internal/runtime/ECMAException.java
+++ b/src/jdk/nashorn/internal/runtime/ECMAException.java
@@ -96,15 +96,17 @@ public final class ECMAException extends NashornException {
// If thrown object is an Error or sub-object like TypeError, then
// an ECMAException object has been already initialized at constructor.
if (thrown instanceof ScriptObject) {
- final ScriptObject sobj = (ScriptObject)thrown;
- final Object exception = getException(sobj);
+ final Object exception = getException((ScriptObject)thrown);
if (exception instanceof ECMAException) {
- // copy over file name, line number and column number.
final ECMAException ee = (ECMAException)exception;
- ee.setFileName(fileName);
- ee.setLineNumber(line);
- ee.setColumnNumber(column);
- return ee;
+ // Make sure exception has correct thrown reference because that's what will end up getting caught.
+ if (ee.getThrown() == thrown) {
+ // copy over file name, line number and column number.
+ ee.setFileName(fileName);
+ ee.setLineNumber(line);
+ ee.setColumnNumber(column);
+ return ee;
+ }
}
}
@@ -154,7 +156,11 @@ public final class ECMAException extends NashornException {
* @return a {@link ECMAException}
*/
public static Object getException(final ScriptObject errObj) {
- return errObj.get(ECMAException.EXCEPTION_PROPERTY);
+ // Exclude inherited properties that may belong to errors in the prototype chain.
+ if (errObj.hasOwnProperty(ECMAException.EXCEPTION_PROPERTY)) {
+ return errObj.get(ECMAException.EXCEPTION_PROPERTY);
+ }
+ return null;
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/FindProperty.java b/src/jdk/nashorn/internal/runtime/FindProperty.java
index b4e00124..3b153c58 100644
--- a/src/jdk/nashorn/internal/runtime/FindProperty.java
+++ b/src/jdk/nashorn/internal/runtime/FindProperty.java
@@ -84,13 +84,18 @@ public final class FindProperty {
* @return method handle for the getter
*/
public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) {
- final MethodHandle getter;
+ MethodHandle getter;
if (isValid(programPoint)) {
getter = property.getOptimisticGetter(type, programPoint);
} else {
getter = property.getGetter(type);
}
if (property instanceof UserAccessorProperty) {
+ getter = MH.insertArguments(getter, 1, UserAccessorProperty.getINVOKE_UA_GETTER(type, programPoint));
+ if (isValid(programPoint) && type.isPrimitive()) {
+ getter = MH.insertArguments(getter, 1, programPoint);
+ }
+ property.setType(type);
return insertAccessorsGetter((UserAccessorProperty) property, request, getter);
}
return getter;
@@ -111,7 +116,8 @@ public final class FindProperty {
public MethodHandle getSetter(final Class<?> type, final boolean strict, final LinkRequest request) {
MethodHandle setter = property.getSetter(type, getOwner().getMap());
if (property instanceof UserAccessorProperty) {
- setter = MH.insertArguments(setter, 1, strict ? property.getKey() : null);
+ setter = MH.insertArguments(setter, 1, UserAccessorProperty.getINVOKE_UA_SETTER(type), strict ? property.getKey() : null);
+ property.setType(type);
return insertAccessorsGetter((UserAccessorProperty) property, request, setter);
}
diff --git a/src/jdk/nashorn/internal/runtime/JSType.java b/src/jdk/nashorn/internal/runtime/JSType.java
index b040b588..2b64ff34 100644
--- a/src/jdk/nashorn/internal/runtime/JSType.java
+++ b/src/jdk/nashorn/internal/runtime/JSType.java
@@ -29,7 +29,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Array;
@@ -115,6 +114,9 @@ public enum JSType {
/** JavaScript compliant conversion function from double to int32 */
public static final Call TO_INT32_D = staticCall(JSTYPE_LOOKUP, JSType.class, "toInt32", int.class, double.class);
+ /** JavaScript compliant conversion function from int to uint32 */
+ public static final Call TO_UINT32_I = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, int.class);
+
/** JavaScript compliant conversion function from Object to uint32 */
public static final Call TO_UINT32 = staticCall(JSTYPE_LOOKUP, JSType.class, "toUint32", long.class, Object.class);
@@ -1002,6 +1004,16 @@ public enum JSType {
}
/**
+ * JavaScript compliant int to uint32 conversion
+ *
+ * @param num an int
+ * @return a uint32
+ */
+ public static long toUint32(final int num) {
+ return num & MAX_UINT;
+ }
+
+ /**
* JavaScript compliant Object to uint16 conversion
* ECMA 9.7 ToUint16: (Unsigned 16 Bit Integer)
*
@@ -1776,6 +1788,23 @@ public enum JSType {
}
/**
+ * Returns the boxed version of a primitive class
+ * @param clazz the class
+ * @return the boxed type of clazz, or unchanged if not primitive
+ */
+ public static Class<?> getBoxedClass(final Class<?> clazz) {
+ if (clazz == int.class) {
+ return Integer.class;
+ } else if (clazz == long.class) {
+ return Long.class;
+ } else if (clazz == double.class) {
+ return Double.class;
+ }
+ assert !clazz.isPrimitive();
+ return clazz;
+ }
+
+ /**
* Create a method handle constant of the correct primitive type
* for a constant object
* @param o object
diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java
index f57246ca..41baa642 100644
--- a/src/jdk/nashorn/internal/runtime/Property.java
+++ b/src/jdk/nashorn/internal/runtime/Property.java
@@ -102,6 +102,13 @@ public abstract class Property implements Serializable {
/** Property field number or spill slot. */
private final int slot;
+ /**
+ * Current type of this object, in object only mode, this is an Object.class. In dual-fields mode
+ * null means undefined, and primitive types are allowed. The reason a special type is used for
+ * undefined, is that are no bits left to represent it in primitive types
+ */
+ private Class<?> type;
+
/** SwitchPoint that is invalidated when property is changed, optional */
protected transient SwitchPoint builtinSwitchPoint;
@@ -536,7 +543,7 @@ public abstract class Property implements Serializable {
* <p>
* see {@link ObjectClassGenerator#createSetter(Class, Class, MethodHandle, MethodHandle)}
* if you are interested in the internal details of this. Note that if you
- * are running in default mode, with {@code -Dnashorn.fields.dual=true}, disabled, the setters
+ * are running with {@code -Dnashorn.fields.objects=true}, the setters
* will currently never change, as all properties are represented as Object field,
* the Object fields are Initialized to {@code ScriptRuntime.UNDEFINED} and primitives are
* boxed/unboxed upon every access, which is not necessarily optimal
@@ -569,7 +576,7 @@ public abstract class Property implements Serializable {
@Override
public int hashCode() {
- final Class<?> type = getCurrentType();
+ final Class<?> type = getLocalType();
return Objects.hashCode(this.key) ^ flags ^ getSlot() ^ (type == null ? 0 : type.hashCode());
}
@@ -586,7 +593,7 @@ public abstract class Property implements Serializable {
final Property otherProperty = (Property)other;
return equalsWithoutType(otherProperty) &&
- getCurrentType() == otherProperty.getCurrentType();
+ getLocalType() == otherProperty.getLocalType();
}
boolean equalsWithoutType(final Property otherProperty) {
@@ -615,7 +622,7 @@ public abstract class Property implements Serializable {
*/
public final String toStringShort() {
final StringBuilder sb = new StringBuilder();
- final Class<?> type = getCurrentType();
+ final Class<?> type = getLocalType();
sb.append(getKey()).append(" (").append(type(type)).append(')');
return sb.toString();
}
@@ -632,7 +639,7 @@ public abstract class Property implements Serializable {
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
- final Class<?> type = getCurrentType();
+ final Class<?> type = getLocalType();
sb.append(indent(getKey(), 20)).
append(" id=").
@@ -656,20 +663,40 @@ public abstract class Property implements Serializable {
}
/**
- * Get the current type of this field. If you are not running with dual fields enabled,
+ * Get the current type of this property. If you are running with object fields enabled,
* this will always be Object.class. See the value representation explanation in
* {@link Property#getSetter(Class, PropertyMap)} and {@link ObjectClassGenerator}
* for more information.
*
+ * <p>Note that for user accessor properties, this returns the type of the last observed
+ * value passed to or returned by a user accessor. Use {@link #getLocalType()} to always get
+ * the type of the actual value stored in the property slot.</p>
+ *
* @return current type of property, null means undefined
*/
- public abstract Class<?> getCurrentType();
+ public final Class<?> getType() {
+ return type;
+ }
/**
- * Reset the current type of this property
- * @param currentType new current type
+ * Set the type of this property.
+ * @param type new type
*/
- public abstract void setCurrentType(final Class<?> currentType);
+ public final void setType(final Class<?> type) {
+ assert type != boolean.class : "no boolean storage support yet - fix this";
+ this.type = type == null ? null : type.isPrimitive() ? type : Object.class;
+ }
+
+ /**
+ * Get the type of the value in the local property slot. This returns the same as
+ * {@link #getType()} for normal properties, but always returns {@code Object.class}
+ * for {@link UserAccessorProperty}s as their local type is a pair of accessor references.
+ *
+ * @return the local property type
+ */
+ protected Class<?> getLocalType() {
+ return getType();
+ }
/**
* Check whether this Property can ever change its type. The default is false, and if
diff --git a/src/jdk/nashorn/internal/runtime/PropertyMap.java b/src/jdk/nashorn/internal/runtime/PropertyMap.java
index 61912332..30a15132 100644
--- a/src/jdk/nashorn/internal/runtime/PropertyMap.java
+++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java
@@ -84,7 +84,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
private transient WeakHashMap<Property, SoftReference<PropertyMap>> history;
/** History of prototypes, used to limit map duplication. */
- private transient WeakHashMap<PropertyMap, SoftReference<PropertyMap>> protoHistory;
+ private transient WeakHashMap<ScriptObject, SoftReference<PropertyMap>> protoHistory;
/** property listeners */
private transient PropertyListeners listeners;
@@ -512,7 +512,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
assert sameType ||
oldProperty instanceof AccessorProperty &&
newProperty instanceof UserAccessorProperty :
- "arbitrary replaceProperty attempted " + sameType + " oldProperty=" + oldProperty.getClass() + " newProperty=" + newProperty.getClass() + " [" + oldProperty.getCurrentType() + " => " + newProperty.getCurrentType() + "]";
+ "arbitrary replaceProperty attempted " + sameType + " oldProperty=" + oldProperty.getClass() + " newProperty=" + newProperty.getClass() + " [" + oldProperty.getLocalType() + " => " + newProperty.getLocalType() + "]";
newMap.flags = flags;
@@ -677,14 +677,14 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
/**
* Check prototype history for an existing property map with specified prototype.
*
- * @param parentMap New prototype object.
+ * @param proto New prototype object.
*
* @return Existing {@link PropertyMap} or {@code null} if not found.
*/
- private PropertyMap checkProtoHistory(final PropertyMap parentMap) {
+ private PropertyMap checkProtoHistory(final ScriptObject proto) {
final PropertyMap cachedMap;
if (protoHistory != null) {
- final SoftReference<PropertyMap> weakMap = protoHistory.get(parentMap);
+ final SoftReference<PropertyMap> weakMap = protoHistory.get(proto);
cachedMap = (weakMap != null ? weakMap.get() : null);
} else {
cachedMap = null;
@@ -700,15 +700,15 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
/**
* Add a map to the prototype history.
*
- * @param parentMap Prototype to add (key.)
+ * @param newProto Prototype to add (key.)
* @param newMap {@link PropertyMap} associated with prototype.
*/
- private void addToProtoHistory(final PropertyMap parentMap, final PropertyMap newMap) {
+ private void addToProtoHistory(final ScriptObject newProto, final PropertyMap newMap) {
if (protoHistory == null) {
protoHistory = new WeakHashMap<>();
}
- protoHistory.put(parentMap, new SoftReference<>(newMap));
+ protoHistory.put(newProto, new SoftReference<>(newMap));
}
/**
@@ -883,8 +883,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*/
public PropertyMap changeProto(final ScriptObject newProto) {
- final PropertyMap parentMap = newProto == null ? null : newProto.getMap();
- final PropertyMap nextMap = checkProtoHistory(parentMap);
+ final PropertyMap nextMap = checkProtoHistory(newProto);
if (nextMap != null) {
return nextMap;
}
@@ -894,7 +893,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
}
final PropertyMap newMap = new PropertyMap(this);
- addToProtoHistory(parentMap, newMap);
+ addToProtoHistory(newProto, newMap);
return newMap;
}
diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java
index 87d28976..a76703cf 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -692,8 +692,7 @@ public abstract class ScriptObject implements PropertyAccess {
assert isValidArrayIndex(index) : "invalid array index";
final long longIndex = ArrayIndex.toLongIndex(index);
doesNotHaveEnsureDelete(longIndex, getArray().length(), false);
- setArray(getArray().ensure(longIndex));
- setArray(getArray().set(index, value, false));
+ setArray(getArray().ensure(longIndex).set(index,value, false));
}
private void checkIntegerKey(final String key) {
@@ -970,7 +969,7 @@ public abstract class ScriptObject implements PropertyAccess {
final UserAccessorProperty uc = (UserAccessorProperty)oldProperty;
final int slot = uc.getSlot();
- assert uc.getCurrentType() == Object.class;
+ assert uc.getLocalType() == Object.class;
if (slot >= spillLength) {
uc.setAccessors(this, getMap(), new UserAccessorProperty.Accessors(getter, setter));
} else {
@@ -1462,9 +1461,8 @@ public abstract class ScriptObject implements PropertyAccess {
//invalidate any fast array setters
final ArrayData array = getArray();
- if (array != null) {
- array.invalidateSetters();
- }
+ assert array != null;
+ setArray(ArrayData.preventExtension(array));
return this;
}
@@ -2645,20 +2643,22 @@ public abstract class ScriptObject implements PropertyAccess {
* @param newLength new length to set
*/
public final void setLength(final long newLength) {
- final long arrayLength = getArray().length();
- if (newLength == arrayLength) {
- return;
- }
+ ArrayData data = getArray();
+ final long arrayLength = data.length();
+ if (newLength == arrayLength) {
+ return;
+ }
- if (newLength > arrayLength) {
- setArray(getArray().ensure(newLength - 1));
- if (getArray().canDelete(arrayLength, newLength - 1, false)) {
- setArray(getArray().delete(arrayLength, newLength - 1));
- }
- return;
- }
+ if (newLength > arrayLength) {
+ data = data.ensure(newLength - 1);
+ if (data.canDelete(arrayLength, newLength - 1, false)) {
+ data = data.delete(arrayLength, newLength - 1);
+ }
+ setArray(data);
+ return;
+ }
- if (newLength < arrayLength) {
+ if (newLength < arrayLength) {
long actualLength = newLength;
// Check for numeric keys in property map and delete them or adjust length, depending on whether
@@ -2680,8 +2680,8 @@ public abstract class ScriptObject implements PropertyAccess {
}
}
- setArray(getArray().shrink(actualLength));
- getArray().setLength(actualLength);
+ setArray(data.shrink(actualLength));
+ data.setLength(actualLength);
}
}
@@ -3194,8 +3194,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(primitiveKey);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3213,8 +3214,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(primitiveKey);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3232,8 +3234,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(primitiveKey);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3251,8 +3254,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(primitiveKey);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3269,8 +3273,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3287,8 +3292,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3305,8 +3311,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3323,8 +3330,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3341,8 +3349,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3359,8 +3368,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3377,8 +3387,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3395,8 +3406,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3413,7 +3425,8 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3429,8 +3442,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3447,8 +3461,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
@@ -3465,8 +3480,9 @@ public abstract class ScriptObject implements PropertyAccess {
final int index = getArrayIndex(key);
if (isValidArrayIndex(index)) {
- if (getArray().has(index)) {
- setArray(getArray().set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
+ final ArrayData data = getArray();
+ if (data.has(index)) {
+ setArray(data.set(index, value, NashornCallSiteDescriptor.isStrictFlag(callSiteFlags)));
} else {
doesNotHave(index, value, callSiteFlags);
}
diff --git a/src/jdk/nashorn/internal/runtime/SpillProperty.java b/src/jdk/nashorn/internal/runtime/SpillProperty.java
index 8ff1b8e5..7b42b2bf 100644
--- a/src/jdk/nashorn/internal/runtime/SpillProperty.java
+++ b/src/jdk/nashorn/internal/runtime/SpillProperty.java
@@ -161,12 +161,12 @@ public class SpillProperty extends AccessorProperty {
*/
public SpillProperty(final String key, final int flags, final int slot) {
super(key, flags, slot, primitiveGetter(slot), primitiveSetter(slot), objectGetter(slot), objectSetter(slot));
- assert !OBJECT_FIELDS_ONLY || getCurrentType() == Object.class;
+ assert !OBJECT_FIELDS_ONLY || getLocalType() == Object.class;
}
SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType) {
this(key, flags, slot);
- setCurrentType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
+ setType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
}
SpillProperty(final String key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
diff --git a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
index 5fdec009..d14dd8e7 100644
--- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
+++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
@@ -27,16 +27,16 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-import static jdk.nashorn.internal.runtime.JSType.CONVERT_OBJECT_OPTIMISTIC;
-import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
+import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
+import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
-import java.util.concurrent.Callable;
import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
+import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
* Property with user defined getters/setters. Actual getter and setter
@@ -69,38 +69,29 @@ public final class UserAccessorProperty extends SpillProperty {
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
/** Getter method handle */
- private final static MethodHandle INVOKE_GETTER_ACCESSOR = findOwnMH_S("invokeGetterAccessor", Object.class, Accessors.class, Object.class);
+ private final static MethodHandle INVOKE_OBJECT_GETTER = findOwnMH_S("invokeObjectGetter", Object.class, Accessors.class, MethodHandle.class, Object.class);
+ private final static MethodHandle INVOKE_INT_GETTER = findOwnMH_S("invokeIntGetter", int.class, Accessors.class, MethodHandle.class, int.class, Object.class);
+ private final static MethodHandle INVOKE_LONG_GETTER = findOwnMH_S("invokeLongGetter", long.class, Accessors.class, MethodHandle.class, int.class, Object.class);
+ private final static MethodHandle INVOKE_NUMBER_GETTER = findOwnMH_S("invokeNumberGetter", double.class, Accessors.class, MethodHandle.class, int.class, Object.class);
/** Setter method handle */
- private final static MethodHandle INVOKE_SETTER_ACCESSOR = findOwnMH_S("invokeSetterAccessor", void.class, Accessors.class, String.class, Object.class, Object.class);
-
- /** Dynamic invoker for getter */
- private static final Object GETTER_INVOKER_KEY = new Object();
-
- private static MethodHandle getINVOKE_UA_GETTER() {
-
- return Context.getGlobal().getDynamicInvoker(GETTER_INVOKER_KEY,
- new Callable<MethodHandle>() {
- @Override
- public MethodHandle call() {
- return Bootstrap.createDynamicInvoker("dyn:call", Object.class,
- Object.class, Object.class);
- }
- });
+ private final static MethodHandle INVOKE_OBJECT_SETTER = findOwnMH_S("invokeObjectSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, Object.class);
+ private final static MethodHandle INVOKE_INT_SETTER = findOwnMH_S("invokeIntSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, int.class);
+ private final static MethodHandle INVOKE_LONG_SETTER = findOwnMH_S("invokeLongSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, long.class);
+ private final static MethodHandle INVOKE_NUMBER_SETTER = findOwnMH_S("invokeNumberSetter", void.class, Accessors.class, MethodHandle.class, String.class, Object.class, double.class);
+
+
+ static MethodHandle getINVOKE_UA_GETTER(final Class<?> returnType, final int programPoint) {
+ if (UnwarrantedOptimismException.isValid(programPoint)) {
+ final int flags = NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC | programPoint << CALLSITE_PROGRAM_POINT_SHIFT;
+ return Bootstrap.createDynamicInvoker("dyn:call", flags, returnType, Object.class, Object.class);
+ } else {
+ return Bootstrap.createDynamicInvoker("dyn:call", Object.class, Object.class, Object.class);
+ }
}
- /** Dynamic invoker for setter */
- private static Object SETTER_INVOKER_KEY = new Object();
-
- private static MethodHandle getINVOKE_UA_SETTER() {
- return Context.getGlobal().getDynamicInvoker(SETTER_INVOKER_KEY,
- new Callable<MethodHandle>() {
- @Override
- public MethodHandle call() {
- return Bootstrap.createDynamicInvoker("dyn:call", void.class,
- Object.class, Object.class, Object.class);
- }
- });
+ static MethodHandle getINVOKE_UA_SETTER(final Class<?> valueType) {
+ return Bootstrap.createDynamicInvoker("dyn:call", void.class, Object.class, Object.class, valueType);
}
/**
@@ -158,7 +149,7 @@ public final class UserAccessorProperty extends SpillProperty {
}
@Override
- public Class<?> getCurrentType() {
+ protected Class<?> getLocalType() {
return Object.class;
}
@@ -189,7 +180,13 @@ public final class UserAccessorProperty extends SpillProperty {
@Override
public Object getObjectValue(final ScriptObject self, final ScriptObject owner) {
- return invokeGetterAccessor(getAccessors((owner != null) ? owner : self), self);
+ try {
+ return invokeObjectGetter(getAccessors((owner != null) ? owner : self), getINVOKE_UA_GETTER(Object.class, INVALID_PROGRAM_POINT), self);
+ } catch (final Error | RuntimeException t) {
+ throw t;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
}
@Override
@@ -209,41 +206,33 @@ public final class UserAccessorProperty extends SpillProperty {
@Override
public void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict) {
- invokeSetterAccessor(getAccessors((owner != null) ? owner : self), strict ? getKey() : null, self, value);
+ try {
+ invokeObjectSetter(getAccessors((owner != null) ? owner : self), getINVOKE_UA_SETTER(Object.class), strict ? getKey() : null, self, value);
+ } catch (final Error | RuntimeException t) {
+ throw t;
+ } catch (final Throwable t) {
+ throw new RuntimeException(t);
+ }
}
@Override
public MethodHandle getGetter(final Class<?> type) {
//this returns a getter on the format (Accessors, Object receiver)
- return Lookup.filterReturnType(INVOKE_GETTER_ACCESSOR, type);
+ return Lookup.filterReturnType(INVOKE_OBJECT_GETTER, type);
}
@Override
public MethodHandle getOptimisticGetter(final Class<?> type, final int programPoint) {
- //fortype is always object, but in the optimistic world we have to throw
- //unwarranted optimism exception for narrower types. We can improve this
- //by checking for boxed types and unboxing them, but it is doubtful that
- //this gives us any performance, as UserAccessorProperties are typically not
- //primitives. Are there? TODO: investigate later. For now we just throw an
- //exception for narrower types than object
-
- if (type.isPrimitive()) {
- final MethodHandle getter = getGetter(Object.class);
- final MethodHandle mh =
- MH.asType(
- MH.filterReturnValue(
- getter,
- MH.insertArguments(
- CONVERT_OBJECT_OPTIMISTIC.get(getAccessorTypeIndex(type)),
- 1,
- programPoint)),
- getter.type().changeReturnType(type));
-
- return mh;
+ if (type == int.class) {
+ return INVOKE_INT_GETTER;
+ } else if (type == long.class) {
+ return INVOKE_LONG_GETTER;
+ } else if (type == double.class) {
+ return INVOKE_NUMBER_GETTER;
+ } else {
+ assert type == Object.class;
+ return INVOKE_OBJECT_GETTER;
}
-
- assert type == Object.class;
- return getGetter(type);
}
@Override
@@ -259,7 +248,16 @@ public final class UserAccessorProperty extends SpillProperty {
@Override
public MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap) {
- return INVOKE_SETTER_ACCESSOR;
+ if (type == int.class) {
+ return INVOKE_INT_SETTER;
+ } else if (type == long.class) {
+ return INVOKE_LONG_SETTER;
+ } else if (type == double.class) {
+ return INVOKE_NUMBER_SETTER;
+ } else {
+ assert type == Object.class;
+ return INVOKE_OBJECT_SETTER;
+ }
}
@Override
@@ -282,31 +280,81 @@ public final class UserAccessorProperty extends SpillProperty {
// getter/setter may be inherited. If so, proto is bound during lookup. In either
// inherited or self case, slot is also bound during lookup. Actual ScriptFunction
// to be called is retrieved everytime and applied.
- private static Object invokeGetterAccessor(final Accessors gs, final Object self) {
+ @SuppressWarnings("unused")
+ private static Object invokeObjectGetter(final Accessors gs, final MethodHandle invoker, final Object self) throws Throwable {
final Object func = gs.getter;
if (func instanceof ScriptFunction) {
- try {
- return getINVOKE_UA_GETTER().invokeExact(func, self);
- } catch (final Error | RuntimeException t) {
- throw t;
- } catch (final Throwable t) {
- throw new RuntimeException(t);
- }
+ return invoker.invokeExact(func, self);
}
return UNDEFINED;
}
- private static void invokeSetterAccessor(final Accessors gs, final String name, final Object self, final Object value) {
+ @SuppressWarnings("unused")
+ private static int invokeIntGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable {
+ final Object func = gs.getter;
+ if (func instanceof ScriptFunction) {
+ return (int) invoker.invokeExact(func, self);
+ }
+
+ throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
+ }
+
+ @SuppressWarnings("unused")
+ private static long invokeLongGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable {
+ final Object func = gs.getter;
+ if (func instanceof ScriptFunction) {
+ return (long) invoker.invokeExact(func, self);
+ }
+
+ throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
+ }
+
+ @SuppressWarnings("unused")
+ private static double invokeNumberGetter(final Accessors gs, final MethodHandle invoker, final int programPoint, final Object self) throws Throwable {
+ final Object func = gs.getter;
+ if (func instanceof ScriptFunction) {
+ return (double) invoker.invokeExact(func, self);
+ }
+
+ throw new UnwarrantedOptimismException(UNDEFINED, programPoint);
+ }
+
+ @SuppressWarnings("unused")
+ private static void invokeObjectSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final Object value) throws Throwable {
+ final Object func = gs.setter;
+ if (func instanceof ScriptFunction) {
+ invoker.invokeExact(func, self, value);
+ } else if (name != null) {
+ throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static void invokeIntSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final int value) throws Throwable {
+ final Object func = gs.setter;
+ if (func instanceof ScriptFunction) {
+ invoker.invokeExact(func, self, value);
+ } else if (name != null) {
+ throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static void invokeLongSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final long value) throws Throwable {
+ final Object func = gs.setter;
+ if (func instanceof ScriptFunction) {
+ invoker.invokeExact(func, self, value);
+ } else if (name != null) {
+ throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static void invokeNumberSetter(final Accessors gs, final MethodHandle invoker, final String name, final Object self, final double value) throws Throwable {
final Object func = gs.setter;
if (func instanceof ScriptFunction) {
- try {
- getINVOKE_UA_SETTER().invokeExact(func, self, value);
- } catch (final Error | RuntimeException t) {
- throw t;
- } catch (final Throwable t) {
- throw new RuntimeException(t);
- }
+ invoker.invokeExact(func, self, value);
} else if (name != null) {
throw typeError("property.has.no.setter", name, ScriptRuntime.safeToString(self));
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/AnyElements.java b/src/jdk/nashorn/internal/runtime/arrays/AnyElements.java
new file mode 100644
index 00000000..d9e01923
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/arrays/AnyElements.java
@@ -0,0 +1,38 @@
+/*
+ * 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. 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.
+ */
+package jdk.nashorn.internal.runtime.arrays;
+
+/**
+ * Marker interface for any ContinuousArray with any elements
+ * Used for type checks that throw ClassCastExceptions and force relinks
+ * for fast NativeArray specializations of builtin methods
+ */
+public interface AnyElements {
+ /**
+ * Return a numeric weight of the element type - wider is higher
+ * @return element type weight
+ */
+ public int getElementWeight();
+} \ No newline at end of file
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
index 9e606ee6..dc41c4d9 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
@@ -28,6 +28,7 @@ package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -37,6 +38,7 @@ import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
/**
@@ -49,10 +51,180 @@ public abstract class ArrayData {
/** Mask for getting a chunk */
protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
+ /** Untouched data - still link callsites as IntArrayData, but expands to
+ * a proper ArrayData when we try to write to it */
+ public static final ArrayData EMPTY_ARRAY = new UntouchedArrayData();
+
/**
* Immutable empty array to get ScriptObjects started.
+ * Use the same array and convert it to mutable as soon as it is modified
*/
- public static final ArrayData EMPTY_ARRAY = new NoTypeArrayData();
+ private static class UntouchedArrayData extends ContinuousArrayData {
+ private UntouchedArrayData() {
+ this(0);
+ }
+
+ private UntouchedArrayData(final int length) {
+ super(length);
+ }
+
+ private ArrayData toRealArrayData() {
+ return toRealArrayData(0);
+ }
+
+ private ArrayData toRealArrayData(final int index) {
+ final IntArrayData newData = new IntArrayData(index + 1);
+ if (index == 0) {
+ return newData;
+ }
+ return new DeletedRangeArrayFilter(newData, 0, index);
+ }
+
+ @Override
+ public ContinuousArrayData copy() {
+ return new UntouchedArrayData((int)length);
+ }
+
+ @Override
+ public Object asArrayOfType(final Class<?> componentType) {
+ return Array.newInstance(componentType, 0);
+ }
+
+ @Override
+ public Object[] asObjectArray() {
+ return ScriptRuntime.EMPTY_ARRAY;
+ }
+
+ @Override
+ public ArrayData ensure(final long safeIndex) {
+ if (safeIndex > 0L) {
+ return toRealArrayData((int)safeIndex).ensure(safeIndex);
+ }
+ return this;
+ }
+
+ @Override
+ public ArrayData convert(final Class<?> type) {
+ return toRealArrayData(0).convert(type);
+ }
+
+ @Override
+ public void shiftLeft(final int by) {
+ //nop, always empty or we wouldn't be of this class
+ }
+
+ @Override
+ public ArrayData shiftRight(final int by) {
+ return this; //always empty or we wouldn't be of this class
+ }
+
+ @Override
+ public ArrayData shrink(final long newLength) {
+ return this;
+ }
+
+ @Override
+ public ArrayData set(final int index, final Object value, final boolean strict) {
+ return toRealArrayData(index).set(index, value, strict);
+ }
+
+ @Override
+ public ArrayData set(final int index, final int value, final boolean strict) {
+ return toRealArrayData(index).set(index, value, strict);
+ }
+
+ @Override
+ public ArrayData set(final int index, final long value, final boolean strict) {
+ return toRealArrayData(index).set(index, value, strict);
+ }
+
+ @Override
+ public ArrayData set(final int index, final double value, final boolean strict) {
+ return toRealArrayData(index).set(index, value, strict);
+ }
+
+ @Override
+ public int getInt(final int index) {
+ throw new ArrayIndexOutOfBoundsException(index); //empty
+ }
+
+ @Override
+ public long getLong(final int index) {
+ throw new ArrayIndexOutOfBoundsException(index); //empty
+ }
+
+ @Override
+ public double getDouble(final int index) {
+ throw new ArrayIndexOutOfBoundsException(index); //empty
+ }
+
+ @Override
+ public Object getObject(final int index) {
+ throw new ArrayIndexOutOfBoundsException(index); //empty
+ }
+
+ @Override
+ public boolean has(final int index) {
+ 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;
+ }
+
+ @Override
+ public ArrayData push(final boolean strict, final Object item) {
+ return toRealArrayData().push(strict, item);
+ }
+
+ @Override
+ public ArrayData slice(final long from, final long to) {
+ return this; //empty
+ }
+
+ @Override
+ public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+ return otherData.copy();
+ }
+
+ //no need to override fastPopInt, as the default behavior is to throw classcast exception so we
+ //can relink and return an undefined, this is the IntArrayData default behavior
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+ return null;
+ }
+
+ @Override
+ public MethodHandle getElementSetter(final Class<?> elementType) {
+ return null;
+ }
+
+ @Override
+ public Class<?> getElementType() {
+ return int.class;
+ }
+
+ @Override
+ public Class<?> getBoxedElementType() {
+ return Integer.class;
+ }
+ };
/**
* Length of the array data. Not necessarily length of the wrapped array.
@@ -77,7 +249,7 @@ public abstract class ArrayData {
* Factory method for unspecified array - start as int
* @return ArrayData
*/
- public static ArrayData initialArray() {
+ public final static ArrayData initialArray() {
return new IntArrayData();
}
@@ -92,24 +264,13 @@ public abstract class ArrayData {
throw new UnwarrantedOptimismException(data.getObject(index), programPoint);
}
- private static int alignUp(final int size) {
- return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
- }
-
- /**
- * Generic invalidation hook for script object to have call sites to this array indexing
- * relinked, e.g. when a native array is marked as non extensible
- */
- public void invalidateGetters() {
- //subclass responsibility
- }
-
/**
- * Generic invalidation hook for script object to have call sites to this array indexing
- * relinked, e.g. when a native array is marked as non extensible
+ * Align an array size up to the nearest array chunk size
+ * @param size size required
+ * @return size given, always >= size
*/
- public void invalidateSetters() {
- //subclass responsibility
+ protected final static int alignUp(final int size) {
+ return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
}
/**
@@ -118,7 +279,7 @@ public abstract class ArrayData {
* @param length the initial length
* @return ArrayData
*/
- public static ArrayData allocate(final int length) {
+ public static final ArrayData allocate(final int length) {
if (length == 0) {
return new IntArrayData();
} else if (length >= SparseArrayData.MAX_DENSE_LENGTH) {
@@ -134,7 +295,7 @@ public abstract class ArrayData {
* @param array the array
* @return ArrayData wrapping this array
*/
- public static ArrayData allocate(final Object array) {
+ public static final ArrayData allocate(final Object array) {
final Class<?> clazz = array.getClass();
if (clazz == int[].class) {
@@ -154,7 +315,7 @@ public abstract class ArrayData {
* @param array the array to use for initial elements
* @return the ArrayData
*/
- public static ArrayData allocate(final int[] array) {
+ public static final ArrayData allocate(final int[] array) {
return new IntArrayData(array, array.length);
}
@@ -164,7 +325,7 @@ public abstract class ArrayData {
* @param array the array to use for initial elements
* @return the ArrayData
*/
- public static ArrayData allocate(final long[] array) {
+ public static final ArrayData allocate(final long[] array) {
return new LongArrayData(array, array.length);
}
@@ -174,7 +335,7 @@ public abstract class ArrayData {
* @param array the array to use for initial elements
* @return the ArrayData
*/
- public static ArrayData allocate(final double[] array) {
+ public static final ArrayData allocate(final double[] array) {
return new NumberArrayData(array, array.length);
}
@@ -184,7 +345,7 @@ public abstract class ArrayData {
* @param array the array to use for initial elements
* @return the ArrayData
*/
- public static ArrayData allocate(final Object[] array) {
+ public static final ArrayData allocate(final Object[] array) {
return new ObjectArrayData(array, array.length);
}
@@ -194,7 +355,7 @@ public abstract class ArrayData {
* @param buf the nio ByteBuffer to wrap
* @return the ArrayData
*/
- public static ArrayData allocate(final ByteBuffer buf) {
+ public static final ArrayData allocate(final ByteBuffer buf) {
return new ByteBufferArrayData(buf);
}
@@ -204,7 +365,7 @@ public abstract class ArrayData {
* @param underlying the underlying ArrayData to wrap in the freeze filter
* @return the frozen ArrayData
*/
- public static ArrayData freeze(final ArrayData underlying) {
+ public static final ArrayData freeze(final ArrayData underlying) {
return new FrozenArrayFilter(underlying);
}
@@ -214,11 +375,21 @@ public abstract class ArrayData {
* @param underlying the underlying ArrayData to wrap in the seal filter
* @return the sealed ArrayData
*/
- public static ArrayData seal(final ArrayData underlying) {
+ public static final ArrayData seal(final ArrayData underlying) {
return new SealedArrayFilter(underlying);
}
/**
+ * Prevent this array from being extended
+ *
+ * @param underlying the underlying ArrayData to wrap in the non extensible filter
+ * @return new array data, filtered
+ */
+ public static final ArrayData preventExtension(final ArrayData underlying) {
+ return new NonExtensibleArrayFilter(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
* other JavaScript Property
@@ -728,5 +899,4 @@ public abstract class ArrayData {
public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
return null;
}
-
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java
index 5c857e11..f979aaa9 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayIndex.java
@@ -182,15 +182,15 @@ public final class ArrayIndex {
}
/**
- * Convert an index to a long value. This basically amounts to ANDing it
- * with {@link JSType#MAX_UINT}, as the maximum array index in JavaScript
+ * Convert an index to a long value. This basically amounts to converting it into a
+ * {@link JSType#toUint32(int)} uint32} as the maximum array index in JavaScript
* is 0xfffffffe
*
* @param index index to convert to long form
* @return index as uint32 in a long
*/
public static long toLongIndex(final int index) {
- return index & JSType.MAX_UINT;
+ return JSType.toUint32(index);
}
/**
@@ -201,7 +201,7 @@ public final class ArrayIndex {
* @return index as string
*/
public static String toKey(final int index) {
- return Long.toString(index & JSType.MAX_UINT);
+ return Long.toString(JSType.toUint32(index));
}
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
index 8724d64a..56840da9 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
@@ -1,5 +1,4 @@
/*
- * Copyright (c) 2010, 2013, 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
@@ -30,7 +29,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -50,9 +48,6 @@ import jdk.nashorn.internal.runtime.logging.Logger;
*/
@Logger(name="arrays")
public abstract class ContinuousArrayData extends ArrayData {
-
- private SwitchPoint sp;
-
/**
* Constructor
* @param length length (elementLength)
@@ -61,18 +56,6 @@ public abstract class ContinuousArrayData extends ArrayData {
super(length);
}
- private SwitchPoint ensureSwitchPointExists() {
- if (sp == null){
- sp = new SwitchPoint();
- }
- return sp;
- }
-
- @Override
- public void invalidateSetters() {
- SwitchPoint.invalidateAll(new SwitchPoint[] { ensureSwitchPointExists() });
- }
-
/**
* Check if we can put one more element at the end of this continous
* array without reallocating, or if we are overwriting an already
@@ -86,6 +69,14 @@ public abstract class ContinuousArrayData extends ArrayData {
}
/**
+ * Check if an arraydata is empty
+ * @return true if empty
+ */
+ public boolean isEmpty() {
+ return length == 0L;
+ }
+
+ /**
* Return element getter for a certain type at a certain program point
* @param returnType return type
* @param programPoint program point
@@ -109,13 +100,16 @@ public abstract class ContinuousArrayData extends ArrayData {
* @param index index to check - currently only int indexes
* @return index
*/
- protected int throwHas(final int index) {
+ protected final int throwHas(final int index) {
if (!has(index)) {
throw new ClassCastException();
}
return index;
}
+ @Override
+ public abstract ContinuousArrayData copy();
+
/**
* Returns the type used to store an element in this array
* @return element type
@@ -128,6 +122,25 @@ public abstract class ContinuousArrayData extends ArrayData {
}
/**
+ * Returns the boxed type of the type used to store an element in this array
+ * @return element type
+ */
+ public abstract Class<?> getBoxedElementType();
+
+ /**
+ * Get the widest element type of two arrays. This can be done faster in subclasses, but
+ * this works for all ContinuousArrayDatas and for where more optimal checks haven't been
+ * implemented.
+ *
+ * @param otherData another ContinuousArrayData
+ * @return the widest boxed element type
+ */
+ public ContinuousArrayData widest(final ContinuousArrayData otherData) {
+ final Class<?> elementType = getElementType();
+ return Type.widest(elementType, otherData.getElementType()) == elementType ? this : otherData;
+ }
+
+ /**
* Look up a continuous array element getter
* @param get getter, sometimes combined with a has check that throws CCE on failure for relink
* @param returnType return type
@@ -256,12 +269,7 @@ public abstract class ContinuousArrayData extends ArrayData {
final Object[] args = request.getArguments();
final int index = (int)args[args.length - 2];
- //sp may be invalidated by e.g. preventExtensions before the first setter is linked
- //then it is already created. otherwise, create it here to guard against future
- //invalidations
- ensureSwitchPointExists();
-
- if (!sp.hasBeenInvalidated() && hasRoomFor(index)) {
+ if (hasRoomFor(index)) {
MethodHandle setElement = getElementSetter(elementType); //Z(continuousarraydata, int, int), return true if successful
if (setElement != null) {
//else we are dealing with a wider type than supported by this callsite
@@ -269,7 +277,7 @@ public abstract class ContinuousArrayData extends ArrayData {
getArray = MH.asType(getArray, getArray.type().changeReturnType(getClass()));
setElement = MH.filterArguments(setElement, 0, getArray);
final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz);
- return new GuardedInvocation(setElement, guard, sp, ClassCastException.class); //CCE if not a scriptObject anymore
+ return new GuardedInvocation(setElement, guard, (SwitchPoint)null, ClassCastException.class); //CCE if not a scriptObject anymore
}
}
}
@@ -344,4 +352,13 @@ public abstract class ContinuousArrayData extends ArrayData {
public Object fastPopObject() {
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
}
+
+ /**
+ * Specialization - fast concat implementation
+ * @param otherData data to concat
+ * @return new arraydata
+ */
+ public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+ throw new ClassCastException(String.valueOf(getClass()) + " != " + String.valueOf(otherData.getClass()));
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
index 0792b6b6..b74b6419 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
@@ -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;
@@ -57,17 +56,32 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
* @param array an int array
* @param length a length, not necessarily array.length
*/
- IntArrayData(final int array[], final int length) {
+ IntArrayData(final int[] array, final int length) {
super(length);
- assert array.length >= length;
+ assert array == null || array.length >= length;
this.array = array;
}
@Override
- public Class<?> getElementType() {
+ public final Class<?> getElementType() {
return int.class;
}
+ @Override
+ public final Class<?> getBoxedElementType() {
+ return Integer.class;
+ }
+
+ @Override
+ public final int getElementWeight() {
+ return 1;
+ }
+
+ @Override
+ public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+ return otherData;
+ }
+
private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle();
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
@@ -104,7 +118,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
}
@Override
- public ArrayData copy() {
+ public IntArrayData copy() {
return new IntArrayData(array.clone(), (int)length);
}
@@ -165,8 +179,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
public ArrayData convert(final Class<?> type) {
if (type == Integer.class) {
return this;
- }
- if (type == Long.class) {
+ } else if (type == Long.class) {
return convertToLong();
} else if (type == Double.class) {
return convertToDouble();
@@ -209,8 +222,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public ArrayData shrink(final long newLength) {
- Arrays.fill(array, (int) newLength, array.length, 0);
-
+ Arrays.fill(array, (int)newLength, array.length, 0);
return this;
}
@@ -322,10 +334,7 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
@Override
public ArrayData slice(final long from, final long to) {
- final long start = from < 0 ? from + length : from;
- final long newLength = to - start;
-
- return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
+ return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)(to - (from < 0 ? from + length : from)));
}
@Override
@@ -347,7 +356,13 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
throw new UnsupportedOperationException();
}
final ArrayData returnValue = removed == 0 ?
- EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
+ EMPTY_ARRAY :
+ new IntArrayData(
+ Arrays.copyOfRange(
+ array,
+ start,
+ start + removed),
+ removed);
if (newLength != oldLength) {
final int[] newArray;
@@ -403,4 +418,26 @@ final class IntArrayData extends ContinuousArrayData implements IntElements {
public Object fastPopObject() {
return fastPopInt();
}
+
+ @Override
+ public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+ final int otherLength = (int)otherData.length;
+ final int thisLength = (int)length;
+ assert otherLength > 0 && thisLength > 0;
+
+ final int[] otherArray = ((IntArrayData)otherData).array;
+ final int newLength = otherLength + thisLength;
+ final int[] newArray = new int[ArrayData.alignUp(newLength)];
+
+ System.arraycopy(array, 0, newArray, 0, thisLength);
+ System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+ return new IntArrayData(newArray, newLength);
+ }
+
+ @Override
+ public String toString() {
+ assert length <= array.length : length + " > " + array.length;
+ return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
index f41ee15a..cbe507b8 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
@@ -52,16 +52,31 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
LongArrayData(final long array[], final int length) {
super(length);
assert array.length >= length;
- this.array = array;
+ this.array = array;
}
@Override
- public Class<?> getElementType() {
+ public final Class<?> getElementType() {
return long.class;
}
@Override
- public ArrayData copy() {
+ public final Class<?> getBoxedElementType() {
+ return Long.class;
+ }
+
+ @Override
+ public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+ return otherData instanceof IntElements ? this : otherData;
+ }
+
+ @Override
+ public final int getElementWeight() {
+ return 2;
+ }
+
+ @Override
+ public LongArrayData copy() {
return new LongArrayData(array.clone(), (int)length);
}
@@ -101,7 +116,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
}
@Override
- public ArrayData convert(final Class<?> type) {
+ public ContinuousArrayData convert(final Class<?> type) {
if (type == Integer.class || type == Long.class) {
return this;
}
@@ -145,8 +160,7 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
@Override
public ArrayData shrink(final long newLength) {
- Arrays.fill(array, (int) newLength, array.length, 0);
-
+ Arrays.fill(array, (int)newLength, array.length, 0L);
return this;
}
@@ -359,4 +373,37 @@ final class LongArrayData extends ContinuousArrayData implements IntOrLongElemen
public Object fastPopObject() {
return fastPopLong();
}
+
+ @Override
+ public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+ final int otherLength = (int)otherData.length;
+ final int thisLength = (int)length;
+ assert otherLength > 0 && thisLength > 0;
+
+ final long[] otherArray = ((LongArrayData)otherData).array;
+ final int newLength = otherLength + thisLength;
+ final long[] newArray = new long[ArrayData.alignUp(newLength)];
+
+ System.arraycopy(array, 0, newArray, 0, thisLength);
+ System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+ return new LongArrayData(newArray, newLength);
+ }
+
+ @Override
+ public String toString() {
+ assert length <= array.length : length + " > " + array.length;
+
+ final StringBuilder sb = new StringBuilder(getClass().getSimpleName()).
+ append(": [");
+ for (int i = 0; i < length; i++) {
+ sb.append(array[i]).append('L'); //make sure L suffix is on elements, to discriminate this from IntArrayData.toString()
+ if (i + 1 < length) {
+ sb.append(", ");
+ }
+ }
+ sb.append(']');
+
+ return sb.toString();
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java
deleted file mode 100644
index 143cd221..00000000
--- a/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, 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.
- */
-
-package jdk.nashorn.internal.runtime.arrays;
-
-import java.lang.reflect.Array;
-import jdk.nashorn.internal.runtime.ScriptRuntime;
-
-/**
- * Place holding array data for non-array objects. Activates a true array when
- * accessed. Should only exist as a singleton defined in ArrayData.
- */
-final class NoTypeArrayData extends ArrayData {
- NoTypeArrayData() {
- super(0);
- }
-
- NoTypeArrayData(final long length) {
- super(length);
- }
-
- @Override
- public Object[] asObjectArray() {
- return ScriptRuntime.EMPTY_ARRAY;
- }
-
- @Override
- public ArrayData copy() {
- return new NoTypeArrayData();
- }
-
- @Override
- public Object asArrayOfType(final Class<?> componentType) {
- return Array.newInstance(componentType, 0);
- }
-
- @Override
- public ArrayData convert(final Class<?> type) {
- final long len = length;
- final ArrayData arrayData;
- if (type == Long.class) {
- arrayData = new LongArrayData(new long[ArrayData.nextSize((int)len)], (int)len);
- } else if (type == Double.class) {
- arrayData = new NumberArrayData(new double[ArrayData.nextSize((int)len)], (int)len);
- } else if (type == Integer.class) {
- arrayData = new IntArrayData(new int[ArrayData.nextSize((int)len)], (int)len);
- } else {
- assert !type.isPrimitive();
- arrayData = new ObjectArrayData(new Object[ArrayData.nextSize((int)len)], (int)len);
- }
- return length == 0 ? arrayData : new DeletedRangeArrayFilter(arrayData, 0, len - 1);
- }
-
- @Override
- public void shiftLeft(final int by) {
- //empty
- }
-
- @Override
- public ArrayData shiftRight(final int by) {
- return this;
- }
-
- @Override
- public ArrayData ensure(final long safeIndex) {
- if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
- return new SparseArrayData(this, safeIndex + 1);
- }
-
- // Don't trample the shared EMPTY_ARRAY.
- if (length == 0) {
- return new NoTypeArrayData(Math.max(safeIndex + 1, length));
- }
-
- setLength(Math.max(safeIndex + 1, length));
- return this;
- }
-
- @Override
- public ArrayData shrink(final long newLength) {
- return this;
- }
-
- @Override
- public ArrayData set(final int index, final Object value, final boolean strict) {
- ArrayData newData;
-
- if (value instanceof Double) {
- newData = convert(Double.class);
- } else if (value instanceof Long) {
- newData = convert(Long.class);
- } else if (value instanceof Integer) {
- newData = convert(Integer.class);
- } else {
- assert !(value instanceof Number);
- newData = convert(value == null ? Object.class : value.getClass());
- }
-
- return newData.set(index, value, strict);
- }
-
- @Override
- public ArrayData set(final int index, final int value, final boolean strict) {
- final ArrayData newData = convert(Integer.class);
- return newData.set(index, value, strict);
- }
-
- @Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- final ArrayData newData = convert(Long.class);
- return newData.set(index, value, strict);
- }
-
- @Override
- public ArrayData set(final int index, final double value, final boolean strict) {
- final ArrayData newData = convert(Double.class);
- return newData.set(index, value, strict);
- }
-
- @Override
- public int getInt(final int index) {
- throw new ArrayIndexOutOfBoundsException(index);
- }
-
- @Override
- public long getLong(final int index) {
- throw new ArrayIndexOutOfBoundsException(index);
- }
-
- @Override
- public double getDouble(final int index) {
- throw new ArrayIndexOutOfBoundsException(index);
- }
-
- @Override
- public Object getObject(final int index) {
- throw new ArrayIndexOutOfBoundsException(index);
- }
-
- @Override
- public boolean has(final int index) {
- return false;
- }
-
- @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;
- }
-
- @Override
- public ArrayData slice(final long from, final long to) {
- return this;
- }
-}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java
new file mode 100644
index 00000000..bb73b89f
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/arrays/NonExtensibleArrayFilter.java
@@ -0,0 +1,68 @@
+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.ScriptRuntime;
+
+/**
+ * Filter class that wrap arrays that have been tagged non extensible
+ */
+public class NonExtensibleArrayFilter extends ArrayFilter {
+
+ /**
+ * Constructor
+ * @param underlying array
+ */
+ public NonExtensibleArrayFilter(final ArrayData underlying) {
+ super(underlying);
+ }
+
+ @Override
+ public ArrayData copy() {
+ return new NonExtensibleArrayFilter(underlying.copy());
+ }
+
+ @Override
+ public ArrayData slice(final long from, final long to) {
+ return new NonExtensibleArrayFilter(underlying.slice(from, to));
+ }
+
+ private ArrayData extensionCheck(final boolean strict, final int index) {
+ if (!strict) {
+ return this;
+ }
+ throw typeError(Global.instance(), "object.non.extensible", String.valueOf(index), ScriptRuntime.safeToString(this));
+ }
+
+ @Override
+ public ArrayData set(final int index, final Object value, final boolean strict) {
+ if (has(index)) {
+ return underlying.set(index, value, strict);
+ }
+ return extensionCheck(strict, index);
+ }
+
+ @Override
+ public ArrayData set(final int index, final int value, final boolean strict) {
+ if (has(index)) {
+ return underlying.set(index, value, strict);
+ }
+ return extensionCheck(strict, index);
+ }
+
+ @Override
+ public ArrayData set(final int index, final long value, final boolean strict) {
+ if (has(index)) {
+ return underlying.set(index, value, strict);
+ }
+ return extensionCheck(strict, index);
+ }
+
+ @Override
+ public ArrayData set(final int index, final double value, final boolean strict) {
+ if (has(index)) {
+ return underlying.set(index, value, strict);
+ }
+ return extensionCheck(strict, index);
+ }
+}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
index 2c57208f..f43c25af 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
@@ -48,19 +48,34 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
* @param array an int array
* @param length a length, not necessarily array.length
*/
- NumberArrayData(final double array[], final int length) {
+ NumberArrayData(final double[] array, final int length) {
super(length);
assert array.length >= length;
- this.array = array;
+ this.array = array;
}
@Override
- public Class<?> getElementType() {
+ public final Class<?> getElementType() {
return double.class;
}
@Override
- public ArrayData copy() {
+ public final Class<?> getBoxedElementType() {
+ return Double.class;
+ }
+
+ @Override
+ public final int getElementWeight() {
+ return 3;
+ }
+
+ @Override
+ public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+ return otherData instanceof IntOrLongElements ? this : otherData;
+ }
+
+ @Override
+ public NumberArrayData copy() {
return new NumberArrayData(array.clone(), (int)length);
}
@@ -88,7 +103,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
}
@Override
- public ArrayData convert(final Class<?> type) {
+ public ContinuousArrayData convert(final Class<?> type) {
if (type != Double.class && type != Integer.class && type != Long.class) {
final int len = (int)length;
return new ObjectArrayData(toObjectArray(false), len);
@@ -129,7 +144,7 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
@Override
public ArrayData shrink(final long newLength) {
- Arrays.fill(array, (int) newLength, array.length, 0.0);
+ Arrays.fill(array, (int)newLength, array.length, 0.0);
return this;
}
@@ -334,4 +349,26 @@ final class NumberArrayData extends ContinuousArrayData implements NumericElemen
public Object fastPopObject() {
return fastPopDouble();
}
+
+ @Override
+ public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+ final int otherLength = (int)otherData.length;
+ final int thisLength = (int)length;
+ assert otherLength > 0 && thisLength > 0;
+
+ final double[] otherArray = ((NumberArrayData)otherData).array;
+ final int newLength = otherLength + thisLength;
+ final double[] newArray = new double[ArrayData.alignUp(newLength)];
+
+ System.arraycopy(array, 0, newArray, 0, thisLength);
+ System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+ return new NumberArrayData(newArray, newLength);
+ }
+
+ @Override
+ public String toString() {
+ assert length <= array.length : length + " > " + array.length;
+ return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java b/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java
index ad940e2a..cb87ea91 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java
@@ -30,6 +30,6 @@ package jdk.nashorn.internal.runtime.arrays;
* Used for type checks that throw ClassCastExceptions and force relinks
* for fast NativeArray specializations of builtin methods
*/
-public interface NumericElements {
+public interface NumericElements extends AnyElements {
//empty
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
index 379ba6e4..0c7f54d0 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
@@ -37,7 +37,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
* Implementation of {@link ArrayData} as soon as an Object has been
* written to the array
*/
-final class ObjectArrayData extends ContinuousArrayData {
+final class ObjectArrayData extends ContinuousArrayData implements AnyElements {
/**
* The wrapped array
@@ -49,19 +49,34 @@ final class ObjectArrayData extends ContinuousArrayData {
* @param array an int array
* @param length a length, not necessarily array.length
*/
- ObjectArrayData(final Object array[], final int length) {
+ ObjectArrayData(final Object[] array, final int length) {
super(length);
assert array.length >= length;
this.array = array;
}
@Override
- public Class<?> getElementType() {
+ public final Class<?> getElementType() {
return Object.class;
}
@Override
- public ArrayData copy() {
+ public final Class<?> getBoxedElementType() {
+ return getElementType();
+ }
+
+ @Override
+ public final int getElementWeight() {
+ return 4;
+ }
+
+ @Override
+ public final ContinuousArrayData widest(final ContinuousArrayData otherData) {
+ return otherData instanceof NumericElements ? this : otherData;
+ }
+
+ @Override
+ public ObjectArrayData copy() {
return new ObjectArrayData(array.clone(), (int)length);
}
@@ -79,7 +94,7 @@ final class ObjectArrayData extends ContinuousArrayData {
}
@Override
- public ArrayData convert(final Class<?> type) {
+ public ObjectArrayData convert(final Class<?> type) {
return this;
}
@@ -325,4 +340,26 @@ final class ObjectArrayData extends ContinuousArrayData {
return returnValue;
}
+
+ @Override
+ public ContinuousArrayData fastConcat(final ContinuousArrayData otherData) {
+ final int otherLength = (int)otherData.length;
+ final int thisLength = (int)length;
+ assert otherLength > 0 && thisLength > 0;
+
+ final Object[] otherArray = ((ObjectArrayData)otherData).array;
+ final int newLength = otherLength + thisLength;
+ final Object[] newArray = new Object[ArrayData.alignUp(newLength)];
+
+ System.arraycopy(array, 0, newArray, 0, thisLength);
+ System.arraycopy(otherArray, 0, newArray, thisLength, otherLength);
+
+ return new ObjectArrayData(newArray, newLength);
+ }
+
+ @Override
+ public String toString() {
+ assert length <= array.length : length + " > " + array.length;
+ return getClass().getSimpleName() + ':' + Arrays.toString(Arrays.copyOf(array, (int)length));
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
index 428678d0..405ff028 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
@@ -88,7 +88,7 @@ public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayDa
}
@Override
- public ArrayData copy() {
+ public TypedArrayData<T> copy() {
throw new UnsupportedOperationException();
}
@@ -133,7 +133,7 @@ public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayDa
}
@Override
- public ArrayData convert(final Class<?> type) {
+ public TypedArrayData<T> convert(final Class<?> type) {
throw new UnsupportedOperationException();
}
diff --git a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
index 67dd88e2..a0842f2d 100644
--- a/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
+++ b/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java
@@ -337,6 +337,20 @@ public final class Bootstrap {
/**
* Returns a dynamic invoker for a specified dynamic operation using the public lookup. Similar to
+ * {@link #createDynamicInvoker(String, Class, Class...)} but with an additional parameter to
+ * set the call site flags of the dynamic invoker.
+ * @param opDesc Dynalink dynamic operation descriptor.
+ * @param flags the call site flags for the operation
+ * @param rtype the return type for the operation
+ * @param ptypes the parameter types for the operation
+ * @return MethodHandle for invoking the operation.
+ */
+ public static MethodHandle createDynamicInvoker(final String opDesc, final int flags, final Class<?> rtype, final Class<?>... ptypes) {
+ return bootstrap(MethodHandles.publicLookup(), opDesc, MethodType.methodType(rtype, ptypes), flags).dynamicInvoker();
+ }
+
+ /**
+ * Returns a dynamic invoker for a specified dynamic operation using the public lookup. Similar to
* {@link #createDynamicInvoker(String, Class, Class...)} but with return and parameter types composed into a
* method type in the signature. See the discussion of that method for details.
* @param opDesc Dynalink dynamic operation descriptor.
diff --git a/test/examples/getter-setter-micro.js b/test/examples/getter-setter-micro.js
new file mode 100644
index 00000000..68ed1c30
--- /dev/null
+++ b/test/examples/getter-setter-micro.js
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * A micro-benchmark for getters and setters with primitive values,
+ * alternating between ints and doubles. Introduction of primitive
+ * and optimistic user accessors in JDK-8062401 make this faster by
+ * 10x or more by allowing inlining and other optimizations to take place.
+ */
+
+var x = {
+ get m() {
+ return this._m;
+ },
+ set m(v) {
+ this._m = v;
+ },
+ get n() {
+ return this._n;
+ },
+ set n(v) {
+ this._n = v;
+ }
+};
+
+
+function bench(v1, v2, result) {
+ var start = Date.now();
+ x.n = v1;
+ for (var i = 0; i < 1e8; i++) {
+ x.m = v2;
+ if (x.m + x.n !== result) {
+ throw "wrong result";
+ }
+ }
+ print("done in", Date.now() - start, "millis");
+}
+
+for (var i = 0; i < 10; i++) {
+ bench(i, 4, 4 + i);
+}
+
+for (var i = 0; i < 10; i++) {
+ bench(i, 4.5, 4.5 + i);
+}
+
+for (var i = 0; i < 10; i++) {
+ bench(i, 5, 5 + i);
+}
+
+for (var i = 0; i < 10; i++) {
+ bench(i, 5.5, 5.5 + i);
+}
diff --git a/test/script/basic/JDK-8061391.js b/test/script/basic/JDK-8061391.js
new file mode 100644
index 00000000..920efe3e
--- /dev/null
+++ b/test/script/basic/JDK-8061391.js
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2010, 2013, 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-8061391 - Checks that the optimistic builtin for concat is semantically
+ * correct.
+ *
+ * @test
+ * @run
+ */
+
+var maxJavaInt = 0x7fffffff;
+
+var ia = [1, 2, 3, 4];
+var la = [maxJavaInt + 1000, maxJavaInt + 2000, maxJavaInt + 3000, maxJavaInt + 4000];
+var da = [1.1, 2.2, 3.3, 4.4];
+var oa = ["one", "two", "three", "four"];
+
+var aa = [ia, la, da, oa];
+
+function concats() {
+ print("shared callsite");
+
+ print(ia);
+ print(la);
+ print(da);
+ print(oa);
+ print(aa);
+
+ for (var i = 0; i < aa.length; i++) {
+ print(aa[i].concat(aa[i][0]));
+ for (var j = 0; j < aa.length ; j++) {
+ print(aa[i].concat(aa[j]));
+ }
+ }
+}
+
+function concats_inline() {
+ print("separate callsites");
+
+ print(ia);
+ print(la);
+ print(da);
+ print(oa);
+ print(aa);
+
+ print(aa[0].concat(aa[0]));
+ print(aa[0].concat(aa[1]));
+ print(aa[0].concat(aa[2]));
+ print(aa[0].concat(aa[3]));
+ print(aa[0].concat(aa[0][0]));
+
+ print(aa[1].concat(aa[0]));
+ print(aa[1].concat(aa[1]));
+ print(aa[1].concat(aa[2]));
+ print(aa[1].concat(aa[3]));
+ print(aa[1].concat(aa[1][0]));
+
+ print(aa[2].concat(aa[0]));
+ print(aa[2].concat(aa[1]));
+ print(aa[2].concat(aa[2]));
+ print(aa[2].concat(aa[3]));
+ print(aa[2].concat(aa[2][0]));
+
+ print(aa[3].concat(aa[0]));
+ print(aa[3].concat(aa[1]));
+ print(aa[3].concat(aa[2]));
+ print(aa[3].concat(aa[3]));
+ print(aa[3].concat(aa[3][0]));
+}
+
+concats();
+concats_inline();
+
+print();
+var oldia = ia.slice(0); //clone ia
+print("oldia = " + oldia);
+ia[10] = "sparse";
+print("oldia = " + oldia);
+
+print();
+print("Redoing with sparse arrays");
+
+concats();
+concats_inline();
+
+ia = oldia;
+print("Restored ia = " + ia);
+
+function concat_expand() {
+ print("concat type expansion");
+ print(ia.concat(la));
+ print(ia.concat(da));
+ print(ia.concat(oa));
+ print(la.concat(ia));
+ print(la.concat(da));
+ print(la.concat(oa));
+ print(da.concat(ia));
+ print(da.concat(la));
+ print(da.concat(oa));
+}
+
+print();
+concat_expand();
+
+print();
+
+function concat_varargs() {
+ print("concat varargs");
+ print(ia.concat(la)); //fast
+ print(ia.concat(la, da, oa)); //slow
+ var slow = ia.concat(1, maxJavaInt * 2, 4711.17, function() { print("hello, world") }); //slow
+ print(slow);
+ return slow;
+}
+
+var slow = concat_varargs();
+
+print();
+print("sanity checks");
+slow.map(
+ function(elem) {
+ if (elem instanceof Function) {
+ elem();
+ } else {
+ print((typeof elem) + " = " + elem);
+ }
+ });
+
+print(ia.concat({key: "value"}));
+print(ia.concat({key: "value"}, {key2: "value2"}));
diff --git a/test/script/basic/JDK-8061391.js.EXPECTED b/test/script/basic/JDK-8061391.js.EXPECTED
new file mode 100644
index 00000000..9b132c3c
--- /dev/null
+++ b/test/script/basic/JDK-8061391.js.EXPECTED
@@ -0,0 +1,138 @@
+shared callsite
+1,2,3,4
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,1
+1,2,3,4,1,2,3,4
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,1.1,2.2,3.3,4.4
+1,2,3,4,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+2147484647,2147485647,2147486647,2147487647,1,2,3,4
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+1.1,2.2,3.3,4.4,1,2,3,4
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+one,two,three,four,one
+one,two,three,four,1,2,3,4
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+separate callsites
+1,2,3,4
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,1,2,3,4
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,1.1,2.2,3.3,4.4
+1,2,3,4,one,two,three,four
+1,2,3,4,1
+2147484647,2147485647,2147486647,2147487647,1,2,3,4
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+1.1,2.2,3.3,4.4,1,2,3,4
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+one,two,three,four,1,2,3,4
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+one,two,three,four,one
+
+oldia = 1,2,3,4
+oldia = 1,2,3,4
+
+Redoing with sparse arrays
+shared callsite
+1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,,,,,,,sparse,1
+1,2,3,4,,,,,,,sparse,1,2,3,4,,,,,,,sparse
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,,,,,,,sparse,1.1,2.2,3.3,4.4
+1,2,3,4,,,,,,,sparse,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+2147484647,2147485647,2147486647,2147487647,1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+1.1,2.2,3.3,4.4,1,2,3,4,,,,,,,sparse
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+one,two,three,four,one
+one,two,three,four,1,2,3,4,,,,,,,sparse
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+separate callsites
+1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4
+one,two,three,four
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,,,,,,,sparse,1,2,3,4,,,,,,,sparse
+1,2,3,4,,,,,,,sparse,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,,,,,,,sparse,1.1,2.2,3.3,4.4
+1,2,3,4,,,,,,,sparse,one,two,three,four
+1,2,3,4,,,,,,,sparse,1
+2147484647,2147485647,2147486647,2147487647,1,2,3,4,,,,,,,sparse
+2147484647,2147485647,2147486647,2147487647,2147484647,2147485647,2147486647,2147487647
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,2147484647
+1.1,2.2,3.3,4.4,1,2,3,4,,,,,,,sparse
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,1.1,2.2,3.3,4.4
+1.1,2.2,3.3,4.4,one,two,three,four
+1.1,2.2,3.3,4.4,1.1
+one,two,three,four,1,2,3,4,,,,,,,sparse
+one,two,three,four,2147484647,2147485647,2147486647,2147487647
+one,two,three,four,1.1,2.2,3.3,4.4
+one,two,three,four,one,two,three,four
+one,two,three,four,one
+Restored ia = 1,2,3,4
+
+concat type expansion
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,1.1,2.2,3.3,4.4
+1,2,3,4,one,two,three,four
+2147484647,2147485647,2147486647,2147487647,1,2,3,4
+2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4
+2147484647,2147485647,2147486647,2147487647,one,two,three,four
+1.1,2.2,3.3,4.4,1,2,3,4
+1.1,2.2,3.3,4.4,2147484647,2147485647,2147486647,2147487647
+1.1,2.2,3.3,4.4,one,two,three,four
+
+concat varargs
+1,2,3,4,2147484647,2147485647,2147486647,2147487647
+1,2,3,4,2147484647,2147485647,2147486647,2147487647,1.1,2.2,3.3,4.4,one,two,three,four
+1,2,3,4,1,4294967294,4711.17,function() { print("hello, world") }
+
+sanity checks
+number = 1
+number = 2
+number = 3
+number = 4
+number = 1
+number = 4294967294
+number = 4711.17
+hello, world
+1,2,3,4,[object Object]
+1,2,3,4,[object Object],[object Object]
diff --git a/test/script/basic/JDK-8061391_2.js b/test/script/basic/JDK-8061391_2.js
new file mode 100644
index 00000000..dff4ab02
--- /dev/null
+++ b/test/script/basic/JDK-8061391_2.js
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/**
+ * Array extension check
+ *
+ * @test
+ * @run
+ */
+
+"use strict";
+var a = [1,2,3];
+Object.preventExtensions(a);
+try {
+ a[4] = 4;
+ print(a);
+} catch (e) {
+ if (!(e instanceof TypeError)) {
+ print("TypeError expected but got e");
+ }
+}
+
+if (a[0] != 1) {
+ throw "element 0 is wrong";
+}
+if (a[1] != 2) {
+ throw "element 1 is wrong";
+}
+if (a[2] != 3) {
+ throw "element 2 is wrong";
+}
+
diff --git a/test/script/basic/JDK-8061391_3.js b/test/script/basic/JDK-8061391_3.js
new file mode 100644
index 00000000..6648ca51
--- /dev/null
+++ b/test/script/basic/JDK-8061391_3.js
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+/**
+ * Array extension check
+ *
+ * @test
+ * @run
+ */
+
+var a = [1,2,3];
+Object.preventExtensions(a);
+a[4] = 4;
+print(a);
+if (a[0] != 1) {
+ throw "element 0 is wrong";
+}
+if (a[1] != 2) {
+ throw "element 1 is wrong";
+}
+if (a[2] != 3) {
+ throw "element 2 is wrong";
+}
+
diff --git a/test/script/basic/JDK-8061391_3.js.EXPECTED b/test/script/basic/JDK-8061391_3.js.EXPECTED
new file mode 100644
index 00000000..b0246d59
--- /dev/null
+++ b/test/script/basic/JDK-8061391_3.js.EXPECTED
@@ -0,0 +1 @@
+1,2,3
diff --git a/test/script/basic/JDK-8062024.js b/test/script/basic/JDK-8062024.js
new file mode 100644
index 00000000..92085cac
--- /dev/null
+++ b/test/script/basic/JDK-8062024.js
@@ -0,0 +1,40 @@
+/*
+ * 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-8062024: Issue with date.setFullYear when time other than midnight
+ *
+ * @test
+ * @option -timezone=Asia/Calcutta
+ * @run
+ */
+
+var date1 = new Date("January 01, 1950 00:00:00");
+print("Before:", date1);
+date1.setFullYear(1960);
+print("After:", date1);
+
+var date2 = new Date("January 01, 1950 00:00:01");
+print("Before:", date2);
+date2.setFullYear(1960);
+print("After:", date2);
diff --git a/test/script/basic/JDK-8062024.js.EXPECTED b/test/script/basic/JDK-8062024.js.EXPECTED
new file mode 100644
index 00000000..ae18fd7d
--- /dev/null
+++ b/test/script/basic/JDK-8062024.js.EXPECTED
@@ -0,0 +1,4 @@
+Before: Sun Jan 01 1950 00:00:00 GMT+0530 (IST)
+After: Fri Jan 01 1960 00:00:00 GMT+0530 (IST)
+Before: Sun Jan 01 1950 00:00:01 GMT+0530 (IST)
+After: Fri Jan 01 1960 00:00:01 GMT+0530 (IST)
diff --git a/test/script/basic/JDK-8062132.js b/test/script/basic/JDK-8062132.js
new file mode 100644
index 00000000..604461df
--- /dev/null
+++ b/test/script/basic/JDK-8062132.js
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+/**
+ * 8062132: Nashorn incorrectly binds "this" for constructor created by another function
+ *
+ * @test
+ * @run
+ */
+
+function subclass(parentCtor, proto) {
+ function C() {
+ parentCtor.call(this);
+ }
+
+ C.prototype = Object.create(parentCtor.prototype);
+
+ for (var prop in proto) {
+ if (proto.hasOwnProperty(prop)) {
+ C.prototype[prop] = proto[prop];
+ }
+ }
+
+ return C;
+}
+
+var Parent = function() {
+ this.init();
+};
+
+Parent.prototype = {
+ init: null
+};
+
+var Child1 = subclass(Parent, {
+ prop1: 1,
+ init: function() {
+ print('child 1');
+ }
+});
+
+var Child2 = subclass(Parent, {
+ init: function() {
+ print('child 2');
+ }
+});
+
+var Child3 = subclass(Parent, {
+ prop1: 1,
+ init: function() {
+ print('child 3');
+ }
+});
+
+new Child1();
+new Child2();
+new Child3();
+new Child1();
+new Child2();
+new Child3();
diff --git a/test/script/basic/JDK-8062132.js.EXPECTED b/test/script/basic/JDK-8062132.js.EXPECTED
new file mode 100644
index 00000000..96df4080
--- /dev/null
+++ b/test/script/basic/JDK-8062132.js.EXPECTED
@@ -0,0 +1,6 @@
+child 1
+child 2
+child 3
+child 1
+child 2
+child 3
diff --git a/test/script/basic/JDK-8062583.js b/test/script/basic/JDK-8062583.js
new file mode 100644
index 00000000..72560b34
--- /dev/null
+++ b/test/script/basic/JDK-8062583.js
@@ -0,0 +1,51 @@
+/*
+ * 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-8062583: Throwing object with error prototype causes error proto to be caught
+ *
+ * @test
+ * @run
+ */
+
+function CustomError() {
+ this.name = "CustomError";
+}
+
+CustomError.prototype = new Error();
+
+var c1 = new CustomError();
+
+try {
+ throw c1;
+} catch (e) {
+ print(e === c1);
+ print(e === CustomError.prototype);
+ print(e.stack.replace(/\\/g, '/'));
+ print(e.nashornException.toString().replace(/\\/g, '/'));
+}
+
+var c2 = new CustomError();
+Error.captureStackTrace(c2);
+print(c2.stack.replace(/\\/g, '/'));
+print(c2.nashornException.toString().replace(/\\/g, '/'));
diff --git a/test/script/basic/JDK-8062583.js.EXPECTED b/test/script/basic/JDK-8062583.js.EXPECTED
new file mode 100644
index 00000000..75201739
--- /dev/null
+++ b/test/script/basic/JDK-8062583.js.EXPECTED
@@ -0,0 +1,8 @@
+true
+false
+CustomError
+ at <program> (test/script/basic/JDK-8062583.js:40)
+test/script/basic/JDK-8062583.js:40:4 CustomError
+CustomError
+ at <program> (test/script/basic/JDK-8062583.js:49)
+test/script/basic/JDK-8062583.js:49 CustomError