aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/runtime')
-rw-r--r--src/jdk/nashorn/internal/runtime/AccessorProperty.java50
-rw-r--r--src/jdk/nashorn/internal/runtime/CodeInstaller.java25
-rw-r--r--src/jdk/nashorn/internal/runtime/CodeStore.java9
-rw-r--r--src/jdk/nashorn/internal/runtime/CompiledFunction.java120
-rw-r--r--src/jdk/nashorn/internal/runtime/Context.java67
-rw-r--r--src/jdk/nashorn/internal/runtime/Debug.java9
-rw-r--r--src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java21
-rw-r--r--src/jdk/nashorn/internal/runtime/FindProperty.java3
-rw-r--r--src/jdk/nashorn/internal/runtime/GlobalConstants.java6
-rw-r--r--src/jdk/nashorn/internal/runtime/GlobalFunctions.java18
-rw-r--r--src/jdk/nashorn/internal/runtime/OptimisticBuiltins.java65
-rw-r--r--src/jdk/nashorn/internal/runtime/Property.java36
-rw-r--r--src/jdk/nashorn/internal/runtime/PropertyMap.java2
-rw-r--r--src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java68
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptEnvironment.java4
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptFunction.java119
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptFunctionData.java26
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptObject.java81
-rw-r--r--src/jdk/nashorn/internal/runtime/ScriptRuntime.java27
-rw-r--r--src/jdk/nashorn/internal/runtime/SetMethodCreator.java25
-rw-r--r--src/jdk/nashorn/internal/runtime/Specialization.java114
-rw-r--r--src/jdk/nashorn/internal/runtime/StoredScript.java6
-rw-r--r--src/jdk/nashorn/internal/runtime/UserAccessorProperty.java1
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ArrayData.java21
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java28
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java84
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java21
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java11
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java111
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/IntElements.java34
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/IntOrLongElements.java34
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java82
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java18
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java81
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/NumericElements.java35
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java82
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java78
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java9
-rw-r--r--src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java17
-rw-r--r--src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java28
-rw-r--r--src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java16
-rw-r--r--src/jdk/nashorn/internal/runtime/resources/Options.properties6
42 files changed, 1306 insertions, 392 deletions
diff --git a/src/jdk/nashorn/internal/runtime/AccessorProperty.java b/src/jdk/nashorn/internal/runtime/AccessorProperty.java
index 44b3c3b0..e2935368 100644
--- a/src/jdk/nashorn/internal/runtime/AccessorProperty.java
+++ b/src/jdk/nashorn/internal/runtime/AccessorProperty.java
@@ -36,7 +36,6 @@ import static jdk.nashorn.internal.lookup.MethodHandleFactory.stripName;
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
import static jdk.nashorn.internal.runtime.JSType.getNumberOfAccessorTypes;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
-
import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.invoke.MethodHandle;
@@ -57,9 +56,7 @@ public class AccessorProperty extends Property {
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
private static final MethodHandle REPLACE_MAP = findOwnMH_S("replaceMap", Object.class, Object.class, PropertyMap.class);
- private static final MethodHandle INVALIDATE_SP = findOwnMH_S("invalidateSwitchPoint", Object.class, Object.class, SwitchPoint.class);
-
- private static final SwitchPoint NO_CHANGE_CALLBACK = new SwitchPoint();
+ private static final MethodHandle INVALIDATE_SP = findOwnMH_S("invalidateSwitchPoint", Object.class, AccessorProperty.class, Object.class);
private static final int NOOF_TYPES = getNumberOfAccessorTypes();
private static final long serialVersionUID = 3371720170182154920L;
@@ -221,7 +218,7 @@ public class AccessorProperty extends Property {
* @param setter the property setter or null if non writable, non configurable
*/
private AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
- super(key, flags | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
+ super(key, flags | IS_BUILTIN | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
assert !isSpill();
// we don't need to prep the setters these will never be invalidated as this is a nasgen
@@ -602,7 +599,6 @@ public class AccessorProperty extends Property {
private Property getWiderProperty(final Class<?> type) {
return copy(type); //invalidate cache of new property
-
}
private PropertyMap getWiderMap(final PropertyMap oldMap, final Property newProperty) {
@@ -627,8 +623,10 @@ public class AccessorProperty extends Property {
}
@SuppressWarnings("unused")
- private static Object invalidateSwitchPoint(final Object obj, final SwitchPoint sp) {
- SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+ private static Object invalidateSwitchPoint(final AccessorProperty property, final Object obj) {
+ if (!property.builtinSwitchPoint.hasBeenInvalidated()) {
+ SwitchPoint.invalidateAll(new SwitchPoint[] { property.builtinSwitchPoint });
+ }
return obj;
}
@@ -668,12 +666,8 @@ public class AccessorProperty extends Property {
mh = generateSetter(!forType.isPrimitive() ? Object.class : forType, type);
}
- /**
- * Check if this is a special global name that requires switchpoint invalidation
- */
- final SwitchPoint ccb = getChangeCallback();
- if (ccb != null && ccb != NO_CHANGE_CALLBACK) {
- mh = MH.filterArguments(mh, 0, MH.insertArguments(debugInvalidate(getKey(), ccb), 1, changeCallback));
+ if (isBuiltin()) {
+ mh = MH.filterArguments(mh, 0, debugInvalidate(MH.insertArguments(INVALIDATE_SP, 0, this), getKey()));
}
assert mh.type().returnType() == void.class : mh.type();
@@ -681,25 +675,6 @@ public class AccessorProperty extends Property {
return mh;
}
- /**
- * Get the change callback for this property
- * @return switchpoint that is invalidated when property changes
- */
- protected SwitchPoint getChangeCallback() {
- if (changeCallback == null) {
- try {
- changeCallback = Global.instance().getChangeCallback(getKey());
- } catch (final NullPointerException e) {
- assert !"apply".equals(getKey()) && !"call".equals(getKey());
- //empty
- }
- if (changeCallback == null) {
- changeCallback = NO_CHANGE_CALLBACK;
- }
- }
- return changeCallback;
- }
-
@Override
public final boolean canChangeType() {
if (OBJECT_FIELDS_ONLY) {
@@ -724,7 +699,6 @@ public class AccessorProperty extends Property {
return currentType;
}
-
private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) {
if (!Context.DEBUG || !Global.hasInstance()) {
return mh;
@@ -780,9 +754,9 @@ public class AccessorProperty extends Property {
return mh;
}
- private static MethodHandle debugInvalidate(final String key, final SwitchPoint sp) {
+ private static MethodHandle debugInvalidate(final MethodHandle invalidator, final String key) {
if (!Context.DEBUG || !Global.hasInstance()) {
- return INVALIDATE_SP;
+ return invalidator;
}
final Context context = Context.getContextTrusted();
@@ -790,11 +764,11 @@ public class AccessorProperty extends Property {
return context.addLoggingToHandle(
ObjectClassGenerator.class,
- INVALIDATE_SP,
+ invalidator,
new Supplier<String>() {
@Override
public String get() {
- return "Field change callback for " + key + " triggered: " + sp;
+ return "Field change callback for " + key + " triggered ";
}
});
}
diff --git a/src/jdk/nashorn/internal/runtime/CodeInstaller.java b/src/jdk/nashorn/internal/runtime/CodeInstaller.java
index 7a7df467..e2b5afe8 100644
--- a/src/jdk/nashorn/internal/runtime/CodeInstaller.java
+++ b/src/jdk/nashorn/internal/runtime/CodeInstaller.java
@@ -81,13 +81,17 @@ public interface CodeInstaller<T> {
/**
* Store a compiled script for later reuse
+ *
+ * @param cacheKey key to use in cache
* @param source the script source
* @param mainClassName the main class name
* @param classBytes map of class names to class bytes
+ * @param initializers compilation id -> FunctionInitializer map
* @param constants constants array
+ * @param compilationId compilation id
*/
- public void storeScript(String cacheKey, Source source, String mainClassName, Map<String, byte[]> classBytes,
- Map<Integer, FunctionInitializer> initializers, Object[] constants, int compilationId);
+ public void storeScript(final String cacheKey, final Source source, final String mainClassName, final Map<String, byte[]> classBytes,
+ final Map<Integer, FunctionInitializer> initializers, final Object[] constants, final int compilationId);
/**
* Load a previously compiled script
@@ -96,4 +100,21 @@ public interface CodeInstaller<T> {
* @return compiled script data
*/
public StoredScript loadScript(Source source, String functionKey);
+
+ /**
+ * Returns a new code installer that shares most of the functionality of this code installer, but uses a
+ * new, independent class loader.
+ * @return a new code installer with a new independent class loader.
+ */
+ public CodeInstaller<T> withNewLoader();
+
+ /**
+ * Returns true if this code installer is compatible with the other code installer. Compatibility is expected to be
+ * an equivalence relation, and installers are supposed to be compatible with those they create using
+ * {@link #withNewLoader()}.
+ * @param other the other code installer tested for compatibility with this code installer.
+ * @return true if this code installer is compatible with the other code installer.
+ */
+ public boolean isCompatibleWith(CodeInstaller<T> other);
+
}
diff --git a/src/jdk/nashorn/internal/runtime/CodeStore.java b/src/jdk/nashorn/internal/runtime/CodeStore.java
index a736cc36..0748ccc3 100644
--- a/src/jdk/nashorn/internal/runtime/CodeStore.java
+++ b/src/jdk/nashorn/internal/runtime/CodeStore.java
@@ -118,6 +118,8 @@ public abstract class CodeStore implements Loggable {
* @param initializers the function initializers
* @param constants the constants array
* @param compilationId the compilation id
+ *
+ * @return stored script
*/
public StoredScript store(final String functionKey,
final Source source,
@@ -153,11 +155,13 @@ public abstract class CodeStore implements Loggable {
/**
* Returns a new StoredScript instance.
*
+ * @param source the source
* @param mainClassName the main class name
* @param classBytes a map of class bytes
* @param initializers function initializers
* @param constants the constants array
* @param compilationId the compilation id
+ *
* @return The compiled script
*/
public StoredScript storedScriptFor(final Source source, final String mainClassName,
@@ -206,7 +210,7 @@ public abstract class CodeStore implements Loggable {
/**
* Constructor
*
- * @throws IOException
+ * @throws IOException if there are read/write problems with the cache and cache directory
*/
public DirectoryCodeStore() throws IOException {
this(Options.getStringProperty("nashorn.persistent.code.cache", "nashorn_code_cache"), false, DEFAULT_MIN_SIZE);
@@ -216,8 +220,9 @@ public abstract class CodeStore implements Loggable {
* Constructor
*
* @param path directory to store code in
+ * @param readOnly is this a read only code store
* @param minSize minimum file size for caching scripts
- * @throws IOException
+ * @throws IOException if there are read/write problems with the cache and cache directory
*/
public DirectoryCodeStore(final String path, final boolean readOnly, final int minSize) throws IOException {
this.dir = checkDirectory(path, readOnly);
diff --git a/src/jdk/nashorn/internal/runtime/CompiledFunction.java b/src/jdk/nashorn/internal/runtime/CompiledFunction.java
index 28a81dea..2655e781 100644
--- a/src/jdk/nashorn/internal/runtime/CompiledFunction.java
+++ b/src/jdk/nashorn/internal/runtime/CompiledFunction.java
@@ -33,12 +33,13 @@ import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.MutableCallSite;
import java.lang.invoke.SwitchPoint;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Supplier;
import java.util.logging.Level;
-
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
@@ -46,6 +47,7 @@ import jdk.nashorn.internal.codegen.TypeMap;
import jdk.nashorn.internal.codegen.types.ArrayType;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.FunctionNode;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
import jdk.nashorn.internal.runtime.events.RecompilationEvent;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
@@ -63,6 +65,8 @@ final class CompiledFunction {
private final DebugLogger log;
+ static final Collection<CompiledFunction> NO_FUNCTIONS = Collections.emptySet();
+
/**
* The method type may be more specific than the invoker, if. e.g.
* the invoker is guarded, and a guard with a generic object only
@@ -75,19 +79,38 @@ final class CompiledFunction {
private final int flags; // from FunctionNode
private final MethodType callSiteType;
+ private final Specialization specialization;
+
CompiledFunction(final MethodHandle invoker) {
- this(invoker, null);
+ this(invoker, null, null);
}
- static CompiledFunction createBuiltInConstructor(final MethodHandle invoker) {
- return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)));
+ static CompiledFunction createBuiltInConstructor(final MethodHandle invoker, final Specialization specialization) {
+ return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)), specialization);
}
- CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
- this(invoker, constructor, 0, null, DebugLogger.DISABLED_LOGGER);
+ CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final Specialization specialization) {
+ this(invoker, constructor, 0, null, specialization, DebugLogger.DISABLED_LOGGER);
}
- CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final int flags, final MethodType callSiteType, final DebugLogger log) {
+ CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final int flags, final MethodType callSiteType, final Specialization specialization, final DebugLogger log) {
+ this.specialization = specialization;
+ if (specialization != null && specialization.isOptimistic()) {
+ /*
+ * An optimistic builtin with isOptimistic=true works like any optimistic generated function, i.e. it
+ * can throw unwarranted optimism exceptions. As native functions trivially can't have parts of them
+ * regenerated as restof methods, this only works if the methods are atomic/functional in their behavior
+ * and doesn't modify state before an UOE can be thrown. If they aren't, we can reexecute a wider version
+ * of the same builtin in a recompilation handler for FinalScriptFunctionData. There are several
+ * candidate methods in Native* that would benefit from this, but I haven't had time to implement any
+ * of them currently. In order to fit in with the relinking framework, the current thinking is
+ * that the methods still take a program point to fit in with other optimistic functions, but
+ * it is set to "first", which is the beginning of the method. The relinker can tell the difference
+ * between builtin and JavaScript functions. This might change. TODO
+ */
+ this.invoker = MH.insertArguments(invoker, invoker.type().parameterCount() - 1, UnwarrantedOptimismException.FIRST_PROGRAM_POINT);
+ throw new AssertionError("Optimistic (UnwarrantedOptimismException throwing) builtin functions are currently not in use");
+ }
this.invoker = invoker;
this.constructor = constructor;
this.flags = flags;
@@ -97,7 +120,7 @@ final class CompiledFunction {
CompiledFunction(final MethodHandle invoker, final RecompilableScriptFunctionData functionData,
final Map<Integer, Type> invalidatedProgramPoints, final MethodType callSiteType, final int flags) {
- this(invoker, null, flags, callSiteType, functionData.getLogger());
+ this(invoker, null, flags, callSiteType, null, functionData.getLogger());
if ((flags & FunctionNode.IS_DEOPTIMIZABLE) != 0) {
optimismInfo = new OptimismInfo(functionData, invalidatedProgramPoints);
} else {
@@ -105,10 +128,45 @@ final class CompiledFunction {
}
}
+ static CompiledFunction createBuiltInConstructor(final MethodHandle invoker) {
+ return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)), null);
+ }
+
+ boolean isSpecialization() {
+ return specialization != null;
+ }
+
+ boolean hasLinkLogic() {
+ return getLinkLogicClass() != null;
+ }
+
+ Class<? extends LinkLogic> getLinkLogicClass() {
+ if (isSpecialization()) {
+ final Class<? extends LinkLogic> linkLogicClass = specialization.getLinkLogicClass();
+ assert !LinkLogic.isEmpty(linkLogicClass) : "empty link logic classes should have been removed by nasgen";
+ return linkLogicClass;
+ }
+ return null;
+ }
+
int getFlags() {
return flags;
}
+ /**
+ * An optimistic specialization is one that can throw UnwarrantedOptimismException.
+ * This is allowed for native methods, as long as they are functional, i.e. don't change
+ * any state between entering and throwing the UOE. Then we can re-execute a wider version
+ * of the method in the continuation. Rest-of method generation for optimistic builtins is
+ * of course not possible, but this approach works and fits into the same relinking
+ * framework
+ *
+ * @return true if optimistic builtin
+ */
+ boolean isOptimistic() {
+ return isSpecialization() ? specialization.isOptimistic() : false;
+ }
+
boolean isApplyToCall() {
return (flags & FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION) != 0;
}
@@ -119,7 +177,19 @@ final class CompiledFunction {
@Override
public String toString() {
- return "[invokerType=" + invoker.type() + " ctor=" + constructor + " weight=" + weight() + " isApplyToCall=" + isApplyToCall() + "]";
+ final StringBuilder sb = new StringBuilder();
+ final Class<? extends LinkLogic> linkLogicClass = getLinkLogicClass();
+
+ sb.append("[invokerType=").
+ append(invoker.type()).
+ append(" ctor=").
+ append(constructor).
+ append(" weight=").
+ append(weight()).
+ append(" linkLogic=").
+ append(linkLogicClass != null ? linkLogicClass.getSimpleName() : "none");
+
+ return sb.toString();
}
boolean needsCallee() {
@@ -281,10 +351,12 @@ final class CompiledFunction {
if (other == null) {
return true;
}
- return betterThanFinal(type(), other.type(), callSiteMethodType);
+ return betterThanFinal(this, other, callSiteMethodType);
}
- static boolean betterThanFinal(final MethodType thisMethodType, final MethodType otherMethodType, final MethodType callSiteMethodType) {
+ private static boolean betterThanFinal(final CompiledFunction cf, final CompiledFunction other, final MethodType callSiteMethodType) {
+ final MethodType thisMethodType = cf.type();
+ final MethodType otherMethodType = other.type();
final int thisParamCount = getParamCount(thisMethodType);
final int otherParamCount = getParamCount(otherMethodType);
final int callSiteRawParamCount = getParamCount(callSiteMethodType);
@@ -406,7 +478,17 @@ final class CompiledFunction {
return false;
}
- throw new AssertionError(thisMethodType + " identically applicable to " + otherMethodType + " for " + callSiteMethodType); // Signatures are identical
+ //if they are equal, pick the specialized one first
+ if (cf.isSpecialization() != other.isSpecialization()) {
+ return cf.isSpecialization(); //always pick the specialized version if we can
+ }
+
+ if (cf.isSpecialization() && other.isSpecialization()) {
+ return cf.getLinkLogicClass() != null; //pick link logic specialization above generic specializations
+ }
+
+ // Signatures are identical
+ throw new AssertionError(thisMethodType + " identically applicable to " + otherMethodType + " for " + callSiteMethodType);
}
private static Type[] toTypeWithoutCallee(final MethodType type, final int thisIndex) {
@@ -427,8 +509,8 @@ final class CompiledFunction {
return ((ArrayType)paramTypes[paramTypes.length - 1]).getElementType();
}
- boolean matchesCallSite(final MethodType callSiteType, final boolean pickVarArg) {
- if (callSiteType.equals(this.callSiteType)) {
+ boolean matchesCallSite(final MethodType other, final boolean pickVarArg) {
+ if (other.equals(this.callSiteType)) {
return true;
}
final MethodType type = type();
@@ -438,7 +520,7 @@ final class CompiledFunction {
return pickVarArg;
}
- final int csParamCount = getParamCount(callSiteType);
+ final int csParamCount = getParamCount(other);
final boolean csIsVarArg = csParamCount == Integer.MAX_VALUE;
final int thisThisIndex = needsCallee() ? 1 : 0; // Index of "this" parameter in this function's type
@@ -447,7 +529,7 @@ final class CompiledFunction {
// We must match all incoming parameters, except "this". Starting from 1 to skip "this".
for(int i = 1; i < minParams; ++i) {
final Type fnType = Type.typeFor(type.parameterType(i + thisThisIndex));
- final Type csType = csIsVarArg ? Type.OBJECT : Type.typeFor(callSiteType.parameterType(i + 1));
+ final Type csType = csIsVarArg ? Type.OBJECT : Type.typeFor(other.parameterType(i + 1));
if(!fnType.isEquivalentTo(csType)) {
return false;
}
@@ -669,9 +751,9 @@ final class CompiledFunction {
return sb.toString();
}
- private void logRecompile(final String reason, final FunctionNode fn, final MethodType callSiteType, final Map<Integer, Type> ipp) {
+ private void logRecompile(final String reason, final FunctionNode fn, final MethodType type, final Map<Integer, Type> ipp) {
if (log.isEnabled()) {
- log.info(reason, DebugLogger.quote(fn.getName()), " signature: ", callSiteType, " ", toStringInvalidations(ipp));
+ log.info(reason, DebugLogger.quote(fn.getName()), " signature: ", type, " ", toStringInvalidations(ipp));
}
}
@@ -732,8 +814,6 @@ final class CompiledFunction {
compiler.persistClassInfo(cacheKey, normalFn);
}
- FunctionNode fn2 = effectiveOptInfo.reparse();
- fn2 = compiler.compile(fn2, CompilationPhases.COMPILE_UPTO_BYTECODE);
log.info("Done.");
final boolean canBeDeoptimized = normalFn.canBeDeoptimized();
diff --git a/src/jdk/nashorn/internal/runtime/Context.java b/src/jdk/nashorn/internal/runtime/Context.java
index aa3306a4..e77c204a 100644
--- a/src/jdk/nashorn/internal/runtime/Context.java
+++ b/src/jdk/nashorn/internal/runtime/Context.java
@@ -33,13 +33,13 @@ import static jdk.nashorn.internal.runtime.CodeStore.newCodeStore;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.Source.sourceFor;
-
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.lang.invoke.SwitchPoint;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
@@ -127,6 +127,16 @@ public final class Context {
private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
private static MethodType CREATE_PROGRAM_FUNCTION_TYPE = MethodType.methodType(ScriptFunction.class, ScriptObject.class);
+ /**
+ * Keeps track of which builtin prototypes and properties have been relinked
+ * Currently we are conservative and associate the name of a builtin class with all
+ * its properties, so it's enough to invalidate a property to break all assumptions
+ * about a prototype. This can be changed to a more fine grained approach, but no one
+ * ever needs this, given the very rare occurance of swapping out only parts of
+ * a builtin v.s. the entire builtin object
+ */
+ private final Map<String, SwitchPoint> builtinSwitchPoints = new HashMap<>();
+
/* Force DebuggerSupport to be loaded. */
static {
DebuggerSupport.FORCELOAD = true;
@@ -148,7 +158,7 @@ public final class Context {
}
/**
- * Return the context for this installer
+ * Return the script environment for this installer
* @return ScriptEnvironment
*/
@Override
@@ -212,6 +222,20 @@ public final class Context {
}
return null;
}
+
+ @Override
+ public CodeInstaller<ScriptEnvironment> withNewLoader() {
+ return new ContextCodeInstaller(context, context.createNewLoader(), codeSource);
+ }
+
+ @Override
+ public boolean isCompatibleWith(final CodeInstaller<ScriptEnvironment> other) {
+ if (other instanceof ContextCodeInstaller) {
+ final ContextCodeInstaller cci = (ContextCodeInstaller)other;
+ return cci.context == context && cci.codeSource == codeSource;
+ }
+ return false;
+ }
}
/** Is Context global debug mode enabled ? */
@@ -1113,6 +1137,9 @@ public final class Context {
StoredScript storedScript = null;
FunctionNode functionNode = null;
+ // We only use the code store here if optimistic types are disabled. With optimistic types,
+ // code is stored per function in RecompilableScriptFunctionData.
+ // TODO: This should really be triggered by lazy compilation, not optimistic types.
final boolean useCodeStore = env._persistent_cache && !env._parse_only && !env._optimistic_types;
final String cacheKey = useCodeStore ? CodeStore.getCacheKey(0, null) : null;
@@ -1199,7 +1226,7 @@ public final class Context {
final String mainClassName = storedScript.getMainClassName();
final byte[] mainClassBytes = classBytes.get(mainClassName);
final Class<?> mainClass = installer.install(mainClassName, mainClassBytes);
- final Map<Integer, FunctionInitializer> initialzers = storedScript.getInitializers();
+ final Map<Integer, FunctionInitializer> initializers = storedScript.getInitializers();
installedClasses.put(mainClassName, mainClass);
@@ -1219,8 +1246,8 @@ public final class Context {
if (constant instanceof RecompilableScriptFunctionData) {
final RecompilableScriptFunctionData data = (RecompilableScriptFunctionData) constant;
data.initTransients(source, installer);
- if (initialzers != null) {
- final FunctionInitializer initializer = initialzers.get(data.getFunctionNodeId());
+ final FunctionInitializer initializer = initializers.get(data.getFunctionNodeId());
+ if (initializer != null) {
initializer.setCode(installedClasses.get(initializer.getClassName()));
data.initializeCode(initializer);
}
@@ -1371,4 +1398,34 @@ public final class Context {
return null;
}
+ /**
+ * This is a special kind of switchpoint used to guard builtin
+ * properties and prototypes. In the future it might contain
+ * logic to e.g. multiple switchpoint classes.
+ */
+ public static final class BuiltinSwitchPoint extends SwitchPoint {
+ //empty
+ }
+
+ /**
+ * Create a new builtin switchpoint and return it
+ * @param name key name
+ * @return new builtin switchpoint
+ */
+ public SwitchPoint newBuiltinSwitchPoint(final String name) {
+ assert builtinSwitchPoints.get(name) == null;
+ final SwitchPoint sp = new BuiltinSwitchPoint();
+ builtinSwitchPoints.put(name, sp);
+ return sp;
+ }
+
+ /**
+ * Return the builtin switchpoint for a particular key name
+ * @param name key name
+ * @return builtin switchpoint or null if none
+ */
+ public SwitchPoint getBuiltinSwitchPoint(final String name) {
+ return builtinSwitchPoints.get(name);
+ }
+
}
diff --git a/src/jdk/nashorn/internal/runtime/Debug.java b/src/jdk/nashorn/internal/runtime/Debug.java
index c152418a..a2d136fc 100644
--- a/src/jdk/nashorn/internal/runtime/Debug.java
+++ b/src/jdk/nashorn/internal/runtime/Debug.java
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.parser.TokenType.EOF;
-
import jdk.nashorn.internal.parser.Lexer;
import jdk.nashorn.internal.parser.Token;
import jdk.nashorn.internal.parser.TokenStream;
@@ -42,12 +41,12 @@ public final class Debug {
/**
* Return the topmost JavaScript frame in a stack trace
- * @param e
+ * @param t throwable that contains the stack trace
* @return line describing the topmost JavaScript frame
*/
- public static String firstJSFrame(final Throwable e) {
- for (final StackTraceElement ste : e.getStackTrace()) {
- if(ECMAErrors.isScriptFrame(ste)) {
+ public static String firstJSFrame(final Throwable t) {
+ for (final StackTraceElement ste : t.getStackTrace()) {
+ if (ECMAErrors.isScriptFrame(ste)) {
return ste.toString();
}
}
diff --git a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
index f75dc829..c868aab2 100644
--- a/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java
@@ -60,13 +60,13 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
* @param specs specializations
* @param flags {@link ScriptFunctionData} flags
*/
- FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final int flags) {
+ FinalScriptFunctionData(final String name, final MethodHandle mh, final Specialization[] specs, final int flags) {
super(name, methodHandleArity(mh), flags);
addInvoker(mh);
if (specs != null) {
- for (final MethodHandle spec : specs) {
- addInvoker(spec);
+ for (final Specialization spec : specs) {
+ addInvoker(spec.getMethodHandle(), spec);
}
}
}
@@ -114,16 +114,25 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
return MethodType.genericMethodType(max + 1);
}
- private void addInvoker(final MethodHandle mh) {
+ private CompiledFunction addInvoker(final MethodHandle mh, final Specialization specialization) {
assert !needsCallee(mh);
+
+ final CompiledFunction invoker;
if (isConstructor(mh)) {
// only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor
// is too conservative a check. However, isConstructor(mh) always implies isConstructor param
assert isConstructor();
- code.add(CompiledFunction.createBuiltInConstructor(mh));
+ invoker = CompiledFunction.createBuiltInConstructor(mh);
} else {
- code.add(new CompiledFunction(mh));
+ invoker = new CompiledFunction(mh, null, specialization);
}
+ code.add(invoker);
+
+ return invoker;
+ }
+
+ private CompiledFunction addInvoker(final MethodHandle mh) {
+ return addInvoker(mh, null);
}
private static int methodHandleArity(final MethodHandle mh) {
diff --git a/src/jdk/nashorn/internal/runtime/FindProperty.java b/src/jdk/nashorn/internal/runtime/FindProperty.java
index 06f682bf..b4e00124 100644
--- a/src/jdk/nashorn/internal/runtime/FindProperty.java
+++ b/src/jdk/nashorn/internal/runtime/FindProperty.java
@@ -79,6 +79,8 @@ public final class FindProperty {
*
* @param type type of getter, e.g. int.class if we want a function with {@code get()I} signature
* @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic
+ * @param request link request
+ *
* @return method handle for the getter
*/
public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) {
@@ -102,6 +104,7 @@ public final class FindProperty {
*
* @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature
* @param strict are we in strict mode
+ * @param request link request
*
* @return method handle for the getter
*/
diff --git a/src/jdk/nashorn/internal/runtime/GlobalConstants.java b/src/jdk/nashorn/internal/runtime/GlobalConstants.java
index 3a104812..6099a70b 100644
--- a/src/jdk/nashorn/internal/runtime/GlobalConstants.java
+++ b/src/jdk/nashorn/internal/runtime/GlobalConstants.java
@@ -358,8 +358,12 @@ public final class GlobalConstants implements Loggable {
* @param c constant value
* @return method handle (with dummy receiver) that returns this constant
*/
+ public static MethodHandle staticConstantGetter(final Object c) {
+ return MH.dropArguments(JSType.unboxConstant(c), 0, Object.class);
+ }
+
private MethodHandle constantGetter(final Object c) {
- final MethodHandle mh = MH.dropArguments(JSType.unboxConstant(c), 0, Object.class);
+ final MethodHandle mh = staticConstantGetter(c);
if (log.isEnabled()) {
return MethodHandleFactory.addDebugPrintout(log, Level.FINEST, mh, "getting as constant");
}
diff --git a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
index 2776cc66..c7094adc 100644
--- a/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
+++ b/src/jdk/nashorn/internal/runtime/GlobalFunctions.java
@@ -42,12 +42,30 @@ public final class GlobalFunctions {
/** 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);
+ /** ParseInt - NaN for booleans (thru string conversion to number conversion) */
+ public static final MethodHandle PARSEINT_Z = MH.dropArguments(MH.dropArguments(MH.constant(double.class, Double.NaN), 0, boolean.class), 0, Object.class);
+
+ /** ParseInt - identity for ints */
+ public static final MethodHandle PARSEINT_I = MH.dropArguments(MH.identity(int.class), 0, Object.class);
+
+ /** ParseInt - identity for longs */
+ public static final MethodHandle PARSEINT_J = MH.dropArguments(MH.identity(long.class), 0, Object.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);
+ /** isNan for integers - always false */
+ public static final MethodHandle IS_NAN_I = MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class);
+
+ /** isNan for longs - always false */
+ public static final MethodHandle IS_NAN_J = MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class);
+
+ /** IsNan for doubles - use Double.isNaN */
+ public static final MethodHandle IS_NAN_D = MH.dropArguments(MH.findStatic(MethodHandles.lookup(), Double.class, "isNaN", MH.type(boolean.class, double.class)), 0, Object.class);
+
/** Methodhandle to implementation of ECMA 15.1.2.4, isNaN */
public static final MethodHandle IS_NAN = findOwnMH("isNaN", boolean.class, Object.class, Object.class);
diff --git a/src/jdk/nashorn/internal/runtime/OptimisticBuiltins.java b/src/jdk/nashorn/internal/runtime/OptimisticBuiltins.java
new file mode 100644
index 00000000..6829ddeb
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/OptimisticBuiltins.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. 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;
+
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
+
+/**
+ * This is an interface for classes that need custom linkage logic. This means Native objects
+ * that contain optimistic native methods, that need special/extra rules for linking, guards and
+ * SwitchPointing, known and internal to the Native object for its linkage
+ */
+public interface OptimisticBuiltins {
+
+ /**
+ * Return an instance of the linking logic we need for a particular LinkLogic
+ * subclass, gotten from the compile time annotation of a specialized builtin method
+ * No assumptions can be made about the lifetime of the instance. The receiver may
+ * keep it as a perpetual final instance field or create new linking logic depending
+ * on its current state for each call, depending on if the global state has changed
+ * or other factors
+ *
+ * @param clazz linking logic class
+ * @return linking logic instance for this class
+ */
+ public SpecializedFunction.LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz);
+
+ /**
+ * Does this link logic vary depending on which instance we are working with.
+ * Then we have to sort out certain primitives, as they are created as new
+ * objects in the wrapFilter by JavaScript semantics. An example of instance only
+ * assumptions are switchPoints per instance, as in NativeArray. NativeString is
+ * fine, as it's only static.
+ *
+ * TODO: finer granularity on this, on the function level so certain functions
+ * are forbidden only. Currently we don't have enough specialization to bump into this
+ *
+ * @return true if there are per instance assumptions for the optimism
+ */
+ public boolean hasPerInstanceAssumptions();
+
+}
diff --git a/src/jdk/nashorn/internal/runtime/Property.java b/src/jdk/nashorn/internal/runtime/Property.java
index 1f9f1459..f57246ca 100644
--- a/src/jdk/nashorn/internal/runtime/Property.java
+++ b/src/jdk/nashorn/internal/runtime/Property.java
@@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
-
import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
@@ -84,6 +83,9 @@ public abstract class Property implements Serializable {
*/
public static final int IS_NASGEN_PRIMITIVE = 1 << 6;
+ /** Is this a builtin property, e.g. Function.prototype.apply */
+ public static final int IS_BUILTIN = 1 << 7;
+
/** Is this property bound to a receiver? This means get/set operations will be delegated to
* a statically defined object instead of the object passed as callsite parameter. */
public static final int IS_BOUND = 1 << 7;
@@ -101,7 +103,7 @@ public abstract class Property implements Serializable {
private final int slot;
/** SwitchPoint that is invalidated when property is changed, optional */
- protected transient SwitchPoint changeCallback;
+ protected transient SwitchPoint builtinSwitchPoint;
private static final long serialVersionUID = 2099814273074501176L;
@@ -125,10 +127,10 @@ public abstract class Property implements Serializable {
* @param property source property
*/
Property(final Property property, final int flags) {
- this.key = property.key;
- this.slot = property.slot;
- this.changeCallback = property.changeCallback;
- this.flags = flags;
+ this.key = property.key;
+ this.slot = property.slot;
+ this.builtinSwitchPoint = property.builtinSwitchPoint;
+ this.flags = flags;
}
/**
@@ -182,8 +184,26 @@ public abstract class Property implements Serializable {
* changed
* @param sp SwitchPoint to use for change callback
*/
- public final void setChangeCallback(final SwitchPoint sp) {
- this.changeCallback = sp;
+ public final void setBuiltinSwitchPoint(final SwitchPoint sp) {
+ this.builtinSwitchPoint = sp;
+ }
+
+ /**
+ * Builtin properties have an invalidation switchpoint that is
+ * invalidated when they are set, this is a getter for it
+ * @return builtin switchpoint, or null if none
+ */
+ public final SwitchPoint getBuiltinSwitchPoint() {
+ return builtinSwitchPoint;
+ }
+
+ /**
+ * Checks if this is a builtin property, this means that it has
+ * a builtin switchpoint that hasn't been invalidated by a setter
+ * @return true if builtin, untouched (unset) property
+ */
+ public boolean isBuiltin() {
+ return builtinSwitchPoint != null && !builtinSwitchPoint.hasBeenInvalidated();
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/PropertyMap.java b/src/jdk/nashorn/internal/runtime/PropertyMap.java
index d8e76082..61912332 100644
--- a/src/jdk/nashorn/internal/runtime/PropertyMap.java
+++ b/src/jdk/nashorn/internal/runtime/PropertyMap.java
@@ -950,7 +950,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
@Override
public void remove() {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("remove");
}
}
diff --git a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
index 2d5ccc05..f3ad2339 100644
--- a/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
@@ -31,6 +31,7 @@ import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -268,7 +269,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
if (this.source == null && this.installer == null) {
this.source = src;
this.installer = inst;
- } else if (this.source != src || this.installer != inst) {
+ } else if (this.source != src || !this.installer.isCompatibleWith(inst)) {
// Existing values must be same as those passed as parameters
throw new IllegalArgumentException();
}
@@ -407,6 +408,17 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return getCompiler(fn, actualCallSiteType, newLocals(runtimeScope), null, null);
}
+ /**
+ * Returns a code installer for installing new code. If we're using either optimistic typing or loader-per-compile,
+ * then asks for a code installer with a new class loader; otherwise just uses the current installer. We use
+ * a new class loader with optimistic typing so that deoptimized code can get reclaimed by GC.
+ * @return a code installer for installing new code.
+ */
+ private CodeInstaller<ScriptEnvironment> getInstallerForNewCode() {
+ final ScriptEnvironment env = installer.getOwner();
+ return env._optimistic_types || env._loader_per_compile ? installer.withNewLoader() : installer;
+ }
+
Compiler getCompiler(final FunctionNode functionNode, final MethodType actualCallSiteType,
final ScriptObject runtimeScope, final Map<Integer, Type> invalidatedProgramPoints,
final int[] continuationEntryPoints) {
@@ -417,7 +429,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return new Compiler(
context,
context.getEnv(),
- installer,
+ getInstallerForNewCode(),
functionNode.getSource(), // source
context.getErrorManager(),
isStrict() | functionNode.isStrict(), // is strict
@@ -454,7 +466,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
// CompilationEnvironment#declareLocalSymbol()).
if (log.isEnabled()) {
- log.info("Type specialization of '", functionName, "' signature: ", actualCallSiteType);
+ log.info("Parameter type specialization of '", functionName, "' signature: ", actualCallSiteType);
}
final boolean persistentCache = usePersistentCodeCache() && persist;
@@ -463,11 +475,12 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
final TypeMap typeMap = typeMap(actualCallSiteType);
final Type[] paramTypes = typeMap == null ? null : typeMap.getParameterTypes(functionNodeId);
cacheKey = CodeStore.getCacheKey(functionNodeId, paramTypes);
- final StoredScript script = installer.loadScript(source, cacheKey);
+ final CodeInstaller<ScriptEnvironment> newInstaller = getInstallerForNewCode();
+ final StoredScript script = newInstaller.loadScript(source, cacheKey);
if (script != null) {
Compiler.updateCompilationId(script.getCompilationId());
- return install(script);
+ return installStoredScript(script, newInstaller);
}
}
@@ -481,15 +494,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return new FunctionInitializer(compiledFn, compiler.getInvalidatedProgramPoints());
}
-
- /**
- * Install this script using the given {@code installer}.
- *
- * @param script the compiled script
- * @return the function initializer
- */
- private FunctionInitializer install(final StoredScript script) {
-
+ private static Map<String, Class<?>> installStoredScriptClasses(final StoredScript script, final CodeInstaller<ScriptEnvironment> installer) {
final Map<String, Class<?>> installedClasses = new HashMap<>();
final Map<String, byte[]> classBytes = script.getClassBytes();
final String mainClassName = script.getMainClassName();
@@ -501,14 +506,25 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
for (final Map.Entry<String, byte[]> entry : classBytes.entrySet()) {
final String className = entry.getKey();
- final byte[] code = entry.getValue();
+ final byte[] bytecode = entry.getValue();
if (className.equals(mainClassName)) {
continue;
}
- installedClasses.put(className, installer.install(className, code));
+ installedClasses.put(className, installer.install(className, bytecode));
}
+ return installedClasses;
+ }
+
+ /**
+ * Install this script using the given {@code installer}.
+ *
+ * @param script the compiled script
+ * @return the function initializer
+ */
+ private FunctionInitializer installStoredScript(final StoredScript script, final CodeInstaller<ScriptEnvironment> newInstaller) {
+ final Map<String, Class<?>> installedClasses = installStoredScriptClasses(script, newInstaller);
final Map<Integer, FunctionInitializer> initializers = script.getInitializers();
assert initializers != null;
@@ -523,7 +539,7 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
}
}
- installer.initialize(installedClasses.values(), source, constants);
+ newInstaller.initialize(installedClasses.values(), source, constants);
initializer.setCode(installedClasses.get(initializer.getClassName()));
return initializer;
}
@@ -588,15 +604,19 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return lookupCodeMethod(fn.getCompileUnit().getCode(), type);
}
- MethodHandle lookupCodeMethod(final Class<?> code, final MethodType targetType) {
- log.info("Looking up ", DebugLogger.quote(name), " type=", targetType);
- return MH.findStatic(LOOKUP, code, functionName, targetType);
+ MethodHandle lookupCodeMethod(final Class<?> codeClass, final MethodType targetType) {
+ if (log.isEnabled()) {
+ log.info("Looking up ", DebugLogger.quote(name), " type=", targetType);
+ }
+ return MH.findStatic(LOOKUP, codeClass, functionName, targetType);
}
/**
* Initializes this function data with the eagerly generated version of the code. This method can only be invoked
* by the compiler internals in Nashorn and is public for implementation reasons only. Attempting to invoke it
* externally will result in an exception.
+ *
+ * @param initializer FunctionInitializer for this data
*/
public void initializeCode(final FunctionInitializer initializer) {
// Since the method is public, we double-check that we aren't invoked with an inappropriate compile unit.
@@ -658,8 +678,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
@Override
- synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) {
- CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope);
+ synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
+ CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope, forbidden);
if (existingBest == null) {
existingBest = addCode(compileTypeSpecialization(callSiteType, runtimeScope, true), callSiteType);
}
@@ -723,6 +743,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
return functionNodeId;
}
+ /**
+ * Get the source for the script
+ * @return source
+ */
public Source getSource() {
return source;
}
diff --git a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
index e6034bf5..cd528a01 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptEnvironment.java
@@ -181,9 +181,6 @@ public final class ScriptEnvironment {
/** print symbols and their contents for the script */
public final boolean _print_symbols;
- /** range analysis for known types */
- public final boolean _range_analysis;
-
/** is this environment in scripting mode? */
public final boolean _scripting;
@@ -255,7 +252,6 @@ public final class ScriptEnvironment {
_print_parse = options.getBoolean("print.parse");
_print_lower_parse = options.getBoolean("print.lower.parse");
_print_symbols = options.getBoolean("print.symbols");
- _range_analysis = options.getBoolean("range.analysis");
_scripting = options.getBoolean("scripting");
_strict = options.getBoolean("strict");
_version = options.getBoolean("version");
diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunction.java b/src/jdk/nashorn/internal/runtime/ScriptFunction.java
index d9f71a2a..0ba06b3a 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptFunction.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunction.java
@@ -30,26 +30,29 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
-
+import java.util.HashSet;
+import java.util.List;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.support.Guards;
import jdk.nashorn.internal.codegen.ApplySpecialization;
+import jdk.nashorn.internal.codegen.Compiler;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.objects.NativeFunction;
-import jdk.nashorn.internal.runtime.ScriptFunctionData;
-import jdk.nashorn.internal.runtime.ScriptObject;
-import jdk.nashorn.internal.runtime.ScriptRuntime;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
+import jdk.nashorn.internal.runtime.logging.DebugLogger;
/**
* Runtime representation of a JavaScript function.
@@ -114,7 +117,7 @@ public abstract class ScriptFunction extends ScriptObject {
final MethodHandle methodHandle,
final PropertyMap map,
final ScriptObject scope,
- final MethodHandle[] specs,
+ final Specialization[] specs,
final int flags) {
this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope);
@@ -468,13 +471,12 @@ public abstract class ScriptFunction extends ScriptObject {
protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
final MethodType type = desc.getMethodType();
assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
- final CompiledFunction cf = data.getBestConstructor(type, scope);
+ final CompiledFunction cf = data.getBestConstructor(type, scope, CompiledFunction.NO_FUNCTIONS);
final GuardedInvocation bestCtorInv = cf.createConstructorInvocation();
//TODO - ClassCastException
return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this, cf.getFlags()), bestCtorInv.getSwitchPoints(), null);
}
- @SuppressWarnings("unused")
private static Object wrapFilter(final Object obj) {
if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
return obj;
@@ -490,6 +492,35 @@ public abstract class ScriptFunction extends ScriptObject {
}
/**
+ * Some receivers are primitive, in that case, according to the Spec we create a new
+ * native object per callsite with the wrap filter. We can only apply optimistic builtins
+ * if there is no per instance state saved for these wrapped objects (e.g. currently NativeStrings),
+ * otherwise we can't create optimistic versions
+ *
+ * @param self receiver
+ * @param linkLogicClass linkLogicClass, or null if no link logic exists
+ * @return link logic instance, or null if one could not be constructed for this receiver
+ */
+ private static LinkLogic getLinkLogic(final Object self, final Class<? extends LinkLogic> linkLogicClass) {
+ if (linkLogicClass == null) {
+ return LinkLogic.EMPTY_INSTANCE; //always OK to link this, specialization but without special linking logic
+ }
+
+ if (!Context.getContextTrusted().getEnv()._optimistic_types) {
+ return null; //if optimistic types are off, optimistic builtins are too
+ }
+
+ final Object wrappedSelf = wrapFilter(self);
+ if (wrappedSelf instanceof OptimisticBuiltins) {
+ if (wrappedSelf != self && ((OptimisticBuiltins)wrappedSelf).hasPerInstanceAssumptions()) {
+ return null; //pessimistic - we created a wrapped object different from the primitive, but the assumptions have instance state
+ }
+ return ((OptimisticBuiltins)wrappedSelf).getLinkLogic(linkLogicClass);
+ }
+ return null;
+ }
+
+ /**
* dyn:call call site signature: (callee, thiz, [args...])
* generated method signature: (callee, thiz, [args...])
*
@@ -547,8 +578,53 @@ public abstract class ScriptFunction extends ScriptObject {
}
} //else just fall through and link as ordinary function or unstable apply
- final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT;
- final CompiledFunction cf = data.getBestInvoker(type, scope);
+ int programPoint = INVALID_PROGRAM_POINT;
+ if (NashornCallSiteDescriptor.isOptimistic(desc)) {
+ programPoint = NashornCallSiteDescriptor.getProgramPoint(desc);
+ }
+
+ CompiledFunction cf = data.getBestInvoker(type, scope, CompiledFunction.NO_FUNCTIONS);
+ final Object self = request.getArguments()[1];
+ final Collection<CompiledFunction> forbidden = new HashSet<>();
+
+ //check for special fast versions of the compiled function
+ final List<SwitchPoint> sps = new ArrayList<>();
+ Class<? extends Throwable> exceptionGuard = null;
+
+ while (cf.isSpecialization()) {
+ final Class<? extends LinkLogic> linkLogicClass = cf.getLinkLogicClass();
+ //if linklogic is null, we can always link with the standard mechanism, it's still a specialization
+ final LinkLogic linkLogic = getLinkLogic(self, linkLogicClass);
+
+ if (linkLogic != null && linkLogic.checkLinkable(self, desc, request)) {
+ final DebugLogger log = Context.getContextTrusted().getLogger(Compiler.class);
+
+ if (log.isEnabled()) {
+ log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc);
+ }
+
+ final SwitchPoint[] msps = linkLogic.getModificationSwitchPoints();
+ if (msps != null) {
+ for (final SwitchPoint sp : msps) {
+ if (sp != null) {
+ assert !sp.hasBeenInvalidated();
+ sps.add(sp);
+ }
+ }
+ }
+
+ exceptionGuard = linkLogic.getRelinkException();
+
+ break;
+ }
+
+ //could not link this specialization because link check failed
+ forbidden.add(cf);
+ final CompiledFunction oldCf = cf;
+ cf = data.getBestInvoker(type, scope, forbidden);
+ assert oldCf != cf;
+ }
+
final GuardedInvocation bestInvoker = cf.createFunctionInvocation(type.returnType(), programPoint);
final MethodHandle callHandle = bestInvoker.getInvocation();
@@ -588,7 +664,20 @@ public abstract class ScriptFunction extends ScriptObject {
boundHandle = pairArguments(boundHandle, type);
- return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this, cf.getFlags()) : guard, bestInvoker.getSwitchPoints(), null);
+ if (bestInvoker.getSwitchPoints() != null) {
+ sps.addAll(Arrays.asList(bestInvoker.getSwitchPoints()));
+ }
+ final SwitchPoint[] spsArray = sps.isEmpty() ? null : sps.toArray(new SwitchPoint[sps.size()]);
+
+ return new GuardedInvocation(
+ boundHandle,
+ guard == null ?
+ getFunctionGuard(
+ this,
+ cf.getFlags()) :
+ guard,
+ spsArray,
+ exceptionGuard);
}
private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
@@ -610,7 +699,7 @@ public abstract class ScriptFunction extends ScriptObject {
//box call back to apply
CallSiteDescriptor appliedDesc = desc;
- final SwitchPoint applyToCallSwitchPoint = Global.instance().getChangeCallback("apply");
+ final SwitchPoint applyToCallSwitchPoint = Global.getBuiltinFunctionApplySwitchPoint();
//enough to change the proto switchPoint here
final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
@@ -656,7 +745,7 @@ public abstract class ScriptFunction extends ScriptObject {
}
}
- appliedDesc = appliedDesc.changeMethodType(appliedType);
+ appliedDesc = appliedDesc.changeMethodType(appliedType); //no extra args
// Create the same arguments for the delegate linking request that would be passed in an actual apply'd invocation
final Object[] appliedArgs = new Object[isApply ? 3 : appliedType.parameterCount()];
@@ -681,6 +770,7 @@ public abstract class ScriptFunction extends ScriptObject {
// Ask the linker machinery for an invocation of the target function
final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
+
GuardedInvocation appliedInvocation;
try {
appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
@@ -742,7 +832,7 @@ public abstract class ScriptFunction extends ScriptObject {
// We need to account for the dropped (apply|call) function argument.
guard = MH.dropArguments(guard, 0, descType.parameterType(0));
// Take the "isApplyFunction" guard, and bind it to this function.
- MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this);
+ MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint
// Adapt the guard to receive all the arguments that the original guard does.
applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray());
// Fold the original function guard into our apply guard.
@@ -894,6 +984,7 @@ public abstract class ScriptFunction extends ScriptObject {
return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
}
+ //TODO this can probably be removed given that we have builtin switchpoints in the context
@SuppressWarnings("unused")
private static boolean isApplyFunction(final boolean appliedFnCondition, final Object self, final Object expectedSelf) {
// NOTE: we're using self == expectedSelf as we're only using this with built-in functions apply() and call()
diff --git a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
index d92b12d9..3472cda1 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptFunctionData.java
@@ -28,13 +28,13 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
@@ -136,7 +136,7 @@ public abstract class ScriptFunctionData implements Serializable {
final MethodHandle boundInvoker = bindInvokeHandle(originalInv.createComposableInvoker(), fn, self, args);
if (isConstructor()) {
- return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.createComposableConstructor(), fn, args));
+ return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.createComposableConstructor(), fn, args), null);
}
return new CompiledFunction(boundInvoker);
@@ -224,18 +224,22 @@ public abstract class ScriptFunctionData implements Serializable {
* @param callSiteType callsite type
* @return compiled function object representing the best invoker.
*/
- final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope) {
- final CompiledFunction cf = getBest(callSiteType, runtimeScope);
+ final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope) {
+ return getBestInvoker(callSiteType, runtimeScope, CompiledFunction.NO_FUNCTIONS);
+ }
+
+ final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
+ final CompiledFunction cf = getBest(callSiteType, runtimeScope, forbidden);
assert cf != null;
return cf;
}
- final CompiledFunction getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope) {
+ final CompiledFunction getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
if (!isConstructor()) {
throw typeError("not.a.constructor", toSource());
}
// Constructor call sites don't have a "this", but getBest is meant to operate on "callee, this, ..." style
- final CompiledFunction cf = getBest(callSiteType.insertParameterTypes(1, Object.class), runtimeScope);
+ final CompiledFunction cf = getBest(callSiteType.insertParameterTypes(1, Object.class), runtimeScope, forbidden);
return cf;
}
@@ -350,7 +354,7 @@ public abstract class ScriptFunctionData implements Serializable {
* scope is not known, but that might cause compilation of code that will need more deoptimization passes.
* @return the best function for the specified call site type.
*/
- CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) {
+ CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
assert callSiteType.parameterCount() >= 2 : callSiteType; // Must have at least (callee, this)
assert callSiteType.parameterType(0).isAssignableFrom(ScriptFunction.class) : callSiteType; // Callee must be assignable from script function
@@ -363,8 +367,8 @@ public abstract class ScriptFunctionData implements Serializable {
}
CompiledFunction best = null;
- for(final CompiledFunction candidate: code) {
- if(candidate.betterThanFinal(best, callSiteType)) {
+ for (final CompiledFunction candidate: code) {
+ if (!forbidden.contains(candidate) && candidate.betterThanFinal(best, callSiteType)) {
best = candidate;
}
}
@@ -376,7 +380,7 @@ public abstract class ScriptFunctionData implements Serializable {
abstract boolean isRecompilable();
CompiledFunction getGeneric(final ScriptObject runtimeScope) {
- return getBest(getGenericType(), runtimeScope);
+ return getBest(getGenericType(), runtimeScope, CompiledFunction.NO_FUNCTIONS);
}
/**
@@ -420,7 +424,7 @@ public abstract class ScriptFunctionData implements Serializable {
final List<CompiledFunction> boundList = new LinkedList<>();
final ScriptObject runtimeScope = fn.getScope();
- final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(runtimeScope), getGenericConstructor(runtimeScope));
+ final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(runtimeScope), getGenericConstructor(runtimeScope), null);
boundList.add(bind(bindTarget, fn, self, allArgs));
return new FinalScriptFunctionData(name, Math.max(0, getArity() - length), boundList, boundFlags);
diff --git a/src/jdk/nashorn/internal/runtime/ScriptObject.java b/src/jdk/nashorn/internal/runtime/ScriptObject.java
index 8d616b58..87d28976 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptObject.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java
@@ -47,7 +47,6 @@ 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;
import java.lang.invoke.MethodType;
@@ -820,6 +819,19 @@ public abstract class ScriptObject implements PropertyAccess {
return false;
}
+ private SwitchPoint findBuiltinSwitchPoint(final String key) {
+ for (ScriptObject myProto = getProto(); myProto != null; myProto = myProto.getProto()) {
+ final Property prop = myProto.getMap().findProperty(key);
+ if (prop != null) {
+ final SwitchPoint sp = prop.getBuiltinSwitchPoint();
+ if (sp != null && !sp.hasBeenInvalidated()) {
+ return sp;
+ }
+ }
+ }
+ return null;
+ }
+
/**
* Add a new property to the object.
* <p>
@@ -923,10 +935,10 @@ public abstract class ScriptObject implements PropertyAccess {
* creating setters that probably aren't used. Inject directly into the spill pool
* the defaults for "arguments" and "caller"
*
- * @param key
- * @param propertyFlags
- * @param getter
- * @param setter
+ * @param key property key
+ * @param propertyFlags flags
+ * @param getter getter for {@link UserAccessorProperty}, null if not present or N/A
+ * @param setter setter for {@link UserAccessorProperty}, null if not present or N/A
*/
protected final void initUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
final int slot = spillLength;
@@ -1514,6 +1526,23 @@ public abstract class ScriptObject implements PropertyAccess {
}
/**
+ * Get the {@link ArrayData}, for this ScriptObject, ensuring it is of a type
+ * that can handle elementType
+ * @param elementType elementType
+ * @return array data
+ */
+ public final ArrayData getArray(final Class<?> elementType) {
+ if (elementType == null) {
+ return arrayData;
+ }
+ final ArrayData newArrayData = arrayData.convert(elementType);
+ if (newArrayData != arrayData) {
+ arrayData = newArrayData;
+ }
+ return newArrayData;
+ }
+
+ /**
* Get the {@link ArrayData} for this ScriptObject if it is an array
* @return array data
*/
@@ -1720,8 +1749,8 @@ public abstract class ScriptObject implements PropertyAccess {
*/
public Object put(final Object key, final Object value, final boolean strict) {
final Object oldValue = get(key);
- final int flags = strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0;
- set(key, value, flags);
+ final int scriptObjectFlags = strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0;
+ set(key, value, scriptObjectFlags);
return oldValue;
}
@@ -1734,9 +1763,9 @@ public abstract class ScriptObject implements PropertyAccess {
* @param strict strict mode or not
*/
public void putAll(final Map<?, ?> otherMap, final boolean strict) {
- final int flags = strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0;
+ final int scriptObjectFlags = strict ? NashornCallSiteDescriptor.CALLSITE_STRICT : 0;
for (final Map.Entry<?, ?> entry : otherMap.entrySet()) {
- set(entry.getKey(), entry.getValue(), flags);
+ set(entry.getKey(), entry.getValue(), scriptObjectFlags);
}
}
@@ -1916,17 +1945,6 @@ public abstract class ScriptObject implements PropertyAccess {
return MH.filterArguments(methodHandle, 0, filter.asType(filter.type().changeReturnType(methodHandle.type().parameterType(0))));
}
- //this will only return true if apply is still builtin
- private static SwitchPoint checkReservedName(final CallSiteDescriptor desc, final LinkRequest request) {
- final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
- final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
- if ("apply".equals(name) && isApplyToCall && Global.instance().isSpecialNameValid(name)) {
- assert Global.instance().getChangeCallback("apply") == Global.instance().getChangeCallback("call");
- return Global.instance().getChangeCallback("apply");
- }
- return null;
- }
-
/**
* Find the appropriate GET method for an invoke dynamic call.
*
@@ -1938,14 +1956,13 @@ public abstract class ScriptObject implements PropertyAccess {
*/
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
- final String name;
- final SwitchPoint reservedNameSwitchPoint;
- reservedNameSwitchPoint = checkReservedName(desc, request);
- if (reservedNameSwitchPoint != null) {
- name = "call"; //turn apply into call, it is the builtin apply and has been modified to explode args
- } else {
- name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+ String name;
+ name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+ if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
+ if (Global.isBuiltinFunctionPrototypeApply()) {
+ name = "call";
+ }
}
if (request.isCallSiteUnstable() || hasWithScope()) {
@@ -2006,7 +2023,7 @@ public abstract class ScriptObject implements PropertyAccess {
assert OBJECT_FIELDS_ONLY || guard != null : "we always need a map guard here";
final GuardedInvocation inv = new GuardedInvocation(mh, guard, protoSwitchPoint, exception);
- return inv.addSwitchPoint(reservedNameSwitchPoint);
+ return inv.addSwitchPoint(findBuiltinSwitchPoint(name));
}
private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
@@ -2029,7 +2046,7 @@ public abstract class ScriptObject implements PropertyAccess {
// Marks a property as declared and sets its value. Used as slow path for block-scoped LET and CONST
@SuppressWarnings("unused")
private void declareAndSet(final String key, final Object value) {
- final PropertyMap map = getMap();
+ final PropertyMap oldMap = getMap();
final FindProperty find = findProperty(key, false);
assert find != null;
@@ -2037,7 +2054,7 @@ public abstract class ScriptObject implements PropertyAccess {
assert property != null;
assert property.needsDeclaration();
- final PropertyMap newMap = map.replaceProperty(property, property.removeFlags(Property.NEEDS_DECLARATION));
+ final PropertyMap newMap = oldMap.replaceProperty(property, property.removeFlags(Property.NEEDS_DECLARATION));
setMap(newMap);
set(key, value, 0);
}
@@ -2166,7 +2183,7 @@ public abstract class ScriptObject implements PropertyAccess {
}
}
- final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation();
+ final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation(findBuiltinSwitchPoint(name));
final GuardedInvocation cinv = Global.getConstants().findSetMethod(find, this, inv, desc, request);
if (cinv != null) {
@@ -2429,7 +2446,7 @@ public abstract class ScriptObject implements PropertyAccess {
@Override
public void remove() {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("remove");
}
}
diff --git a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
index 47b2a8da..e927d4fc 100644
--- a/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
+++ b/src/jdk/nashorn/internal/runtime/ScriptRuntime.java
@@ -32,9 +32,9 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
import static jdk.nashorn.internal.runtime.ECMAErrors.syntaxError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
+import java.lang.invoke.SwitchPoint;
import java.lang.reflect.Array;
import java.util.Collections;
import java.util.Iterator;
@@ -46,6 +46,7 @@ import java.util.Objects;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.internal.codegen.ApplySpecialization;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.ir.debug.JSONWriter;
@@ -113,6 +114,11 @@ public final class ScriptRuntime {
public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError", void.class, String.class);
/**
+ * Used to invalidate builtin names, e.g "Function" mapping to all properties in Function.prototype and Function.prototype itself.
+ */
+ public static final Call INVALIDATE_RESERVED_BUILTIN_NAME = staticCallNoLookup(ScriptRuntime.class, "invalidateReservedBuiltinName", void.class, String.class);
+
+ /**
* Converts a switch tag value to a simple integer. deflt value if it can't.
*
* @param tag Switch statement tag value.
@@ -290,7 +296,7 @@ public final class ScriptRuntime {
@Override
public void remove() {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("remove");
}
}
@@ -328,7 +334,7 @@ public final class ScriptRuntime {
@Override
public void remove() {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("remove");
}
};
}
@@ -998,4 +1004,19 @@ public final class ScriptRuntime {
return nx < ny;
}
+ /**
+ * Tag a reserved name as invalidated - used when someone writes
+ * to a property with this name - overly conservative, but link time
+ * is too late to apply e.g. apply-&gt;call specialization
+ * @param name property name
+ */
+ public static void invalidateReservedBuiltinName(final String name) {
+ final Context context = Context.getContextTrusted();
+ final SwitchPoint sp = context.getBuiltinSwitchPoint(name);
+ assert sp != null;
+ if (sp != null) {
+ context.getLogger(ApplySpecialization.class).info("Overwrote special name '" + name +"' - invalidating switchpoint");
+ SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+ }
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
index 99ec3135..90bbf43c 100644
--- a/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
+++ b/src/jdk/nashorn/internal/runtime/SetMethodCreator.java
@@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
@@ -81,8 +80,8 @@ final class SetMethodCreator {
* Creates the actual guarded invocation that represents the dynamic setter method for the property.
* @return the actual guarded invocation that represents the dynamic setter method for the property.
*/
- GuardedInvocation createGuardedInvocation() {
- return createSetMethod().createGuardedInvocation();
+ GuardedInvocation createGuardedInvocation(final SwitchPoint builtinSwitchPoint) {
+ return createSetMethod(builtinSwitchPoint).createGuardedInvocation();
}
/**
@@ -119,7 +118,7 @@ final class SetMethodCreator {
}
}
- private SetMethod createSetMethod() {
+ private SetMethod createSetMethod(final SwitchPoint builtinSwitchPoint) {
if (find != null) {
return createExistingPropertySetter();
}
@@ -130,7 +129,7 @@ final class SetMethodCreator {
return createGlobalPropertySetter();
}
- return createNewPropertySetter();
+ return createNewPropertySetter(builtinSwitchPoint);
}
private void checkStrictCreateNewVariable() {
@@ -185,8 +184,8 @@ final class SetMethodCreator {
return new SetMethod(MH.filterArguments(global.addSpill(type, getName()), 0, ScriptObject.GLOBALFILTER), null);
}
- private SetMethod createNewPropertySetter() {
- final SetMethod sm = map.getFreeFieldSlot() > -1 ? createNewFieldSetter() : createNewSpillPropertySetter();
+ private SetMethod createNewPropertySetter(final SwitchPoint builtinSwitchPoint) {
+ final SetMethod sm = map.getFreeFieldSlot() > -1 ? createNewFieldSetter(builtinSwitchPoint) : createNewSpillPropertySetter(builtinSwitchPoint);
final PropertyListeners listeners = map.getListeners();
if (listeners != null) {
listeners.propertyAdded(sm.property);
@@ -194,7 +193,9 @@ final class SetMethodCreator {
return sm;
}
- private SetMethod createNewSetter(final Property property) {
+ private SetMethod createNewSetter(final Property property, final SwitchPoint builtinSwitchPoint) {
+ property.setBuiltinSwitchPoint(builtinSwitchPoint);
+
final PropertyMap oldMap = getMap();
final PropertyMap newMap = getNewMap(property);
final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
@@ -230,12 +231,12 @@ final class SetMethodCreator {
return new SetMethod(MH.asType(MH.guardWithTest(extCheck, casGuard, nop), fastSetter.type()), property);
}
- private SetMethod createNewFieldSetter() {
- return createNewSetter(new AccessorProperty(getName(), 0, sobj.getClass(), getMap().getFreeFieldSlot(), type));
+ private SetMethod createNewFieldSetter(final SwitchPoint builtinSwitchPoint) {
+ return createNewSetter(new AccessorProperty(getName(), 0, sobj.getClass(), getMap().getFreeFieldSlot(), type), builtinSwitchPoint);
}
- private SetMethod createNewSpillPropertySetter() {
- return createNewSetter(new SpillProperty(getName(), 0, getMap().getFreeSpillSlot(), type));
+ private SetMethod createNewSpillPropertySetter(final SwitchPoint builtinSwitchPoint) {
+ return createNewSetter(new SpillProperty(getName(), 0, getMap().getFreeSpillSlot(), type), builtinSwitchPoint);
}
private PropertyMap getNewMap(final Property property) {
diff --git a/src/jdk/nashorn/internal/runtime/Specialization.java b/src/jdk/nashorn/internal/runtime/Specialization.java
new file mode 100644
index 00000000..9807cc61
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/Specialization.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime;
+
+import java.lang.invoke.MethodHandle;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
+
+/**
+ * Specialization info for a {@link SpecializedFunction}
+ */
+public final class Specialization {
+ private final MethodHandle mh;
+ private final Class<? extends LinkLogic> linkLogicClass;
+ private final boolean isOptimistic;
+
+ /**
+ * Constructor
+ *
+ * @param mh invoker method handler
+ */
+ public Specialization(final MethodHandle mh) {
+ this(mh, false);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param mh invoker method handler
+ * @param isOptimistic is this an optimistic native method, i.e. can it throw {@link UnwarrantedOptimismException}
+ * which would have to lead to a relink and return value processing
+ */
+ public Specialization(final MethodHandle mh, final boolean isOptimistic) {
+ this(mh, null, isOptimistic);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param mh invoker method handler
+ * @param linkLogicClass extra link logic needed for this function. Instances of this class also contains logic for checking
+ * if this can be linked on its first encounter, which is needed as per our standard linker semantics
+ * @param isOptimistic is this an optimistic native method, i.e. can it throw {@link UnwarrantedOptimismException}
+ * which would have to lead to a relink and return value processing
+ */
+ public Specialization(final MethodHandle mh, final Class<? extends LinkLogic> linkLogicClass, final boolean isOptimistic) {
+ this.mh = mh;
+ this.isOptimistic = isOptimistic;
+ if (linkLogicClass != null) {
+ //null out the "empty" link logic class for optimization purposes
+ //we only use the empty instance because we can't default class annotations
+ //to null
+ this.linkLogicClass = LinkLogic.isEmpty(linkLogicClass) ? null : linkLogicClass;
+ } else {
+ this.linkLogicClass = null;
+ }
+ }
+
+ /**
+ * Get the method handle for the invoker of this ScriptFunction
+ * @return the method handle
+ */
+ public MethodHandle getMethodHandle() {
+ return mh;
+ }
+
+ /**
+ * Get the link logic class for this ScriptFunction
+ * @return link logic class info, i.e. one whose instance contains stuff like
+ * "do we need exception check for every call", and logic to check if we may link
+ */
+ public Class<? extends LinkLogic> getLinkLogicClass() {
+ return linkLogicClass;
+ }
+
+ /**
+ * An optimistic specialization is one that can throw UnwarrantedOptimismException.
+ * This is allowed for native methods, as long as they are functional, i.e. don't change
+ * any state between entering and throwing the UOE. Then we can re-execute a wider version
+ * of the method in the continuation. Rest-of method generation for optimistic builtins is
+ * of course not possible, but this approach works and fits into the same relinking
+ * framework
+ *
+ * @return true if optimistic
+ */
+ public boolean isOptimistic() {
+ return isOptimistic;
+ }
+
+}
+
diff --git a/src/jdk/nashorn/internal/runtime/StoredScript.java b/src/jdk/nashorn/internal/runtime/StoredScript.java
index 5b6a77b2..14a0ced0 100644
--- a/src/jdk/nashorn/internal/runtime/StoredScript.java
+++ b/src/jdk/nashorn/internal/runtime/StoredScript.java
@@ -55,8 +55,10 @@ public final class StoredScript implements Serializable {
/**
* Constructor.
*
+ * @param compilationId compilation id
* @param mainClassName main class name
* @param classBytes map of class names to class bytes
+ * @param initializers initializer map, id -> FunctionInitializer
* @param constants constants array
*/
public StoredScript(final int compilationId, final String mainClassName, final Map<String, byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers, final Object[] constants) {
@@ -67,6 +69,10 @@ public final class StoredScript implements Serializable {
this.initializers = initializers;
}
+ /**
+ * Get the compilation id for this StoredScript
+ * @return compilation id
+ */
public int getCompilationId() {
return compilationId;
}
diff --git a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
index 7350ff43..5fdec009 100644
--- a/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
+++ b/src/jdk/nashorn/internal/runtime/UserAccessorProperty.java
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.runtime;
-import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.CONVERT_OBJECT_OPTIMISTIC;
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
index 897636eb..9e606ee6 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@@ -58,7 +57,7 @@ public abstract class ArrayData {
/**
* Length of the array data. Not necessarily length of the wrapped array.
*/
- private long length;
+ protected long length;
/**
* Method handle to throw an {@link UnwarrantedOptimismException} when getting an element
@@ -520,7 +519,7 @@ public abstract class ArrayData {
* @param type new element type
* @return new array data
*/
- protected abstract ArrayData convert(Class<?> type);
+ public abstract ArrayData convert(Class<?> type);
/**
* Push an array of items to the end of the array
@@ -537,7 +536,7 @@ public abstract class ArrayData {
final Class<?> widest = widestType(items);
ArrayData newData = convert(widest);
- long pos = newData.length();
+ long pos = newData.length;
for (final Object item : items) {
newData = newData.ensure(pos); //avoid sparse array
newData.set((int)pos++, item, strict);
@@ -655,7 +654,7 @@ public abstract class ArrayData {
* @param size current size
* @return next size to allocate for internal array
*/
- protected static int nextSize(final int size) {
+ public static int nextSize(final int size) {
return alignUp(size + 1) * 2;
}
@@ -681,6 +680,18 @@ public abstract class ArrayData {
}
}
+ /**
+ * Find a fast call if one exists
+ *
+ * @param clazz array data class
+ * @param desc callsite descriptor
+ * @param request link request
+ * @return fast property getter if one is found
+ */
+ public GuardedInvocation findFastCallMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) {
+ return null;
+ }
+
/**
* Find a fast property getter if one exists
*
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
index be41673b..8d71cc04 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
@@ -39,7 +39,7 @@ abstract class ArrayFilter extends ArrayData {
protected ArrayData underlying;
ArrayFilter(final ArrayData underlying) {
- super(underlying.length());
+ super(underlying.length);
this.underlying = underlying;
}
@@ -70,13 +70,13 @@ abstract class ArrayFilter extends ArrayData {
@Override
public void shiftLeft(final int by) {
underlying.shiftLeft(by);
- setLength(underlying.length());
+ setLength(underlying.length);
}
@Override
public ArrayData shiftRight(final int by) {
underlying = underlying.shiftRight(by);
- setLength(underlying.length());
+ setLength(underlying.length);
return this;
}
@@ -84,7 +84,7 @@ abstract class ArrayFilter extends ArrayData {
@Override
public ArrayData ensure(final long safeIndex) {
underlying = underlying.ensure(safeIndex);
- setLength(underlying.length());
+ setLength(underlying.length);
return this;
}
@@ -92,7 +92,7 @@ abstract class ArrayFilter extends ArrayData {
@Override
public ArrayData shrink(final long newLength) {
underlying = underlying.shrink(newLength);
- setLength(underlying.length());
+ setLength(underlying.length);
return this;
}
@@ -100,7 +100,7 @@ abstract class ArrayFilter extends ArrayData {
@Override
public ArrayData set(final int index, final Object value, final boolean strict) {
underlying = underlying.set(index, value, strict);
- setLength(underlying.length());
+ setLength(underlying.length);
return this;
}
@@ -108,7 +108,7 @@ abstract class ArrayFilter extends ArrayData {
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
underlying = underlying.set(index, value, strict);
- setLength(underlying.length());
+ setLength(underlying.length);
return this;
}
@@ -116,7 +116,7 @@ abstract class ArrayFilter extends ArrayData {
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
underlying = underlying.set(index, value, strict);
- setLength(underlying.length());
+ setLength(underlying.length);
return this;
}
@@ -124,7 +124,7 @@ abstract class ArrayFilter extends ArrayData {
@Override
public ArrayData set(final int index, final double value, final boolean strict) {
underlying = underlying.set(index, value, strict);
- setLength(underlying.length());
+ setLength(underlying.length);
return this;
}
@@ -189,28 +189,28 @@ abstract class ArrayFilter extends ArrayData {
@Override
public ArrayData delete(final int index) {
underlying = underlying.delete(index);
- setLength(underlying.length());
+ setLength(underlying.length);
return this;
}
@Override
public ArrayData delete(final long from, final long to) {
underlying = underlying.delete(from, to);
- setLength(underlying.length());
+ setLength(underlying.length);
return this;
}
@Override
- protected ArrayData convert(final Class<?> type) {
+ public ArrayData convert(final Class<?> type) {
underlying = underlying.convert(type);
- setLength(underlying.length());
+ setLength(underlying.length);
return this;
}
@Override
public Object pop() {
final Object value = underlying.pop();
- setLength(underlying.length());
+ setLength(underlying.length);
return value;
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
index f6e4d38c..dfa6133d 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java
@@ -30,7 +30,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -77,11 +76,11 @@ public abstract class ContinuousArrayData extends ArrayData {
* array without reallocating, or if we are overwriting an already
* allocated element
*
- * @param index
+ * @param index index to check
* @return true if we don't need to do any array reallocation to fit an element at index
*/
public final boolean hasRoomFor(final int index) {
- return has(index) || (index == length() && ensure(index) == this);
+ return has(index) || (index == length && ensure(index) == this);
}
/**
@@ -116,6 +115,12 @@ public abstract class ContinuousArrayData extends ArrayData {
}
/**
+ * Returns the type used to store an element in this array
+ * @return element type
+ */
+ public abstract Class<?> getElementType();
+
+ /**
* 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
@@ -175,11 +180,6 @@ public abstract class ContinuousArrayData extends ArrayData {
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 =
@@ -269,4 +269,72 @@ public abstract class ContinuousArrayData extends ArrayData {
return null;
}
+
+ /**
+ * Specialization - fast push implementation
+ * @param arg argument
+ * @return new array length
+ */
+ public long fastPush(final int arg) {
+ throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+ }
+
+ /**
+ * Specialization - fast push implementation
+ * @param arg argument
+ * @return new array length
+ */
+ public long fastPush(final long arg) {
+ throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+ }
+
+ /**
+ * Specialization - fast push implementation
+ * @param arg argument
+ * @return new array length
+ */
+ public long fastPush(final double arg) {
+ throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+ }
+
+ /**
+ * Specialization - fast push implementation
+ * @param arg argument
+ * @return new array length
+ */
+ public long fastPush(final Object arg) {
+ throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+ }
+
+ /**
+ * Specialization - fast pop implementation
+ * @return element value
+ */
+ public int fastPopInt() {
+ throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+ }
+
+ /**
+ * Specialization - fast pop implementation
+ * @return element value
+ */
+ public long fastPopLong() {
+ throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+ }
+
+ /**
+ * Specialization - fast pop implementation
+ * @return element value
+ */
+ public double fastPopDouble() {
+ throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+ }
+
+ /**
+ * Specialization - fast pop implementation
+ * @return element value
+ */
+ public Object fastPopObject() {
+ throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java
index bf120eac..4f54b639 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedArrayFilter.java
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
import java.lang.reflect.Array;
import jdk.nashorn.internal.runtime.BitVector;
@@ -40,7 +39,7 @@ final class DeletedArrayFilter extends ArrayFilter {
DeletedArrayFilter(final ArrayData underlying) {
super(underlying);
- this.deleted = new BitVector(underlying.length());
+ this.deleted = new BitVector(underlying.length);
}
@Override
@@ -80,25 +79,25 @@ final class DeletedArrayFilter extends ArrayFilter {
@Override
public void shiftLeft(final int by) {
super.shiftLeft(by);
- deleted.shiftLeft(by, length());
+ deleted.shiftLeft(by, length);
}
@Override
public ArrayData shiftRight(final int by) {
super.shiftRight(by);
- deleted.shiftRight(by, length());
+ deleted.shiftRight(by, length);
return this;
}
@Override
public ArrayData ensure(final long safeIndex) {
- if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
+ if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
return new SparseArrayData(this, safeIndex + 1);
}
super.ensure(safeIndex);
- deleted.resize(length());
+ deleted.resize(length);
return this;
}
@@ -106,7 +105,7 @@ final class DeletedArrayFilter extends ArrayFilter {
@Override
public ArrayData shrink(final long newLength) {
super.shrink(newLength);
- deleted.resize(length());
+ deleted.resize(length);
return this;
}
@@ -147,7 +146,7 @@ final class DeletedArrayFilter extends ArrayFilter {
@Override
public ArrayData delete(final int index) {
final long longIndex = ArrayIndex.toLongIndex(index);
- assert longIndex >= 0 && longIndex < length();
+ assert longIndex >= 0 && longIndex < length;
deleted.set(longIndex);
underlying.setEmpty(index);
return this;
@@ -155,7 +154,7 @@ final class DeletedArrayFilter extends ArrayFilter {
@Override
public ArrayData delete(final long fromIndex, final long toIndex) {
- assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length();
+ assert fromIndex >= 0 && fromIndex <= toIndex && toIndex < length;
deleted.setRange(fromIndex, toIndex + 1);
underlying.setEmpty(fromIndex, toIndex);
return this;
@@ -163,7 +162,7 @@ final class DeletedArrayFilter extends ArrayFilter {
@Override
public Object pop() {
- final long index = length() - 1;
+ final long index = length - 1;
if (super.has((int)index)) {
final boolean isDeleted = deleted.isSet(index);
@@ -180,7 +179,7 @@ final class DeletedArrayFilter extends ArrayFilter {
final ArrayData newArray = underlying.slice(from, to);
final DeletedArrayFilter newFilter = new DeletedArrayFilter(newArray);
newFilter.getDeleted().copy(deleted);
- newFilter.getDeleted().shiftLeft(from, newFilter.length());
+ newFilter.getDeleted().shiftLeft(from, newFilter.length);
return newFilter;
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java
index b74d0782..8732add9 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/DeletedRangeArrayFilter.java
@@ -45,7 +45,7 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
if(hi < SparseArrayData.MAX_DENSE_LENGTH || underlying instanceof SparseArrayData) {
return underlying;
}
- return new SparseArrayData(underlying, underlying.length());
+ return new SparseArrayData(underlying, underlying.length);
}
private boolean isEmpty() {
@@ -93,7 +93,7 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
@Override
public ArrayData ensure(final long safeIndex) {
- if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
+ if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
return new SparseArrayData(this, safeIndex + 1);
}
@@ -110,8 +110,9 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
@Override
public ArrayData shiftRight(final int by) {
super.shiftRight(by);
- lo = Math.min(length(), lo + by);
- hi = Math.min(length() - 1, hi + by);
+ final long len = length;
+ lo = Math.min(len, lo + by);
+ hi = Math.min(len - 1, hi + by);
return isEmpty() ? getUnderlying() : this;
}
@@ -237,7 +238,7 @@ final class DeletedRangeArrayFilter extends ArrayFilter {
@Override
public Object pop() {
- final int index = (int)(length() - 1);
+ final int index = (int)length - 1;
if (super.has(index)) {
final boolean isDeleted = isDeleted(index);
final Object value = super.pop();
diff --git a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
index 57d0cd90..48dd088e 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@@ -38,7 +37,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
* 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 ContinuousArrayData {
+final class IntArrayData extends ContinuousArrayData implements IntElements {
/**
* The wrapped array
*/
@@ -64,9 +63,19 @@ final class IntArrayData extends ContinuousArrayData {
this.array = array;
}
+ @Override
+ public Class<?> getElementType() {
+ return int.class;
+ }
+
private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle();
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
+ @Override
+ public Object[] asObjectArray() {
+ return toObjectArray();
+ }
+
@SuppressWarnings("unused")
private int getElem(final int index) {
if (has(index)) {
@@ -96,23 +105,18 @@ final class IntArrayData extends ContinuousArrayData {
@Override
public ArrayData copy() {
- return new IntArrayData(array.clone(), (int) length());
- }
-
- @Override
- public Object[] asObjectArray() {
- return toObjectArray(array, (int) length());
+ return new IntArrayData(array.clone(), (int)length);
}
@Override
public Object asArrayOfType(final Class<?> componentType) {
if (componentType == int.class) {
- return array.length == length() ? array.clone() : Arrays.copyOf(array, (int) length());
+ return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
}
return super.asArrayOfType(componentType);
}
- private static Object[] toObjectArray(final int[] array, final int length) {
+ private Object[] toObjectArray() {
assert length <= array.length : "length exceeds internal array size";
final Object[] oarray = new Object[array.length];
@@ -123,7 +127,7 @@ final class IntArrayData extends ContinuousArrayData {
return oarray;
}
- private static double[] toDoubleArray(final int[] array, final int length) {
+ private double[] toDoubleArray() {
assert length <= array.length : "length exceeds internal array size";
final double[] darray = new double[array.length];
@@ -134,7 +138,7 @@ final class IntArrayData extends ContinuousArrayData {
return darray;
}
- private static long[] toLongArray(final int[] array, final int length) {
+ private long[] toLongArray() {
assert length <= array.length : "length exceeds internal array size";
final long[] larray = new long[array.length];
@@ -145,18 +149,30 @@ final class IntArrayData extends ContinuousArrayData {
return larray;
}
+ private LongArrayData convertToLong() {
+ return new LongArrayData(toLongArray(), (int)length);
+ }
+
+ private NumberArrayData convertToDouble() {
+ return new NumberArrayData(toDoubleArray(), (int)length);
+ }
+
+ private ObjectArrayData convertToObject() {
+ return new ObjectArrayData(toObjectArray(), (int)length);
+ }
+
@Override
public ArrayData convert(final Class<?> type) {
if (type == Integer.class) {
return this;
}
- final int length = (int) length();
if (type == Long.class) {
- return new LongArrayData(IntArrayData.toLongArray(array, length), length);
+ return convertToLong();
} else if (type == Double.class) {
- return new NumberArrayData(IntArrayData.toDoubleArray(array, length), length);
+ return convertToDouble();
} else {
- return new ObjectArrayData(IntArrayData.toObjectArray(array, length), length);
+ assert type == null || (!Number.class.isAssignableFrom(type) && !type.isPrimitive());
+ return convertToObject();
}
}
@@ -167,7 +183,7 @@ final class IntArrayData extends ContinuousArrayData {
@Override
public ArrayData shiftRight(final int by) {
- final ArrayData newData = ensure(by + length() - 1);
+ final ArrayData newData = ensure(by + length - 1);
if (newData != this) {
newData.shiftRight(by);
return newData;
@@ -213,7 +229,7 @@ final class IntArrayData extends ContinuousArrayData {
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
array[index] = value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@@ -222,7 +238,7 @@ final class IntArrayData extends ContinuousArrayData {
public ArrayData set(final int index, final long value, final boolean strict) {
if (JSType.isRepresentableAsInt(value)) {
array[index] = JSType.toInt32(value);
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@@ -233,7 +249,7 @@ final class IntArrayData extends ContinuousArrayData {
public ArrayData set(final int index, final double value, final boolean strict) {
if (JSType.isRepresentableAsInt(value)) {
array[index] = (int)(long)value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@@ -282,7 +298,7 @@ final class IntArrayData extends ContinuousArrayData {
@Override
public boolean has(final int index) {
- return 0 <= index && index < length();
+ return 0 <= index && index < length;
}
@Override
@@ -297,11 +313,11 @@ final class IntArrayData extends ContinuousArrayData {
@Override
public Object pop() {
- if (length() == 0) {
+ if (length == 0) {
return ScriptRuntime.UNDEFINED;
}
- final int newLength = (int) length() - 1;
+ final int newLength = (int)length - 1;
final int elem = array[newLength];
array[newLength] = 0;
setLength(newLength);
@@ -311,7 +327,7 @@ final class IntArrayData extends ContinuousArrayData {
@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);
@@ -319,18 +335,18 @@ final class IntArrayData extends ContinuousArrayData {
@Override
public final ArrayData push(final boolean strict, final int item) {
- final long length = length();
- final ArrayData newData = ensure(length);
+ final long len = length;
+ final ArrayData newData = ensure(len);
if (newData == this) {
- array[(int)length] = item;
+ array[(int)len] = item;
return this;
}
- return newData.set((int)length, item, strict);
+ return newData.set((int)len, item, strict);
}
@Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
- final long oldLength = length();
+ final long oldLength = length;
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
@@ -355,4 +371,41 @@ final class IntArrayData extends ContinuousArrayData {
return returnValue;
}
+
+ @Override
+ public long fastPush(final int arg) {
+ final int len = (int)length;
+ if (len == array.length) {
+ array = Arrays.copyOf(array, nextSize(len));
+ }
+ array[len] = arg;
+ return ++length;
+ }
+
+ //length must not be zero
+ @Override
+ public int fastPopInt() {
+ if (length == 0) {
+ throw new ClassCastException(); //relink
+ }
+ final int newLength = (int)--length;
+ final int elem = array[newLength];
+ array[newLength] = 0;
+ return elem;
+ }
+
+ @Override
+ public long fastPopLong() {
+ return fastPopInt();
+ }
+
+ @Override
+ public double fastPopDouble() {
+ return fastPopInt();
+ }
+
+ @Override
+ public Object fastPopObject() {
+ return fastPopInt();
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/IntElements.java b/src/jdk/nashorn/internal/runtime/arrays/IntElements.java
new file mode 100644
index 00000000..5bd26843
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntElements.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.internal.runtime.arrays;
+
+/**
+ * Marker interface for any ContinuousArray with int elements
+ * Used for type checks that throw ClassCastExceptions and force relinks
+ * for fast NativeArray specializations of builtin methods
+ */
+public interface IntElements extends IntOrLongElements {
+ //empty
+}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/IntOrLongElements.java b/src/jdk/nashorn/internal/runtime/arrays/IntOrLongElements.java
new file mode 100644
index 00000000..f176d757
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/arrays/IntOrLongElements.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.internal.runtime.arrays;
+
+/**
+ * Marker interface for any ContinuousArray with int or long elements
+ * Used for type checks that throw ClassCastExceptions and force relinks
+ * for fast NativeArray specializations of builtin methods
+ */
+public interface IntOrLongElements extends NumericElements {
+ //empty
+}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
index 4fc0c63e..ad050d69 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java
@@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@@ -39,7 +38,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
* Implementation of {@link ArrayData} as soon as a long has been
* written to the array
*/
-final class LongArrayData extends ContinuousArrayData {
+final class LongArrayData extends ContinuousArrayData implements IntOrLongElements {
/**
* The wrapped array
*/
@@ -57,13 +56,18 @@ final class LongArrayData extends ContinuousArrayData {
}
@Override
+ public Class<?> getElementType() {
+ return long.class;
+ }
+
+ @Override
public ArrayData copy() {
- return new LongArrayData(array.clone(), (int)length());
+ return new LongArrayData(array.clone(), (int)length);
}
@Override
public Object[] asObjectArray() {
- return toObjectArray(array, (int)length());
+ return toObjectArray(array, (int)length);
}
private static Object[] toObjectArray(final long[] array, final int length) {
@@ -80,7 +84,7 @@ final class LongArrayData extends ContinuousArrayData {
@Override
public Object asArrayOfType(final Class<?> componentType) {
if (componentType == long.class) {
- return array.length == length() ? array.clone() : Arrays.copyOf(array, (int)length());
+ return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
}
return super.asArrayOfType(componentType);
}
@@ -101,11 +105,11 @@ final class LongArrayData extends ContinuousArrayData {
if (type == Integer.class || type == Long.class) {
return this;
}
- final int length = (int) length();
+ final int len = (int)length;
if (type == Double.class) {
- return new NumberArrayData(LongArrayData.toDoubleArray(array, length), length);
+ return new NumberArrayData(LongArrayData.toDoubleArray(array, len), len);
}
- return new ObjectArrayData(LongArrayData.toObjectArray(array, length), length);
+ return new ObjectArrayData(LongArrayData.toObjectArray(array, len), len);
}
@Override
@@ -115,7 +119,7 @@ final class LongArrayData extends ContinuousArrayData {
@Override
public ArrayData shiftRight(final int by) {
- final ArrayData newData = ensure(by + length() - 1);
+ final ArrayData newData = ensure(by + length - 1);
if (newData != this) {
newData.shiftRight(by);
return newData;
@@ -161,14 +165,14 @@ final class LongArrayData extends ContinuousArrayData {
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
array[index] = value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
array[index] = value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@@ -176,7 +180,7 @@ final class LongArrayData extends ContinuousArrayData {
public ArrayData set(final int index, final double value, final boolean strict) {
if (JSType.isRepresentableAsLong(value)) {
array[index] = (long)value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
return convert(Double.class).set(index, value, strict);
@@ -252,7 +256,7 @@ final class LongArrayData extends ContinuousArrayData {
@Override
public boolean has(final int index) {
- return 0 <= index && index < length();
+ return 0 <= index && index < length;
}
@Override
@@ -267,11 +271,11 @@ final class LongArrayData extends ContinuousArrayData {
@Override
public Object pop() {
- if (length() == 0) {
+ if (length == 0) {
return ScriptRuntime.UNDEFINED;
}
- final int newLength = (int) (length() - 1);
+ final int newLength = (int)length - 1;
final long elem = array[newLength];
array[newLength] = 0;
setLength(newLength);
@@ -281,25 +285,25 @@ final class LongArrayData extends ContinuousArrayData {
@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);
+ final long len = length;
+ final ArrayData newData = ensure(len);
if (newData == this) {
- array[(int)length] = item;
+ array[(int)len] = item;
return this;
}
- return newData.set((int)length, item, strict);
+ return newData.set((int)len, item, strict);
}
@Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
- final long oldLength = length();
+ final long oldLength = length;
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
@@ -324,4 +328,40 @@ final class LongArrayData extends ContinuousArrayData {
return returnValue;
}
+
+ @Override
+ public long fastPush(final int arg) {
+ return fastPush((long)arg);
+ }
+
+ @Override
+ public long fastPush(final long arg) {
+ final int len = (int)length;
+ if (len == array.length) {
+ array = Arrays.copyOf(array, nextSize(len));
+ }
+ array[len] = arg;
+ return ++length;
+ }
+
+ @Override
+ public long fastPopLong() {
+ if (length == 0) {
+ throw new ClassCastException();
+ }
+ final int newLength = (int)--length;
+ final long elem = array[newLength];
+ array[newLength] = 0;
+ return elem;
+ }
+
+ @Override
+ public double fastPopDouble() {
+ return fastPopLong();
+ }
+
+ @Override
+ public Object fastPopObject() {
+ return fastPopLong();
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java
index 4e0ce373..143cd221 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/NoTypeArrayData.java
@@ -58,19 +58,19 @@ final class NoTypeArrayData extends ArrayData {
@Override
public ArrayData convert(final Class<?> type) {
- final long length = length();
+ final long len = length;
final ArrayData arrayData;
if (type == Long.class) {
- arrayData = new LongArrayData(new long[ArrayData.nextSize((int)length)], (int)length);
+ arrayData = new LongArrayData(new long[ArrayData.nextSize((int)len)], (int)len);
} else if (type == Double.class) {
- arrayData = new NumberArrayData(new double[ArrayData.nextSize((int)length)], (int)length);
+ arrayData = new NumberArrayData(new double[ArrayData.nextSize((int)len)], (int)len);
} else if (type == Integer.class) {
- arrayData = new IntArrayData(new int[ArrayData.nextSize((int)length)], (int)length);
+ arrayData = new IntArrayData(new int[ArrayData.nextSize((int)len)], (int)len);
} else {
assert !type.isPrimitive();
- arrayData = new ObjectArrayData(new Object[ArrayData.nextSize((int)length)], (int)length);
+ arrayData = new ObjectArrayData(new Object[ArrayData.nextSize((int)len)], (int)len);
}
- return length == 0 ? arrayData : new DeletedRangeArrayFilter(arrayData, 0, length - 1);
+ return length == 0 ? arrayData : new DeletedRangeArrayFilter(arrayData, 0, len - 1);
}
@Override
@@ -90,11 +90,11 @@ final class NoTypeArrayData extends ArrayData {
}
// Don't trample the shared EMPTY_ARRAY.
- if (length() == 0) {
- return new NoTypeArrayData(Math.max(safeIndex + 1, length()));
+ if (length == 0) {
+ return new NoTypeArrayData(Math.max(safeIndex + 1, length));
}
- setLength(Math.max(safeIndex + 1, length()));
+ setLength(Math.max(safeIndex + 1, length));
return this;
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
index 0739ae8e..b2d843e6 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java
@@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@@ -38,7 +37,7 @@ import jdk.nashorn.internal.codegen.types.Type;
* Implementation of {@link ArrayData} as soon as a double has been
* written to the array
*/
-final class NumberArrayData extends ContinuousArrayData {
+final class NumberArrayData extends ContinuousArrayData implements NumericElements {
/**
* The wrapped array
*/
@@ -56,13 +55,18 @@ final class NumberArrayData extends ContinuousArrayData {
}
@Override
+ public Class<?> getElementType() {
+ return double.class;
+ }
+
+ @Override
public ArrayData copy() {
- return new NumberArrayData(array.clone(), (int) length());
+ return new NumberArrayData(array.clone(), (int)length);
}
@Override
public Object[] asObjectArray() {
- return toObjectArray(array, (int) length());
+ return toObjectArray(array, (int)length);
}
private static Object[] toObjectArray(final double[] array, final int length) {
@@ -78,7 +82,7 @@ final class NumberArrayData extends ContinuousArrayData {
@Override
public Object asArrayOfType(final Class<?> componentType) {
if(componentType == double.class) {
- return array.length == length() ? array.clone() : Arrays.copyOf(array, (int) length());
+ return array.length == length ? array.clone() : Arrays.copyOf(array, (int)length);
}
return super.asArrayOfType(componentType);
}
@@ -86,8 +90,8 @@ final class NumberArrayData extends ContinuousArrayData {
@Override
public ArrayData convert(final Class<?> type) {
if (type != Double.class && type != Integer.class && type != Long.class) {
- final int length = (int) length();
- return new ObjectArrayData(NumberArrayData.toObjectArray(array, length), length);
+ final int len = (int)length;
+ return new ObjectArrayData(NumberArrayData.toObjectArray(array, len), len);
}
return this;
}
@@ -99,7 +103,7 @@ final class NumberArrayData extends ContinuousArrayData {
@Override
public ArrayData shiftRight(final int by) {
- final ArrayData newData = ensure(by + length() - 1);
+ final ArrayData newData = ensure(by + length - 1);
if (newData != this) {
newData.shiftRight(by);
return newData;
@@ -144,21 +148,21 @@ final class NumberArrayData extends ContinuousArrayData {
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
array[index] = value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
array[index] = value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@Override
public ArrayData set(final int index, final double value, final boolean strict) {
array[index] = value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@@ -227,7 +231,7 @@ final class NumberArrayData extends ContinuousArrayData {
@Override
public boolean has(final int index) {
- return 0 <= index && index < length();
+ return 0 <= index && index < length;
}
@Override
@@ -242,11 +246,11 @@ final class NumberArrayData extends ContinuousArrayData {
@Override
public Object pop() {
- if (length() == 0) {
+ if (length == 0) {
return UNDEFINED;
}
- final int newLength = (int) (length() - 1);
+ final int newLength = (int)length - 1;
final double elem = array[newLength];
array[newLength] = 0;
setLength(newLength);
@@ -255,25 +259,25 @@ final class NumberArrayData extends ContinuousArrayData {
@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);
+ final long len = length;
+ final ArrayData newData = ensure(len);
if (newData == this) {
- array[(int)length] = item;
+ array[(int)len] = item;
return this;
}
- return newData.set((int)length, item, strict);
+ return newData.set((int)len, item, strict);
}
@Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
- final long oldLength = length();
+ final long oldLength = length;
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
@@ -298,4 +302,41 @@ final class NumberArrayData extends ContinuousArrayData {
return returnValue;
}
+
+ @Override
+ public long fastPush(final int arg) {
+ return fastPush((double)arg);
+ }
+
+ @Override
+ public long fastPush(final long arg) {
+ return fastPush((double)arg);
+ }
+
+ @Override
+ public long fastPush(final double arg) {
+ final int len = (int)length;
+ if (len == array.length) {
+ //note that fastpush never creates spares arrays, there is nothing to gain by that - it will just use even more memory
+ array = Arrays.copyOf(array, nextSize(len));
+ }
+ array[len] = arg;
+ return ++length;
+ }
+
+ @Override
+ public double fastPopDouble() {
+ if (length == 0) {
+ throw new ClassCastException();
+ }
+ final int newLength = (int)--length;
+ final double elem = array[newLength];
+ array[newLength] = 0;
+ return elem;
+ }
+
+ @Override
+ public Object fastPopObject() {
+ return fastPopDouble();
+ }
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java b/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java
new file mode 100644
index 00000000..ad940e2a
--- /dev/null
+++ b/src/jdk/nashorn/internal/runtime/arrays/NumericElements.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.nashorn.internal.runtime.arrays;
+
+/**
+ * Marker interface for any ContinuousArray with numeric elements
+ * (int, long or double)
+ * Used for type checks that throw ClassCastExceptions and force relinks
+ * for fast NativeArray specializations of builtin methods
+ */
+public interface NumericElements {
+ //empty
+}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
index 636c8c25..8fd1a453 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
@@ -57,20 +56,25 @@ final class ObjectArrayData extends ContinuousArrayData {
}
@Override
+ public Class<?> getElementType() {
+ return Object.class;
+ }
+
+ @Override
public ArrayData copy() {
- return new ObjectArrayData(array.clone(), (int) length());
+ return new ObjectArrayData(array.clone(), (int)length);
}
@Override
public Object[] asObjectArray() {
- return array.length == length() ? array.clone() : asObjectArrayCopy();
+ return array.length == length ? array.clone() : asObjectArrayCopy();
}
private Object[] asObjectArrayCopy() {
- final long l = length();
- assert l <= Integer.MAX_VALUE;
- final Object[] copy = new Object[(int)l];
- System.arraycopy(array, 0, copy, 0, (int)l);
+ final long len = length;
+ assert len <= Integer.MAX_VALUE;
+ final Object[] copy = new Object[(int)len];
+ System.arraycopy(array, 0, copy, 0, (int)len);
return copy;
}
@@ -86,7 +90,7 @@ final class ObjectArrayData extends ContinuousArrayData {
@Override
public ArrayData shiftRight(final int by) {
- final ArrayData newData = ensure(by + length() - 1);
+ final ArrayData newData = ensure(by + length - 1);
if (newData != this) {
newData.shiftRight(by);
return newData;
@@ -118,28 +122,28 @@ final class ObjectArrayData extends ContinuousArrayData {
@Override
public ArrayData set(final int index, final Object value, final boolean strict) {
array[index] = value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@Override
public ArrayData set(final int index, final int value, final boolean strict) {
array[index] = value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@Override
public ArrayData set(final int index, final long value, final boolean strict) {
array[index] = value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@Override
public ArrayData set(final int index, final double value, final boolean strict) {
array[index] = value;
- setLength(Math.max(index + 1, length()));
+ setLength(Math.max(index + 1, length));
return this;
}
@@ -216,7 +220,7 @@ final class ObjectArrayData extends ContinuousArrayData {
@Override
public boolean has(final int index) {
- return 0 <= index && index < length();
+ return 0 <= index && index < length;
}
@Override
@@ -232,12 +236,48 @@ final class ObjectArrayData extends ContinuousArrayData {
}
@Override
+ public long fastPush(final int arg) {
+ return fastPush((Object)arg);
+ }
+
+ @Override
+ public long fastPush(final long arg) {
+ return fastPush((Object)arg);
+ }
+
+ @Override
+ public long fastPush(final double arg) {
+ return fastPush((Object)arg);
+ }
+
+ @Override
+ public long fastPush(final Object arg) {
+ final int len = (int)length;
+ if (len == array.length) {
+ array = Arrays.copyOf(array, nextSize(len));
+ }
+ array[len] = arg;
+ return ++length;
+ }
+
+ @Override
+ public Object fastPopObject() {
+ if (length == 0) {
+ return ScriptRuntime.UNDEFINED;
+ }
+ final int newLength = (int)--length;
+ final Object elem = array[newLength];
+ array[newLength] = ScriptRuntime.EMPTY;
+ return elem;
+ }
+
+ @Override
public Object pop() {
- if (length() == 0) {
+ if (length == 0) {
return ScriptRuntime.UNDEFINED;
}
- final int newLength = (int) (length() - 1);
+ final int newLength = (int)length - 1;
final Object elem = array[newLength];
setEmpty(newLength);
setLength(newLength);
@@ -246,25 +286,25 @@ final class ObjectArrayData extends ContinuousArrayData {
@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);
+ final long len = length;
+ final ArrayData newData = ensure(len);
if (newData == this) {
- array[(int)length] = item;
+ array[(int)len] = item;
return this;
}
- return newData.set((int)length, item, strict);
+ return newData.set((int)len, item, strict);
}
@Override
public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
- final long oldLength = length();
+ final long oldLength = length;
final long newLength = oldLength - removed + added;
if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
throw new UnsupportedOperationException();
diff --git a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
index 623e3159..d28b731c 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java
@@ -53,28 +53,28 @@ class SparseArrayData extends ArrayData {
SparseArrayData(final ArrayData underlying, final long length, final TreeMap<Long, Object> sparseMap) {
super(length);
- assert underlying.length() <= length;
+ assert underlying.length <= length;
this.underlying = underlying;
- this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length());
+ this.maxDenseLength = Math.max(MAX_DENSE_LENGTH, underlying.length);
this.sparseMap = sparseMap;
}
@Override
public ArrayData copy() {
- return new SparseArrayData(underlying.copy(), length(), new TreeMap<>(sparseMap));
+ return new SparseArrayData(underlying.copy(), length, new TreeMap<>(sparseMap));
}
@Override
public Object[] asObjectArray() {
- final int length = (int) Math.min(length(), Integer.MAX_VALUE);
- final int underlyingLength = (int) Math.min(length, underlying.length());
- final Object[] objArray = new Object[length];
+ final int len = (int)Math.min(length, Integer.MAX_VALUE);
+ final int underlyingLength = (int)Math.min(len, underlying.length);
+ final Object[] objArray = new Object[len];
for (int i = 0; i < underlyingLength; i++) {
objArray[i] = underlying.getObject(i);
}
- Arrays.fill(objArray, underlyingLength, length, ScriptRuntime.UNDEFINED);
+ Arrays.fill(objArray, underlyingLength, len, ScriptRuntime.UNDEFINED);
for (final Map.Entry<Long, Object> entry : sparseMap.entrySet()) {
final long key = entry.getKey();
@@ -104,14 +104,14 @@ class SparseArrayData extends ArrayData {
}
sparseMap = newSparseMap;
- setLength(Math.max(length() - by, 0));
+ setLength(Math.max(length - by, 0));
}
@Override
public ArrayData shiftRight(final int by) {
final TreeMap<Long, Object> newSparseMap = new TreeMap<>();
- if (underlying.length() + by > maxDenseLength) {
- for (long i = maxDenseLength - by; i < underlying.length(); i++) {
+ if (underlying.length + by > maxDenseLength) {
+ for (long i = maxDenseLength - by; i < underlying.length; i++) {
if (underlying.has((int) i)) {
newSparseMap.put(Long.valueOf(i + by), underlying.getObject((int) i));
}
@@ -127,23 +127,23 @@ class SparseArrayData extends ArrayData {
}
sparseMap = newSparseMap;
- setLength(length() + by);
+ setLength(length + by);
return this;
}
@Override
public ArrayData ensure(final long safeIndex) {
- if (safeIndex < maxDenseLength && underlying.length() <= safeIndex) {
+ if (safeIndex < maxDenseLength && underlying.length <= safeIndex) {
underlying = underlying.ensure(safeIndex);
}
- setLength(Math.max(safeIndex + 1, length()));
+ setLength(Math.max(safeIndex + 1, length));
return this;
}
@Override
public ArrayData shrink(final long newLength) {
- if (newLength < underlying.length()) {
+ if (newLength < underlying.length) {
underlying = underlying.shrink(newLength);
underlying.setLength(newLength);
sparseMap.clear();
@@ -160,11 +160,11 @@ class SparseArrayData extends ArrayData {
if (index >= 0 && index < maxDenseLength) {
ensure(index);
underlying = underlying.set(index, value, strict);
- setLength(Math.max(underlying.length(), length()));
+ setLength(Math.max(underlying.length, length));
} else {
final Long longIndex = indexToKey(index);
sparseMap.put(longIndex, value);
- setLength(Math.max(longIndex + 1, length()));
+ setLength(Math.max(longIndex + 1, length));
}
return this;
@@ -175,11 +175,11 @@ class SparseArrayData extends ArrayData {
if (index >= 0 && index < maxDenseLength) {
ensure(index);
underlying = underlying.set(index, value, strict);
- setLength(Math.max(underlying.length(), length()));
+ setLength(Math.max(underlying.length, length));
} else {
final Long longIndex = indexToKey(index);
sparseMap.put(longIndex, value);
- setLength(Math.max(longIndex + 1, length()));
+ setLength(Math.max(longIndex + 1, length));
}
return this;
}
@@ -189,11 +189,11 @@ class SparseArrayData extends ArrayData {
if (index >= 0 && index < maxDenseLength) {
ensure(index);
underlying = underlying.set(index, value, strict);
- setLength(Math.max(underlying.length(), length()));
+ setLength(Math.max(underlying.length, length));
} else {
final Long longIndex = indexToKey(index);
sparseMap.put(longIndex, value);
- setLength(Math.max(longIndex + 1, length()));
+ setLength(Math.max(longIndex + 1, length));
}
return this;
}
@@ -203,11 +203,11 @@ class SparseArrayData extends ArrayData {
if (index >= 0 && index < maxDenseLength) {
ensure(index);
underlying = underlying.set(index, value, strict);
- setLength(Math.max(underlying.length(), length()));
+ setLength(Math.max(underlying.length, length));
} else {
final Long longIndex = indexToKey(index);
sparseMap.put(longIndex, value);
- setLength(Math.max(longIndex + 1, length()));
+ setLength(Math.max(longIndex + 1, length));
}
return this;
}
@@ -294,7 +294,7 @@ class SparseArrayData extends ArrayData {
@Override
public boolean has(final int index) {
if (index >= 0 && index < maxDenseLength) {
- return index < underlying.length() && underlying.has(index);
+ return index < underlying.length && underlying.has(index);
}
return sparseMap.containsKey(indexToKey(index));
@@ -303,7 +303,7 @@ class SparseArrayData extends ArrayData {
@Override
public ArrayData delete(final int index) {
if (index >= 0 && index < maxDenseLength) {
- if (index < underlying.length()) {
+ if (index < underlying.length) {
underlying = underlying.delete(index);
}
} else {
@@ -315,8 +315,8 @@ class SparseArrayData extends ArrayData {
@Override
public ArrayData delete(final long fromIndex, final long toIndex) {
- if (fromIndex < maxDenseLength && fromIndex < underlying.length()) {
- underlying = underlying.delete(fromIndex, Math.min(toIndex, underlying.length() - 1));
+ if (fromIndex < maxDenseLength && fromIndex < underlying.length) {
+ underlying = underlying.delete(fromIndex, Math.min(toIndex, underlying.length - 1));
}
if (toIndex >= maxDenseLength) {
sparseMap.subMap(fromIndex, true, toIndex, true).clear();
@@ -329,37 +329,37 @@ class SparseArrayData extends ArrayData {
}
@Override
- protected ArrayData convert(final Class<?> type) {
+ public ArrayData convert(final Class<?> type) {
underlying = underlying.convert(type);
return this;
}
@Override
public Object pop() {
- if (length() == 0) {
+ if (length == 0) {
return ScriptRuntime.UNDEFINED;
}
- if (length() == underlying.length()) {
+ if (length == underlying.length) {
final Object result = underlying.pop();
- setLength(underlying.length());
+ setLength(underlying.length);
return result;
}
- setLength(length() - 1);
- final Long key = Long.valueOf(length());
+ setLength(length - 1);
+ final Long key = Long.valueOf(length);
return sparseMap.containsKey(key) ? sparseMap.remove(key) : ScriptRuntime.UNDEFINED;
}
@Override
public ArrayData slice(final long from, final long to) {
- assert to <= length();
- final long start = from < 0 ? (from + length()) : from;
+ assert to <= length;
+ final long start = from < 0 ? (from + length) : from;
final long newLength = to - start;
if (start >= 0 && to <= maxDenseLength) {
- if (newLength <= underlying.length()) {
+ if (newLength <= underlying.length) {
return underlying.slice(from, to);
}
- return underlying.slice(from, to).ensure(newLength - 1).delete(underlying.length(), newLength);
+ return underlying.slice(from, to).ensure(newLength - 1).delete(underlying.length, newLength);
}
ArrayData sliced = EMPTY_ARRAY;
@@ -369,13 +369,13 @@ class SparseArrayData extends ArrayData {
sliced = sliced.set((int)(i - start), getObject((int)i), false);
}
}
- assert sliced.length() == newLength;
+ assert sliced.length == newLength;
return sliced;
}
@Override
public long nextIndex(final long index) {
- if (index < underlying.length() - 1) {
+ if (index < underlying.length - 1) {
return underlying.nextIndex(index);
}
@@ -383,6 +383,6 @@ class SparseArrayData extends ArrayData {
if (nextKey != null) {
return nextKey;
}
- return length();
+ return length;
}
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
index 291e59e0..428678d0 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java
@@ -26,7 +26,6 @@
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;
@@ -55,11 +54,11 @@ public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayDa
}
/**
- * Length in elements. Accessed from {@code ArrayBufferView}
+ * Length in number of elements. Accessed from {@code ArrayBufferView}
* @return element length
*/
public final int getElementLength() {
- return (int)length();
+ return (int)length;
}
/**
@@ -120,7 +119,7 @@ public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayDa
@Override
public final boolean has(final int index) {
- return 0 <= index && index < length();
+ return 0 <= index && index < length;
}
@Override
@@ -134,7 +133,7 @@ public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayDa
}
@Override
- protected ArrayData convert(final Class<?> type) {
+ public ArrayData convert(final Class<?> type) {
throw new UnsupportedOperationException();
}
diff --git a/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java b/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
index e2488d34..f744aacd 100644
--- a/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
+++ b/src/jdk/nashorn/internal/runtime/arrays/UndefinedArrayFilter.java
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.runtime.arrays;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
import java.lang.reflect.Array;
import jdk.nashorn.internal.runtime.BitVector;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
@@ -41,7 +40,7 @@ final class UndefinedArrayFilter extends ArrayFilter {
UndefinedArrayFilter(final ArrayData underlying) {
super(underlying);
- this.undefined = new BitVector(underlying.length());
+ this.undefined = new BitVector(underlying.length);
}
@Override
@@ -81,25 +80,25 @@ final class UndefinedArrayFilter extends ArrayFilter {
@Override
public void shiftLeft(final int by) {
super.shiftLeft(by);
- undefined.shiftLeft(by, length());
+ undefined.shiftLeft(by, length);
}
@Override
public ArrayData shiftRight(final int by) {
super.shiftRight(by);
- undefined.shiftRight(by, length());
+ undefined.shiftRight(by, length);
return this;
}
@Override
public ArrayData ensure(final long safeIndex) {
- if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length()) {
+ if (safeIndex >= SparseArrayData.MAX_DENSE_LENGTH && safeIndex >= length) {
return new SparseArrayData(this, safeIndex + 1);
}
super.ensure(safeIndex);
- undefined.resize(length());
+ undefined.resize(length);
return this;
}
@@ -107,7 +106,7 @@ final class UndefinedArrayFilter extends ArrayFilter {
@Override
public ArrayData shrink(final long newLength) {
super.shrink(newLength);
- undefined.resize(length());
+ undefined.resize(length);
return this;
}
@@ -217,7 +216,7 @@ final class UndefinedArrayFilter extends ArrayFilter {
@Override
public Object pop() {
- final long index = length() - 1;
+ final long index = length - 1;
if (super.has((int)index)) {
final boolean isUndefined = undefined.isSet(index);
@@ -234,7 +233,7 @@ final class UndefinedArrayFilter extends ArrayFilter {
final ArrayData newArray = underlying.slice(from, to);
final UndefinedArrayFilter newFilter = new UndefinedArrayFilter(newArray);
newFilter.getUndefined().copy(undefined);
- newFilter.getUndefined().shiftLeft(from, newFilter.length());
+ newFilter.getUndefined().shiftLeft(from, newFilter.length);
return newFilter;
}
diff --git a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
index f377c9d8..2a536bbf 100644
--- a/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
+++ b/src/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java
@@ -26,14 +26,16 @@
package jdk.nashorn.internal.runtime.linker;
import static jdk.nashorn.internal.lookup.Lookup.MH;
-
import java.lang.invoke.MethodHandle;
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;
import jdk.internal.dynalink.support.Guards;
+import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.FindProperty;
+import jdk.nashorn.internal.runtime.GlobalConstants;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.UserAccessorProperty;
@@ -86,27 +88,41 @@ public final class PrimitiveLookup {
final MethodHandle protoFilter) {
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
- if(desc.getNameTokenCount() > 2) {
+ //checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem)
+ //if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be.
+ //so in that case we can skip creation of primitive wrapper and start our search with the prototype.
+ if (desc.getNameTokenCount() > 2) {
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final FindProperty find = wrappedReceiver.findProperty(name, true);
- if(find == null) {
+
+ if (find == null) {
// Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
return null;
- } else if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
+ }
+
+ final SwitchPoint sp = find.getProperty().getBuiltinSwitchPoint(); //can use this instead of proto filter
+ if (sp instanceof Context.BuiltinSwitchPoint && !sp.hasBeenInvalidated()) {
+ return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
+ }
+
+ if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
// If property is found in the prototype object bind the method handle directly to
// the proto filter instead of going through wrapper instantiation below.
final ScriptObject proto = wrappedReceiver.getProto();
final GuardedInvocation link = proto.lookup(desc, request);
if (link != null) {
- final MethodHandle invocation = link.getInvocation();
+ final MethodHandle invocation = link.getInvocation(); //this contains the builtin switchpoint
+
final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
+
return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
}
}
}
+
final GuardedInvocation link = wrappedReceiver.lookup(desc, request);
if (link != null) {
MethodHandle method = link.getInvocation();
@@ -116,8 +132,10 @@ public final class PrimitiveLookup {
assert receiverType.isAssignableFrom(wrapType.returnType());
method = MH.filterArguments(method, 0, MH.asType(wrapFilter, wrapType.changeReturnType(receiverType)));
}
+
return new GuardedInvocation(method, guard, link.getSwitchPoints(), null);
}
+
return null;
}
}
diff --git a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java
index 08168b63..77b1b3dc 100644
--- a/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java
+++ b/src/jdk/nashorn/internal/runtime/regexp/RegExpFactory.java
@@ -25,6 +25,9 @@
package jdk.nashorn.internal.runtime.regexp;
+import java.util.Collections;
+import java.util.Set;
+import java.util.WeakHashMap;
import jdk.nashorn.internal.runtime.ParserException;
import jdk.nashorn.internal.runtime.options.Options;
@@ -39,6 +42,15 @@ public class RegExpFactory {
private final static String JDK = "jdk";
private final static String JONI = "joni";
+ /** Weak cache of already validated regexps - when reparsing, we don't, for example
+ * need to recompile (reverify) all regexps that have previously been parsed by this
+ * RegExpFactory in a previous compilation. This saves significant time in e.g. avatar
+ * startup */
+ private static final Set<String> VALID_CACHE_SET =
+ Collections.newSetFromMap(
+ Collections.synchronizedMap(
+ new WeakHashMap<String, Boolean>()));
+
static {
final String impl = Options.getStringProperty("nashorn.regexp.impl", JONI);
switch (impl) {
@@ -88,7 +100,9 @@ public class RegExpFactory {
*/
// @SuppressWarnings({"unused"})
public static void validate(final String pattern, final String flags) throws ParserException {
- instance.compile(pattern, flags);
+ if (VALID_CACHE_SET.add(pattern + flags)) {
+ instance.compile(pattern, flags);
+ }
}
/**
diff --git a/src/jdk/nashorn/internal/runtime/resources/Options.properties b/src/jdk/nashorn/internal/runtime/resources/Options.properties
index a5e8cd5a..57943e01 100644
--- a/src/jdk/nashorn/internal/runtime/resources/Options.properties
+++ b/src/jdk/nashorn/internal/runtime/resources/Options.properties
@@ -203,9 +203,9 @@ nashorn.option.lazy.compilation = {
nashorn.option.optimistic.types = { \
name="--optimistic-types", \
- is_undocumented=true, \
- desc="Use optimistic type assumptions with deoptimizing recompilation.", \
- default=true \
+ short_name="-ot", \
+ desc="Use optimistic type assumptions with deoptimizing recompilation. This makes the compiler try, for any program symbol whose type cannot be proven at compile time, to type it as narrow and primitive as possible. If the runtime encounters an error because symbol type is too narrow, a wider method will be generated until steady stage is reached. While this produces as optimal Java Bytecode as possible, erroneous type guesses will lead to longer warmup. Optimistic typing is currently disabled by default, but can be enabled for significantly better peak performance.", \
+ default=false \
}
nashorn.option.loader.per.compile = { \