8035836: Array performance improvements
Summary: Implement typed arrays with native byte buffers and do fast linking for all continuous arrays
Reviewed-by: attila, jlaskey, sundar, hannesw
--- a/nashorn/bin/runnormal.sh Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/sh
-FILENAME="./pessimistic_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-$JAVA_HOME/bin/java -ea -Xms2G -Xmx2G -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=128 -Djava.ext.dirs=dist jdk.nashorn.tools.Shell ${@}
--- a/nashorn/bin/runnormaldual.sh Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/sh
-FILENAME="./optimistic_dual_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-$JAVA_HOME/bin/java -ea -Dnashorn.fields.dual -Xms2G -Xmx2G -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=128 -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:+UseMathExactIntrinsics ${@}
--- a/nashorn/bin/runopt.sh Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/sh
-FILENAME="./optimistic_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-$JAVA_HOME/bin/java -ea -Dnashorn.optimistic -Dnashorn.fastrewrite -Xms2G -Xmx2G -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=128 -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-UseMathExactIntrinsics -Xbootclasspath/p:dist/nashorn.jar jdk.nashorn.tools.Shell ${@}
--- a/nashorn/bin/runoptdual.sh Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-#!/bin/sh
-FILENAME="./optimistic_dual_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
-$JAVA_HOME/bin/java -ea -Dnashorn.fields.dual -Dnashorn.optimistic -Xms2G -Xmx2G -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=$FILENAME,stackdepth=128 -XX:TypeProfileLevel=222 -XX:+UnlockExperimentalVMOptions -XX:+UseTypeSpeculation -XX:-UseMathExactIntrinsics ${@}
--- a/nashorn/bin/runoptdualcatch.sh Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/bin/runoptdualcatch.sh Mon Mar 03 11:24:44 2014 +0100
@@ -2,15 +2,18 @@
#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"
-FILENAME="./optimistic_dual_catch$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
+FILENAME="./optimistic_dual_catch_$(date|sed "s/ /_/g"|sed "s/:/_/g").jfr"
+
+DIR=/Users/marcus/src/tip/
+FAST_CATCH_COMBINATOR=$DIR/bin/fastCatchCombinator.jar
+NASHORN_JAR=$DIR/dist/nashorn.jar
$JAVA_HOME/bin/java \
+$FLAGS \
-ea \
-esa \
-$FLAGS \
--Dnashorn.fastrewrite \
-Dnashorn.optimistic \
--Xbootclasspath/p:/Users/marcus/src/tip/dist/nashorn.jar \
+-Xbootclasspath/p:$FAST_CATCH_COMBINATOR:$NASHORN_JAR \
-Xms2G -Xmx2G \
-XX:+UnlockCommercialFeatures \
-XX:+FlightRecorder \
@@ -23,3 +26,8 @@
-cp $CLASSPATH:../build/test/classes/ \
jdk.nashorn.tools.Shell ${@}
+#-XX:+UnlockDiagnosticVMOptions \
+#-XX:+ShowHiddenFrames \
+#-XX:+PrintOptoAssembly \
+#-XX:-TieredCompilation \
+#-XX:CICompilerCount=1 \
--- a/nashorn/bin/verbose_octane.bat Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-rem
-rem Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
-rem DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-rem
-rem This code is free software; you can redistribute it and/or modify it
-rem under the terms of the GNU General Public License version 2 only, as
-rem published by the Free Software Foundation.
-rem
-rem This code is distributed in the hope that it will be useful, but WITHOUT
-rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-rem version 2 for more details (a copy is included in the LICENSE file that
-rem accompanied this code).
-rem
-rem You should have received a copy of the GNU General Public License version
-rem 2 along with this work; if not, write to the Free Software Foundation,
-rem Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-rem
-rem Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-rem or visit www.oracle.com if you need additional information or have any
-rem questions.
-rem
-@echo off
-
-if "%JAVA_HOME%" neq "" (
- call :run "%JAVA_HOME%/bin/java"
-) else (
- call :run java
-)
-goto :EOF
-
-:run
-setlocal
-set NASHORN_JAR=dist/nashorn.jar
-set JVM_FLAGS=-Xms2G -Xmx2G -XX:-TieredCompilation -server -esa -ea -jar %NASHORN_JAR%
-set JVM_FLAGS7=-Xbootclasspath/p:%NASHORN_JAR% %JVM_FLAGS%
-set OCTANE_ARGS=--verbose --iterations 7
-
-%1 -fullversion 2>&1 | findstr /L /C:"version ""1.7"
-if %errorlevel% equ 0 (
- set CMD=%1 %JVM_FLAGS7%
-) else (
- %1 -fullversion
- set CMD=%1 %JVM_FLAGS%
-)
-
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/box2d.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/code-load.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/crypto.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/deltablue.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/gbemu.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/navier-stokes.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/pdfjs.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/raytrace.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/regexp.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/richards.js %OCTANE_ARGS%
-%CMD% test/script/basic/run-octane.js -- test/script/external/octane/splay.js %OCTANE_ARGS%
-endlocal
-goto :EOF
--- a/nashorn/bin/verbose_octane.sh Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-#!/bin/bash
-# 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.
-#
-
-ITERS=$1
-if [ -z $ITERS ]; then
- ITERS=7
-fi
-NASHORN_JAR=dist/nashorn.jar
-JVM_FLAGS="-Djava.ext.dirs=`dirname $0`/../dist:$JAVA_HOME/jre/lib/ext -XX:+UnlockDiagnosticVMOptions -Dnashorn.unstable.relink.threshold=8 -Xms2G -Xmx2G -XX:+TieredCompilation -server -jar ${NASHORN_JAR}"
-JVM_FLAGS7="-Xbootclasspath/p:${NASHORN_JAR} ${JVM_FLAGS}"
-OCTANE_ARGS="--verbose --iterations ${ITERS}"
-
-BENCHMARKS=( "box2d.js" "code-load.js" "crypto.js" "deltablue.js" "earley-boyer.js" "gbemu.js" "navier-stokes.js" "pdfjs.js" "raytrace.js" "regexp.js" "richards.js" "splay.js" )
-# TODO mandreel.js has metaspace issues
-
-if [ ! -z $JAVA7_HOME ]; then
- echo "running ${ITERS} iterations with java7 using JAVA_HOME=${JAVA7_HOME}..."
- for BENCHMARK in "${BENCHMARKS[@]}"
- do
- CMD="${JAVA7_HOME}/bin/java ${JVM_FLAGS} test/script/basic/run-octane.js -- test/script/external/octane/${BENCHMARK} ${OCTANE_ARGS}"
- $CMD
- done
-else
- echo "no JAVA7_HOME set. skipping java7"
-fi
-
-if [ ! -z $JAVA8_HOME ]; then
- echo "running ${ITERS} iterations with java8 using JAVA_HOME=${JAVA8_HOME}..."
- for BENCHMARK in "${BENCHMARKS[@]}"
- do
- CMD="${JAVA8_HOME}/bin/java ${JVM_FLAGS} test/script/basic/run-octane.js -- test/script/external/octane/${BENCHMARK} ${OCTANE_ARGS}"
- $CMD
- done
-else
- echo "no JAVA8_HOME set."
-fi
-
-echo "Done"
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java Mon Mar 03 11:24:44 2014 +0100
@@ -248,17 +248,17 @@
if (kind == Kind.CONSTRUCTOR) {
final Type returnType = Type.getReturnType(javaDesc);
if (! returnType.toString().equals(OBJECT_DESC)) {
- error("return value should be of Object type, found" + returnType);
+ error("return value should be of Object type, found " + returnType);
}
final Type[] argTypes = Type.getArgumentTypes(javaDesc);
if (argTypes.length < 2) {
error("constructor methods should have at least 2 args");
}
if (! argTypes[0].equals(Type.BOOLEAN_TYPE)) {
- error("first argument should be of boolean type, found" + argTypes[0]);
+ error("first argument should be of boolean type, found " + argTypes[0]);
}
if (! argTypes[1].toString().equals(OBJECT_DESC)) {
- error("second argument should be of Object type, found" + argTypes[0]);
+ error("second argument should be of Object type, found " + argTypes[0]);
}
if (argTypes.length > 2) {
@@ -284,7 +284,7 @@
error("function methods should have at least 1 arg");
}
if (! argTypes[0].toString().equals(OBJECT_DESC)) {
- error("first argument should be of Object type, found" + argTypes[0]);
+ error("first argument should be of Object type, found " + argTypes[0]);
}
if (argTypes.length > 1) {
--- a/nashorn/make/build-benchmark.xml Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/make/build-benchmark.xml Mon Mar 03 11:24:44 2014 +0100
@@ -400,6 +400,8 @@
fork="true"
dir=".">
<jvmarg line="${run.test.jvmargs.octane} -Xms${run.test.xms} -Xmx${run.test.xmx}"/>
+ <arg value="-opt"/>
+ <arg value="9"/>
<arg value="${octane-test-sys-prop.test.js.framework}"/>
<arg value="${octane-tests}"/>
<arg value="--runtime"/>
--- a/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java Mon Mar 03 11:24:44 2014 +0100
@@ -88,6 +88,7 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicReference;
+
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.support.AbstractRelinkableCallSite;
import jdk.internal.dynalink.support.Lookup;
@@ -103,8 +104,27 @@
* handle is always at the start of the chain.
*/
public class ChainedCallSite extends AbstractRelinkableCallSite {
- private static final MethodHandle PRUNE = Lookup.findOwnSpecial(MethodHandles.lookup(), "prune", MethodHandle.class,
- MethodHandle.class);
+ private static final MethodHandle PRUNE_CATCHES =
+ MethodHandles.insertArguments(
+ Lookup.findOwnSpecial(
+ MethodHandles.lookup(),
+ "prune",
+ MethodHandle.class,
+ MethodHandle.class,
+ boolean.class),
+ 2,
+ true);
+
+ private static final MethodHandle PRUNE_SWITCHPOINTS =
+ MethodHandles.insertArguments(
+ Lookup.findOwnSpecial(
+ MethodHandles.lookup(),
+ "prune",
+ MethodHandle.class,
+ MethodHandle.class,
+ boolean.class),
+ 2,
+ false);
private final AtomicReference<LinkedList<GuardedInvocation>> invocations = new AtomicReference<>();
@@ -127,23 +147,25 @@
@Override
public void relink(GuardedInvocation guardedInvocation, MethodHandle fallback) {
- relinkInternal(guardedInvocation, fallback, false);
+ relinkInternal(guardedInvocation, fallback, false, false);
}
@Override
public void resetAndRelink(GuardedInvocation guardedInvocation, MethodHandle fallback) {
- relinkInternal(guardedInvocation, fallback, true);
+ relinkInternal(guardedInvocation, fallback, true, false);
}
- private MethodHandle relinkInternal(GuardedInvocation invocation, MethodHandle relink, boolean reset) {
+ private MethodHandle relinkInternal(GuardedInvocation invocation, MethodHandle relink, boolean reset, boolean removeCatches) {
final LinkedList<GuardedInvocation> currentInvocations = invocations.get();
@SuppressWarnings({ "unchecked", "rawtypes" })
final LinkedList<GuardedInvocation> newInvocations =
currentInvocations == null || reset ? new LinkedList<>() : (LinkedList)currentInvocations.clone();
- // First, prune the chain of invalidated switchpoints.
+ // First, prune the chain of invalidated switchpoints, we always do this
+ // We also remove any catches if the remove catches flag is set
for(Iterator<GuardedInvocation> it = newInvocations.iterator(); it.hasNext();) {
- if(it.next().hasBeenInvalidated()) {
+ final GuardedInvocation inv = it.next();
+ if(inv.hasBeenInvalidated() || (removeCatches && inv.getException() != null)) {
it.remove();
}
}
@@ -160,12 +182,13 @@
// prune-and-invoke is used as the fallback for invalidated switchpoints. If a switchpoint gets invalidated, we
// rebuild the chain and get rid of all invalidated switchpoints instead of letting them linger.
- final MethodHandle pruneAndInvoke = makePruneAndInvokeMethod(relink);
+ final MethodHandle pruneAndInvokeSwitchPoints = makePruneAndInvokeMethod(relink, getPruneSwitchpoints());
+ final MethodHandle pruneAndInvokeCatches = makePruneAndInvokeMethod(relink, getPruneCatches());
// Fold the new chain
MethodHandle target = relink;
for(GuardedInvocation inv: newInvocations) {
- target = inv.compose(pruneAndInvoke, target);
+ target = inv.compose(target, pruneAndInvokeSwitchPoints, pruneAndInvokeCatches);
}
// If nobody else updated the call site while we were rebuilding the chain, set the target to our chain. In case
@@ -178,14 +201,30 @@
}
/**
+ * Get the switchpoint pruning function for a chained call site
+ * @return function that removes invalidated switchpoints tied to callsite guard chain and relinks
+ */
+ protected MethodHandle getPruneSwitchpoints() {
+ return PRUNE_SWITCHPOINTS;
+ }
+
+ /**
+ * Get the catch pruning function for a chained call site
+ * @return function that removes all catches tied to callsite guard chain and relinks
+ */
+ protected MethodHandle getPruneCatches() {
+ return PRUNE_CATCHES;
+ }
+
+ /**
* Creates a method that rebuilds our call chain, pruning it of any invalidated switchpoints, and then invokes that
* chain.
* @param relink the ultimate fallback for the chain (the {@code DynamicLinker}'s relink).
* @return a method handle for prune-and-invoke
*/
- private MethodHandle makePruneAndInvokeMethod(MethodHandle relink) {
+ private MethodHandle makePruneAndInvokeMethod(MethodHandle relink, MethodHandle prune) {
// Bind prune to (this, relink)
- final MethodHandle boundPrune = MethodHandles.insertArguments(PRUNE, 0, this, relink);
+ final MethodHandle boundPrune = MethodHandles.insertArguments(prune, 0, this, relink);
// Make it ignore all incoming arguments
final MethodHandle ignoreArgsPrune = MethodHandles.dropArguments(boundPrune, 0, type().parameterList());
// Invoke prune, then invoke the call site target with original arguments
@@ -193,7 +232,7 @@
}
@SuppressWarnings("unused")
- private MethodHandle prune(MethodHandle relink) {
- return relinkInternal(null, relink, false);
+ private MethodHandle prune(MethodHandle relink, final boolean catches) {
+ return relinkInternal(null, relink, false, catches);
}
}
--- a/nashorn/src/jdk/internal/dynalink/DynamicLinker.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/DynamicLinker.java Mon Mar 03 11:24:44 2014 +0100
@@ -227,8 +227,8 @@
final boolean callSiteUnstable = unstableDetectionEnabled && relinkCount >= unstableRelinkThreshold;
final LinkRequest linkRequest =
runtimeContextArgCount == 0 ?
- new LinkRequestImpl(callSiteDescriptor, callSite, callSiteUnstable, arguments) :
- new RuntimeContextLinkRequestImpl(callSiteDescriptor, callSite, callSiteUnstable, arguments, runtimeContextArgCount);
+ new LinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments) :
+ new RuntimeContextLinkRequestImpl(callSiteDescriptor, callSite, relinkCount, callSiteUnstable, arguments, runtimeContextArgCount);
GuardedInvocation guardedInvocation = linkerServices.getGuardedInvocation(linkRequest);
--- a/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/linker/GuardedInvocation.java Mon Mar 03 11:24:44 2014 +0100
@@ -89,6 +89,7 @@
import java.lang.invoke.SwitchPoint;
import java.lang.invoke.WrongMethodTypeException;
import java.util.List;
+
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.support.CatchExceptionCombinator;
import jdk.internal.dynalink.support.Guards;
@@ -344,21 +345,44 @@
* @return a composite method handle.
*/
public MethodHandle compose(MethodHandle fallback) {
- return compose(fallback, fallback);
+ return compose(fallback, fallback, fallback);
}
/**
* Composes the invocation, switchpoint, and the guard into a composite method handle that knows how to fall back.
* @param switchpointFallback the fallback method handle in case switchpoint is invalidated.
* @param guardFallback the fallback method handle in case guard returns false.
+ * @param catchFallback the fallback method in case the exception handler triggers
* @return a composite method handle.
*/
- public MethodHandle compose(MethodHandle switchpointFallback, MethodHandle guardFallback) {
+ public MethodHandle compose(MethodHandle guardFallback, MethodHandle switchpointFallback, MethodHandle catchFallback) {
final MethodHandle guarded =
- guard == null ? invocation : MethodHandles.guardWithTest(guard, invocation, guardFallback);
- final MethodHandle catchGuarded = exception == null ? guarded : catchException(guarded, exception,
- MethodHandles.dropArguments(guardFallback, 0, exception));
- return switchPoint == null ? catchGuarded : switchPoint.guardWithTest(catchGuarded, switchpointFallback);
+ guard == null ?
+ invocation :
+ MethodHandles.guardWithTest(
+ guard,
+ invocation,
+ guardFallback);
+
+ final MethodHandle catchGuarded =
+ exception == null ?
+ guarded :
+ catchException(
+ guarded,
+ exception,
+ MethodHandles.dropArguments(
+ catchFallback,
+ 0,
+ exception));
+
+ final MethodHandle spGuarded =
+ switchPoint == null ?
+ catchGuarded :
+ switchPoint.guardWithTest(
+ catchGuarded,
+ switchpointFallback);
+
+ return spGuarded;
}
private static MethodHandle catchException(final MethodHandle target, final Class<? extends Throwable> exType, final MethodHandle handler) {
@@ -367,6 +391,7 @@
}
return MethodHandles.catchException(target, exType, handler);
}
+
private static void assertType(MethodHandle mh, MethodType type) {
if(!mh.type().equals(type)) {
throw new WrongMethodTypeException("Expected type: " + type + " actual type: " + mh.type());
--- a/nashorn/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/linker/GuardedTypeConversion.java Mon Mar 03 11:24:44 2014 +0100
@@ -83,19 +83,35 @@
package jdk.internal.dynalink.linker;
+/**
+ * Guarded type conversion
+ */
public class GuardedTypeConversion {
private final GuardedInvocation conversionInvocation;
private final boolean cacheable;
+ /**
+ * Constructor
+ * @param conversionInvocation guarded invocation for this type conversion
+ * @param cacheable is this invocation cacheable
+ */
public GuardedTypeConversion(final GuardedInvocation conversionInvocation, final boolean cacheable) {
this.conversionInvocation = conversionInvocation;
this.cacheable = cacheable;
}
+ /**
+ * Get the invocation
+ * @return invocation
+ */
public GuardedInvocation getConversionInvocation() {
return conversionInvocation;
}
+ /**
+ * Check if invocation is cacheable
+ * @return true if cachable, false otherwise
+ */
public boolean isCacheable() {
return cacheable;
}
--- a/nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/linker/LinkRequest.java Mon Mar 03 11:24:44 2014 +0100
@@ -127,6 +127,17 @@
public Object getReceiver();
/**
+ * Returns the number of times this callsite has been linked/relinked. This can be useful if you want to
+ * change e.g. exception based relinking to guard based relinking. It's probably not a good idea to keep,
+ * for example, expensive exception throwing relinkage based on failed type checks/ClassCastException in
+ * a nested callsite tree where the exception is thrown repeatedly for the common case. There it would be
+ * much more performant to use exact type guards instead.
+ *
+ * @return link count for call site
+ */
+ public int getLinkCount();
+
+ /**
* Returns true if the call site is considered unstable, that is, it has been relinked more times than was
* specified in {@link DynamicLinkerFactory#setUnstableRelinkThreshold(int)}. Linkers should use this as a
* hint to prefer producing linkage that is more stable (its guard fails less frequently), even if that assumption
--- a/nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/support/LinkRequestImpl.java Mon Mar 03 11:24:44 2014 +0100
@@ -98,18 +98,21 @@
private final Object callSiteToken;
private final Object[] arguments;
private final boolean callSiteUnstable;
+ private final int linkCount;
/**
* Creates a new link request.
*
* @param callSiteDescriptor the descriptor for the call site being linked
* @param callSiteToken the opaque token for the call site being linked.
+ * @param linkCount how many times this callsite has been linked/relinked
* @param callSiteUnstable true if the call site being linked is considered unstable
* @param arguments the arguments for the invocation
*/
- public LinkRequestImpl(CallSiteDescriptor callSiteDescriptor, Object callSiteToken, boolean callSiteUnstable, Object... arguments) {
+ public LinkRequestImpl(CallSiteDescriptor callSiteDescriptor, Object callSiteToken, int linkCount, boolean callSiteUnstable, Object... arguments) {
this.callSiteDescriptor = callSiteDescriptor;
this.callSiteToken = callSiteToken;
+ this.linkCount = linkCount;
this.callSiteUnstable = callSiteUnstable;
this.arguments = arguments;
}
@@ -140,12 +143,17 @@
}
@Override
+ public int getLinkCount() {
+ return linkCount;
+ }
+
+ @Override
public LinkRequest withoutRuntimeContext() {
return this;
}
@Override
public LinkRequest replaceArguments(CallSiteDescriptor newCallSiteDescriptor, Object[] newArguments) {
- return new LinkRequestImpl(newCallSiteDescriptor, callSiteToken, callSiteUnstable, newArguments);
+ return new LinkRequestImpl(newCallSiteDescriptor, callSiteToken, linkCount, callSiteUnstable, newArguments);
}
}
--- a/nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/support/RuntimeContextLinkRequestImpl.java Mon Mar 03 11:24:44 2014 +0100
@@ -103,14 +103,15 @@
* @param callSiteDescriptor the descriptor for the call site being linked
* @param callSiteToken the opaque token for the call site being linked.
* @param arguments the arguments for the invocation
+ * @param linkCount number of times callsite has been linked/relinked
* @param callSiteUnstable true if the call site being linked is considered unstable
* @param runtimeContextArgCount the number of the leading arguments on the stack that represent the language
* runtime specific context arguments.
* @throws IllegalArgumentException if runtimeContextArgCount is less than 1.
*/
public RuntimeContextLinkRequestImpl(CallSiteDescriptor callSiteDescriptor, Object callSiteToken,
- boolean callSiteUnstable, Object[] arguments, int runtimeContextArgCount) {
- super(callSiteDescriptor, callSiteToken, callSiteUnstable, arguments);
+ int linkCount, boolean callSiteUnstable, Object[] arguments, int runtimeContextArgCount) {
+ super(callSiteDescriptor, callSiteToken, linkCount, callSiteUnstable, arguments);
if(runtimeContextArgCount < 1) {
throw new IllegalArgumentException("runtimeContextArgCount < 1");
}
@@ -122,14 +123,14 @@
if(contextStrippedRequest == null) {
contextStrippedRequest =
new LinkRequestImpl(CallSiteDescriptorFactory.dropParameterTypes(getCallSiteDescriptor(), 1,
- runtimeContextArgCount + 1), getCallSiteToken(), isCallSiteUnstable(), getTruncatedArguments());
+ runtimeContextArgCount + 1), getCallSiteToken(), getLinkCount(), isCallSiteUnstable(), getTruncatedArguments());
}
return contextStrippedRequest;
}
@Override
public LinkRequest replaceArguments(CallSiteDescriptor callSiteDescriptor, Object[] arguments) {
- return new RuntimeContextLinkRequestImpl(callSiteDescriptor, getCallSiteToken(), isCallSiteUnstable(), arguments,
+ return new RuntimeContextLinkRequestImpl(callSiteDescriptor, getCallSiteToken(), getLinkCount(), isCallSiteUnstable(), arguments,
runtimeContextArgCount);
}
--- a/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java Mon Mar 03 11:24:44 2014 +0100
@@ -91,6 +91,7 @@
import java.security.PrivilegedAction;
import java.util.LinkedList;
import java.util.List;
+
import jdk.internal.dynalink.linker.ConversionComparator;
import jdk.internal.dynalink.linker.ConversionComparator.Comparison;
import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -372,6 +373,7 @@
/*private*/ static final MethodHandle IDENTITY_CONVERSION = MethodHandles.identity(Object.class);
+ @SuppressWarnings("serial")
private static class NotCacheableConverter extends RuntimeException {
final MethodHandle converter;
--- a/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CodeGenerator.java Mon Mar 03 11:24:44 2014 +0100
@@ -394,7 +394,7 @@
}
previousWasBlock = true;
} else {
- if ((node instanceof WithNode && previousWasBlock) || (node instanceof FunctionNode && CodeGeneratorLexicalContext.isFunctionDynamicScope((FunctionNode)node))) {
+ if (node instanceof WithNode && previousWasBlock || node instanceof FunctionNode && CodeGeneratorLexicalContext.isFunctionDynamicScope((FunctionNode)node)) {
// If we hit a scope that can have symbols introduced into it at run time before finding the defining
// block, the symbol can't be fast scoped. A WithNode only counts if we've immediately seen a block
// before - its block. Otherwise, we are currently processing the WithNode's expression, and that's
@@ -963,7 +963,7 @@
if (callNode.isEval()) {
evalCall(node, flags);
} else if (useCount <= SharedScopeCall.FAST_SCOPE_CALL_THRESHOLD
- || (!isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD)
+ || !isFastScope(symbol) && useCount <= SharedScopeCall.SLOW_SCOPE_CALL_THRESHOLD
|| CodeGenerator.this.lc.inDynamicScope()
|| isOptimisticOrRestOf()) {
scopeCall(node, flags);
@@ -1186,7 +1186,7 @@
* @return flags without optimism
*/
static int nonOptimisticFlags(int flags) {
- return flags & ~(CALLSITE_OPTIMISTIC | (-1 << CALLSITE_PROGRAM_POINT_SHIFT));
+ return flags & ~(CALLSITE_OPTIMISTIC | -1 << CALLSITE_PROGRAM_POINT_SHIFT);
}
@Override
@@ -1398,7 +1398,7 @@
//this symbol will be put fielded, we can't initialize it as undefined with a known type
@Override
public Class<?> getValueType() {
- return (OBJECT_FIELDS_ONLY || value == null || value.getSymbolType().isBoolean()) ? Object.class : value.getSymbolType().getTypeClass();
+ return OBJECT_FIELDS_ONLY || value == null || value.getSymbolType().isBoolean() ? Object.class : value.getSymbolType().getTypeClass();
//return OBJECT_FIELDS_ONLY ? Object.class : symbol.getSymbolType().getTypeClass();
}
});
@@ -1482,7 +1482,7 @@
}
// Nested functions are not visited when we either recompile or lazily compile, only the outermost function is.
- if (compileOutermostOnly() && (lc.getOutermostFunction() != functionNode)) {
+ if (compileOutermostOnly() && lc.getOutermostFunction() != functionNode) {
// In case we are not generating code for the function, we must create or retrieve the function object and
// load it on the stack here.
newFunctionObject(functionNode, false);
@@ -1790,7 +1790,7 @@
} else if (value instanceof String) {
final String string = (String)value;
- if (string.length() > (MethodEmitter.LARGE_STRING_THRESHOLD / 3)) { // 3 == max bytes per encoded char
+ if (string.length() > MethodEmitter.LARGE_STRING_THRESHOLD / 3) { // 3 == max bytes per encoded char
loadConstant(string);
} else {
method.load(string);
@@ -1907,7 +1907,7 @@
tuples.add(new MapTuple<Expression>(key, symbol, value) {
@Override
public Class<?> getValueType() {
- return (OBJECT_FIELDS_ONLY || value == null || value.getType().isBoolean()) ? Object.class : value.getType().getTypeClass();
+ return OBJECT_FIELDS_ONLY || value == null || value.getType().isBoolean() ? Object.class : value.getType().getTypeClass();
}
});
}
@@ -2397,7 +2397,7 @@
final Label entry = caseNode.getEntry();
// Take first duplicate.
- if (!(tree.containsKey(value))) {
+ if (!tree.containsKey(value)) {
tree.put(value, entry);
}
}
@@ -2435,7 +2435,7 @@
}
// If reasonable size and not too sparse (80%), use table otherwise use lookup.
- if (range > 0 && range < 4096 && range <= (size * 5 / 4)) {
+ if (range > 0 && range < 4096 && range <= size * 5 / 4) {
final Label[] table = new Label[range];
Arrays.fill(table, defaultLabel);
for (int i = 0; i < size; i++) {
@@ -2650,7 +2650,7 @@
if (needsScope) {
load(init);
- int flags = CALLSITE_SCOPE | getCallSiteFlags();
+ final int flags = CALLSITE_SCOPE | getCallSiteFlags();
if (isFastScope(identSymbol)) {
storeFastScopeVar(identSymbol, flags);
} else {
@@ -2984,7 +2984,7 @@
new Store<BinaryNode>(binaryNode, lhs) {
@Override
protected void evaluate() {
- if ((lhs instanceof IdentNode) && !lhs.getSymbol().isScope()) {
+ if (lhs instanceof IdentNode && !lhs.getSymbol().isScope()) {
load(rhs, lhsType);
} else {
load(rhs);
@@ -4064,10 +4064,9 @@
// There are at least as many as are declared by the current blocks.
int usedSlots = lc.getUsedSlotCount();
// Look at every load on the stack, and bump the number of used slots up by the temporaries seen there.
- for(int i = 0; i < localLoadsOnStack.length; ++i) {
- final int slot = localLoadsOnStack[i];
+ for (final int slot : localLoadsOnStack) {
if(slot != Label.Stack.NON_LOAD) {
- int afterSlot = slot + localVariableTypes.get(slot).getSlots();
+ final int afterSlot = slot + localVariableTypes.get(slot).getSlots();
if(afterSlot > usedSlots) {
usedSlots = afterSlot;
}
@@ -4085,8 +4084,8 @@
}
private static boolean everyLocalLoadIsValid(final int[] loads, int localCount) {
- for(int i = 0; i < loads.length; ++i) {
- if(loads[i] < 0 || loads[i] >= localCount) {
+ for (final int load : loads) {
+ if(load < 0 || load >= localCount) {
return false;
}
}
@@ -4106,8 +4105,8 @@
}
private static boolean everyStackValueIsLocalLoad(final int[] loads) {
- for(int i = 0; i < loads.length; ++i) {
- if(loads[i] == Label.Stack.NON_LOAD) {
+ for (final int load : loads) {
+ if(load == Label.Stack.NON_LOAD) {
return false;
}
}
@@ -4330,7 +4329,7 @@
@Override
public String toString() {
- StringBuilder b = new StringBuilder(64).append("[HandlerSpec ").append(lvarSpec);
+ final StringBuilder b = new StringBuilder(64).append("[HandlerSpec ").append(lvarSpec);
if(catchTarget) {
b.append(", catchTarget");
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilationEnvironment.java Mon Mar 03 11:24:44 2014 +0100
@@ -338,6 +338,7 @@
* @return most optimistic type in current environment
*/
Type getOptimisticType(final Optimistic node) {
+
assert useOptimisticTypes();
final Type invalidType = invalidatedProgramPoints.get(node.getProgramPoint());
if (invalidType != null) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Compiler.java Mon Mar 03 11:24:44 2014 +0100
@@ -136,11 +136,10 @@
compilationEnv.setIsStrict(true);
}
- final StringBuilder sb = new StringBuilder();
- sb.append(functionNode.uniqueName(className)).
- append('$').
- append(safeSourceName(functionNode.getSource()));
- this.scriptName = sb.toString();
+ final String name = className + '$' + safeSourceName(functionNode.getSource());
+ final String uniqueName = functionNode.uniqueName(name);
+
+ this.scriptName = uniqueName;
}
private Compiler(final CompilationEnvironment compilationEnv, final ScriptEnvironment scriptEnv, final CodeInstaller<ScriptEnvironment> installer) {
@@ -437,11 +436,11 @@
}
baseName = baseName.replace('.', '_').replace('-', '_');
- if (! scriptEnv._loader_per_compile) {
+ if (!scriptEnv._loader_per_compile) {
baseName = baseName + installer.getUniqueScriptId();
}
+
final String mangled = NameCodec.encode(baseName);
-
return mangled != null ? mangled : baseName;
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/CompilerConstants.java Mon Mar 03 11:24:44 2014 +0100
@@ -553,6 +553,48 @@
}
/**
+ * Create a special call, given an explicit lookup, looking up the method handle for it at the same time
+ *
+ * @param lookup the lookup
+ * @param thisClass this class
+ * @param clazz the class
+ * @param name the name of the method
+ * @param rtype the return type
+ * @param ptypes the parameter types
+ *
+ * @return the call object representing the virtual call
+ */
+ public static Call specialCall0(final MethodHandles.Lookup lookup, final Class<?> thisClass, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
+ return new Call(MH.findSpecial(lookup, clazz, name, MH.type(rtype, ptypes), thisClass), className(clazz), name, methodDescriptor(rtype, ptypes)) {
+ @Override
+ public MethodEmitter invoke(final MethodEmitter method) {
+ return method.invokespecial(className, name, descriptor);
+ }
+ };
+ }
+
+ /**
+ * Create a special call, given an explicit lookup, looking up the method handle for it at the same time.
+ * clazz is used as this class
+ *
+ * @param lookup the lookup
+ * @param clazz the class
+ * @param name the name of the method
+ * @param rtype the return type
+ * @param ptypes the parameter types
+ *
+ * @return the call object representing the virtual call
+ */
+ public static Call specialCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
+ return new Call(MH.findSpecial(lookup, clazz, name, MH.type(rtype, ptypes), clazz), className(clazz), name, methodDescriptor(rtype, ptypes)) {
+ @Override
+ public MethodEmitter invoke(final MethodEmitter method) {
+ return method.invokespecial(className, name, descriptor);
+ }
+ };
+ }
+
+ /**
* Returns true if the passed string looks like a method name of an internally generated Nashorn method. Basically,
* if it starts with a colon character {@code :} but is not the name of the program method {@code :program}.
* Program function is not considered internal as we want it to show up in exception stack traces.
--- a/nashorn/src/jdk/nashorn/internal/codegen/Label.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Label.java Mon Mar 03 11:24:44 2014 +0100
@@ -40,9 +40,9 @@
static final class Stack {
static final int NON_LOAD = -1;
- Type[] data = new Type[8];
+ Type[] data = new Type[8];
int[] localLoads = new int[8];
- int sp = 0;
+ int sp;
Stack() {
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/MapCreator.java Mon Mar 03 11:24:44 2014 +0100
@@ -77,8 +77,16 @@
final String key = tuple.key;
final Symbol symbol = tuple.symbol;
final Class<?> initialType = tuple.getValueType();
+
if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) {
- properties.add(new AccessorProperty(key, getPropertyFlags(symbol, hasArguments), structure, symbol.getFieldIndex(), initialType));
+ final int flags = getPropertyFlags(symbol, hasArguments);
+ final Property property = new AccessorProperty(
+ key,
+ flags,
+ structure,
+ symbol.getFieldIndex(),
+ initialType);
+ properties.add(property);
}
}
@@ -94,8 +102,14 @@
final String key = tuple.key;
final Symbol symbol = tuple.symbol;
+ //TODO initial type is object here no matter what. Is that right?
if (symbol != null && !isValidArrayIndex(getArrayIndex(key))) {
- properties.add(new SpillProperty(key, getPropertyFlags(symbol, hasArguments), spillIndex++));
+ final int flags = getPropertyFlags(symbol, hasArguments);
+ properties.add(
+ new SpillProperty(
+ key,
+ flags,
+ spillIndex++));
}
}
@@ -110,11 +124,11 @@
*
* @return flags to use for fields
*/
- protected int getPropertyFlags(final Symbol symbol, final boolean hasArguments) {
+ static int getPropertyFlags(final Symbol symbol, final boolean hasArguments) {
int flags = 0;
if (symbol.isParam()) {
- flags |= Property.IS_ALWAYS_OBJECT | Property.IS_PARAMETER;
+ flags |= Property.IS_PARAMETER;
}
if (hasArguments) {
--- a/nashorn/src/jdk/nashorn/internal/codegen/Namespace.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/Namespace.java Mon Mar 03 11:24:44 2014 +0100
@@ -80,7 +80,6 @@
if (counter != null) {
final int count = counter + 1;
namespaceDirectory.put(base, count);
-
return base + '-' + count;
}
}
--- a/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/codegen/ObjectClassGenerator.java Mon Mar 03 11:24:44 2014 +0100
@@ -215,7 +215,7 @@
* @param clazz the JavaScript scope class.
* @return the number of fields in the scope class.
*/
- public static int getFieldCount(Class<?> clazz) {
+ public static int getFieldCount(final Class<?> clazz) {
final String name = clazz.getSimpleName();
final String prefix = JS_OBJECT_PREFIX.symbolName();
if (prefix.equals(name)) {
@@ -247,13 +247,16 @@
* @param fieldNames fields to initialize to undefined, where applicable
*/
private static void initializeToUndefined(final MethodEmitter init, final String className, final List<String> fieldNames) {
+ if (!OBJECT_FIELDS_ONLY) {
+ // no need to initialize anything to undefined in the dual field world
+ // - then we have a constant getter for undefined for any unknown type
+ return;
+ }
+
if (fieldNames.isEmpty()) {
return;
}
- // always initialize fields to undefined, even with --dual-fields. Then it's ok to
- // remember things like "widest set type" in properties, and if it's object, don't
- // add any special "return undefined" getters, saving an invalidation
init.load(Type.OBJECT, JAVA_THIS.slot());
init.loadUndefined(Type.OBJECT);
@@ -565,7 +568,7 @@
final boolean isPrimitiveStorage = forType != null && forType.isPrimitive();
//which is the primordial getter
- final MethodHandle getter = OBJECT_FIELDS_ONLY ? objectGetter : (isPrimitiveStorage ? primitiveGetter : objectGetter);
+ final MethodHandle getter = OBJECT_FIELDS_ONLY ? objectGetter : isPrimitiveStorage ? primitiveGetter : objectGetter;
if (forType == null) {
if (isOptimistic) {
--- a/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/AccessNode.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,9 +25,6 @@
package jdk.nashorn.internal.ir;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -120,9 +117,6 @@
if (this.optimisticType == optimisticType) {
return this;
}
- if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), optimisticType)) {
- ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", optimisticType, " instead of ", getType());
- }
return new AccessNode(this, base, property, isFunction(), optimisticType, isOptimistic, programPoint);
}
--- a/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/FunctionNode.java Mon Mar 03 11:24:44 2014 +0100
@@ -436,7 +436,6 @@
return namespace.uniqueName(base);
}
-
@Override
public void toString(final StringBuilder sb) {
sb.append('[').
--- a/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/IdentNode.java Mon Mar 03 11:24:44 2014 +0100
@@ -147,7 +147,7 @@
* @return true if this is a property name
*/
public boolean isPropertyName() {
- return (flags & PROPERTY_NAME) != 0;
+ return (flags & PROPERTY_NAME) == PROPERTY_NAME;
}
/**
@@ -166,7 +166,7 @@
* @return true if this is a future strict name
*/
public boolean isFutureStrictName() {
- return (flags & FUTURESTRICT_NAME) != 0;
+ return (flags & FUTURESTRICT_NAME) == FUTURESTRICT_NAME;
}
/**
@@ -185,7 +185,7 @@
* @return true if IdentNode is initialized on creation
*/
public boolean isInitializedHere() {
- return (flags & INITIALIZED_HERE) != 0;
+ return (flags & INITIALIZED_HERE) == INITIALIZED_HERE;
}
/**
@@ -211,7 +211,7 @@
@Override
public boolean isFunction() {
- return (flags & FUNCTION) != 0;
+ return (flags & FUNCTION) == FUNCTION;
}
@Override
@@ -219,7 +219,7 @@
if (this.optimisticType == callSiteType) {
return this;
}
- if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), callSiteType)) {
+ if (DEBUG_FIELDS && ObjectClassGenerator.shouldInstrument(getName()) && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), callSiteType)) {
ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", callSiteType, " instead of ", getType());
}
return new IdentNode(this, name, callSiteType, flags, programPoint);
--- a/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/ir/IndexNode.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,9 +25,6 @@
package jdk.nashorn.internal.ir;
-import static jdk.nashorn.internal.codegen.ObjectClassGenerator.DEBUG_FIELDS;
-
-import jdk.nashorn.internal.codegen.ObjectClassGenerator;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -120,9 +117,6 @@
if (this.optimisticType == optimisticType) {
return this;
}
- if (DEBUG_FIELDS && getSymbol() != null && !Type.areEquivalent(getSymbol().getSymbolType(), optimisticType)) {
- ObjectClassGenerator.LOG.info(getClass().getName(), " ", this, " => ", optimisticType, " instead of ", getType());
- }
return new IndexNode(this, base, index, isFunction(), optimisticType, isOptimistic, programPoint);
}
--- a/nashorn/src/jdk/nashorn/internal/lookup/Lookup.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/lookup/Lookup.java Mon Mar 03 11:24:44 2014 +0100
@@ -129,6 +129,50 @@
}
/**
+ * This method filters primitive argument types using JavaScript semantics. For example,
+ * an (int) cast of a double in Java land is not the same thing as invoking toInt32 on it.
+ * If you are returning values to JavaScript that have to be of a specific type, this is
+ * the correct return value filter to use, as the explicitCastArguments just uses the
+ * Java boxing equivalents
+ *
+ * @param mh method handle for which to filter argument value
+ * @param n argument index
+ * @param from old argument type, the new one is given by the sent method handle
+ * @return method handle for appropriate argument type conversion
+ */
+ public static MethodHandle filterArgumentType(final MethodHandle mh, final int n, final Class<?> from) {
+ final Class<?> to = mh.type().parameterType(n);
+
+ if (from == int.class) {
+ //fallthru
+ } else if (from == long.class) {
+ //fallthru
+ } else if (from == double.class) {
+ if (to == int.class) {
+ return MH.filterArguments(mh, n, JSType.TO_INT32_D.methodHandle());
+ } else if (to == long.class) {
+ return MH.filterArguments(mh, n, JSType.TO_UINT32_D.methodHandle());
+ }
+ //fallthru
+ } else if (!from.isPrimitive()) {
+ if (to == int.class) {
+ return MH.filterArguments(mh, n, JSType.TO_INT32.methodHandle());
+ } else if (to == long.class) {
+ return MH.filterArguments(mh, n, JSType.TO_UINT32.methodHandle());
+ } else if (to == double.class) {
+ return MH.filterArguments(mh, n, JSType.TO_NUMBER.methodHandle());
+ } else if (!to.isPrimitive()) {
+ return mh;
+ }
+
+ assert false : "unsupported Lookup.filterReturnType type " + from + " -> " + to;
+ }
+
+ //use a standard cast - we don't need to check JavaScript special cases
+ return MH.explicitCastArguments(mh, mh.type().changeParameterType(2, to));
+ }
+
+ /**
* This method filters primitive return types using JavaScript semantics. For example,
* an (int) cast of a double in Java land is not the same thing as invoking toInt32 on it.
* If you are returning values to JavaScript that have to be of a specific type, this is
--- a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFactory.java Mon Mar 03 11:24:44 2014 +0100
@@ -142,7 +142,7 @@
final String str = "\treturn" +
(VOID_TAG.equals(value) ?
";" :
- (" " + stripName(value) + "; // [type=" + (value == null ? "null" : stripName(value.getClass()) + ']')));
+ " " + stripName(value) + "; // [type=" + (value == null ? "null" : stripName(value.getClass()) + ']'));
logger.log(TRACE_LEVEL, str);
logger.log(TRACE_LEVEL, Debug.firstJSFrame());
return value;
@@ -214,7 +214,7 @@
if (arg instanceof ScriptObject) {
return arg.toString() +
- " (map=" + Debug.id((((ScriptObject)arg).getMap())) +
+ " (map=" + Debug.id(((ScriptObject)arg).getMap()) +
")";
}
@@ -430,6 +430,15 @@
}
@Override
+ public MethodHandle findSpecial(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type, final Class<?> thisClass) {
+ try {
+ return explicitLookup.findSpecial(clazz, name, type, thisClass);
+ } catch (final NoSuchMethodException | IllegalAccessException e) {
+ throw new LookupException(e);
+ }
+ }
+
+ @Override
public MethodHandle findVirtual(final MethodHandles.Lookup explicitLookup, final Class<?> clazz, final String name, final MethodType type) {
try {
return explicitLookup.findVirtual(clazz, name, type);
--- a/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java Mon Mar 03 11:24:44 2014 +0100
@@ -297,6 +297,19 @@
public MethodHandle findVirtual(MethodHandles.Lookup explicitLookup, Class<?> clazz, String name, MethodType type);
/**
+ * Wrapper for {@link java.lang.invoke.MethodHandles.Lookup#findSpecial(Class, String, MethodType, Class)}
+ *
+ * @param explicitLookup explicit lookup to be used
+ * @param clazz class to look in
+ * @param name name of method
+ * @param type method type
+ * @param thisClass thisClass
+ *
+ * @return method handle for virtual method
+ */
+ public MethodHandle findSpecial(MethodHandles.Lookup explicitLookup, Class<?> clazz, String name, MethodType type, final Class<?> thisClass);
+
+ /**
* Wrapper for SwitchPoint creation. Just like {@code new SwitchPoint()} but potentially
* tracked
*
--- a/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/ArrayBufferView.java Mon Mar 03 11:24:44 2014 +0100
@@ -26,8 +26,15 @@
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.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
@@ -36,9 +43,12 @@
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
@ScriptClass("ArrayBufferView")
abstract class ArrayBufferView extends ScriptObject {
+ private final NativeArrayBuffer buffer;
+ private final int byteOffset;
// initialized by nasgen
private static PropertyMap $nasgenmap$;
@@ -49,24 +59,34 @@
private ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength, final Global global) {
super(global.getArrayBufferViewMap());
- checkConstructorArgs(buffer, byteOffset, elementLength);
- this.setProto(getPrototype(global));
- this.setArray(factory().createArrayData(buffer, byteOffset, elementLength));
+
+ final int bytesPerElement = bytesPerElement();
+
+ checkConstructorArgs(buffer.getByteLength(), bytesPerElement, byteOffset, elementLength);
+ setProto(getPrototype(global));
+
+ this.buffer = buffer;
+ this.byteOffset = byteOffset;
+
+ assert byteOffset % bytesPerElement == 0;
+ final int start = byteOffset / bytesPerElement;
+ final ByteBuffer newNioBuffer = buffer.getNioBuffer().duplicate().order(ByteOrder.nativeOrder());
+ final ArrayData data = factory().createArrayData(newNioBuffer, start, start + elementLength);
+
+ setArray(data);
}
- ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
+ protected ArrayBufferView(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
this(buffer, byteOffset, elementLength, Global.instance());
}
- private void checkConstructorArgs(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
+ private static void checkConstructorArgs(final int byteLength, final int bytesPerElement, final int byteOffset, final int elementLength) {
if (byteOffset < 0 || elementLength < 0) {
- throw new RuntimeException("byteOffset or length must not be negative");
- }
- if (byteOffset + elementLength * bytesPerElement() > buffer.getByteLength()) {
- throw new RuntimeException("byteOffset + byteLength out of range");
- }
- if (byteOffset % bytesPerElement() != 0) {
- throw new RuntimeException("byteOffset must be a multiple of the element size");
+ throw new RuntimeException("byteOffset or length must not be negative, byteOffset=" + byteOffset + ", elementLength=" + elementLength + ", bytesPerElement=" + bytesPerElement);
+ } else if (byteOffset + elementLength * bytesPerElement > byteLength) {
+ throw new RuntimeException("byteOffset + byteLength out of range, byteOffset=" + byteOffset + ", elementLength=" + elementLength + ", bytesPerElement=" + bytesPerElement);
+ } else if (byteOffset % bytesPerElement != 0) {
+ throw new RuntimeException("byteOffset must be a multiple of the element size, byteOffset=" + byteOffset + " bytesPerElement=" + bytesPerElement);
}
}
@@ -76,22 +96,22 @@
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
public static Object buffer(final Object self) {
- return ((ArrayDataImpl)((ArrayBufferView)self).getArray()).buffer;
+ return ((ArrayBufferView)self).buffer;
}
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
public static Object byteOffset(final Object self) {
- return ((ArrayDataImpl)((ArrayBufferView)self).getArray()).byteOffset;
+ return ((ArrayBufferView)self).byteOffset;
}
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
- public static Object byteLength(final Object self) {
+ public static int byteLength(final Object self) {
final ArrayBufferView view = (ArrayBufferView)self;
- return ((ArrayDataImpl)view.getArray()).elementLength * view.bytesPerElement();
+ return ((TypedArrayData<?>)view.getArray()).getElementLength() * view.bytesPerElement();
}
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
- public static Object length(final Object self) {
+ public static int length(final Object self) {
return ((ArrayBufferView)self).elementLength();
}
@@ -101,182 +121,7 @@
}
private int elementLength() {
- return ((ArrayDataImpl)getArray()).elementLength;
- }
-
- protected static abstract class ArrayDataImpl extends ArrayData {
- protected final NativeArrayBuffer buffer;
- protected final int byteOffset;
- private final int elementLength;
-
- protected ArrayDataImpl(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
- super(elementLength);
- this.buffer = buffer;
- this.byteOffset = byteOffset;
- this.elementLength = elementLength;
- }
-
- @Override
- public ArrayData copy() {
- throw new UnsupportedOperationException(); // Not used for ArrayBuffers
- }
-
- @Override
- public Object[] asObjectArray() {
- final Object[] array = new Object[elementLength];
- for (int i = 0; i < elementLength; i++) {
- array[i] = getObjectImpl(i);
- }
- return array;
- }
-
- @Override
- public ArrayData ensure(final long safeIndex) {
- return this;
- }
-
- @Override
- public void setLength(final long length) {
- //empty?
- //TODO is this right?
- }
-
- @Override
- public ArrayData shrink(final long newLength) {
- return this;
- }
-
- @Override
- public ArrayData set(final int index, final Object value, final boolean strict) {
- if (has(index)) {
- setImpl(index, value);
- }
- return this;
- }
-
- @Override
- public ArrayData set(final int index, final int value, final boolean strict) {
- if (has(index)) {
- setImpl(index, value);
- }
- return this;
- }
-
- @Override
- public ArrayData set(final int index, final long value, final boolean strict) {
- if (has(index)) {
- setImpl(index, value);
- }
- return this;
- }
-
- @Override
- public ArrayData set(final int index, final double value, final boolean strict) {
- if (has(index)) {
- setImpl(index, value);
- }
- return this;
- }
-
- @Override
- public int getInt(final int index) {
- return getIntImpl(index);
- }
-
- @Override
- public long getLong(final int index) {
- return getLongImpl(index);
- }
-
- @Override
- public double getDouble(final int index) {
- return getDoubleImpl(index);
- }
-
- @Override
- public Object getObject(final int index) {
- return getObjectImpl(index);
- }
-
- @Override
- public boolean has(final int index) {
- return index >= 0 && index < elementLength;
- }
-
- @Override
- public boolean canDelete(final int index, final boolean strict) {
- return false;
- }
-
- @Override
- public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
- return false;
- }
-
- @Override
- public ArrayData delete(final int index) {
- return this;
- }
-
- @Override
- public ArrayData delete(final long fromIndex, final long toIndex) {
- return this;
- }
-
- @Override
- protected ArrayData convert(final Class<?> type) {
- return this;
- }
-
- @Override
- public void shiftLeft(final int by) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ArrayData shiftRight(final int by) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object pop() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public ArrayData slice(final long from, final long to) {
- throw new UnsupportedOperationException();
- }
-
- protected abstract int getIntImpl(int key);
-
- protected long getLongImpl(final int key) {
- return getIntImpl(key);
- }
-
- protected double getDoubleImpl(final int key) {
- return getIntImpl(key);
- }
-
- protected Object getObjectImpl(final int key) {
- return getIntImpl(key);
- }
-
- protected abstract void setImpl(int key, int value);
-
- protected void setImpl(final int key, final long value) {
- setImpl(key, (int)value);
- }
-
- protected void setImpl(final int key, final double value) {
- setImpl(key, JSType.toInt32(value));
- }
-
- protected void setImpl(final int key, final Object value) {
- setImpl(key, JSType.toInt32(value));
- }
-
- protected abstract int byteIndex(int index);
+ return ((TypedArrayData<?>)getArray()).getElementLength();
}
protected static abstract class Factory {
@@ -284,12 +129,12 @@
final int maxElementLength;
public Factory(final int bytesPerElement) {
- this.bytesPerElement = bytesPerElement;
+ this.bytesPerElement = bytesPerElement;
this.maxElementLength = Integer.MAX_VALUE / bytesPerElement;
}
public final ArrayBufferView construct(final int elementLength) {
- if(elementLength > maxElementLength) {
+ if (elementLength > maxElementLength) {
throw rangeError("inappropriate.array.buffer.length", JSType.toString(elementLength));
}
return construct(new NativeArrayBuffer(elementLength * bytesPerElement), 0, elementLength);
@@ -297,25 +142,39 @@
public abstract ArrayBufferView construct(NativeArrayBuffer buffer, int byteOffset, int elementLength);
- public abstract ArrayData createArrayData(NativeArrayBuffer buffer, int byteOffset, int elementLength);
+ public abstract TypedArrayData<?> createArrayData(ByteBuffer nb, int start, int end);
+
+ public abstract String getClassName();
}
protected abstract Factory factory();
protected abstract ScriptObject getPrototype(final Global global);
+ @Override
+ public final String getClassName() {
+ return factory().getClassName();
+ }
+
protected boolean isFloatArray() {
return false;
}
- protected static ArrayBufferView constructorImpl(final Object[] args, final Factory factory) {
- final Object arg0 = args.length != 0 ? args[0] : 0;
- final ArrayBufferView dst;
- final int length;
+ protected static ArrayBufferView constructorImpl(final boolean newObj, final Object[] args, final Factory factory) {
+ final Object arg0 = args.length != 0 ? args[0] : 0;
+ final ArrayBufferView dest;
+ final int length;
+
+ if (!newObj) {
+ throw typeError("constructor.requires.new", factory.getClassName());
+ }
+
+
if (arg0 instanceof NativeArrayBuffer) {
// Constructor(ArrayBuffer buffer, optional unsigned long byteOffset, optional unsigned long length)
- final NativeArrayBuffer buffer = (NativeArrayBuffer) arg0;
- final int byteOffset = args.length > 1 ? JSType.toInt32(args[1]) : 0;
+ final NativeArrayBuffer buffer = (NativeArrayBuffer)arg0;
+ final int byteOffset = args.length > 1 ? JSType.toInt32(args[1]) : 0;
+
if (args.length > 2) {
length = JSType.toInt32(args[2]);
} else {
@@ -324,15 +183,16 @@
}
length = (buffer.getByteLength() - byteOffset) / factory.bytesPerElement;
}
+
return factory.construct(buffer, byteOffset, length);
} else if (arg0 instanceof ArrayBufferView) {
// Constructor(TypedArray array)
length = ((ArrayBufferView)arg0).elementLength();
- dst = factory.construct(length);
+ dest = factory.construct(length);
} else if (arg0 instanceof NativeArray) {
// Constructor(type[] array)
length = lengthToInt(((NativeArray) arg0).getArray().length());
- dst = factory.construct(length);
+ dest = factory.construct(length);
} else {
// Constructor(unsigned long length). Treating infinity as 0 is a special case for ArrayBufferView.
final double dlen = JSType.toNumber(arg0);
@@ -340,8 +200,9 @@
return factory.construct(length);
}
- copyElements(dst, length, (ScriptObject)arg0, 0);
- return dst;
+ copyElements(dest, length, (ScriptObject)arg0, 0);
+
+ return dest;
}
protected static Object setImpl(final Object self, final Object array, final Object offset0) {
@@ -357,7 +218,7 @@
throw new RuntimeException("argument is not of array type");
}
- final ScriptObject source = (ScriptObject) array;
+ final ScriptObject source = (ScriptObject)array;
final int offset = JSType.toInt32(offset0); // default=0
if (dest.elementLength() < length + offset || offset < 0) {
@@ -385,15 +246,39 @@
if (length > Integer.MAX_VALUE || length < 0) {
throw rangeError("inappropriate.array.buffer.length", JSType.toString(length));
}
- return (int) (length & Integer.MAX_VALUE);
+ return (int)(length & Integer.MAX_VALUE);
}
protected static Object subarrayImpl(final Object self, final Object begin0, final Object end0) {
- final ArrayBufferView arrayView = ((ArrayBufferView)self);
- final int elementLength = arrayView.elementLength();
- final int begin = NativeArrayBuffer.adjustIndex(JSType.toInt32(begin0), elementLength);
- final int end = NativeArrayBuffer.adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : elementLength, elementLength);
- final ArrayDataImpl arrayData = (ArrayDataImpl)arrayView.getArray();
- return arrayView.factory().construct(arrayData.buffer, arrayData.byteIndex(begin), Math.max(end - begin, 0));
+ final ArrayBufferView arrayView = ((ArrayBufferView)self);
+ final int byteOffset = arrayView.byteOffset;
+ final int bytesPerElement = arrayView.bytesPerElement();
+ final int elementLength = arrayView.elementLength();
+ final int begin = NativeArrayBuffer.adjustIndex(JSType.toInt32(begin0), elementLength);
+ final int end = NativeArrayBuffer.adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : elementLength, elementLength);
+ final int length = Math.max(end - begin, 0);
+
+ assert byteOffset % bytesPerElement == 0;
+
+ //second is byteoffset
+ return arrayView.factory().construct(arrayView.buffer, begin * bytesPerElement + byteOffset, length);
+ }
+
+ @Override
+ protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+ final GuardedInvocation inv = getArray().findFastGetIndexMethod(getArray().getClass(), desc, request);
+ if (inv != null) {
+ return inv;
+ }
+ return super.findGetIndexMethod(desc, request);
+ }
+
+ @Override
+ protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+ final GuardedInvocation inv = getArray().findFastSetIndexMethod(getArray().getClass(), desc, request);
+ if (inv != null) {
+ return inv;
+ }
+ return super.findSetIndexMethod(desc, request);
}
}
--- a/nashorn/src/jdk/nashorn/internal/objects/Global.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java Mon Mar 03 11:24:44 2014 +0100
@@ -38,7 +38,6 @@
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
@@ -472,7 +471,7 @@
* @return the global singleton
*/
public static Global instance() {
- ScriptObject global = Context.getGlobal();
+ final ScriptObject global = Context.getGlobal();
if (! (global instanceof Global)) {
throw new IllegalStateException("no current global instance");
}
@@ -705,7 +704,7 @@
private final int size;
private final ReferenceQueue<Class<?>> queue;
- ClassCache(int size) {
+ ClassCache(final int size) {
super(size, 0.75f, true);
this.size = size;
this.queue = new ReferenceQueue<>();
@@ -721,7 +720,7 @@
}
@Override
- public ClassReference get(Object key) {
+ public ClassReference get(final Object key) {
for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) {
remove(ref.source);
}
@@ -743,7 +742,7 @@
@Override
public Class<?> findCachedClass(final Source source) {
assert classCache != null : "Class cache used without being initialized";
- ClassReference ref = classCache.get(source);
+ final ClassReference ref = classCache.get(source);
return ref != null ? ref.get() : null;
}
@@ -815,7 +814,7 @@
return str;
}
final Global global = Global.instance();
- final ScriptObject scope = (self instanceof ScriptObject) ? (ScriptObject)self : global;
+ final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global;
return global.getContext().eval(scope, str.toString(), callThis, location, Boolean.TRUE.equals(strict));
}
@@ -856,7 +855,7 @@
*/
public static Object load(final Object self, final Object source) throws IOException {
final Global global = Global.instance();
- final ScriptObject scope = (self instanceof ScriptObject) ? (ScriptObject)self : global;
+ final ScriptObject scope = self instanceof ScriptObject ? (ScriptObject)self : global;
return global.getContext().load(scope, source);
}
@@ -1610,11 +1609,13 @@
* not the case
*
* @param obj and object to check
+ * @return the script object
*/
- public static void checkObject(final Object obj) {
+ public static ScriptObject checkObject(final Object obj) {
if (!(obj instanceof ScriptObject)) {
throw typeError("not.an.object", ScriptRuntime.safeToString(obj));
}
+ return (ScriptObject)obj;
}
/**
@@ -1665,7 +1666,8 @@
// initialize global function properties
this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL);
- this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT);
+ this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT,
+ new MethodHandle[] { GlobalFunctions.PARSEINT_OI, GlobalFunctions.PARSEINT_O });
this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN);
this.isFinite = ScriptFunctionImpl.makeFunction("isFinite", GlobalFunctions.IS_FINITE);
@@ -1751,13 +1753,12 @@
copyBuiltins();
// expose script (command line) arguments as "arguments" property of global
- final List<String> arguments = env.getArguments();
- final Object argsObj = wrapAsObject(arguments.toArray());
- final int flags = jdk.nashorn.internal.runtime.Property.IS_ALWAYS_OBJECT | Attribute.NOT_ENUMERABLE;
- addOwnProperty("arguments", flags, argsObj);
+ final Object argumentsObject = wrapAsObject(env.getArguments().toArray());
+ final int argumentsFlags = Attribute.NOT_ENUMERABLE;
+ addOwnProperty("arguments", argumentsFlags, argumentsObject);
if (env._scripting) {
// synonym for "arguments" in scripting mode
- addOwnProperty("$ARG", flags, argsObj);
+ addOwnProperty("$ARG", argumentsFlags, argumentsObject);
}
}
@@ -1857,7 +1858,7 @@
}
private static void copyOptions(final ScriptObject options, final ScriptEnvironment scriptEnv) {
- for (Field f : scriptEnv.getClass().getFields()) {
+ for (final Field f : scriptEnv.getClass().getFields()) {
try {
options.set(f.getName(), f.get(scriptEnv), false);
} catch (final IllegalArgumentException | IllegalAccessException exp) {
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArray.java Mon Mar 03 11:24:44 2014 +0100
@@ -29,12 +29,10 @@
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.VALUE;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
-import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator;
import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator;
import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -42,11 +40,11 @@
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
+
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.api.scripting.JSObject;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -54,8 +52,10 @@
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Setter;
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.Context;
+import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
import jdk.nashorn.internal.runtime.PropertyMap;
@@ -66,11 +66,9 @@
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
-import jdk.nashorn.internal.runtime.arrays.ContinuousArray;
import jdk.nashorn.internal.runtime.arrays.IteratorAction;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
-import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
* Runtime representation of a JavaScript array. NativeArray only holds numeric
@@ -97,7 +95,7 @@
NativeArray(final long length) {
// TODO assert valid index in long before casting
- this(ArrayData.allocate((int) length));
+ this(ArrayData.allocate((int)length));
}
NativeArray(final int[] array) {
@@ -142,65 +140,30 @@
}
@Override
- protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
- final ArrayData data = getArray();
- final MethodType callType = desc.getMethodType();
- final Class<?> indexType = callType.parameterType(1);
- final Class<?> returnType = callType.returnType();
-
- if (data instanceof ContinuousArray && indexType == int.class) {
- final Object[] args = request.getArguments();
- final int index = (int)args[args.length - 1];
+ protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+ final GuardedInvocation inv = getArray().findFastGetMethod(getArray().getClass(), desc, request, operator);
+ if (inv != null) {
+ return inv;
+ }
+ return super.findGetMethod(desc, request, operator);
+ }
- if (data.has(index)) {
- final MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle();
- final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT;
- MethodHandle getElement = ((ContinuousArray)data).getElementGetter(returnType, programPoint);
- if (getElement != null) {
- getElement = MH.filterArguments(getElement, 0, MH.asType(getArray, getArray.type().changeReturnType(ContinuousArray.class)));
- //System.err.println("Relink fast GET "+ desc+ " "+ DynamicLinker.getLinkedCallSiteLocation());
- return new GuardedInvocation(getElement, null, null, ClassCastException.class);
- }
- }
+ @Override
+ protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+ final GuardedInvocation inv = getArray().findFastGetIndexMethod(getArray().getClass(), desc, request);
+ if (inv != null) {
+ return inv;
}
- //System.err.println("Relink slow GET "+ desc+ " "+ DynamicLinker.getLinkedCallSiteLocation());
-
return super.findGetIndexMethod(desc, request);
}
@Override
- protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
-
- final ArrayData data = getArray();
- final MethodType callType = desc.getMethodType();
- final Class<?> indexType = callType.parameterType(1);
- final Class<?> elementType = callType.parameterType(2);
-
- if (data instanceof ContinuousArray && indexType == int.class) {
- final ContinuousArray cdata = (ContinuousArray)data;
- final Object[] args = request.getArguments();
- final int index = (int)args[args.length - 2];
-
- if (data.has(index)) {
- MethodHandle hasGuard = cdata.getSetGuard();
- hasGuard = MH.asType(hasGuard, hasGuard.type().changeParameterType(0, ContinuousArray.class));
-
- MethodHandle setElement = cdata.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
- MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle();
- getArray = MH.asType(getArray, getArray.type().changeReturnType(ContinuousArray.class));
- setElement = MH.filterArguments(setElement, 0, getArray);
- hasGuard = MH.filterArguments(hasGuard, 0, getArray);
- //if this is the first invocation we have to execute the setter ourselves, we know it will work
-
- //System.err.println("Relink fast SET "+ desc + " "+ DynamicLinker.getLinkedCallSiteLocation());
- return new GuardedInvocation(setElement, hasGuard, null, ClassCastException.class); //CCE if not a scriptObject anymore
- }
- }
+ protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
+ final GuardedInvocation inv = getArray().findFastSetIndexMethod(getArray().getClass(), desc, request);
+ if (inv != null) {
+ return inv;
}
- //System.err.println("Relink slow SET "+ desc + " "+ DynamicLinker.getLinkedCallSiteLocation());
return super.findSetIndexMethod(desc, request);
}
@@ -856,13 +819,10 @@
try {
final ScriptObject sobj = (ScriptObject)self;
- if (bulkable(sobj)) {
- if (sobj.getArray().length() + args.length <= JSType.MAX_UINT) {
- final ArrayData newData = sobj.getArray().push(true, args);
- sobj.setArray(newData);
- return newData.length();
- }
- //fallthru
+ if (bulkable(sobj) && sobj.getArray().length() + args.length <= JSType.MAX_UINT) {
+ final ArrayData newData = sobj.getArray().push(true, args);
+ sobj.setArray(newData);
+ return newData.length();
}
long len = JSType.toUint32(sobj.getLength());
@@ -878,6 +838,88 @@
}
/**
+ * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single int argument
+ *
+ * @param self self reference
+ * @param arg argument to push
+ * @return array after pushes
+ */
+/* @SpecializedFunction
+ public static long push(final Object self, final int arg) {
+ try {
+ final ScriptObject sobj = (ScriptObject)self;
+ final ArrayData arrayData = sobj.getArray();
+ final long length = arrayData.length();
+
+ if (bulkable(sobj) && length + 1 <= JSType.MAX_UINT) {
+ sobj.setArray(arrayData.ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
+ return length + 1;
+ }
+
+ long len = JSType.toUint32(sobj.getLength());
+ sobj.set(len++, arg, true);
+ sobj.set("length", len, true);
+ return len;
+ } catch (final ClassCastException | NullPointerException e) {
+ throw typeError("not.an.object", ScriptRuntime.safeToString(self));
+ }
+ }
+*/
+ /**
+ * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single number argument
+ *
+ * @param self self reference
+ * @param arg argument to push
+ * @return array after pushes
+ */
+ /* @SpecializedFunction
+ public static long push(final Object self, final double arg) {
+ try {
+ final ScriptObject sobj = (ScriptObject)self; final ArrayData arrayData = sobj.getArray();
+ final long length = arrayData.length();
+
+ if (bulkable(sobj) && length + 1 <= JSType.MAX_UINT) {
+ sobj.setArray(arrayData.ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
+ return length + 1;
+ }
+
+ long len = JSType.toUint32(sobj.getLength());
+ sobj.set(len++, arg, true);
+ sobj.set("length", len, true);
+ return len;
+ } catch (final ClassCastException | NullPointerException e) {
+ throw typeError("not.an.object", ScriptRuntime.safeToString(self));
+ }
+ }
+*/
+ /**
+ * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single object argument
+ *
+ * @param self self reference
+ * @param arg argument to push
+ * @return array after pushes
+ */
+ @SpecializedFunction
+ public static long push(final Object self, final Object arg) {
+ try {
+ final ScriptObject sobj = (ScriptObject)self;
+ final ArrayData arrayData = sobj.getArray();
+ final long length = arrayData.length();
+ if (bulkable(sobj) && length < JSType.MAX_UINT) {
+ sobj.setArray(arrayData.push(true, arg)); //ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
+ return length + 1;
+ }
+
+ long len = JSType.toUint32(sobj.getLength());
+ sobj.set(len++, arg, true);
+ sobj.set("length", len, true);
+ return len;
+ } catch (final ClassCastException | NullPointerException e) {
+ throw typeError("not.an.object", ScriptRuntime.safeToString(self));
+ }
+ }
+
+ /**
* ECMA 15.4.4.8 Array.prototype.reverse ()
*
* @param self self reference
@@ -1086,7 +1128,7 @@
}
sobj.setArray(array);
- }
+ }
return sobj;
} catch (final ClassCastException | NullPointerException e) {
@@ -1243,7 +1285,7 @@
}
for (int j = 0; j < items.length; j++) {
- sobj.set(j, items[j], true);
+ sobj.set(j, items[j], true);
}
}
@@ -1520,4 +1562,9 @@
return false;
}
+
+ @Override
+ public String toString() {
+ return "NativeArray@" + Debug.id(this) + '@' + getArray().getClass().getSimpleName();
+ }
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeArrayBuffer.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,20 +25,28 @@
package jdk.nashorn.internal.objects;
-import java.util.Arrays;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
+import java.nio.ByteBuffer;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
+/**
+ * NativeArrayBuffer - ArrayBuffer as described in the JS typed
+ * array spec
+ */
@ScriptClass("ArrayBuffer")
-final class NativeArrayBuffer extends ScriptObject {
- private final byte[] buffer;
+public final class NativeArrayBuffer extends ScriptObject {
+ private final ByteBuffer nb;
// initialized by nasgen
private static PropertyMap $nasgenmap$;
@@ -47,8 +55,19 @@
return $nasgenmap$;
}
+ /**
+ * Constructor
+ * @param newObj is this a new call
+ * @param self self
+ * @param args arguments
+ * @return new native array buffer
+ */
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
+ if (!newObj) {
+ throw typeError("constructor.requires.new", "ArrayBuffer");
+ }
+
if (args.length == 0) {
throw new RuntimeException("missing length argument");
}
@@ -56,21 +75,56 @@
return new NativeArrayBuffer(JSType.toInt32(args[0]));
}
- protected NativeArrayBuffer(final byte[] byteArray, final Global global) {
+ /**
+ * Constructor
+ * @param nb native byte buffer to wrap
+ * @param global global instance
+ */
+ protected NativeArrayBuffer(final ByteBuffer nb, final Global global) {
super(global.getArrayBufferPrototype(), global.getArrayBufferMap());
- this.buffer = byteArray;
+ this.nb = nb;
+ }
+
+ /**
+ * Constructor
+ * @param nb native byte buffer to wrap
+ */
+ protected NativeArrayBuffer(final ByteBuffer nb) {
+ this(nb, Global.instance());
}
- protected NativeArrayBuffer(final byte[] byteArray) {
- this(byteArray, Global.instance());
+ /**
+ * Constructor
+ * @param byteLength byteLength for buffer
+ */
+ protected NativeArrayBuffer(final int byteLength) {
+ this(ByteBuffer.allocateDirect(byteLength));
}
- protected NativeArrayBuffer(final int byteLength) {
- this(new byte[byteLength]);
+ /**
+ * Clone constructor
+ * Used only for slice
+ * @param other original buffer
+ * @param begin begin byte index
+ * @param end end byte index
+ */
+ protected NativeArrayBuffer(final NativeArrayBuffer other, final int begin, final int end) {
+ this(cloneBuffer(other.getNioBuffer(), begin, end));
}
- protected NativeArrayBuffer(final NativeArrayBuffer other, final int begin, final int end) {
- this(Arrays.copyOfRange(other.buffer, begin, end));
+ private static ByteBuffer cloneBuffer(ByteBuffer original, final int begin, final int end) {
+ final ByteBuffer clone = ByteBuffer.allocateDirect(original.capacity());
+ original.rewind();//copy from the beginning
+ clone.put(original);
+ original.rewind();
+ clone.flip();
+ clone.position(begin);
+ clone.limit(end);
+ return clone.slice();
+ }
+
+ ByteBuffer getNioBuffer() {
+ return nb;
}
@Override
@@ -78,19 +132,55 @@
return "ArrayBuffer";
}
+ /**
+ * Byte length for native array buffer
+ * @param self native array buffer
+ * @return byte length
+ */
@Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_WRITABLE | Attribute.NOT_CONFIGURABLE)
- public static Object byteLength(final Object self) {
- return ((NativeArrayBuffer)self).buffer.length;
+ public static int byteLength(final Object self) {
+ return ((NativeArrayBuffer)self).getByteLength();
}
+ /**
+ * Slice function
+ * @param self native array buffer
+ * @param begin0 start byte index
+ * @param end0 end byte index
+ * @return new array buffer, sliced
+ */
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object slice(final Object self, final Object begin0, final Object end0) {
final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self;
- int begin = JSType.toInt32(begin0);
- int end = end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : arrayBuffer.getByteLength();
- begin = adjustIndex(begin, arrayBuffer.getByteLength());
- end = adjustIndex(end, arrayBuffer.getByteLength());
- return new NativeArrayBuffer((NativeArrayBuffer) self, begin, Math.max(end, begin));
+ final int byteLength = arrayBuffer.getByteLength();
+ final int begin = adjustIndex(JSType.toInt32(begin0), byteLength);
+ final int end = adjustIndex(end0 != ScriptRuntime.UNDEFINED ? JSType.toInt32(end0) : byteLength, byteLength);
+ return new NativeArrayBuffer(arrayBuffer, begin, Math.max(end, begin));
+ }
+
+ /**
+ * Specialized slice function
+ * @param self native array buffer
+ * @param begin start byte index
+ * @param end end byte index
+ * @return new array buffer, sliced
+ */
+ @SpecializedFunction
+ public static Object slice(final Object self, final int begin, final int end) {
+ final NativeArrayBuffer arrayBuffer = (NativeArrayBuffer)self;
+ final int byteLength = arrayBuffer.getByteLength();
+ return new NativeArrayBuffer(arrayBuffer, adjustIndex(begin, byteLength), Math.max(adjustIndex(end, byteLength), begin));
+ }
+
+ /**
+ * Specialized slice function
+ * @param self native array buffer
+ * @param begin start byte index
+ * @return new array buffer, sliced
+ */
+ @SpecializedFunction
+ public static Object slice(final Object self, final int begin) {
+ return slice(self, begin, ((NativeArrayBuffer)self).getByteLength());
}
/**
@@ -103,10 +193,7 @@
* @return valid index index in the range [0, length).
*/
static int adjustIndex(final int index, final int length) {
- if (index < 0) {
- return clamp(index + length, length);
- }
- return clamp(index, length);
+ return index < 0 ? clamp(index + length, length) : clamp(index, length);
}
/**
@@ -121,11 +208,7 @@
return index;
}
- public byte[] getByteArray() {
- return buffer;
- }
-
- public int getByteLength() {
- return buffer.length;
+ int getByteLength() {
+ return nb.limit();
}
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeDebug.java Mon Mar 03 11:24:44 2014 +0100
@@ -108,6 +108,7 @@
/**
* Returns true if if the two objects are both property maps, and they have identical properties in the same order,
* but allows the properties to differ in their types.
+ * @param self self
* @param m1 first property map
* @param m2 second property map
* @return true if they have identical properties in same order, with possibly different types.
@@ -119,6 +120,7 @@
/**
* Returns a diagnostic string representing the difference of two property maps.
+ * @param self self
* @param m1 first property map
* @param m2 second property map
* @return a diagnostic string representing the difference of two property maps.
@@ -128,7 +130,6 @@
return PropertyMap.diff((PropertyMap)m1, (PropertyMap)m2);
}
-
/**
* Object util - getClass
*
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeError.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeError.java Mon Mar 03 11:24:44 2014 +0100
@@ -151,8 +151,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object captureStackTrace(final Object self, final Object errorObj) {
- Global.checkObject(errorObj);
- final ScriptObject sobj = (ScriptObject)errorObj;
+ final ScriptObject sobj = Global.checkObject(errorObj);
initException(sobj);
sobj.delete(STACK, false);
if (! sobj.has("stack")) {
@@ -188,8 +187,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object printStackTrace(final Object self) {
- Global.checkObject(self);
- return ECMAException.printStackTrace((ScriptObject)self);
+ return ECMAException.printStackTrace(Global.checkObject(self));
}
/**
@@ -203,8 +201,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object getStackTrace(final Object self) {
- Global.checkObject(self);
- final ScriptObject sobj = (ScriptObject)self;
+ final ScriptObject sobj = Global.checkObject(self);
final Object exception = ECMAException.getException(sobj);
Object[] res;
if (exception instanceof Throwable) {
@@ -224,8 +221,7 @@
* @return line number from which error was thrown
*/
public static Object getLineNumber(final Object self) {
- Global.checkObject(self);
- final ScriptObject sobj = (ScriptObject)self;
+ final ScriptObject sobj = Global.checkObject(self);
return sobj.has(LINENUMBER) ? sobj.get(LINENUMBER) : ECMAException.getLineNumber(sobj);
}
@@ -238,8 +234,7 @@
* @return value that was set
*/
public static Object setLineNumber(final Object self, final Object value) {
- Global.checkObject(self);
- final ScriptObject sobj = (ScriptObject)self;
+ final ScriptObject sobj = Global.checkObject(self);
if (sobj.hasOwnProperty(LINENUMBER)) {
sobj.put(LINENUMBER, value, false);
} else {
@@ -256,8 +251,7 @@
* @return column number from which error was thrown
*/
public static Object getColumnNumber(final Object self) {
- Global.checkObject(self);
- final ScriptObject sobj = (ScriptObject)self;
+ final ScriptObject sobj = Global.checkObject(self);
return sobj.has(COLUMNNUMBER) ? sobj.get(COLUMNNUMBER) : ECMAException.getColumnNumber((ScriptObject)self);
}
@@ -270,8 +264,7 @@
* @return value that was set
*/
public static Object setColumnNumber(final Object self, final Object value) {
- Global.checkObject(self);
- final ScriptObject sobj = (ScriptObject)self;
+ final ScriptObject sobj = Global.checkObject(self);
if (sobj.hasOwnProperty(COLUMNNUMBER)) {
sobj.put(COLUMNNUMBER, value, false);
} else {
@@ -288,8 +281,7 @@
* @return file name from which error was thrown
*/
public static Object getFileName(final Object self) {
- Global.checkObject(self);
- final ScriptObject sobj = (ScriptObject)self;
+ final ScriptObject sobj = Global.checkObject(self);
return sobj.has(FILENAME) ? sobj.get(FILENAME) : ECMAException.getFileName((ScriptObject)self);
}
@@ -302,8 +294,7 @@
* @return value that was set
*/
public static Object setFileName(final Object self, final Object value) {
- Global.checkObject(self);
- final ScriptObject sobj = (ScriptObject)self;
+ final ScriptObject sobj = Global.checkObject(self);
if (sobj.hasOwnProperty(FILENAME)) {
sobj.put(FILENAME, value, false);
} else {
@@ -322,8 +313,7 @@
* @return value of "stack" property
*/
public static Object getStack(final Object self) {
- Global.checkObject(self);
- final ScriptObject sobj = (ScriptObject)self;
+ final ScriptObject sobj = Global.checkObject(self);
if (sobj.has(STACK)) {
return sobj.get(STACK);
}
@@ -348,8 +338,7 @@
* @return value that was set
*/
public static Object setStack(final Object self, final Object value) {
- Global.checkObject(self);
- final ScriptObject sobj = (ScriptObject)self;
+ final ScriptObject sobj = Global.checkObject(self);
sobj.set(STACK, value, false);
return value;
}
@@ -364,9 +353,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object toString(final Object self) {
// Step 1 and 2 : check if 'self' is object it not throw TypeError
- Global.checkObject(self);
-
- final ScriptObject sobj = (ScriptObject)self;
+ final ScriptObject sobj = Global.checkObject(self);
// Step 3 & 4 : get "name" and convert to String.
// But if message is undefined make it "Error".
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat32Array.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,6 +25,13 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -35,6 +42,7 @@
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
/**
* Float32 array for the TypedArray extension
@@ -56,73 +64,103 @@
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
return new NativeFloat32Array(buffer, byteOffset, length);
}
+
@Override
- public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
- return new Float32ArrayData(buffer, byteOffset, length);
- }
- };
-
- private static final class Float32ArrayData extends ArrayDataImpl {
- private Float32ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
- super(buffer, byteOffset, elementLength);
+ public Float32ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+ return new Float32ArrayData(nb.asFloatBuffer(), start, end);
}
@Override
- protected int byteIndex(final int index) {
- return index * BYTES_PER_ELEMENT + byteOffset;
+ public String getClassName() {
+ return "Float32Array";
+ }
+ };
+
+ private static final class Float32ArrayData extends TypedArrayData<FloatBuffer> {
+
+ private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Float32ArrayData.class, "getElem", double.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Float32ArrayData.class, "setElem", void.class, int.class, double.class).methodHandle();
+
+ private Float32ArrayData(final FloatBuffer nb, final int start, final int end) {
+ super(((FloatBuffer)nb.position(start).limit(end)).slice(), end - start);
}
@Override
- protected double getDoubleImpl(final int index) {
- final int byteIndex = byteIndex(index);
- final byte[] byteArray = buffer.getByteArray();
- final int bits = byteArray[byteIndex ] & 0x0000_00ff |
- byteArray[byteIndex+1] << 8 & 0x0000_ff00 |
- byteArray[byteIndex+2] << 16 & 0x00ff_0000 |
- byteArray[byteIndex+3] << 24 & 0xff00_0000 ;
- return Float.intBitsToFloat(bits);
- }
-
- @Override
- protected int getIntImpl(final int index) {
- return (int)getDoubleImpl(index);
+ protected MethodHandle getGetElem() {
+ return GET_ELEM;
}
@Override
- protected long getLongImpl(final int key) {
- return (long)getDoubleImpl(key);
+ protected MethodHandle getSetElem() {
+ return SET_ELEM;
+ }
+
+ private double getElem(final int index) {
+ try {
+ return nb.get(index);
+ } catch (final IndexOutOfBoundsException e) {
+ throw new ClassCastException(); //force relink - this works for unoptimistic too
+ }
+ }
+
+ private void setElem(final int index, final double elem) {
+ try {
+ nb.put(index, (float)elem);
+ } catch (final IndexOutOfBoundsException e) {
+ //swallow valid array indexes. it's ok.
+ if (index < 0) {
+ throw new ClassCastException();
+ }
+ }
}
@Override
- protected Object getObjectImpl(final int key) {
- return getDoubleImpl(key);
+ public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+ if (returnType == int.class || returnType == long.class) {
+ return null;
+ }
+ return getContinuousElementGetter(getClass(), GET_ELEM, returnType, programPoint);
}
@Override
- protected void setImpl(final int index, final double value) {
- final int bits = Float.floatToRawIntBits((float)value);
- final int byteIndex = byteIndex(index);
- @SuppressWarnings("MismatchedReadAndWriteOfArray")
- final byte[] byteArray = buffer.getByteArray();
- byteArray[byteIndex ] = (byte)(bits & 0xff);
- byteArray[byteIndex+1] = (byte)(bits >>> 8 & 0xff);
- byteArray[byteIndex+2] = (byte)(bits >>> 16 & 0xff);
- byteArray[byteIndex+3] = (byte)(bits >>> 24 & 0xff);
+ public int getInt(int index) {
+ return (int)getDouble(index);
+ }
+
+ @Override
+ public long getLong(int index) {
+ return (long)getDouble(index);
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return getElem(index);
}
@Override
- protected void setImpl(final int key, final int value) {
- setImpl(key, (double)value);
+ public Object getObject(int index) {
+ return getDouble(index);
+ }
+
+ @Override
+ public ArrayData set(int index, Object value, boolean strict) {
+ return set(index, JSType.toNumber(value), strict);
}
@Override
- protected void setImpl(final int key, final long value) {
- setImpl(key, (double)value);
+ public ArrayData set(int index, int value, boolean strict) {
+ return set(index, (double)value, strict);
}
@Override
- protected void setImpl(final int key, final Object value) {
- setImpl(key, JSType.toNumber(value));
+ public ArrayData set(int index, long value, boolean strict) {
+ return set(index, (double)value, strict);
+ }
+
+ @Override
+ public ArrayData set(int index, double value, boolean strict) {
+ setElem(index, value);
+ return this;
}
}
@@ -137,7 +175,7 @@
*/
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- return constructorImpl(args, FACTORY);
+ return constructorImpl(newObj, args, FACTORY);
}
NativeFloat32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -145,11 +183,6 @@
}
@Override
- public String getClassName() {
- return "Float32Array";
- }
-
- @Override
protected Factory factory() {
return FACTORY;
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeFloat64Array.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,6 +25,13 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
+import java.nio.DoubleBuffer;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -35,6 +42,7 @@
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
/**
* Float64 array for the TypedArray extension
@@ -56,83 +64,103 @@
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
return new NativeFloat64Array(buffer, byteOffset, length);
}
- @Override
- public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
- return new Float64ArrayData(buffer, byteOffset, length);
- }
- };
-
- private static final class Float64ArrayData extends ArrayDataImpl {
- private Float64ArrayData(final NativeArrayBuffer buffer,
- final int byteOffset, final int elementLength) {
- super(buffer, byteOffset, elementLength);
- }
@Override
- protected int byteIndex(final int index) {
- return index * BYTES_PER_ELEMENT + byteOffset;
+ public Float64ArrayData createArrayData(final ByteBuffer nb, final int start, final int length) {
+ return new Float64ArrayData(nb.asDoubleBuffer(), start, length);
}
@Override
- protected double getDoubleImpl(final int index) {
- final int byteIndex = byteIndex(index);
- final byte[] byteArray = buffer.getByteArray();
- final long bits;
- bits = byteArray[byteIndex ] & 0x0000_0000_0000_00ffL |
- (long)byteArray[byteIndex+1] << 8 & 0x0000_0000_0000_ff00L |
- (long)byteArray[byteIndex+2] << 16 & 0x0000_0000_00ff_0000L |
- (long)byteArray[byteIndex+3] << 24 & 0x0000_0000_ff00_0000L |
- (long)byteArray[byteIndex+4] << 32 & 0x0000_00ff_0000_0000L |
- (long)byteArray[byteIndex+5] << 40 & 0x0000_ff00_0000_0000L |
- (long)byteArray[byteIndex+6] << 48 & 0x00ff_0000_0000_0000L |
- (long)byteArray[byteIndex+7] << 56 & 0xff00_0000_0000_0000L ;
- return Double.longBitsToDouble(bits);
+ public String getClassName() {
+ return "Float64Array";
+ }
+ };
+
+ private static final class Float64ArrayData extends TypedArrayData<DoubleBuffer> {
+
+ private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Float64ArrayData.class, "getElem", double.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Float64ArrayData.class, "setElem", void.class, int.class, double.class).methodHandle();
+
+ private Float64ArrayData(final DoubleBuffer nb, final int start, final int end) {
+ super(((DoubleBuffer)nb.position(start).limit(end)).slice(), end - start);
}
@Override
- protected int getIntImpl(final int index) {
- return (int)getDoubleImpl(index);
+ protected MethodHandle getGetElem() {
+ return GET_ELEM;
}
@Override
- protected long getLongImpl(final int key) {
- return (long)getDoubleImpl(key);
+ protected MethodHandle getSetElem() {
+ return SET_ELEM;
+ }
+
+ private double getElem(final int index) {
+ try {
+ return nb.get(index);
+ } catch (final IndexOutOfBoundsException e) {
+ throw new ClassCastException(); //force relink - this works for unoptimistic too
+ }
+ }
+
+ private void setElem(final int index, final double elem) {
+ try {
+ nb.put(index, elem);
+ } catch (final IndexOutOfBoundsException e) {
+ //swallow valid array indexes. it's ok.
+ if (index < 0) {
+ throw new ClassCastException();
+ }
+ }
}
@Override
- protected Object getObjectImpl(final int key) {
- return getDoubleImpl(key);
+ public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+ if (returnType == int.class || returnType == long.class) {
+ return null;
+ }
+ return getContinuousElementGetter(getClass(), GET_ELEM, returnType, programPoint);
}
@Override
- protected void setImpl(final int index, final double value) {
- final long bits = Double.doubleToRawLongBits(value);
- final int byteIndex = byteIndex(index);
- @SuppressWarnings("MismatchedReadAndWriteOfArray")
- final byte[] byteArray = buffer.getByteArray();
- byteArray[byteIndex ] = (byte)(bits & 0xff);
- byteArray[byteIndex+1] = (byte)(bits >>> 8 & 0xff);
- byteArray[byteIndex+2] = (byte)(bits >>> 16 & 0xff);
- byteArray[byteIndex+3] = (byte)(bits >>> 24 & 0xff);
- byteArray[byteIndex+4] = (byte)(bits >>> 32 & 0xff);
- byteArray[byteIndex+5] = (byte)(bits >>> 40 & 0xff);
- byteArray[byteIndex+6] = (byte)(bits >>> 48 & 0xff);
- byteArray[byteIndex+7] = (byte)(bits >>> 56 & 0xff);
+ public int getInt(final int index) {
+ return (int)getDouble(index);
+ }
+
+ @Override
+ public long getLong(final int index) {
+ return (long)getDouble(index);
+ }
+
+ @Override
+ public double getDouble(final int index) {
+ return getElem(index);
}
@Override
- protected void setImpl(final int key, final int value) {
- setImpl(key, (double)value);
+ public Object getObject(final int index) {
+ return getDouble(index);
+ }
+
+ @Override
+ public ArrayData set(final int index, final Object value, final boolean strict) {
+ return set(index, JSType.toNumber(value), strict);
}
@Override
- protected void setImpl(final int key, final long value) {
- setImpl(key, (double)value);
+ public ArrayData set(final int index, final int value, final boolean strict) {
+ return set(index, (double)value, strict);
}
@Override
- protected void setImpl(final int key, final Object value) {
- setImpl(key, JSType.toNumber(value));
+ public ArrayData set(final int index, final long value, final boolean strict) {
+ return set(index, (double)value, strict);
+ }
+
+ @Override
+ public ArrayData set(final int index, final double value, final boolean strict) {
+ setElem(index, value);
+ return this;
}
}
@@ -147,7 +175,7 @@
*/
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- return constructorImpl(args, FACTORY);
+ return constructorImpl(newObj, args, FACTORY);
}
NativeFloat64Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -155,11 +183,6 @@
}
@Override
- public String getClassName() {
- return "Float64Array";
- }
-
- @Override
protected Factory factory() {
return FACTORY;
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt16Array.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,15 +25,24 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
+import java.nio.ShortBuffer;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
/**
* Int16 array for the TypedArray extension
@@ -56,37 +65,95 @@
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
return new NativeInt16Array(buffer, byteOffset, length);
}
+
@Override
- public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
- return new Int16ArrayData(buffer, byteOffset, length);
+ public Int16ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+ return new Int16ArrayData(nb.asShortBuffer(), start, end);
+ }
+
+ @Override
+ public String getClassName() {
+ return "Int16Array";
}
};
- private static final class Int16ArrayData extends ArrayDataImpl {
- private Int16ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
- super(buffer, byteOffset, elementLength);
+ private static final class Int16ArrayData extends TypedArrayData<ShortBuffer> {
+
+ private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Int16ArrayData.class, "getElem", int.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Int16ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+ private Int16ArrayData(final ShortBuffer nb, final int start, final int end) {
+ super(((ShortBuffer)nb.position(start).limit(end)).slice(), end - start);
+ }
+
+ @Override
+ protected MethodHandle getGetElem() {
+ return GET_ELEM;
}
@Override
- protected int byteIndex(final int index) {
- return index * BYTES_PER_ELEMENT + byteOffset;
+ protected MethodHandle getSetElem() {
+ return SET_ELEM;
+ }
+
+ private int getElem(final int index) {
+ try {
+ return nb.get(index);
+ } catch (final IndexOutOfBoundsException e) {
+ throw new ClassCastException(); //force relink - this works for unoptimistic too
+ }
+ }
+
+ private void setElem(final int index, final int elem) {
+ try {
+ nb.put(index, (short)elem);
+ } catch (final IndexOutOfBoundsException e) {
+ //swallow valid array indexes. it's ok.
+ if (index < 0) {
+ throw new ClassCastException();
+ }
+ }
+ }
+
+ @Override
+ public int getInt(int index) {
+ return getElem(index);
}
@Override
- protected int getIntImpl(final int index) {
- final int byteIndex = byteIndex(index);
- final byte[] byteArray = buffer.getByteArray();
- return byteArray[byteIndex ] & (short)0x00ff |
- byteArray[byteIndex+1] << 8 & (short)0xff00 ;
+ public long getLong(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public Object getObject(int index) {
+ return getInt(index);
}
@Override
- protected void setImpl(final int index, final int value) {
- final int byteIndex = byteIndex(index);
- @SuppressWarnings("MismatchedReadAndWriteOfArray")
- final byte[] byteArray = buffer.getByteArray();
- byteArray[byteIndex ] = (byte)(value & 0xff);
- byteArray[byteIndex+1] = (byte)(value >>> 8 & 0xff);
+ public ArrayData set(int index, Object value, boolean strict) {
+ return set(index, JSType.toInt32(value), strict);
+ }
+
+ @Override
+ public ArrayData set(int index, int value, boolean strict) {
+ setElem(index, value);
+ return this;
+ }
+
+ @Override
+ public ArrayData set(int index, long value, boolean strict) {
+ return set(index, (int)value, strict);
+ }
+
+ @Override
+ public ArrayData set(int index, double value, boolean strict) {
+ return set(index, (int)value, strict);
}
}
@@ -101,7 +168,7 @@
*/
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- return constructorImpl(args, FACTORY);
+ return constructorImpl(newObj, args, FACTORY);
}
NativeInt16Array(final NativeArrayBuffer buffer, final int byteOffset, final int byteLength) {
@@ -109,11 +176,6 @@
}
@Override
- public String getClassName() {
- return "Int16Array";
- }
-
- @Override
protected Factory factory() {
return FACTORY;
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt32Array.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,15 +25,24 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
/**
* Int32 array for the TypedArray extension
@@ -55,41 +64,94 @@
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
return new NativeInt32Array(buffer, byteOffset, length);
}
+
@Override
- public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
- return new Int32ArrayData(buffer, byteOffset, length);
+ public Int32ArrayData createArrayData(final ByteBuffer nb, final int start, final int length) {
+ return new Int32ArrayData(nb.asIntBuffer(), start, length);
+ }
+
+ @Override
+ public String getClassName() {
+ return "Int32Array";
}
};
- private static final class Int32ArrayData extends ArrayDataImpl {
- private Int32ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
- super(buffer, byteOffset, elementLength);
+ private static final class Int32ArrayData extends TypedArrayData<IntBuffer> {
+
+ private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Int32ArrayData.class, "getElem", int.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Int32ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+ private Int32ArrayData(final IntBuffer nb, final int start, final int end) {
+ super(((IntBuffer)nb.position(start).limit(end)).slice(), end - start);
}
@Override
- protected int byteIndex(final int index) {
- return index * BYTES_PER_ELEMENT + byteOffset;
+ protected MethodHandle getGetElem() {
+ return GET_ELEM;
}
@Override
- protected int getIntImpl(final int index) {
- final int byteIndex = byteIndex(index);
- final byte[] byteArray = buffer.getByteArray();
- return byteArray[byteIndex ] & 0x0000_00ff |
- byteArray[byteIndex+1] << 8 & 0x0000_ff00 |
- byteArray[byteIndex+2] << 16 & 0x00ff_0000 |
- byteArray[byteIndex+3] << 24 & 0xff00_0000 ;
+ protected MethodHandle getSetElem() {
+ return SET_ELEM;
+ }
+
+ private int getElem(final int index) {
+ try {
+ return nb.get(index);
+ } catch (final IndexOutOfBoundsException e) {
+ throw new ClassCastException(); //force relink - this works for unoptimistic too
+ }
+ }
+
+ private void setElem(final int index, final int elem) {
+ try {
+ nb.put(index, elem);
+ } catch (final IndexOutOfBoundsException e) {
+ if (index < 0) {
+ throw new ClassCastException();
+ }
+ }
+ }
+
+ @Override
+ public int getInt(int index) {
+ return getElem(index);
}
@Override
- protected void setImpl(final int index, final int value) {
- final int byteIndex = byteIndex(index);
- @SuppressWarnings("MismatchedReadAndWriteOfArray")
- final byte[] byteArray = buffer.getByteArray();
- byteArray[byteIndex ] = (byte)(value & 0xff);
- byteArray[byteIndex+1] = (byte)(value >>> 8 & 0xff);
- byteArray[byteIndex+2] = (byte)(value >>> 16 & 0xff);
- byteArray[byteIndex+3] = (byte)(value >>> 24 & 0xff);
+ public long getLong(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public Object getObject(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public ArrayData set(int index, Object value, boolean strict) {
+ return set(index, JSType.toInt32(value), strict);
+ }
+
+ @Override
+ public ArrayData set(int index, int value, boolean strict) {
+ setElem(index, value);
+ return this;
+ }
+
+ @Override
+ public ArrayData set(int index, long value, boolean strict) {
+ return set(index, (int)value, strict);
+ }
+
+ @Override
+ public ArrayData set(int index, double value, boolean strict) {
+ return set(index, (int)value, strict);
}
}
@@ -104,7 +166,7 @@
*/
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- return constructorImpl(args, FACTORY);
+ return constructorImpl(newObj, args, FACTORY);
}
NativeInt32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -112,11 +174,6 @@
}
@Override
- public String getClassName() {
- return "Int32Array";
- }
-
- @Override
protected Factory factory() {
return FACTORY;
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeInt8Array.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,15 +25,23 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
/**
* Int8Array for the TypedArray extension
@@ -57,32 +65,97 @@
}
@Override
- public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
- return new Int8ArrayData(buffer, byteOffset, length);
+ public Int8ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+ return new Int8ArrayData(nb, start, end);
+ }
+
+ @Override
+ public String getClassName() {
+ return "Int8Array";
}
};
- private static final class Int8ArrayData extends ArrayDataImpl {
- private Int8ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
- super(buffer, byteOffset, elementLength);
+ private static final class Int8ArrayData extends TypedArrayData<ByteBuffer> {
+
+ private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Int8ArrayData.class, "getElem", int.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Int8ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+ private Int8ArrayData(final ByteBuffer nb, final int start, final int end) {
+ super(((ByteBuffer)nb.position(start).limit(end)).slice(), end - start);
+ }
+
+ @Override
+ protected MethodHandle getGetElem() {
+ return GET_ELEM;
}
@Override
- protected int byteIndex(final int index) {
- return index * BYTES_PER_ELEMENT + byteOffset;
+ protected MethodHandle getSetElem() {
+ return SET_ELEM;
+ }
+
+ private int getElem(final int index) {
+ try {
+ return nb.get(index);
+ } catch (final IndexOutOfBoundsException e) {
+ throw new ClassCastException(); //force relink - this works for unoptimistic too
+ }
+ }
+
+ private void setElem(final int index, final int elem) {
+ try {
+ nb.put(index, (byte)elem);
+ } catch (final IndexOutOfBoundsException e) {
+ //swallow valid array indexes. it's ok.
+ if (index < 0) {
+ throw new ClassCastException();
+ }
+ }
+ }
+
+ @Override
+ public int getInt(int index) {
+ return getElem(index);
}
@Override
- protected int getIntImpl(final int index) {
- return buffer.getByteArray()[byteIndex(index)];
+ public long getLong(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public Object getObject(int index) {
+ return getInt(index);
}
@Override
- protected void setImpl(final int index, final int value) {
- buffer.getByteArray()[byteIndex(index)] = (byte)value;
+ public ArrayData set(int index, Object value, boolean strict) {
+ return set(index, JSType.toInt32(value), strict);
+ }
+
+ @Override
+ public ArrayData set(int index, int value, boolean strict) {
+ setElem(index, value);
+ return this;
+ }
+
+ @Override
+ public ArrayData set(int index, long value, boolean strict) {
+ return set(index, (int)value, strict);
+ }
+
+ @Override
+ public ArrayData set(int index, double value, boolean strict) {
+ return set(index, (int)value, strict);
}
}
+
/**
* Constructor
*
@@ -94,7 +167,7 @@
*/
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- return constructorImpl(args, FACTORY);
+ return constructorImpl(newObj, args, FACTORY);
}
NativeInt8Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -102,11 +175,6 @@
}
@Override
- public String getClassName() {
- return "Int8Array";
- }
-
- @Override
protected Factory factory() {
return FACTORY;
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeMath.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeMath.java Mon Mar 03 11:24:44 2014 +0100
@@ -489,6 +489,20 @@
}
/**
+ * ECMA 15.8.2.11 max(x) - specialized version for two Object args
+ *
+ * @param self self reference
+ * @param x first argument
+ * @param y second argument
+ *
+ * @return largest value of x and y
+ */
+ @SpecializedFunction
+ public static double max(final Object self, final Object x, final Object y) {
+ return Math.max(JSType.toNumber(x), JSType.toNumber(y));
+ }
+
+ /**
* ECMA 15.8.2.12 min(x)
*
* @param self self reference
@@ -567,6 +581,20 @@
}
/**
+ * ECMA 15.8.2.12 min(x) - specialized version for two Object args
+ *
+ * @param self self reference
+ * @param x first argument
+ * @param y second argument
+ *
+ * @return smallest value of x and y
+ */
+ @SpecializedFunction
+ public static double min(final Object self, final Object x, final Object y) {
+ return Math.min(JSType.toNumber(x), JSType.toNumber(y));
+ }
+
+ /**
* ECMA 15.8.2.13 pow(x,y)
*
* @param self self reference
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeNumber.java Mon Mar 03 11:24:44 2014 +0100
@@ -41,6 +41,7 @@
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
@@ -156,8 +157,20 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object toFixed(final Object self, final Object fractionDigits) {
- final int f = JSType.toInteger(fractionDigits);
- if (f < 0 || f > 20) {
+ return toFixed(self, JSType.toInteger(fractionDigits));
+ }
+
+ /**
+ * ECMA 15.7.4.5 Number.prototype.toFixed (fractionDigits) specialized for int fractionDigits
+ *
+ * @param self self reference
+ * @param fractionDigits how many digits should be after the decimal point, 0 if undefined
+ *
+ * @return number in decimal fixed point notation
+ */
+ @SpecializedFunction
+ public static Object toFixed(final Object self, final int fractionDigits) {
+ if (fractionDigits < 0 || fractionDigits > 20) {
throw rangeError("invalid.fraction.digits", "toFixed");
}
@@ -171,8 +184,8 @@
}
final NumberFormat format = NumberFormat.getNumberInstance(Locale.US);
- format.setMinimumFractionDigits(f);
- format.setMaximumFractionDigits(f);
+ format.setMinimumFractionDigits(fractionDigits);
+ format.setMaximumFractionDigits(fractionDigits);
format.setGroupingUsed(false);
return format.format(x);
@@ -210,7 +223,7 @@
* ECMA 15.7.4.7 Number.prototype.toPrecision (precision)
*
* @param self self reference
- * @param precision use {@code precision - 1} digits after the significand's decimal point or call {@link NativeDate#toString} if undefined
+ * @param precision use {@code precision - 1} digits after the significand's decimal point or call {@link JSType#toString} if undefined
*
* @return number in decimal exponentiation notation or decimal fixed notation depending on {@code precision}
*/
@@ -220,8 +233,23 @@
if (precision == UNDEFINED) {
return JSType.toString(x);
}
+ return (toPrecision(x, JSType.toInteger(precision)));
+ }
- final int p = JSType.toInteger(precision);
+ /**
+ * ECMA 15.7.4.7 Number.prototype.toPrecision (precision) specialized f
+ *
+ * @param self self reference
+ * @param precision use {@code precision - 1} digits after the significand's decimal point.
+ *
+ * @return number in decimal exponentiation notation or decimal fixed notation depending on {@code precision}
+ */
+ @SpecializedFunction
+ public static Object toPrecision(Object self, final int precision) {
+ return toPrecision(getNumberValue(self), precision);
+ }
+
+ private static Object toPrecision(final double x, final int p) {
if (Double.isNaN(x)) {
return "NaN";
} else if (Double.isInfinite(x)) {
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java Mon Mar 03 11:24:44 2014 +0100
@@ -250,8 +250,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
- Global.checkObject(obj);
- ((ScriptObject)obj).defineOwnProperty(JSType.toString(prop), attr, true);
+ Global.checkObject(obj).defineOwnProperty(JSType.toString(prop), attr, true);
return obj;
}
@@ -265,9 +264,7 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object defineProperties(final Object self, final Object obj, final Object props) {
- Global.checkObject(obj);
-
- final ScriptObject sobj = (ScriptObject)obj;
+ final ScriptObject sobj = Global.checkObject(obj);
final Object propsObj = Global.toObject(props);
if (propsObj instanceof ScriptObject) {
@@ -425,7 +422,7 @@
// Object(null), Object(undefined), Object() are same as "new Object()"
- if (newObj || (type == JSType.NULL || type == JSType.UNDEFINED)) {
+ if (newObj || type == JSType.NULL || type == JSType.UNDEFINED) {
switch (type) {
case BOOLEAN:
case NUMBER:
@@ -513,7 +510,7 @@
final Object key = JSType.toPrimitive(v, String.class);
final Object obj = Global.toObject(self);
- return (obj instanceof ScriptObject) && ((ScriptObject)obj).hasOwnProperty(key);
+ return obj instanceof ScriptObject && ((ScriptObject)obj).hasOwnProperty(key);
}
/**
@@ -627,12 +624,10 @@
@Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
public static Object bindProperties(final Object self, final Object target, final Object source) {
// target object has to be a ScriptObject
- Global.checkObject(target);
+ final ScriptObject targetObj = Global.checkObject(target);
// check null or undefined source object
Global.checkObjectCoercible(source);
- final ScriptObject targetObj = (ScriptObject)target;
-
if (source instanceof ScriptObject) {
final ScriptObject sourceObj = (ScriptObject)source;
@@ -753,7 +748,7 @@
Bootstrap.bindDynamicMethod(methodGetter.invoke(source), source)), 0, Object.class);
} catch(RuntimeException|Error e) {
throw e;
- } catch(Throwable t) {
+ } catch(final Throwable t) {
throw new RuntimeException(t);
}
}
@@ -766,7 +761,7 @@
assert passesGuard(source, inv.getGuard());
} catch(RuntimeException|Error e) {
throw e;
- } catch(Throwable t) {
+ } catch(final Throwable t) {
throw new RuntimeException(t);
}
assert inv.getSwitchPoint() == null; // Linkers in Dynalink's beans package don't use switchpoints.
@@ -780,6 +775,6 @@
private static LinkRequest createLinkRequest(String operation, MethodType methodType, Object source) {
return new LinkRequestImpl(CallSiteDescriptorFactory.create(MethodHandles.publicLookup(), operation,
- methodType), null, false, source);
+ methodType), null, 0, false, source);
}
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeRegExp.java Mon Mar 03 11:24:44 2014 +0100
@@ -602,7 +602,7 @@
for (int i = 0, lastGroupStart = matcher.start(); i <= groupCount; i++) {
final int groupStart = matcher.start(i);
if (lastGroupStart > groupStart
- || (groupsInNegativeLookahead != null && groupsInNegativeLookahead.isSet(i))) {
+ || groupsInNegativeLookahead != null && groupsInNegativeLookahead.isSet(i)) {
// (1) ECMA 15.10.2.5 NOTE 3: need to clear Atom's captures each time Atom is repeated.
// (2) ECMA 15.10.2.8 NOTE 3: Backreferences to captures in (?!Disjunction) from elsewhere
// in the pattern always return undefined because the negative lookahead must fail.
@@ -750,8 +750,8 @@
cursor++;
if (cursor < replacement.length() && firstDigit < matcher.groupCount()) {
final int secondDigit = replacement.charAt(cursor) - '0';
- if ((secondDigit >= 0) && (secondDigit <= 9)) {
- final int newRefNum = (firstDigit * 10) + secondDigit;
+ if (secondDigit >= 0 && secondDigit <= 9) {
+ final int newRefNum = firstDigit * 10 + secondDigit;
if (newRefNum <= matcher.groupCount() && newRefNum > 0) {
// $nn ($01-$99)
refNum = newRefNum;
@@ -922,7 +922,6 @@
}
private static NativeRegExp checkRegExp(final Object self) {
- Global.checkObjectCoercible(self);
if (self instanceof NativeRegExp) {
return (NativeRegExp)self;
} else if (self != null && self == Global.instance().getRegExpPrototype()) {
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeString.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeString.java Mon Mar 03 11:24:44 2014 +0100
@@ -443,22 +443,8 @@
public static Object fromCharCode(final Object self, final Object value) {
if (value instanceof Integer) {
return fromCharCode(self, (int)value);
- } else if (value instanceof String) {
- return "" + (char)JSType.toUint16(value);
}
- return fromCharCode(self, new Object[] { value });
- }
-
- /**
- * fromCharCode specialization
- *
- * @param self self reference
- * @param value one argument to be interpreted as char
- * @return string with one charcode
- */
- @SpecializedFunction
- public static Object fromCharCode(final Object self, final String value) {
- return fromCharCode(self, new Object[] { value });
+ return Character.toString((char)JSType.toUint16(value));
}
/**
@@ -469,18 +455,46 @@
*/
@SpecializedFunction
public static Object fromCharCode(final Object self, final int value) {
- return "" + (char)(value & 0xffff);
+ return Character.toString((char)(value & 0xffff));
+ }
+
+ /**
+ * ECMA 15.5.3.2 - specialization for two chars of int type
+ * @param self self reference
+ * @param ch1 first char
+ * @param ch2 second char
+ * @return string with one charcode
+ */
+ @SpecializedFunction
+ public static Object fromCharCode(final Object self, final int ch1, final int ch2) {
+ return Character.toString((char)(ch1 & 0xffff)) + Character.toString((char)(ch2 & 0xffff));
}
/**
- * ECMA 15.5.3.2 - specialization for one char of long type
+ * ECMA 15.5.3.2 - specialization for three chars of int type
* @param self self reference
- * @param value one argument to be interpreted as char
+ * @param ch1 first char
+ * @param ch2 second char
+ * @param ch3 third char
* @return string with one charcode
*/
@SpecializedFunction
- public static Object fromCharCode(final Object self, final long value) {
- return "" + (char)((int)value & 0xffff);
+ public static Object fromCharCode(final Object self, final int ch1, final int ch2, final int ch3) {
+ return Character.toString((char)(ch1 & 0xffff)) + Character.toString((char)(ch2 & 0xffff)) + Character.toString((char)(ch3 & 0xffff));
+ }
+
+ /**
+ * ECMA 15.5.3.2 - specialization for four chars of int type
+ * @param self self reference
+ * @param ch1 first char
+ * @param ch2 second char
+ * @param ch3 third char
+ * @param ch4 fourth char
+ * @return string with one charcode
+ */
+ @SpecializedFunction
+ public static Object fromCharCode(final Object self, final int ch1, final int ch2, final int ch3, final int ch4) {
+ return Character.toString((char)(ch1 & 0xffff)) + Character.toString((char)(ch2 & 0xffff)) + Character.toString((char)(ch3 & 0xffff)) + Character.toString((char)(ch4 & 0xffff));
}
/**
@@ -491,7 +505,7 @@
*/
@SpecializedFunction
public static Object fromCharCode(final Object self, final double value) {
- return "" + (char)JSType.toUint16(value);
+ return Character.toString((char)JSType.toUint16(value));
}
/**
@@ -548,7 +562,7 @@
}
private static String charAtImpl(final String str, final int pos) {
- return (pos < 0 || pos >= str.length()) ? "" : String.valueOf(str.charAt(pos));
+ return pos < 0 || pos >= str.length() ? "" : String.valueOf(str.charAt(pos));
}
/**
@@ -585,7 +599,7 @@
}
private static double charCodeAtImpl(final String str, final int pos) {
- return (pos < 0 || pos >= str.length()) ? Double.NaN : str.charAt(pos);
+ return pos < 0 || pos >= str.length() ? Double.NaN : str.charAt(pos);
}
/**
@@ -820,7 +834,7 @@
@SpecializedFunction
public static Object slice(final Object self, final int start) {
final String str = checkObjectToString(self);
- final int from = (start < 0) ? Math.max(str.length() + start, 0) : Math.min(start, str.length());
+ final int from = start < 0 ? Math.max(str.length() + start, 0) : Math.min(start, str.length());
return str.substring(from);
}
@@ -851,8 +865,8 @@
final String str = checkObjectToString(self);
final int len = str.length();
- final int from = (start < 0) ? Math.max(len + start, 0) : Math.min(start, len);
- final int to = (end < 0) ? Math.max(len + end, 0) : Math.min(end, len);
+ final int from = start < 0 ? Math.max(len + start, 0) : Math.min(start, len);
+ final int to = end < 0 ? Math.max(len + end, 0) : Math.min(end, len);
return str.substring(Math.min(from, to), to);
}
@@ -881,7 +895,7 @@
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static Object split(final Object self, final Object separator, final Object limit) {
final String str = checkObjectToString(self);
- final long lim = (limit == UNDEFINED) ? JSType.MAX_UINT : JSType.toUint32(limit);
+ final long lim = limit == UNDEFINED ? JSType.MAX_UINT : JSType.toUint32(limit);
if (separator == UNDEFINED) {
return lim == 0 ? new NativeArray() : new NativeArray(new Object[]{str});
@@ -912,7 +926,7 @@
int n = 0;
while (pos < strLength && n < limit) {
- int found = str.indexOf(separator, pos);
+ final int found = str.indexOf(separator, pos);
if (found == -1) {
break;
}
@@ -945,7 +959,7 @@
intStart = Math.max(intStart + strLength, 0);
}
- final int intLen = Math.min(Math.max((length == UNDEFINED) ? Integer.MAX_VALUE : JSType.toInteger(length), 0), strLength - intStart);
+ final int intLen = Math.min(Math.max(length == UNDEFINED ? Integer.MAX_VALUE : JSType.toInteger(length), 0), strLength - intStart);
return intLen <= 0 ? "" : str.substring(intStart, intStart + intLen);
}
@@ -1011,8 +1025,8 @@
public static String substring(final Object self, final int start, final int end) {
final String str = checkObjectToString(self);
final int len = str.length();
- final int validStart = start < 0 ? 0 : (start > len ? len : start);
- final int validEnd = end < 0 ? 0 : (end > len ? len : end);
+ final int validStart = start < 0 ? 0 : start > len ? len : start;
+ final int validEnd = end < 0 ? 0 : end > len ? len : end;
if (validStart < validEnd) {
return str.substring(validStart, validEnd);
@@ -1105,7 +1119,7 @@
final String str = checkObjectToString(self);
int start = 0;
- int end = str.length() - 1;
+ final int end = str.length() - 1;
while (start <= end && ScriptRuntime.isJSWhitespace(str.charAt(start))) {
start++;
@@ -1123,7 +1137,7 @@
public static Object trimRight(final Object self) {
final String str = checkObjectToString(self);
- int start = 0;
+ final int start = 0;
int end = str.length() - 1;
while (end >= start && ScriptRuntime.isJSWhitespace(str.charAt(end))) {
@@ -1150,7 +1164,7 @@
*/
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- final CharSequence str = (args.length > 0) ? JSType.toCharSequence(args[0]) : "";
+ final CharSequence str = args.length > 0 ? JSType.toCharSequence(args[0]) : "";
return newObj ? newObj(self, str) : str.toString();
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint16Array.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,15 +25,24 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
/**
* Uint16 array for TypedArray extension
@@ -55,37 +64,100 @@
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
return new NativeUint16Array(buffer, byteOffset, length);
}
+
@Override
- public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
- return new Uint16ArrayData(buffer, byteOffset, length);
+ public Uint16ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+ return new Uint16ArrayData(nb.asCharBuffer(), start, end);
+ }
+
+ @Override
+ public String getClassName() {
+ return "Uint16Array";
}
};
- private static final class Uint16ArrayData extends ArrayDataImpl {
- private Uint16ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
- super(buffer, byteOffset, elementLength);
+ private static final class Uint16ArrayData extends TypedArrayData<CharBuffer> {
+
+ private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Uint16ArrayData.class, "getElem", int.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint16ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+ private Uint16ArrayData(final CharBuffer nb, final int start, final int end) {
+ super(((CharBuffer)nb.position(start).limit(end)).slice(), end - start);
+ }
+
+ @Override
+ protected MethodHandle getGetElem() {
+ return GET_ELEM;
}
@Override
- protected int byteIndex(final int index) {
- return index * BYTES_PER_ELEMENT + byteOffset;
+ protected MethodHandle getSetElem() {
+ return SET_ELEM;
+ }
+
+ private int getElem(final int index) {
+ try {
+ return nb.get(index);
+ } catch (final IndexOutOfBoundsException e) {
+ throw new ClassCastException(); //force relink - this works for unoptimistic too
+ }
+ }
+
+ private void setElem(final int index, final int elem) {
+ try {
+ nb.put(index, (char)elem);
+ } catch (final IndexOutOfBoundsException e) {
+ //swallow valid array indexes. it's ok.
+ if (index < 0) {
+ throw new ClassCastException();
+ }
+ }
+ }
+
+ @Override
+ public boolean isUnsigned() {
+ return true;
+ }
+
+ @Override
+ public int getInt(int index) {
+ return getElem(index);
}
@Override
- protected int getIntImpl(final int index) {
- final int byteIndex = byteIndex(index);
- final byte[] byteArray = buffer.getByteArray();
- return byteArray[byteIndex ] & 0x0000_00ff |
- byteArray[byteIndex+1] << 8 & 0x0000_ff00 ;
+ public long getLong(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public Object getObject(int index) {
+ return getInt(index);
}
@Override
- protected void setImpl(final int index, final int value) {
- final int byteIndex = byteIndex(index);
- @SuppressWarnings("MismatchedReadAndWriteOfArray")
- final byte[] byteArray = buffer.getByteArray();
- byteArray[byteIndex ] = (byte)(value & 0xff);
- byteArray[byteIndex+1] = (byte)(value >>> 8 & 0xff);
+ public ArrayData set(int index, Object value, boolean strict) {
+ return set(index, JSType.toInt32(value), strict);
+ }
+
+ @Override
+ public ArrayData set(int index, int value, boolean strict) {
+ setElem(index, value);
+ return this;
+ }
+
+ @Override
+ public ArrayData set(int index, long value, boolean strict) {
+ return set(index, (int)value, strict);
+ }
+
+ @Override
+ public ArrayData set(int index, double value, boolean strict) {
+ return set(index, (int)value, strict);
}
}
@@ -100,7 +172,7 @@
*/
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- return constructorImpl(args, FACTORY);
+ return constructorImpl(newObj, args, FACTORY);
}
NativeUint16Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -108,11 +180,6 @@
}
@Override
- public String getClassName() {
- return "Uint16Array";
- }
-
- @Override
protected Factory factory() {
return FACTORY;
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint32Array.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,6 +25,14 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -35,6 +43,7 @@
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
/**
* Uint32 array for TypedArray extension
@@ -56,55 +65,108 @@
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteBegin, final int length) {
return new NativeUint32Array(buffer, byteBegin, length);
}
+
@Override
- public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
- return new Uint32ArrayData(buffer, byteOffset, length);
+ public Uint32ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+ return new Uint32ArrayData(nb.order(ByteOrder.nativeOrder()).asIntBuffer(), start, end);
+ }
+
+ @Override
+ public String getClassName() {
+ return "Uint32Array";
}
};
- private static final class Uint32ArrayData extends ArrayDataImpl {
- private Uint32ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
- super(buffer, byteOffset, elementLength);
+ private static final class Uint32ArrayData extends TypedArrayData<IntBuffer> {
+
+ private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Uint32ArrayData.class, "getElem", long.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint32ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+ private Uint32ArrayData(final IntBuffer nb, final int start, final int end) {
+ super(((IntBuffer)nb.position(start).limit(end)).slice(), end - start);
}
@Override
- protected int byteIndex(final int index) {
- return index * BYTES_PER_ELEMENT + byteOffset;
+ protected MethodHandle getGetElem() {
+ return GET_ELEM;
+ }
+
+ @Override
+ protected MethodHandle getSetElem() {
+ return SET_ELEM;
}
@Override
- protected int getIntImpl(final int index) {
- final int byteIndex = byteIndex(index);
- final byte[] byteArray = buffer.getByteArray();
- return byteArray[byteIndex ] & 0x0000_00ff |
- byteArray[byteIndex+1] << 8 & 0x0000_ff00 |
- byteArray[byteIndex+2] << 16 & 0x00ff_0000 |
- byteArray[byteIndex+3] << 24 & 0xff00_0000 ;
+ public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+ if (returnType == int.class) {
+ return null;
+ }
+ return getContinuousElementGetter(getClass(), GET_ELEM, returnType, programPoint);
+ }
+
+ private long getElem(final int index) {
+ try {
+ return nb.get(index) & JSType.MAX_UINT;
+ } catch (final IndexOutOfBoundsException e) {
+ throw new ClassCastException(); //force relink - this works for unoptimistic too
+ }
+ }
+
+ private void setElem(final int index, final int elem) {
+ try {
+ nb.put(index, elem);
+ } catch (final IndexOutOfBoundsException e) {
+ //swallow valid array indexes. it's ok.
+ if (index < 0) {
+ throw new ClassCastException();
+ }
+ }
}
@Override
- protected long getLongImpl(final int key) {
- return getIntImpl(key) & JSType.MAX_UINT;
+ public boolean isUnsigned() {
+ return true;
}
@Override
- protected double getDoubleImpl(final int key) {
- return getIntImpl(key) & JSType.MAX_UINT;
+ public int getInt(int index) {
+ return (int)getLong(index);
+ }
+
+ @Override
+ public long getLong(int index) {
+ return getElem(index);
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return getLong(index);
}
@Override
- protected Object getObjectImpl(final int key) {
- return getIntImpl(key) & JSType.MAX_UINT;
+ public Object getObject(int index) {
+ return getLong(index);
+ }
+
+ @Override
+ public ArrayData set(int index, Object value, boolean strict) {
+ return set(index, JSType.toInt32(value), strict);
}
@Override
- protected void setImpl(final int index, final int value) {
- final int byteIndex = byteIndex(index);
- final byte[] byteArray = buffer.getByteArray();
- byteArray[byteIndex ] = (byte)(value & 0xff);
- byteArray[byteIndex+1] = (byte)(value >>> 8 & 0xff);
- byteArray[byteIndex+2] = (byte)(value >>> 16 & 0xff);
- byteArray[byteIndex+3] = (byte)(value >>> 24 & 0xff);
+ public ArrayData set(int index, int value, boolean strict) {
+ setElem(index, value);
+ return this;
+ }
+
+ @Override
+ public ArrayData set(int index, long value, boolean strict) {
+ return set(index, (int)value, strict);
+ }
+
+ @Override
+ public ArrayData set(int index, double value, boolean strict) {
+ return set(index, (int)value, strict);
}
}
@@ -119,7 +181,7 @@
*/
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- return constructorImpl(args, FACTORY);
+ return constructorImpl(newObj, args, FACTORY);
}
NativeUint32Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -127,11 +189,6 @@
}
@Override
- public String getClassName() {
- return "Uint32Array";
- }
-
- @Override
protected Factory factory() {
return FACTORY;
}
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8Array.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,21 +25,30 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Where;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
/**
* Uint8 array for TypedArray extension
*/
@ScriptClass("Uint8Array")
public final class NativeUint8Array extends ArrayBufferView {
+
/**
* The size in bytes of each element in the array.
*/
@@ -55,31 +64,102 @@
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
return new NativeUint8Array(buffer, byteOffset, length);
}
+
@Override
- public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
- return new Uint8ArrayData(buffer, byteOffset, length);
+ public Uint8ArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+ return new Uint8ArrayData(nb, start, end);
+ }
+
+ @Override
+ public String getClassName() {
+ return "Uint8Array";
}
};
- private static final class Uint8ArrayData extends ArrayDataImpl {
- private Uint8ArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
- super(buffer, byteOffset, elementLength);
+ private static final class Uint8ArrayData extends TypedArrayData<ByteBuffer> {
+
+ private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Uint8ArrayData.class, "getElem", int.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint8ArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+
+ private Uint8ArrayData(final ByteBuffer nb, final int start, final int end) {
+ super(((ByteBuffer)nb.position(start).limit(end)).slice(), end - start);
+ }
+
+ @Override
+ protected MethodHandle getGetElem() {
+ return GET_ELEM;
}
@Override
- protected int byteIndex(final int index) {
- return index * BYTES_PER_ELEMENT + byteOffset;
+ protected MethodHandle getSetElem() {
+ return SET_ELEM;
+ }
+
+ private int getElem(final int index) {
+ try {
+ return nb.get(index) & 0xff;
+ } catch (final IndexOutOfBoundsException e) {
+ throw new ClassCastException(); //force relink - this works for unoptimistic too
+ }
+ }
+
+ private void setElem(final int index, final int elem) {
+ try {
+ nb.put(index, (byte)elem);
+ } catch (final IndexOutOfBoundsException e) {
+ //swallow valid array indexes. it's ok.
+ if (index < 0) {
+ throw new ClassCastException();
+ }
+ }
+ }
+
+ @Override
+ public boolean isUnsigned() {
+ return true;
+ }
+
+ @Override
+ public int getInt(int index) {
+ return getElem(index);
}
@Override
- protected int getIntImpl(final int index) {
- return buffer.getByteArray()[byteIndex(index)] & 0xff;
+ public long getLong(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public Object getObject(int index) {
+ return getInt(index);
}
@Override
- protected void setImpl(final int index, final int value) {
- buffer.getByteArray()[byteIndex(index)] = (byte)value;
+ public ArrayData set(int index, Object value, boolean strict) {
+ return set(index, JSType.toInt32(value), strict);
+ }
+
+ @Override
+ public ArrayData set(int index, int value, boolean strict) {
+ setElem(index, value);
+ return this;
}
+
+ @Override
+ public ArrayData set(int index, long value, boolean strict) {
+ return set(index, (int)value, strict);
+ }
+
+ @Override
+ public ArrayData set(int index, double value, boolean strict) {
+ return set(index, (int)value, strict);
+ }
+
}
/**
@@ -93,16 +173,11 @@
*/
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- return constructorImpl(args, FACTORY);
+ return constructorImpl(newObj, args, FACTORY);
}
- NativeUint8Array(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
- super(buffer, byteOffset, length);
- }
-
- @Override
- public String getClassName() {
- return "Uint8Array";
+ NativeUint8Array(NativeArrayBuffer buffer, int byteOffset, int elementLength) {
+ super(buffer, byteOffset, elementLength);
}
@Override
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,6 +25,14 @@
package jdk.nashorn.internal.objects;
+import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
+import static jdk.nashorn.internal.lookup.Lookup.MH;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.nio.ByteBuffer;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
@@ -35,6 +43,7 @@
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
+import jdk.nashorn.internal.runtime.arrays.TypedArrayData;
/**
* Uint8 clamped array for TypedArray extension
@@ -56,47 +65,127 @@
public ArrayBufferView construct(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
return new NativeUint8ClampedArray(buffer, byteOffset, length);
}
+
@Override
- public ArrayData createArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
- return new Uint8ClampedArrayData(buffer, byteOffset, length);
+ public Uint8ClampedArrayData createArrayData(final ByteBuffer nb, final int start, final int end) {
+ return new Uint8ClampedArrayData(nb, start, end);
+ }
+
+ @Override
+ public String getClassName() {
+ return "Uint8ClampedArray";
}
};
- private static final class Uint8ClampedArrayData extends ArrayDataImpl {
- private Uint8ClampedArrayData(final NativeArrayBuffer buffer, final int byteOffset, final int elementLength) {
- super(buffer, byteOffset, elementLength);
+ private static final class Uint8ClampedArrayData extends TypedArrayData<ByteBuffer> {
+
+ private static final MethodHandle GET_ELEM = specialCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "getElem", int.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+ private static final MethodHandle RINT = staticCall(MethodHandles.lookup(), Uint8ClampedArrayData.class, "rint", double.class, double.class).methodHandle();
+
+ private Uint8ClampedArrayData(final ByteBuffer nb, final int start, final int end) {
+ super(((ByteBuffer)nb.position(start).limit(end)).slice(), end - start);
}
@Override
- protected int byteIndex(final int index) {
- return index * BYTES_PER_ELEMENT + byteOffset;
+ protected MethodHandle getGetElem() {
+ return GET_ELEM;
+ }
+
+ @Override
+ protected MethodHandle getSetElem() {
+ return SET_ELEM;
+ }
+
+ private int getElem(final int index) {
+ try {
+ return nb.get(index) & 0xff;
+ } catch (final IndexOutOfBoundsException e) {
+ throw new ClassCastException(); //force relink - this works for unoptimistic too
+ }
}
@Override
- protected int getIntImpl(final int index) {
- return buffer.getByteArray()[byteIndex(index)] & 0xff;
+ public MethodHandle getElementSetter(final Class<?> elementType) {
+ final MethodHandle setter = super.getElementSetter(elementType); //getContinuousElementSetter(getClass(), setElem(), elementType);
+ if (setter != null && elementType == double.class) {
+ return MH.filterArguments(setter, 2, RINT);
+ }
+ return setter;
+ }
+
+ private void setElem(final int index, final int elem) {
+ try {
+ final byte clamped;
+ if ((elem & 0xffff_ff00) == 0) {
+ clamped = (byte)elem;
+ } else {
+ clamped = elem < 0 ? 0 : (byte)0xff;
+ }
+ nb.put(index, clamped);
+ } catch (final IndexOutOfBoundsException e) {
+ //swallow valid array indexes. it's ok.
+ if (index < 0) {
+ throw new ClassCastException();
+ }
+ }
+ }
+
+ @Override
+ public boolean isClamped() {
+ return true;
+ }
+
+ @Override
+ public boolean isUnsigned() {
+ return true;
}
@Override
- protected void setImpl(final int index, final int value) {
- final byte clamped;
- if ((value & 0xffff_ff00) == 0) {
- clamped = (byte) value;
- } else {
- clamped = value < 0 ? 0 : (byte)0xff;
- }
- buffer.getByteArray()[byteIndex(index)] = clamped;
+ public int getInt(int index) {
+ return getElem(index);
+ }
+
+ @Override
+ public long getLong(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public double getDouble(int index) {
+ return getInt(index);
+ }
+
+ @Override
+ public Object getObject(int index) {
+ return getInt(index);
}
@Override
- protected void setImpl(final int key, final double value) {
- setImpl(key, (int)Math.rint(value));
+ public ArrayData set(int index, Object value, boolean strict) {
+ return set(index, JSType.toNumber(value), strict);
+ }
+
+ @Override
+ public ArrayData set(int index, int value, boolean strict) {
+ setElem(index, value);
+ return this;
}
@Override
- protected void setImpl(final int key, final Object value) {
- setImpl(key, JSType.toNumber(value));
+ public ArrayData set(int index, long value, boolean strict) {
+ return set(index, (int)value, strict);
}
+
+ @Override
+ public ArrayData set(int index, double value, boolean strict) {
+ return set(index, rint(value), strict);
+ }
+
+ private static double rint(double rint) {
+ return (int)Math.rint(rint);
+ }
+
}
/**
@@ -110,7 +199,7 @@
*/
@Constructor(arity = 1)
public static Object constructor(final boolean newObj, final Object self, final Object... args) {
- return constructorImpl(args, FACTORY);
+ return constructorImpl(newObj, args, FACTORY);
}
NativeUint8ClampedArray(final NativeArrayBuffer buffer, final int byteOffset, final int length) {
@@ -118,11 +207,6 @@
}
@Override
- public String getClassName() {
- return "Uint8ClampedArray";
- }
-
- @Override
protected Factory factory() {
return FACTORY;
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/AccessorProperty.java Mon Mar 03 11:24:44 2014 +0100
@@ -184,13 +184,21 @@
* @param primitiveGetter
* @param primitiveSetter
*/
- protected AccessorProperty(final String key, final int flags, final int slot, final MethodHandle primitiveGetter, final MethodHandle primitiveSetter, final MethodHandle objectGetter, final MethodHandle objectSetter) {
+ protected AccessorProperty(
+ final String key,
+ final int flags,
+ final int slot,
+ final MethodHandle primitiveGetter,
+ final MethodHandle primitiveSetter,
+ final MethodHandle objectGetter,
+ final MethodHandle objectSetter) {
super(key, flags, slot);
assert getClass() != AccessorProperty.class;
this.primitiveGetter = primitiveGetter;
this.primitiveSetter = primitiveSetter;
this.objectGetter = objectGetter;
this.objectSetter = objectSetter;
+// setCurrentType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
initializeType();
}
@@ -357,13 +365,15 @@
*/
protected final void initializeType() {
Class<?> initialType = null;
- if (OBJECT_FIELDS_ONLY || isAlwaysObject()) {
+ if (OBJECT_FIELDS_ONLY) {
initialType = Object.class;
} else {
if (!canBeUndefined()) { //todo if !canBeUndefined it means that we have an exact initialType
initialType = int.class;
}
- info(getKey(), canBeUndefined() ? " can be undefined" : " is always defined");
+ if (shouldInstrument(getKey())) {
+ info(getKey(), canBeUndefined() ? " can be undefined" : " is always defined");
+ }
}
setCurrentType(initialType);
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/GlobalFunctions.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.runtime;
-import static jdk.nashorn.internal.runtime.JSType.digit;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
@@ -38,7 +37,13 @@
public final class GlobalFunctions {
/** Methodhandle to implementation of ECMA 15.1.2.2, parseInt */
- public static final MethodHandle PARSEINT = findOwnMH("parseInt", double.class, Object.class, Object.class, Object.class);
+ public static final MethodHandle PARSEINT = findOwnMH("parseInt", double.class, Object.class, Object.class, Object.class);
+
+ /** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
+ public static final MethodHandle PARSEINT_OI = findOwnMH("parseInt", double.class, Object.class, Object.class, int.class);
+
+ /** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
+ public static final MethodHandle PARSEINT_O = findOwnMH("parseInt", double.class, Object.class, Object.class);
/** Methodhandle to implementation of ECMA 15.1.2.3, parseFloat */
public static final MethodHandle PARSEFLOAT = findOwnMH("parseFloat", double.class, Object.class, Object.class);
@@ -78,19 +83,44 @@
/**
* ECMA 15.1.2.2 parseInt implementation
*
- * TODO: specialize
+ * @param self self reference
+ * @param string string to parse
+ * @param rad radix
+ *
+ * @return numeric type representing string contents as an int
+ */
+ public static double parseInt(final Object self, final Object string, final Object rad) {
+ return parseIntInternal(JSType.trimLeft(JSType.toString(string)), JSType.toInt32(rad));
+ }
+
+ /**
+ * ECMA 15.1.2.2 parseInt implementation specialized for int radix
*
* @param self self reference
* @param string string to parse
* @param rad radix
*
- * @return numeric type representing string contents as an int (TODO: specialize for int case)
+ * @return numeric type representing string contents as an int
*/
- //TODO specialize
- public static double parseInt(final Object self, final Object string, final Object rad) {
- final String str = JSType.trimLeft(JSType.toString(string));
- final int length = str.length();
- int radix = JSType.toInt32(rad);
+ public static double parseInt(final Object self, final Object string, final int rad) {
+ return parseIntInternal(JSType.trimLeft(JSType.toString(string)), rad);
+ }
+
+ /**
+ * ECMA 15.1.2.2 parseInt implementation specialized for no radix argument
+ *
+ * @param self self reference
+ * @param string string to parse
+ *
+ * @return numeric type representing string contents as an int
+ */
+ public static double parseInt(final Object self, final Object string) {
+ return parseIntInternal(JSType.trimLeft(JSType.toString(string)), 0);
+ }
+
+ private static double parseIntInternal(final String str, final int rad) {
+ final int length = str.length();
+ int radix = rad;
// empty string is not valid
if (length == 0) {
@@ -142,7 +172,7 @@
// we should see atleast one valid digit
boolean entered = false;
while (idx < length) {
- digit = digit(str.charAt(idx++), radix, true);
+ digit = fastDigit(str.charAt(idx++), radix);
if (digit < 0) {
break;
}
@@ -456,6 +486,20 @@
return ScriptRuntime.UNDEFINED;
}
+ private static int fastDigit(int ch, int radix) {
+ int n = -1;
+ if (ch >= '0' && ch <= '9') {
+ n = ch - '0';
+ } else if (radix > 10) {
+ if (ch >= 'a' && ch <= 'z') {
+ n = ch - 'a' + 10;
+ } else if (ch >= 'A' && ch <= 'Z') {
+ n = ch - 'A' + 10;
+ }
+ }
+ return n < radix ? n : -1;
+ }
+
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
return MH.findStatic(MethodHandles.lookup(), GlobalFunctions.class, name, MH.type(rtype, types));
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/NativeJavaPackage.java Mon Mar 03 11:24:44 2014 +0100
@@ -205,8 +205,8 @@
}
@Override
- protected Object invokeNoSuchProperty(final String name, final int programPoint) {
- final Object retval = createProperty(name);
+ protected Object invokeNoSuchProperty(final String key, final int programPoint) {
+ final Object retval = createProperty(key);
if (isValid(programPoint)) {
throw new UnwarrantedOptimismException(retval, programPoint);
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/Property.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/Property.java Mon Mar 03 11:24:44 2014 +0100
@@ -32,7 +32,6 @@
import java.lang.invoke.MethodHandle;
import java.util.Objects;
import jdk.nashorn.internal.codegen.ObjectClassGenerator;
-import jdk.nashorn.internal.codegen.types.Type;
/**
* This is the abstract superclass representing a JavaScript Property.
@@ -64,7 +63,7 @@
/** ECMA 8.6.1 - Is this property not configurable? */
public static final int NOT_CONFIGURABLE = 1 << 2;
- private static final int MODIFY_MASK = (NOT_WRITABLE | NOT_ENUMERABLE | NOT_CONFIGURABLE);
+ private static final int MODIFY_MASK = NOT_WRITABLE | NOT_ENUMERABLE | NOT_CONFIGURABLE;
/** Is this a function parameter? */
public static final int IS_PARAMETER = 1 << 3;
@@ -72,14 +71,11 @@
/** Is parameter accessed thru arguments? */
public static final int HAS_ARGUMENTS = 1 << 4;
- /** Is this property always represented as an Object? See {@link ObjectClassGenerator} and dual fields flag. */
- public static final int IS_ALWAYS_OBJECT = 1 << 5;
-
/** Can this property be undefined? */
- public static final int CAN_BE_UNDEFINED = 1 << 6;
+ public static final int CAN_BE_UNDEFINED = 1 << 5;
/** Is this a function declaration property ? */
- public static final int IS_FUNCTION_DECLARATION = 1 << 7;
+ public static final int IS_FUNCTION_DECLARATION = 1 << 6;
/**
* Is this is a primitive field given to us by Nasgen, i.e.
@@ -87,7 +83,7 @@
* is narrower than object, e.g. Math.PI which is declared
* as a double
*/
- public static final int IS_NASGEN_PRIMITIVE = 1 << 8;
+ public static final int IS_NASGEN_PRIMITIVE = 1 << 7;
/** Property key. */
private final String key;
@@ -290,6 +286,16 @@
}
/**
+ * Check if a flag is set for a property
+ * @param property property
+ * @param flag flag to check
+ * @return true if flag is set
+ */
+ public static boolean checkFlag(final Property property, final int flag) {
+ return (property.getFlags() & flag) == flag;
+ }
+
+ /**
* Get the flags for this property
* @return property flags
*/
@@ -609,17 +615,6 @@
}
/**
- * Check whether this Property is ever used as anything but an Object. If this is used only
- * as an object, dual fields mode need not even try to represent it as a primitive at any
- * callsite, saving map rewrites for performance.
- *
- * @return true if representation should always be an object field
- */
- public boolean isAlwaysObject() {
- return (flags & IS_ALWAYS_OBJECT) == IS_ALWAYS_OBJECT;
- }
-
- /**
* Check whether this property can be primitive. This is a conservative
* analysis result, so {@code true} might mean that it can still be
* defined, but it will never say that a property can not be undefined
--- a/nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/PropertyHashMap.java Mon Mar 03 11:24:44 2014 +0100
@@ -303,7 +303,7 @@
* @return The bin index.
*/
private static int binIndex(final Element[] bins, final String key) {
- return key.hashCode() & (bins.length - 1);
+ return key.hashCode() & bins.length - 1;
}
/**
@@ -315,7 +315,7 @@
*/
private static int binsNeeded(final int n) {
// 50% padding
- return 1 << (32 - Integer.numberOfLeadingZeros((n + (n >>> 1)) | (INITIAL_BINS - 1)));
+ return 1 << 32 - Integer.numberOfLeadingZeros(n + (n >>> 1) | INITIAL_BINS - 1);
}
/**
@@ -442,15 +442,11 @@
if (bins != null) {
final int binIndex = binIndex(bins, key);
Element bin = bins[binIndex];
- // System.err.println("oldBin = " + bin);
bin = replaceInList(bin, key, property);
- // System.err.println("newBin = " + bin);
bins[binIndex] = bin;
}
Element newList = list;
- //System.err.println("oldList = " + newList);
newList = replaceInList(newList, key, property);
- //System.err.println("newList = " + newList);
return new PropertyHashMap(size, bins, newList);
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Mon Mar 03 11:24:44 2014 +0100
@@ -118,6 +118,7 @@
* @param allocatorClassName name of our allocator class, will be looked up dynamically if used as a constructor
* @param allocatorMap allocator map to seed instances with, when constructing
* @param nestedFunctions nested function map
+ * @param sourceURL source URL
*/
public RecompilableScriptFunctionData(
final FunctionNode functionNode,
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunction.java Mon Mar 03 11:24:44 2014 +0100
@@ -469,6 +469,7 @@
final MethodType type = desc.getMethodType();
assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
final GuardedInvocation bestCtorInv = data.getBestConstructor(type);
+ //TODO - ClassCastException
return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this), bestCtorInv.getSwitchPoint());
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java Mon Mar 03 11:24:44 2014 +0100
@@ -37,6 +37,7 @@
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
+
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.nashorn.internal.runtime.linker.JavaAdapterFactory;
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
@@ -234,7 +235,6 @@
private MethodHandle createGenericInvoker() {
return makeGenericMethod(getGeneric().createComposableInvoker());
-// TODO hannes return code.generic().getInvoker();
}
final MethodHandle getGenericConstructor() {
@@ -298,7 +298,7 @@
final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(), getGenericConstructor());
boundList.add(bind(bindTarget, fn, self, allArgs));
- ScriptFunctionData boundData = new FinalScriptFunctionData(name, Math.max(0, getArity() - length), boundList, isStrict(), isBuiltin(), isConstructor(), isVariableArity());
+ final ScriptFunctionData boundData = new FinalScriptFunctionData(name, Math.max(0, getArity() - length), boundList, isStrict(), isBuiltin(), isConstructor(), isVariableArity());
return boundData;
}
@@ -381,7 +381,7 @@
} else {
// If target is already bound, insert additional bound arguments after "this" argument, at position 1.
final int argInsertPos = isTargetBound ? 1 : 0;
- final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount() - argInsertPos, args.length + (isTargetBound ? 0 : (needsCallee ? 2 : 1)))];
+ final Object[] boundArgs = new Object[Math.min(originalInvoker.type().parameterCount() - argInsertPos, args.length + (isTargetBound ? 0 : needsCallee ? 2 : 1))];
int next = 0;
if (!isTargetBound) {
if (needsCallee) {
@@ -463,7 +463,7 @@
*/
private static MethodHandle makeGenericMethod(final MethodHandle mh) {
final MethodType type = mh.type();
- MethodType newType = makeGenericType(type);
+ final MethodType newType = makeGenericType(type);
return type.equals(newType) ? mh : mh.asType(newType);
}
@@ -681,7 +681,7 @@
}
final Class<?> param0 = type.parameterType(0);
- return param0 == ScriptFunction.class || (param0 == boolean.class && length > 1 && type.parameterType(1) == ScriptFunction.class);
+ return param0 == ScriptFunction.class || param0 == boolean.class && length > 1 && type.parameterType(1) == ScriptFunction.class;
}
/**
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptLoader.java Mon Mar 03 11:24:44 2014 +0100
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime;
import java.security.CodeSource;
-import java.security.ProtectionDomain;
/**
* Responsible for loading script generated classes.
--- a/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/ScriptObject.java Mon Mar 03 11:24:44 2014 +0100
@@ -45,6 +45,7 @@
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
+import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -60,6 +61,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@@ -105,19 +107,19 @@
static final String NO_SUCH_PROPERTY_NAME = "__noSuchProperty__";
/** Per ScriptObject flag - is this a scope object? */
- public static final int IS_SCOPE = 0b0000_0001;
+ public static final int IS_SCOPE = 1 << 0;
/** Per ScriptObject flag - is this an array object? */
- public static final int IS_ARRAY = 0b0000_0010;
+ public static final int IS_ARRAY = 1 << 1;
/** Per ScriptObject flag - is this an arguments object? */
- public static final int IS_ARGUMENTS = 0b0000_0100;
+ public static final int IS_ARGUMENTS = 1 << 2;
/** Is this a prototype PropertyMap? */
- public static final int IS_PROTOTYPE = 0b0000_1000;
+ public static final int IS_PROTOTYPE = 1 << 3;
/** Is length property not-writable? */
- public static final int IS_LENGTH_NOT_WRITABLE = 0b0001_0000;
+ public static final int IS_LENGTH_NOT_WRITABLE = 1 << 4;
/**
* Spill growth rate - by how many elements does {@link ScriptObject#primitiveSpill} and
@@ -252,7 +254,7 @@
}
private static int alignUp(final int size, final int alignment) {
- return (((size) + ((alignment) - 1)) & ~((alignment) - 1));
+ return size + alignment - 1 & ~(alignment - 1);
}
/**
@@ -448,10 +450,10 @@
if (property instanceof UserAccessorProperty) {
return global.newAccessorDescriptor(
- (get != null) ?
+ get != null ?
get :
UNDEFINED,
- (set != null) ?
+ set != null ?
set :
UNDEFINED,
configurable,
@@ -921,7 +923,7 @@
final int slot = spillLength;
ensureSpillSize(spillLength); //arguments=slot0, caller=slot0
objectSpill[slot] = new UserAccessorProperty.Accessors(getter, setter);
- PropertyMap oldMap = getMap();
+ final PropertyMap oldMap = getMap();
Property newProperty;
PropertyMap newMap;
do {
@@ -1374,16 +1376,16 @@
*/
public ScriptObject preventExtensions() {
PropertyMap oldMap = getMap();
-
- while (true) {
- final PropertyMap newMap = getMap().preventExtensions();
-
- if (!compareAndSetMap(oldMap, newMap)) {
- oldMap = getMap();
- } else {
- return this;
- }
+ while (!compareAndSetMap(oldMap, getMap().preventExtensions())) {
+ oldMap = getMap();
}
+
+ //invalidate any fast array setters
+ final ArrayData array = getArray();
+ if (array != null) {
+ array.invalidateSetters();
+ }
+ return this;
}
/**
@@ -1394,7 +1396,7 @@
* @return true if array
*/
public static boolean isArray(final Object obj) {
- return (obj instanceof ScriptObject) && ((ScriptObject)obj).isArray();
+ return obj instanceof ScriptObject && ((ScriptObject)obj).isArray();
}
/**
@@ -1857,17 +1859,26 @@
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
- final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+ final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
+ final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+
if (request.isCallSiteUnstable() || hasWithScope()) {
return findMegaMorphicGetMethod(desc, name, "getMethod".equals(operator));
}
final FindProperty find = findProperty(name, true);
- MethodHandle methodHandle;
+ MethodHandle mh;
if (find == null) {
if (PROTO_PROPERTY_NAME.equals(name)) {
- return new GuardedInvocation(GETPROTO, null, null, ClassCastException.class);
+ return new GuardedInvocation(
+ GETPROTO,
+ explicitInstanceOfCheck ?
+ NashornGuards.getScriptObjectGuard() :
+ null,
+ null,
+ explicitInstanceOfCheck ?
+ null : ClassCastException.class);
}
switch (operator) {
@@ -1876,42 +1887,57 @@
case "getMethod":
return noSuchMethod(desc, request);
case "getElem":
- return createEmptyGetter(desc, name);
+ return createEmptyGetter(desc, explicitInstanceOfCheck, name);
default:
- throw new AssertionError(); // never invoked with any other operation
+ throw new AssertionError(operator); // never invoked with any other operation
}
}
final Class<?> returnType = desc.getMethodType().returnType();
- final Property property = find.getProperty();
+ final Property property = find.getProperty();
final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ?
NashornCallSiteDescriptor.getProgramPoint(desc) :
UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
- methodHandle = find.getGetter(returnType, programPoint);
-
+
+ mh = find.getGetter(returnType, programPoint);
+ //we never need a guard if noGuard is set
final boolean noGuard = OBJECT_FIELDS_ONLY && NashornCallSiteDescriptor.isFastScope(desc) && !property.canChangeType();
// getMap() is fine as we have the prototype switchpoint depending on where the property was found
- final MethodHandle guard = noGuard ? null : NashornGuards.getMapGuard(getMap());
-
- if (methodHandle != null) {
- assert methodHandle.type().returnType().equals(returnType) : "returntype mismatch for getter " + methodHandle.type().returnType() + " != " + returnType;
- if (find.isSelf()) {
- return new GuardedInvocation(methodHandle, guard, null, noGuard ? null : ClassCastException.class);
- }
-
- if (!property.hasGetterFunction(find.getOwner())) {
- // If not a scope bind to actual prototype as changing prototype will change the property map.
- // For scopes we install a filter that replaces the self object with the prototype owning the property.
- methodHandle = isScope() ?
- addProtoFilter(methodHandle, find.getProtoChainLength()) :
- bindTo(methodHandle, find.getOwner());
- }
- return new GuardedInvocation(methodHandle, guard, noGuard ? null : getMap().getProtoGetSwitchPoint(proto, name), noGuard ? null : ClassCastException.class);
+ final MethodHandle guard;
+ final Class<? extends Throwable> exception;
+ if (noGuard) {
+ guard = null;
+ exception = null;
+ } else {
+ guard = NashornGuards.getMapGuard(map, explicitInstanceOfCheck);
+ exception = explicitInstanceOfCheck ? null : ClassCastException.class;
}
- assert !NashornCallSiteDescriptor.isFastScope(desc);
- return new GuardedInvocation(Lookup.emptyGetter(returnType), guard, getMap().getProtoGetSwitchPoint(proto, name), ClassCastException.class);
+ assert noGuard == (guard == null);
+
+ if (mh == null) {
+ mh = Lookup.emptyGetter(returnType);
+ } else {
+ assert mh.type().returnType().equals(returnType) : "returntype mismatch for getter " + mh.type().returnType() + " != " + returnType;
+ if (find.isSelf()) {
+ return new GuardedInvocation(mh, guard, null, exception);
+ }
+
+ if (!property.hasGetterFunction(find.getOwner())) {
+ // If not a scope bind to actual prototype as changing prototype will change the property map.
+ // For scopes we install a filter that replaces the self object with the prototype owning the property.
+ mh = isScope() ? addProtoFilter(mh, find.getProtoChainLength()) : bindTo(mh, find.getOwner());
+ }
+ }
+
+ assert OBJECT_FIELDS_ONLY || guard != null : "we always need a map guard here";
+
+ return new GuardedInvocation(
+ mh,
+ guard,
+ getMap().getProtoGetSwitchPoint(proto, name),
+ exception);
}
private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
@@ -1939,10 +1965,11 @@
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findGetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) {
- final MethodType callType = desc.getMethodType();
- final Class<?> returnType = callType.returnType();
- final Class<?> returnClass = returnType.isPrimitive() ? returnType : Object.class;
- final Class<?> keyClass = callType.parameterType(1);
+ final MethodType callType = desc.getMethodType();
+ final Class<?> returnType = callType.returnType();
+ final Class<?> returnClass = returnType.isPrimitive() ? returnType : Object.class;
+ final Class<?> keyClass = callType.parameterType(1);
+ final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
final String name;
if (returnClass.isPrimitive()) {
@@ -1954,7 +1981,7 @@
}
final MethodHandle mh = findGetIndexMethodHandle(returnClass, name, keyClass, desc);
- return new GuardedInvocation(mh, null, null, ClassCastException.class);
+ return new GuardedInvocation(mh, NashornGuards.getScriptObjectGuard(explicitInstanceOfCheck), null, explicitInstanceOfCheck ? null : ClassCastException.class);
}
/**
@@ -1965,7 +1992,7 @@
* @param desc call site descriptor
* @return method handle for getter
*/
- protected MethodHandle findGetIndexMethodHandle(final Class<?> returnType, String name, final Class<?> elementType, final CallSiteDescriptor desc) {
+ protected MethodHandle findGetIndexMethodHandle(final Class<?> returnType, final String name, final Class<?> elementType, final CallSiteDescriptor desc) {
if (!returnType.isPrimitive()) {
return findOwnMH_V(getClass(), name, returnType, elementType);
}
@@ -1987,12 +2014,14 @@
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) {
- final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+ final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
if (request.isCallSiteUnstable() || hasWithScope()) {
return findMegaMorphicSetMethod(desc, name);
}
- final boolean scope = isScope();
+ final boolean scope = isScope();
+ final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
+
/*
* If doing property set on a scope object, we should stop proto search on the first
* non-scope object. Without this, for example, when assigning "toString" on global scope,
@@ -2006,7 +2035,7 @@
if (!scope && find != null && find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
// We should still check if inherited data property is not writable
if (isExtensible() && !find.getProperty().isWritable()) {
- return createEmptySetMethod(desc, "property.not.writable", false);
+ return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", false);
}
// Otherwise, forget the found property
find = null;
@@ -2015,27 +2044,35 @@
if (find != null) {
if (!find.getProperty().isWritable()) {
// Existing, non-writable property
- return createEmptySetMethod(desc, "property.not.writable", true);
+ return createEmptySetMethod(desc, explicitInstanceOfCheck, "property.not.writable", true);
}
} else {
if (PROTO_PROPERTY_NAME.equals(name)) {
- return new GuardedInvocation(SETPROTOCHECK, null, null, ClassCastException.class);
- } else if (! isExtensible()) {
- return createEmptySetMethod(desc, "object.non.extensible", false);
+ return new GuardedInvocation(
+ SETPROTOCHECK,
+ NashornGuards.getScriptObjectGuard(explicitInstanceOfCheck),
+ null,
+ explicitInstanceOfCheck ? null : ClassCastException.class);
+ } else if (!isExtensible()) {
+ return createEmptySetMethod(desc, explicitInstanceOfCheck, "object.non.extensible", false);
}
}
- return new SetMethodCreator(this, find, desc).createGuardedInvocation();
+ return new SetMethodCreator(this, find, desc, explicitInstanceOfCheck).createGuardedInvocation();
}
- private GuardedInvocation createEmptySetMethod(final CallSiteDescriptor desc, String strictErrorMessage, boolean canBeFastScope) {
- final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
- if (NashornCallSiteDescriptor.isStrict(desc)) {
- throw typeError(strictErrorMessage, name, ScriptRuntime.safeToString((this)));
- }
- assert canBeFastScope || !NashornCallSiteDescriptor.isFastScope(desc);
- final PropertyMap myMap = getMap();
- return new GuardedInvocation(Lookup.EMPTY_SETTER, NashornGuards.getMapGuard(myMap), myMap.getProtoGetSwitchPoint(proto, name), ClassCastException.class);
+ private GuardedInvocation createEmptySetMethod(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String strictErrorMessage, final boolean canBeFastScope) {
+ final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+ if (NashornCallSiteDescriptor.isStrict(desc)) {
+ throw typeError(strictErrorMessage, name, ScriptRuntime.safeToString(this));
+ }
+ assert canBeFastScope || !NashornCallSiteDescriptor.isFastScope(desc);
+ final PropertyMap myMap = getMap();
+ return new GuardedInvocation(
+ Lookup.EMPTY_SETTER,
+ NashornGuards.getMapGuard(myMap, explicitInstanceOfCheck),
+ myMap.getProtoGetSwitchPoint(proto, name),
+ explicitInstanceOfCheck ? null : ClassCastException.class);
}
@SuppressWarnings("unused")
@@ -2052,8 +2089,9 @@
}
private GuardedInvocation findMegaMorphicSetMethod(final CallSiteDescriptor desc, final String name) {
- final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
- final GuardedInvocation inv = findSetIndexMethod(getClass(), type, NashornCallSiteDescriptor.isStrict(desc));
+ final MethodType type = desc.getMethodType().insertParameterTypes(1, Object.class);
+ //never bother with ClassCastExceptionGuard for megamorphic callsites
+ final GuardedInvocation inv = findSetIndexMethod(getClass(), false, type, NashornCallSiteDescriptor.isStrict(desc));
return inv.replaceMethods(MH.insertArguments(inv.getInvocation(), 1, name), inv.getGuard());
}
@@ -2067,7 +2105,7 @@
* @return GuardedInvocation to be invoked at call site.
*/
protected GuardedInvocation findSetIndexMethod(final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
- return findSetIndexMethod(getClass(), desc.getMethodType(), NashornCallSiteDescriptor.isStrict(desc));
+ return findSetIndexMethod(getClass(), explicitInstanceOfCheck(desc, request), desc.getMethodType(), NashornCallSiteDescriptor.isStrict(desc));
}
/**
@@ -2078,15 +2116,15 @@
*
* @return GuardedInvocation to be invoked at call site.
*/
- private static GuardedInvocation findSetIndexMethod(final Class<? extends ScriptObject> clazz, final MethodType callType, final boolean isStrict) {
+ private static GuardedInvocation findSetIndexMethod(final Class<? extends ScriptObject> clazz, final boolean explicitInstanceOfCheck, final MethodType callType, final boolean isStrict) {
assert callType.parameterCount() == 3;
- final Class<?> keyClass = callType.parameterType(1);
- final Class<?> valueClass = callType.parameterType(2);
+ final Class<?> keyClass = callType.parameterType(1);
+ final Class<?> valueClass = callType.parameterType(2);
MethodHandle methodHandle = findOwnMH_V(clazz, "set", void.class, keyClass, valueClass, boolean.class);
methodHandle = MH.insertArguments(methodHandle, 3, isStrict);
- return new GuardedInvocation(methodHandle, null, null, ClassCastException.class);
+ return new GuardedInvocation(methodHandle, NashornGuards.getScriptObjectGuard(explicitInstanceOfCheck), null, explicitInstanceOfCheck ? null : ClassCastException.class);
}
/**
@@ -2104,17 +2142,26 @@
return noSuchProperty(desc, request);
}
+ final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
+
final Object value = getObjectValue(find);
- if (! (value instanceof ScriptFunction)) {
- return createEmptyGetter(desc, name);
+ if (!(value instanceof ScriptFunction)) {
+ return createEmptyGetter(desc, explicitInstanceOfCheck, name);
}
final ScriptFunction func = (ScriptFunction)value;
- final Object thiz = scopeCall && func.isStrict() ? ScriptRuntime.UNDEFINED : this;
+ final Object thiz = scopeCall && func.isStrict() ? ScriptRuntime.UNDEFINED : this;
// TODO: It'd be awesome if we could bind "name" without binding "this".
- return new GuardedInvocation(MH.dropArguments(MH.constant(ScriptFunction.class,
- func.makeBoundFunction(thiz, new Object[] { name })), 0, Object.class),
- NashornGuards.getMapGuard(getMap()), null, ClassCastException.class);
+ return new GuardedInvocation(
+ MH.dropArguments(
+ MH.constant(
+ ScriptFunction.class,
+ func.makeBoundFunction(thiz, new Object[] { name })),
+ 0,
+ Object.class),
+ NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck),
+ null,
+ explicitInstanceOfCheck ? null : ClassCastException.class);
}
/**
@@ -2125,9 +2172,9 @@
*/
@SuppressWarnings("null")
public GuardedInvocation noSuchProperty(final CallSiteDescriptor desc, final LinkRequest request) {
- final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
- final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
- final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
+ final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+ final FindProperty find = findProperty(NO_SUCH_PROPERTY_NAME, true);
+ final boolean scopeAccess = isScope() && NashornCallSiteDescriptor.isScope(desc);
if (find != null) {
final Object value = getObjectValue(find);
@@ -2145,9 +2192,15 @@
}
return new GuardedInvocation(
methodHandle,
- getKnownFunctionPropertyGuard(getMap(), find.getGetter(Object.class, INVALID_PROGRAM_POINT), find.getOwner(), func),
+ //TODO this always does a scriptobject check
+ getKnownFunctionPropertyGuard(
+ getMap(),
+ find.getGetter(Object.class, INVALID_PROGRAM_POINT),
+ find.getOwner(),
+ func),
find.isInherited() ? getMap().getProtoGetSwitchPoint(proto, NO_SUCH_PROPERTY_NAME) : null,
- ClassCastException.class);
+ //TODO this doesn't need a ClassCastException as guard always checks script object
+ null);
}
}
@@ -2155,12 +2208,13 @@
throw referenceError("not.defined", name);
}
- return createEmptyGetter(desc, name);
+ return createEmptyGetter(desc, explicitInstanceOfCheck(desc, request), name);
}
/**
* Invoke fall back if a property is not found.
* @param name Name of property.
+ * @param programPoint program point
* @return Result from call.
*/
protected Object invokeNoSuchProperty(final String name, final int programPoint) {
@@ -2204,11 +2258,19 @@
return ((ScriptFunction)value).makeBoundFunction(this, new Object[] {name});
}
- private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final String name) {
- if(NashornCallSiteDescriptor.isOptimistic(desc)) {
+ private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String name) {
+ if (NashornCallSiteDescriptor.isOptimistic(desc)) {
throw new UnwarrantedOptimismException(UNDEFINED, NashornCallSiteDescriptor.getProgramPoint(desc), Type.OBJECT);
}
- return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), NashornGuards.getMapGuard(getMap()), getMap().getProtoGetSwitchPoint(proto, name), ClassCastException.class);
+
+ return new GuardedInvocation(
+ Lookup.emptyGetter(
+ desc.getMethodType().returnType()),
+ NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck),
+ getMap().getProtoGetSwitchPoint(proto, name),
+ explicitInstanceOfCheck ?
+ null :
+ ClassCastException.class);
}
private abstract static class ScriptObjectIterator <T extends Object> implements Iterator<T> {
@@ -2284,8 +2346,8 @@
*/
private Property addSpillProperty(final String key, final int propertyFlags, final Object value, final boolean hasInitialValue) {
final PropertyMap propertyMap = getMap();
- final int fieldCount = propertyMap.getFieldCount();
- final int fieldMax = propertyMap.getFieldMaximum();
+ final int fieldCount = propertyMap.getFieldCount();
+ final int fieldMax = propertyMap.getFieldMaximum();
Property property;
if (fieldCount < fieldMax) {
@@ -2354,8 +2416,8 @@
final int callCount = callType.parameterCount();
final boolean isCalleeVarArg = parameterCount > 0 && methodType.parameterType(parameterCount - 1).isArray();
- final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : (callCount > 0 &&
- callType.parameterType(callCount - 1).isArray());
+ final boolean isCallerVarArg = callerVarArg != null ? callerVarArg.booleanValue() : callCount > 0 &&
+ callType.parameterType(callCount - 1).isArray();
if (isCalleeVarArg) {
return isCallerVarArg ?
@@ -2443,8 +2505,8 @@
if (newLength > arrayLength) {
setArray(getArray().ensure(newLength - 1));
- if (getArray().canDelete(arrayLength, (newLength - 1), false)) {
- setArray(getArray().delete(arrayLength, (newLength - 1)));
+ if (getArray().canDelete(arrayLength, newLength - 1, false)) {
+ setArray(getArray().delete(arrayLength, newLength - 1));
}
return;
}
@@ -2869,8 +2931,8 @@
private void doesNotHaveEnsureDelete(final long longIndex, final long oldLength, final boolean strict) {
if (longIndex > oldLength) {
ArrayData array = getArray();
- if (array.canDelete(oldLength, (longIndex - 1), strict)) {
- array = array.delete(oldLength, (longIndex - 1));
+ if (array.canDelete(oldLength, longIndex - 1, strict)) {
+ array = array.delete(oldLength, longIndex - 1);
}
setArray(array);
}
@@ -3306,7 +3368,7 @@
}
private boolean hasOwnArrayProperty(final int index) {
- return getArray().has(index) || (getMap().containsArrayKeys() && hasProperty(ArrayIndex.toKey(index), false));
+ return getArray().has(index) || getMap().containsArrayKeys() && hasProperty(ArrayIndex.toKey(index), false);
}
@Override
--- a/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/SetMethodCreator.java Mon Mar 03 11:24:44 2014 +0100
@@ -36,7 +36,6 @@
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
import jdk.nashorn.internal.runtime.linker.NashornGuards;
-
/**
* Instances of this class are quite ephemeral; they only exist for the duration of an invocation of
* {@link ScriptObject#findSetMethod(CallSiteDescriptor, jdk.internal.dynalink.linker.LinkRequest)} and
@@ -49,6 +48,7 @@
private final FindProperty find;
private final CallSiteDescriptor desc;
private final Class<?> type;
+ private final boolean explicitInstanceOfCheck;
/**
* Creates a new property setter method creator.
@@ -57,12 +57,13 @@
* want to create a setter for. Can be null if the property does not yet exist on the object.
* @param desc the descriptor of the call site that triggered the property setter lookup
*/
- SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc) {
+ SetMethodCreator(final ScriptObject sobj, final FindProperty find, final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck) {
this.sobj = sobj;
this.map = sobj.getMap();
this.find = find;
this.desc = desc;
this.type = desc.getMethodType().parameterType(1);
+ this.explicitInstanceOfCheck = explicitInstanceOfCheck;
}
@@ -118,7 +119,7 @@
}
private MethodHandle getGuard() {
- return needsNoGuard() ? null : NashornGuards.getMapGuard(getMap());
+ return needsNoGuard() ? null : NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck);
}
private boolean needsNoGuard() {
--- a/nashorn/src/jdk/nashorn/internal/runtime/SpillProperty.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/SpillProperty.java Mon Mar 03 11:24:44 2014 +0100
@@ -27,6 +27,7 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
import static jdk.nashorn.internal.lookup.Lookup.MH;
@@ -156,6 +157,7 @@
* @param flags the property flags
* @param slot spill slot
*/
+ @SuppressWarnings("unused")
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;
--- a/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/WithObject.java Mon Mar 03 11:24:44 2014 +0100
@@ -31,6 +31,7 @@
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
+
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
@@ -66,7 +67,6 @@
this.expression = expression;
}
-
/**
* Delete a property based on a key.
* @param key Any valid JavaScript value.
@@ -99,7 +99,7 @@
final boolean isNamedOperation;
final String name;
- if(desc.getNameTokenCount() > 2) {
+ if (desc.getNameTokenCount() > 2) {
isNamedOperation = true;
name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
} else {
@@ -114,7 +114,6 @@
if (find != null) {
link = self.lookup(desc, request);
-
if (link != null) {
return fixExpressionCallSite(ndesc, link);
}
@@ -239,21 +238,33 @@
private static GuardedInvocation fixExpressionCallSite(final NashornCallSiteDescriptor desc, final GuardedInvocation link) {
// If it's not a getMethod, just add an expression filter that converts WithObject in "this" position to its
// expression.
- if(!"getMethod".equals(desc.getFirstOperator())) {
+ if (!"getMethod".equals(desc.getFirstOperator())) {
return fixReceiverType(link, WITHEXPRESSIONFILTER).filterArguments(0, WITHEXPRESSIONFILTER);
}
- final MethodHandle linkInvocation = link.getInvocation();
- final MethodType linkType = linkInvocation.type();
- final boolean linkReturnsFunction = ScriptFunction.class.isAssignableFrom(linkType.returnType());
+ final MethodHandle linkInvocation = link.getInvocation();
+ final MethodType linkType = linkInvocation.type();
+ final boolean linkReturnsFunction = ScriptFunction.class.isAssignableFrom(linkType.returnType());
return link.replaceMethods(
// Make sure getMethod will bind the script functions it receives to WithObject.expression
- MH.foldArguments(linkReturnsFunction ? BIND_TO_EXPRESSION_FN : BIND_TO_EXPRESSION_OBJ,
- filterReceiver(linkInvocation.asType(linkType.changeReturnType(
- linkReturnsFunction ? ScriptFunction.class : Object.class).changeParameterType(0, ScriptObject.class)), WITHEXPRESSIONFILTER)),
- // No clever things for the guard -- it is still identically filtered.
- filterGuardReceiver(link, WITHEXPRESSIONFILTER));
+ MH.foldArguments(
+ linkReturnsFunction ?
+ BIND_TO_EXPRESSION_FN :
+ BIND_TO_EXPRESSION_OBJ,
+ filterReceiver(
+ linkInvocation.asType(
+ linkType.changeReturnType(
+ linkReturnsFunction ?
+ ScriptFunction.class :
+ Object.class).
+ changeParameterType(
+ 0,
+ ScriptObject.class)),
+ WITHEXPRESSIONFILTER)),
+ filterGuardReceiver(link, WITHEXPRESSIONFILTER));
+ // No clever things for the guard -- it is still identically filtered.
+
}
private GuardedInvocation fixScopeCallSite(final GuardedInvocation link, final String name) {
@@ -271,10 +282,20 @@
private static MethodHandle filterGuardReceiver(final GuardedInvocation link, final MethodHandle receiverFilter) {
final MethodHandle test = link.getGuard();
- return test == null ? null : filterReceiver(test, receiverFilter);
+ if (test == null) {
+ return null;
+ }
+
+ final Class<?> receiverType = test.type().parameterType(0);
+ final MethodHandle filter = MH.asType(receiverFilter,
+ receiverFilter.type().changeParameterType(0, receiverType).
+ changeReturnType(receiverType));
+
+ return filterReceiver(test, filter);
}
private static MethodHandle filterReceiver(final MethodHandle mh, final MethodHandle receiverFilter) {
+ //With expression filter == receiverFilter, i.e. receiver is cast to withobject and its expression returned
return MH.filterArguments(mh, 0, receiverFilter);
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java Mon Mar 03 11:24:44 2014 +0100
@@ -26,16 +26,16 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
-import static jdk.nashorn.internal.lookup.Lookup.MH;
-import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
-import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
+
import java.nio.ByteBuffer;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.types.Type;
-import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.runtime.GlobalObject;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
@@ -66,7 +66,7 @@
}*/
/** Minimum chunk size for underlying arrays */
- protected static final int CHUNK_SIZE = 16;
+ protected static final int CHUNK_SIZE = 32;
/** Mask for getting a chunk */
protected static final int CHUNK_MASK = CHUNK_SIZE - 1;
@@ -88,31 +88,6 @@
protected static final CompilerConstants.Call THROW_UNWARRANTED = staticCall(MethodHandles.lookup(), ArrayData.class, "throwUnwarranted", void.class, ArrayData.class, int.class, int.class);
/**
- * Unwarranted thrower
- *
- * @param data array data
- * @param programPoint program point
- * @param index array index
- */
- protected static void throwUnwarranted(final ArrayData data, final int programPoint, final int index) {
- throw new UnwarrantedOptimismException(data.getObject(index), programPoint);
- }
-
- /**
- * Version of has that throws a class cast exception if element does not exist
- * used for relinking
- *
- * @param index index to check - currently only int indexes
- * @return index
- */
- protected int throwHas(final int index) {
- if (!has(index)) {
- throw new ClassCastException();
- }
- return index;
- }
-
- /**
* Constructor
* @param length Virtual length of the array.
*/
@@ -129,40 +104,34 @@
}
/**
- * Return element getter for a {@link ContinuousArray}
- * @param getHas has getter
- * @param returnType return type
+ * Unwarranted thrower
+ *
+ * @param data array data
* @param programPoint program point
- * @return method handle for element setter
+ * @param index array index
*/
- protected final static MethodHandle getContinuousElementGetter(final MethodHandle getHas, final Class<?> returnType, final int programPoint) {
- final boolean isOptimistic = isValid(programPoint);
- final int fti = getAccessorTypeIndex(getHas.type().returnType());
- final int ti = getAccessorTypeIndex(returnType);
- MethodHandle mh = getHas;
+ protected static void throwUnwarranted(final ArrayData data, final int programPoint, final int index) {
+ throw new UnwarrantedOptimismException(data.getObject(index), programPoint);
+ }
- if (isOptimistic) {
- if (ti < fti) {
- mh = MH.insertArguments(ArrayData.THROW_UNWARRANTED.methodHandle(), 1, programPoint);
- }
- }
- mh = MH.asType(mh, mh.type().changeReturnType(returnType).changeParameterType(0, ContinuousArray.class));
-
- if (!isOptimistic) {
- //for example a & array[17];
- return Lookup.filterReturnType(mh, returnType);
- }
- return mh;
+ private static int alignUp(final int size) {
+ return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
}
/**
- * Return element setter for a {@link ContinuousArray}
- * @param setHas set has guard
- * @param elementType element type
- * @return method handle for element setter
+ * 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
*/
- protected final static MethodHandle getContinuousElementSetter(final MethodHandle setHas, final Class<?> elementType) {
- return MH.asType(setHas, setHas.type().changeParameterType(2, elementType).changeParameterType(0, ContinuousArray.class));
+ 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
+ */
+ public void invalidateSetters() {
+ //subclass responsibility
}
/**
@@ -598,6 +567,50 @@
}
/**
+ * Push an array of items to the end of the array
+ *
+ * @param strict are we in strict mode
+ * @param item the item
+ * @return new array data (or same)
+ */
+ public ArrayData push(final boolean strict, final Object item) {
+ return push(strict, new Object[] { item });
+ }
+
+ /**
+ * Push an array of items to the end of the array
+ *
+ * @param strict are we in strict mode
+ * @param item the item
+ * @return new array data (or same)
+ */
+ public ArrayData push(final boolean strict, final double item) {
+ return push(strict, item);
+ }
+
+ /**
+ * Push an array of items to the end of the array
+ *
+ * @param strict are we in strict mode
+ * @param item the item
+ * @return new array data (or same)
+ */
+ public ArrayData push(final boolean strict, final long item) {
+ return push(strict, item);
+ }
+
+ /**
+ * Push an array of items to the end of the array
+ *
+ * @param strict are we in strict mode
+ * @param item the item
+ * @return new array data (or same)
+ */
+ public ArrayData push(final boolean strict, final int item) {
+ return push(strict, item);
+ }
+
+ /**
* Pop an element from the end of the array
*
* @return the popped element
@@ -662,16 +675,7 @@
* @return next size to allocate for internal array
*/
protected static int nextSize(final int size) {
- if (size == 0) {
- return CHUNK_SIZE;
- }
-
- int i = size;
- while ((i & CHUNK_MASK) != 0) {
- i++;
- }
-
- return i << 1;
+ return alignUp(size + 1) * 2;
}
/**
@@ -696,4 +700,41 @@
}
}
+ /**
+ * Find a fast property getter if one exists
+ *
+ * @param clazz array data class
+ * @param desc callsite descriptor
+ * @param request link request
+ * @param operator operator
+ * @return fast property getter if one is found
+ */
+ public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+ return null;
+ }
+
+ /**
+ * Find a fast element getter if one exists
+ *
+ * @param clazz array data class
+ * @param desc callsite descriptor
+ * @param request link request
+ * @return fast index getter if one is found
+ */
+ public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
+ return null;
+ }
+
+ /**
+ * Find a fast element setter if one exists
+ *
+ * @param clazz array data class
+ * @param desc callsite descriptor
+ * @param request link request
+ * @return fast index getter if one is found
+ */
+ public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
+ return null;
+ }
+
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArray.java Wed Feb 26 13:17:57 2014 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +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.invoke.MethodHandle;
-
-/**
- * Interface implemented by all arrays that are directly accessible as underlying
- * native arrays
- */
-public interface ContinuousArray {
-
- /**
- * Return the guard used for the setter, usually some kind of {@link ArrayData#has}
- * @return guard handle for setters
- */
- public MethodHandle getSetGuard();
-
- /**
- * Return element getter for a certain type at a certain program point
- * @param returnType return type
- * @param programPoint program point
- * @return element getter or null if not supported (used to implement slow linkage instead
- * as fast isn't possible)
- */
- public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint);
-
- /**
- * Return element getter for a certain type at a certain program point
- * @param elementType element type
- * @return element setter or null if not supported (used to implement slow linkage instead
- * as fast isn't possible)
- */
- public MethodHandle getElementSetter(final Class<?> elementType);
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Mon Mar 03 11:24:44 2014 +0100
@@ -0,0 +1,284 @@
+/*
+ * 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 static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
+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;
+import java.lang.invoke.SwitchPoint;
+
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.DynamicLinker;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.lookup.Lookup;
+import jdk.nashorn.internal.runtime.DebugLogger;
+import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
+
+/**
+ * Interface implemented by all arrays that are directly accessible as underlying
+ * native arrays
+ */
+public abstract class ContinuousArrayData extends ArrayData {
+
+ /** Logger for array accessor linkage */
+ protected static DebugLogger LOG = new DebugLogger("arrays");
+
+ private SwitchPoint sp;
+
+ /**
+ * Constructor
+ * @param length length (elementLength)
+ */
+ protected ContinuousArrayData(final long length) {
+ 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
+ * allocated element
+ *
+ * @param index
+ * @return true if we don't need to do any array reallocation to fit an element at index
+ */
+ public final boolean hasRoomFor(final int index) {
+ return has(index) || (index == length() && ensure(index) == this);
+ }
+
+ /**
+ * Return element getter for a certain type at a certain program point
+ * @param returnType return type
+ * @param programPoint program point
+ * @return element getter or null if not supported (used to implement slow linkage instead
+ * as fast isn't possible)
+ */
+ public abstract MethodHandle getElementGetter(final Class<?> returnType, final int programPoint);
+
+ /**
+ * Return element getter for a certain type at a certain program point
+ * @param elementType element type
+ * @return element setter or null if not supported (used to implement slow linkage instead
+ * as fast isn't possible)
+ */
+ public abstract MethodHandle getElementSetter(final Class<?> elementType);
+
+ /**
+ * Version of has that throws a class cast exception if element does not exist
+ * used for relinking
+ *
+ * @param index index to check - currently only int indexes
+ * @return index
+ */
+ protected int throwHas(final int index) {
+ if (!has(index)) {
+ throw new ClassCastException();
+ }
+ return index;
+ }
+
+ /**
+ * 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
+ * @param programPoint program point
+ * @return array getter
+ */
+ protected final MethodHandle getContinuousElementGetter(final MethodHandle get, final Class<?> returnType, final int programPoint) {
+ return getContinuousElementGetter(getClass(), get, returnType, programPoint);
+ }
+
+ /**
+ * Look up a continuous array element setter
+ * @param set setter, sometimes combined with a has check that throws CCE on failure for relink
+ * @param returnType return type
+ * @return array setter
+ */
+ protected final MethodHandle getContinuousElementSetter(final MethodHandle set, final Class<?> returnType) {
+ return getContinuousElementSetter(getClass(), set, returnType);
+ }
+
+ /**
+ * Return element getter for a {@link ContinuousArrayData}
+ * @param clazz clazz for exact type guard
+ * @param getHas has getter
+ * @param returnType return type
+ * @param programPoint program point
+ * @return method handle for element setter
+ */
+ protected MethodHandle getContinuousElementGetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle getHas, final Class<?> returnType, final int programPoint) {
+ final boolean isOptimistic = isValid(programPoint);
+ final int fti = getAccessorTypeIndex(getHas.type().returnType());
+ final int ti = getAccessorTypeIndex(returnType);
+ MethodHandle mh = getHas;
+
+ if (isOptimistic) {
+ if (ti < fti) {
+ mh = MH.insertArguments(ArrayData.THROW_UNWARRANTED.methodHandle(), 1, programPoint);
+ }
+ }
+ mh = MH.asType(mh, mh.type().changeReturnType(returnType).changeParameterType(0, clazz));
+
+ if (!isOptimistic) {
+ //for example a & array[17];
+ return Lookup.filterReturnType(mh, returnType);
+ }
+ return mh;
+ }
+
+ /**
+ * Return element setter for a {@link ContinuousArrayData}
+ * @param clazz clazz for exact type guard
+ * @param setHas set has guard
+ * @param elementType element type
+ * @return method handle for element setter
+ */
+ protected MethodHandle getContinuousElementSetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle setHas, final Class<?> elementType) {
+ return MH.asType(setHas, setHas.type().changeParameterType(2, elementType).changeParameterType(0, clazz));
+ }
+
+ @Override
+ public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
+ return null;
+ }
+
+ /** Fast access guard - it is impractical for JIT performance reasons to use only CCE asType as guard :-(, also we need
+ the null case explicitly, which is the one that CCE doesn't handle */
+ protected static final MethodHandle FAST_ACCESS_GUARD =
+ MH.dropArguments(
+ staticCall(
+ MethodHandles.lookup(),
+ ContinuousArrayData.class,
+ "guard",
+ boolean.class,
+ Class.class,
+ ScriptObject.class).methodHandle(),
+ 2,
+ int.class);
+
+ @SuppressWarnings("unused")
+ private static final boolean guard(final Class<? extends ContinuousArrayData> clazz, final ScriptObject sobj) {
+ if (sobj != null && sobj.getArray().getClass() == clazz) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Return a fast linked array getter, or null if we have to dispatch to super class
+ * @param desc descriptor
+ * @param request link request
+ * @return invocation or null if needs to be sent to slow relink
+ */
+ @Override
+ public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) {
+ final MethodType callType = desc.getMethodType();
+ final Class<?> indexType = callType.parameterType(1);
+ final Class<?> returnType = callType.returnType();
+
+ if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) {
+ final Object[] args = request.getArguments();
+ final int index = (int)args[args.length - 1];
+
+ if (has(index)) {
+ final MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle();
+ final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT;
+ MethodHandle getElement = getElementGetter(returnType, programPoint);
+ if (getElement != null) {
+ getElement = MH.filterArguments(getElement, 0, MH.asType(getArray, getArray.type().changeReturnType(clazz)));
+ final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz);
+ return new GuardedInvocation(getElement, guard, null, ClassCastException.class);
+ }
+ }
+ }
+
+ if (LOG.isEnabled()) {
+ LOG.info(getClass().getSimpleName() + ": Missed fast GETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+ }
+
+ return null;
+ }
+
+ /**
+ * Return a fast linked array setter, or null if we have to dispatch to super class
+ * @param desc descriptor
+ * @param request link request
+ * @return invocation or null if needs to be sent to slow relink
+ */
+ @Override
+ public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
+ final MethodType callType = desc.getMethodType();
+ final Class<?> indexType = callType.parameterType(1);
+ final Class<?> elementType = callType.parameterType(2);
+
+ if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) {
+ 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)) {
+ 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
+ MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle();
+ 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
+ }
+ }
+ }
+
+ if (LOG.isEnabled()) {
+ LOG.info(getClass().getSimpleName() + ": Missed fast SETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+ }
+
+ return null;
+ }
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,7 +25,7 @@
package jdk.nashorn.internal.runtime.arrays;
-import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -39,7 +39,7 @@
* Implementation of {@link ArrayData} as soon as an int has been
* written to the array. This is the default data for new arrays
*/
-final class IntArrayData extends ArrayData implements ContinuousArray {
+final class IntArrayData extends ContinuousArrayData {
/**
* The wrapped array
*/
@@ -65,14 +65,8 @@
this.array = array;
}
- private static final MethodHandle HAS_GET_ELEM = virtualCall(MethodHandles.lookup(), IntArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", int.class, int.class).methodHandle();
- private static final MethodHandle SET_ELEM = virtualCall(MethodHandles.lookup(), IntArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, int.class).methodHandle();
- private static final MethodHandle HAS = virtualCall(MethodHandles.lookup(), IntArrayData.class, "has", boolean.class, int.class).methodHandle();
-
- @Override
- public final MethodHandle getSetGuard() {
- return HAS;
- }
+ private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", int.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, int.class).methodHandle();
private final static long UNSAFE_BASE = UNSAFE == null ? 0L : UNSAFE.arrayBaseOffset(int[].class);
private final static long UNSAFE_SCALE = UNSAFE == null ? 0L : UNSAFE.arrayIndexScale(int[].class);
@@ -95,12 +89,20 @@
@SuppressWarnings("unused")
private void setElemUnsafe(final int index, final int elem) {
- UNSAFE.putInt(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+ if (hasRoomFor(index)) {
+ UNSAFE.putInt(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+ return;
+ }
+ throw new ClassCastException();
}
@SuppressWarnings("unused")
private void setElem(final int index, final int elem) {
- array[index] = elem;
+ if (hasRoomFor(index)) {
+ array[index] = elem;
+ return;
+ }
+ throw new ClassCastException();
}
@Override
@@ -198,22 +200,15 @@
@Override
public ArrayData ensure(final long safeIndex) {
- if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= array.length) {
+ if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
return new SparseArrayData(this, safeIndex + 1);
}
-
- int newLength = array.length;
-
- while (newLength <= safeIndex) {
- newLength = ArrayData.nextSize(newLength);
- }
-
- if (array.length <= safeIndex) {
+ final int alen = array.length;
+ if (safeIndex >= alen) {
+ final int newLength = ArrayData.nextSize((int)safeIndex);
array = Arrays.copyOf(array, newLength);
}
-
setLength(safeIndex + 1);
-
return this;
}
@@ -337,20 +332,31 @@
@Override
public ArrayData slice(final long from, final long to) {
- final long start = from < 0 ? (from + length()) : from;
+ final long start = from < 0 ? from + length() : from;
final long newLength = to - start;
return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
@Override
+ public final ArrayData push(final boolean strict, final int item) {
+ final long length = length();
+ final ArrayData newData = ensure(length);
+ if (newData == this) {
+ array[(int)length] = item;
+ return this;
+ }
+ return newData.set((int)length, item, strict);
+ }
+
+ @Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
final long oldLength = length();
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
}
- final ArrayData returnValue = (removed == 0) ?
+ final ArrayData returnValue = removed == 0 ?
EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
if (newLength != oldLength) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Mon Mar 03 11:24:44 2014 +0100
@@ -26,7 +26,7 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.lookup.Lookup.MH;
-import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -40,7 +40,7 @@
* Implementation of {@link ArrayData} as soon as a long has been
* written to the array
*/
-final class LongArrayData extends ArrayData implements ContinuousArray {
+final class LongArrayData extends ContinuousArrayData {
/**
* The wrapped array
*/
@@ -128,22 +128,15 @@
@Override
public ArrayData ensure(final long safeIndex) {
- if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= array.length) {
+ if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
return new SparseArrayData(this, safeIndex + 1);
}
-
- int newLength = array.length;
-
- while (newLength <= safeIndex) {
- newLength = ArrayData.nextSize(newLength);
- }
-
- if (array.length <= safeIndex) {
+ final int alen = array.length;
+ if (safeIndex >= alen) {
+ final int newLength = ArrayData.nextSize((int)safeIndex);
array = Arrays.copyOf(array, newLength);
}
-
setLength(safeIndex + 1);
-
return this;
}
@@ -195,18 +188,12 @@
return Type.LONG;
}
- private static final MethodHandle HAS_GET_ELEM = virtualCall(MethodHandles.lookup(), LongArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", long.class, int.class).methodHandle();
- private static final MethodHandle SET_ELEM = virtualCall(MethodHandles.lookup(), LongArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, long.class).methodHandle();
- private static final MethodHandle HAS = virtualCall(MethodHandles.lookup(), LongArrayData.class, "has", boolean.class, int.class).methodHandle();
+ private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", long.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), LongArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, long.class).methodHandle();
private final static long UNSAFE_BASE = UNSAFE == null ? 0L : UNSAFE.arrayBaseOffset(long[].class);
private final static long UNSAFE_SCALE = UNSAFE == null ? 0L : UNSAFE.arrayIndexScale(long[].class);
- @Override
- public final MethodHandle getSetGuard() {
- return HAS;
- }
-
@SuppressWarnings("unused")
private long getElemUnsafe(final int index) {
if (has(index)) {
@@ -225,12 +212,20 @@
@SuppressWarnings("unused")
private void setElemUnsafe(final int index, final long elem) {
- UNSAFE.putLong(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+ if (hasRoomFor(index)) {
+ UNSAFE.putLong(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+ return;
+ }
+ throw new ClassCastException();
}
@SuppressWarnings("unused")
private void setElem(final int index, final long elem) {
- array[index] = elem;
+ if (hasRoomFor(index)) {
+ array[index] = elem;
+ return;
+ }
+ throw new ClassCastException();
}
@Override
@@ -243,7 +238,7 @@
@Override
public MethodHandle getElementSetter(final Class<?> elementType) {
- return (elementType == int.class || elementType == long.class) ? getContinuousElementSetter(MH.asType(SET_ELEM, SET_ELEM.type().changeParameterType(2, elementType)), elementType) : null;
+ return elementType == int.class || elementType == long.class ? getContinuousElementSetter(MH.asType(SET_ELEM, SET_ELEM.type().changeParameterType(2, elementType)), elementType) : null;
}
@Override
@@ -307,19 +302,30 @@
@Override
public ArrayData slice(final long from, final long to) {
- final long start = from < 0 ? (from + length()) : from;
+ final long start = from < 0 ? from + length() : from;
final long newLength = to - start;
return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
@Override
+ public final ArrayData push(final boolean strict, final long item) {
+ final long length = length();
+ final ArrayData newData = ensure(length);
+ if (newData == this) {
+ array[(int)length] = item;
+ return this;
+ }
+ return newData.set((int)length, item, strict);
+ }
+
+ @Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
final long oldLength = length();
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
}
- final ArrayData returnValue = (removed == 0) ?
+ final ArrayData returnValue = removed == 0 ?
EMPTY_ARRAY : new LongArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
if (newLength != oldLength) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Mon Mar 03 11:24:44 2014 +0100
@@ -26,7 +26,7 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
@@ -39,7 +39,7 @@
* Implementation of {@link ArrayData} as soon as a double has been
* written to the array
*/
-final class NumberArrayData extends ArrayData implements ContinuousArray {
+final class NumberArrayData extends ContinuousArrayData {
/**
* The wrapped array
*/
@@ -111,24 +111,17 @@
@Override
public ArrayData ensure(final long safeIndex) {
- if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= array.length) {
+ if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
return new SparseArrayData(this, safeIndex + 1);
}
-
- int newLength = array.length;
-
- while (newLength <= safeIndex) {
- newLength = ArrayData.nextSize(newLength);
+ final int alen = array.length;
+ if (safeIndex >= alen) {
+ final int newLength = ArrayData.nextSize((int)safeIndex);
+ array = Arrays.copyOf(array, newLength); //todo fill with nan or never accessed?
}
+ setLength(safeIndex + 1);
+ return this;
- if (array.length <= safeIndex) {
- array = Arrays.copyOf(array, newLength);
- Arrays.fill(array, (int) length(), newLength, Double.NaN);
- }
-
- setLength(safeIndex + 1);
-
- return this;
}
@Override
@@ -175,18 +168,12 @@
return Type.NUMBER;
}
- private static final MethodHandle HAS_GET_ELEM = virtualCall(MethodHandles.lookup(), NumberArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", double.class, int.class).methodHandle();
- private static final MethodHandle SET_ELEM = virtualCall(MethodHandles.lookup(), NumberArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, double.class).methodHandle();
- private static final MethodHandle HAS = virtualCall(MethodHandles.lookup(), NumberArrayData.class, "has", boolean.class, int.class).methodHandle();
+ private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", double.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), NumberArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, double.class).methodHandle();
private final static long UNSAFE_BASE = UNSAFE == null ? 0L : UNSAFE.arrayBaseOffset(double[].class);
private final static long UNSAFE_SCALE = UNSAFE == null ? 0L : UNSAFE.arrayIndexScale(double[].class);
- @Override
- public final MethodHandle getSetGuard() {
- return HAS;
- }
-
@SuppressWarnings("unused")
private double getElemUnsafe(final int index) {
if (has(index)) {
@@ -205,12 +192,20 @@
@SuppressWarnings("unused")
private void setElemUnsafe(final int index, final double elem) {
- UNSAFE.putDouble(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+ if (hasRoomFor(index)) {
+ UNSAFE.putDouble(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+ return;
+ }
+ throw new ClassCastException();
}
@SuppressWarnings("unused")
private void setElem(final int index, final double elem) {
- array[index] = elem;
+ if (hasRoomFor(index)) {
+ array[index] = elem;
+ return;
+ }
+ throw new ClassCastException();
}
@Override
@@ -281,19 +276,30 @@
@Override
public ArrayData slice(final long from, final long to) {
- final long start = from < 0 ? (from + length()) : from;
+ final long start = from < 0 ? from + length() : from;
final long newLength = to - start;
return new NumberArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
@Override
+ public final ArrayData push(final boolean strict, final double item) {
+ final long length = length();
+ final ArrayData newData = ensure(length);
+ if (newData == this) {
+ array[(int)length] = item;
+ return this;
+ }
+ return newData.set((int)length, item, strict);
+ }
+
+ @Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
final long oldLength = length();
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
}
- final ArrayData returnValue = (removed == 0) ?
+ final ArrayData returnValue = removed == 0 ?
EMPTY_ARRAY : new NumberArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
if (newLength != oldLength) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Mon Mar 03 11:24:44 2014 +0100
@@ -25,7 +25,7 @@
package jdk.nashorn.internal.runtime.arrays;
-import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCall;
+import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
@@ -39,7 +39,7 @@
* Implementation of {@link ArrayData} as soon as an Object has been
* written to the array
*/
-final class ObjectArrayData extends ArrayData implements ContinuousArray {
+final class ObjectArrayData extends ContinuousArrayData {
/**
* The wrapped array
@@ -98,23 +98,15 @@
@Override
public ArrayData ensure(final long safeIndex) {
- if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= array.length) {
+ if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH) {
return new SparseArrayData(this, safeIndex + 1);
}
-
- int newLength = array.length;
-
- while (newLength <= safeIndex) {
- newLength = ArrayData.nextSize(newLength);
+ final int alen = array.length;
+ if (safeIndex >= alen) {
+ final int newLength = ArrayData.nextSize((int)safeIndex);
+ array = Arrays.copyOf(array, newLength); //fill with undefined or OK? TODO
}
-
- if (array.length <= safeIndex) {
- array = Arrays.copyOf(array, newLength);
- Arrays.fill(array, (int) length(), newLength, ScriptRuntime.UNDEFINED);
- }
-
setLength(safeIndex + 1);
-
return this;
}
@@ -169,18 +161,12 @@
return Type.OBJECT;
}
- private static final MethodHandle HAS_GET_ELEM = virtualCall(MethodHandles.lookup(), ObjectArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", Object.class, int.class).methodHandle();
- private static final MethodHandle SET_ELEM = virtualCall(MethodHandles.lookup(), ObjectArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, Object.class).methodHandle();
- private static final MethodHandle HAS = virtualCall(MethodHandles.lookup(), ObjectArrayData.class, "has", boolean.class, int.class).methodHandle();
+ private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, UNSAFE == null ? "getElem" : "getElemUnsafe", Object.class, int.class).methodHandle();
+ private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), ObjectArrayData.class, UNSAFE == null ? "setElem" : "setElemUnsafe", void.class, int.class, Object.class).methodHandle();
private final static long UNSAFE_BASE = UNSAFE == null ? 0L : UNSAFE.arrayBaseOffset(Object[].class);
private final static long UNSAFE_SCALE = UNSAFE == null ? 0L : UNSAFE.arrayIndexScale(Object[].class);
- @Override
- public final MethodHandle getSetGuard() {
- return HAS;
- }
-
@SuppressWarnings("unused")
private Object getElemUnsafe(final int index) {
if (has(index)) {
@@ -199,12 +185,20 @@
@SuppressWarnings("unused")
private void setElemUnsafe(final int index, final Object elem) {
- UNSAFE.putObject(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+ if (hasRoomFor(index)) {
+ UNSAFE.putObject(array, UNSAFE_BASE + UNSAFE_SCALE * index, elem);
+ return;
+ }
+ throw new ClassCastException();
}
@SuppressWarnings("unused")
private void setElem(final int index, final Object elem) {
- array[index] = elem;
+ if (hasRoomFor(index)) {
+ array[index] = elem;
+ return;
+ }
+ throw new ClassCastException();
}
@Override
@@ -273,19 +267,30 @@
@Override
public ArrayData slice(final long from, final long to) {
- final long start = from < 0 ? (from + length()) : from;
+ final long start = from < 0 ? from + length() : from;
final long newLength = to - start;
return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
}
@Override
+ public ArrayData push(final boolean strict, final Object item) {
+ final long length = length();
+ final ArrayData newData = ensure(length);
+ if (newData == this) {
+ array[(int)length] = item;
+ return this;
+ }
+ return newData.set((int)length, item, strict);
+ }
+
+ @Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
final long oldLength = length();
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
}
- final ArrayData returnValue = (removed == 0) ?
+ final ArrayData returnValue = removed == 0 ?
EMPTY_ARRAY : new ObjectArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
if (newLength != oldLength) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java Mon Mar 03 11:24:44 2014 +0100
@@ -0,0 +1,215 @@
+/*
+ * 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 static jdk.nashorn.internal.lookup.Lookup.MH;
+
+import java.lang.invoke.MethodHandle;
+import java.nio.Buffer;
+
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.DynamicLinker;
+import jdk.internal.dynalink.linker.GuardedInvocation;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.lookup.Lookup;
+
+/**
+ * The superclass of all ArrayData used by TypedArrays
+ *
+ * @param <T> buffer implementation
+ */
+public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayData {
+
+ /** wrapped native buffer */
+ protected final T nb;
+
+ /**
+ * Constructor
+ * @param nb wrapped native buffer
+ * @param elementLength length in elements
+ */
+ protected TypedArrayData(final T nb, final int elementLength) {
+ super(elementLength); //TODO is this right?
+ this.nb = nb;
+ }
+
+ /**
+ * Length in elements. Accessed from {@code ArrayBufferView}
+ * @return element length
+ */
+ public final int getElementLength() {
+ return (int)length();
+ }
+
+ /**
+ * Is this an unsigned array data?
+ * @return true if unsigned
+ */
+ public boolean isUnsigned() {
+ return false;
+ }
+
+ /**
+ * Is this a clamped array data?
+ * @return true if clamped
+ */
+ public boolean isClamped() {
+ return false;
+ }
+
+ @Override
+ public boolean canDelete(final int index, final boolean strict) {
+ return false;
+ }
+
+ @Override
+ public boolean canDelete(final long fromIndex, final long toIndex, final boolean strict) {
+ return false;
+ }
+
+ @Override
+ public ArrayData copy() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object[] asObjectArray() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void shiftLeft(int by) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ArrayData shiftRight(int by) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ArrayData ensure(long safeIndex) {
+ return this;
+ }
+
+ @Override
+ public ArrayData shrink(long newLength) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public final boolean has(final int index) {
+ return 0 <= index && index < length();
+ }
+
+ @Override
+ public ArrayData delete(int index) {
+ return this;
+ }
+
+ @Override
+ public ArrayData delete(long fromIndex, long toIndex) {
+ return this;
+ }
+
+ @Override
+ protected ArrayData convert(Class<?> type) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object pop() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ArrayData slice(long from, long to) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Element getter method handle
+ * @return getter
+ */
+ protected abstract MethodHandle getGetElem();
+
+ /**
+ * Element setter method handle
+ * @return setter
+ */
+ protected abstract MethodHandle getSetElem();
+
+ @Override
+ public MethodHandle getElementGetter(final Class<?> returnType, final int programPoint) {
+ final MethodHandle getter = getContinuousElementGetter(getClass(), getGetElem(), returnType, programPoint);
+ if (getter != null) {
+ return Lookup.filterReturnType(getter, returnType);
+ }
+ return getter;
+ }
+
+ @Override
+ public MethodHandle getElementSetter(final Class<?> elementType) {
+ return getContinuousElementSetter(getClass(), Lookup.filterArgumentType(getSetElem(), 2, elementType), elementType);
+ }
+
+ @Override
+ protected MethodHandle getContinuousElementSetter(final Class<? extends ContinuousArrayData> clazz, final MethodHandle setHas, final Class<?> elementType) {
+ final MethodHandle mh = Lookup.filterArgumentType(setHas, 2, elementType);
+ return MH.asType(mh, mh.type().changeParameterType(0, clazz));
+ }
+
+ @Override
+ public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) {
+ final GuardedInvocation inv = super.findFastGetIndexMethod(clazz, desc, request);
+
+ if (inv != null) {
+ return inv;
+ }
+
+ if (LOG.isEnabled()) {
+ LOG.info(clazz.getSimpleName() + ": Missed fast GETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+ }
+
+ return null;
+ }
+
+ @Override
+ public GuardedInvocation findFastSetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { // array, index, value
+ final GuardedInvocation inv = super.findFastSetIndexMethod(clazz, desc, request);
+
+ if (inv != null) {
+ return inv;
+ }
+
+ if (LOG.isEnabled()) {
+ LOG.info(clazz.getSimpleName() + ": Missed fast SETTER " + clazz.getSimpleName() + " " + desc + " " + " line:" + DynamicLinker.getLinkedCallSiteLocation().getLineNumber());
+ }
+
+ return null;
+ }
+
+}
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Mon Mar 03 11:24:44 2014 +0100
@@ -164,7 +164,7 @@
final StaticClass adapterClass = getAdapterClassFor(new Class<?>[] { targetType }, null, lookup);
return MH.bindTo(Bootstrap.getLinkerServices().getGuardedInvocation(new LinkRequestImpl(
NashornCallSiteDescriptor.get(lookup, "dyn:new",
- MethodType.methodType(targetType, StaticClass.class, sourceType), 0), null, false,
+ MethodType.methodType(targetType, StaticClass.class, sourceType), 0), null, 0, false,
adapterClass, null)).getInvocation(), adapterClass);
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java Mon Mar 03 11:24:44 2014 +0100
@@ -43,6 +43,7 @@
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+
import jdk.internal.dynalink.ChainedCallSite;
import jdk.internal.dynalink.DynamicLinker;
import jdk.internal.dynalink.linker.GuardedInvocation;
@@ -63,6 +64,9 @@
private static final String PROFILEFILE = Options.getStringProperty("nashorn.profilefile", "NashornProfile.txt");
private static final MethodHandle INCREASE_MISS_COUNTER = MH.findStatic(MethodHandles.lookup(), LinkerCallSite.class, "increaseMissCount", MH.type(Object.class, String.class, Object.class));
+ private static final MethodHandle ON_CATCH_INVALIDATION = MH.findStatic(MethodHandles.lookup(), LinkerCallSite.class, "onCatchInvalidation", MH.type(ChainedCallSite.class, LinkerCallSite.class));
+
+ private int catchInvalidations;
LinkerCallSite(final NashornCallSiteDescriptor descriptor) {
super(descriptor);
@@ -71,6 +75,34 @@
}
}
+ @Override
+ protected MethodHandle getPruneCatches() {
+ return MH.filterArguments(super.getPruneCatches(), 0, ON_CATCH_INVALIDATION);
+ }
+
+ /**
+ * Action to perform when a catch guard around a callsite triggers. Increases
+ * catch invalidation counter
+ * @param callSite callsite
+ * @return the callsite, so this can be used as argument filter
+ */
+ @SuppressWarnings("unused")
+ private static ChainedCallSite onCatchInvalidation(final LinkerCallSite callSite) {
+ ++callSite.catchInvalidations;
+ return callSite;
+ }
+
+ /**
+ * Get the number of catch invalidations that have happened at this call site so far
+ * @param callSiteToken call site token, unique to the callsite.
+ * @return number of catch invalidations, i.e. thrown exceptions caught by the linker
+ */
+ public static int getCatchInvalidationCount(final Object callSiteToken) {
+ if (callSiteToken instanceof LinkerCallSite) {
+ return ((LinkerCallSite)callSiteToken).catchInvalidations;
+ }
+ return 0;
+ }
/**
* Construct a new linker call site.
* @param name Name of method.
@@ -78,8 +110,7 @@
* @param flags Call site specific flags.
* @return New LinkerCallSite.
*/
- static LinkerCallSite newLinkerCallSite(final MethodHandles.Lookup lookup, final String name, final MethodType type,
- final int flags) {
+ static LinkerCallSite newLinkerCallSite(final MethodHandles.Lookup lookup, final String name, final MethodType type, final int flags) {
final NashornCallSiteDescriptor desc = NashornCallSiteDescriptor.get(lookup, name, type, flags);
if (desc.isProfile()) {
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornGuards.java Mon Mar 03 11:24:44 2014 +0100
@@ -30,30 +30,73 @@
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.internal.runtime.PropertyMap;
+import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.options.Options;
/**
* Constructor of method handles used to guard call sites.
*/
public final class NashornGuards {
- private static final MethodHandle IS_MAP = findOwnMH("isMap", boolean.class, ScriptObject.class, PropertyMap.class);
- private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class);
+ private static final MethodHandle IS_MAP = findOwnMH("isMap", boolean.class, ScriptObject.class, PropertyMap.class);
+ private static final MethodHandle IS_MAP_SCRIPTOBJECT = findOwnMH("isMap", boolean.class, Object.class, PropertyMap.class);
+ private static final MethodHandle IS_INSTANCEOF_2 = findOwnMH("isInstanceOf2", boolean.class, Object.class, Class.class, Class.class);
+ private static final MethodHandle IS_SCRIPTOBJECT = findOwnMH("isScriptObject", boolean.class, Object.class);
+
+ private static final boolean CCE_ONLY = Options.getBooleanProperty("nashorn.cce");
// don't create me!
private NashornGuards() {
}
/**
+ * Given a callsite descriptor and a link request, determine whether we should use an instanceof
+ * check explicitly for the guard if needed, or if we should link it with a try/catch ClassCastException
+ * combinator as its relink criteria - i.e. relink when CCE is thrown.
+ *
+ * @param desc callsite descriptor
+ * @param request link request
+ * @return true of explicit instanceof check is needed
+ */
+ public static boolean explicitInstanceOfCheck(final CallSiteDescriptor desc, final LinkRequest request) {
+ //THIS is currently true, as the inliner encounters several problems with sun.misc.ValueConversions.castReference
+ //otherwise. We should only use the exception based relink where we have no choice, and the result is faster code,
+ //for example in the NativeArray, TypedArray, ContinuousArray getters. For the standard callsite, it appears that
+ //we lose performance rather than gain it, due to JVM issues. :-(
+ return !CCE_ONLY;
+ }
+
+ /**
+ * Returns a guard that does an instanceof ScriptObject check on the receiver
+ * @return guard
+ */
+ public static MethodHandle getScriptObjectGuard() {
+ return IS_SCRIPTOBJECT;
+ }
+
+ /**
+ * Returns a guard that does an instanceof ScriptObject check on the receiver
+ * @param explicitInstanceOfCheck - if false, then this is a nop, because it's all the guard does
+ * @return guard
+ */
+ public static MethodHandle getScriptObjectGuard(final boolean explicitInstanceOfCheck) {
+ return explicitInstanceOfCheck ? IS_SCRIPTOBJECT : null;
+ }
+
+ /**
* Get the guard that checks if a {@link PropertyMap} is equal to
* a known map, using reference comparison
*
+ * @param explicitInstanceOfCheck true if we should do an explicit script object instanceof check instead of just casting
* @param map The map to check against. This will be bound to the guard method handle
*
* @return method handle for guard
*/
- public static MethodHandle getMapGuard(final PropertyMap map) {
- return MH.insertArguments(IS_MAP, 1, map);
+ public static MethodHandle getMapGuard(final PropertyMap map, final boolean explicitInstanceOfCheck) {
+ return MH.insertArguments(explicitInstanceOfCheck ? IS_MAP_SCRIPTOBJECT : IS_MAP, 1, map);
}
/**
@@ -68,17 +111,37 @@
}
@SuppressWarnings("unused")
+ private static boolean isScriptObject(final Object self) {
+ return self instanceof ScriptObject;
+ }
+
+ @SuppressWarnings("unused")
+ private static boolean isScriptObject(final Class<? extends ScriptObject> clazz, final Object self) {
+ return clazz.isInstance(self);
+ }
+
+ @SuppressWarnings("unused")
private static boolean isMap(final ScriptObject self, final PropertyMap map) {
return self.getMap() == map;
}
@SuppressWarnings("unused")
+ private static boolean isMap(final Object self, final PropertyMap map) {
+ return self instanceof ScriptObject && ((ScriptObject)self).getMap() == map;
+ }
+
+
+ @SuppressWarnings("unused")
private static boolean isInstanceOf2(final Object self, final Class<?> class1, final Class<?> class2) {
return class1.isInstance(self) || class2.isInstance(self);
}
+ @SuppressWarnings("unused")
+ private static boolean isScriptFunction(final Object self) {
+ return self instanceof ScriptFunction;
+ }
+
private static MethodHandle findOwnMH(final String name, final Class<?> rtype, final Class<?>... types) {
return MH.findStatic(MethodHandles.lookup(), NashornGuards.class, name, MH.type(rtype, types));
}
-
}
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/NashornLinker.java Mon Mar 03 11:24:44 2014 +0100
@@ -101,7 +101,7 @@
} else if (self instanceof Undefined) {
inv = Undefined.lookup(desc);
} else {
- throw new AssertionError(); // Should never reach here.
+ throw new AssertionError(self.getClass().getName()); // Should never reach here.
}
return inv;
--- a/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/src/jdk/nashorn/internal/runtime/resources/Messages.properties Mon Mar 03 11:24:44 2014 +0100
@@ -138,6 +138,8 @@
type.error.method.not.constructor=Java method {0} can't be used as a constructor.
type.error.env.not.object=$ENV must be an Object.
type.error.unsupported.java.to.type=Unsupported Java.to target type {0}.
+type.error.constructor.requires.new=Constructor {0} requires 'new'.
+
range.error.inappropriate.array.length=inappropriate array length: {0}
range.error.inappropriate.array.buffer.length=inappropriate array buffer length: {0}
range.error.invalid.fraction.digits=fractionDigits argument to {0} must be in [0, 20]
--- a/nashorn/test/examples/string-micro.js Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/test/examples/string-micro.js Mon Mar 03 11:24:44 2014 +0100
@@ -46,12 +46,18 @@
str[2];
});
-bench("fromCharCode", function() {
+bench("fromCharCode 1", function() {
String.fromCharCode(97);
String.fromCharCode(98);
String.fromCharCode(99);
});
+bench("fromCharCode 2", function() {
+ String.fromCharCode(97, 98);
+ String.fromCharCode(97, 98, 99);
+ String.fromCharCode(97, 98, 99, 100);
+});
+
bench("charAt 1", function() {
str.charAt(0);
str.charAt(1);
--- a/nashorn/test/script/basic/JDK-8020357.js Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/test/script/basic/JDK-8020357.js Mon Mar 03 11:24:44 2014 +0100
@@ -35,7 +35,7 @@
// A value over the limit should throw a RangeError.
try {
- Int32Array(limit)
+ new Int32Array(limit)
} catch(e) {
print(e)
}
--- a/nashorn/test/script/basic/NASHORN-377.js Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/test/script/basic/NASHORN-377.js Mon Mar 03 11:24:44 2014 +0100
@@ -194,7 +194,7 @@
})();
(function test_slice() {
- var b = ArrayBuffer(16);
+ var b = new ArrayBuffer(16);
fillArray(new Int8Array(b));
print(bufstr(b));
print("slice(4,8)=" + bufstr(b.slice(4, 8)), "slice(-8,-4)=" + bufstr(b.slice(-8, -4))); // negative index refers from the end of the array
--- a/nashorn/test/script/basic/typedarrays.js Wed Feb 26 13:17:57 2014 +0100
+++ b/nashorn/test/script/basic/typedarrays.js Mon Mar 03 11:24:44 2014 +0100
@@ -83,7 +83,7 @@
var arr = Object.getOwnPropertyNames(instance);
arr.forEach(function(p) {
var val = instance[p];
- if(!isNaN(p)){
+ if(!isNaN(p)) {
val[p] = 99;
}
});