8025435: Optimistic builtins support, implemented initial optimistic versions of push, pop, and charCodeAt
Reviewed-by: attila, hannesw, sundar
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ClassGenerator.java Thu Sep 25 15:53:47 2014 +0200
@@ -292,7 +292,6 @@
mi.push(memInfo.getArity());
mi.invokeVirtual(SCRIPTFUNCTION_TYPE, SCRIPTFUNCTION_SETARITY, SCRIPTFUNCTION_SETARITY_DESC);
}
-
}
static void linkerAddGetterSetter(final MethodGenerator mi, final String className, final MemberInfo memInfo) {
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MemberInfo.java Thu Sep 25 15:53:47 2014 +0200
@@ -28,7 +28,6 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.STRING_DESC;
-
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.nashorn.internal.objects.annotations.Where;
@@ -75,10 +74,6 @@
* This is a specialized version of a function
*/
SPECIALIZED_FUNCTION,
- /**
- * This is a specialized version of a constructor
- */
- SPECIALIZED_CONSTRUCTOR
}
// keep in sync with jdk.nashorn.internal.objects.annotations.Attribute
@@ -107,6 +102,12 @@
private Where where;
+ private Type linkLogicClass;
+
+ private boolean isSpecializedConstructor;
+
+ private boolean isOptimistic;
+
/**
* @return the kind
*/
@@ -136,6 +137,57 @@
}
/**
+ * Tag something as specialized constructor or not
+ * @param isSpecializedConstructor boolean, true if specialized constructor
+ */
+ public void setIsSpecializedConstructor(final boolean isSpecializedConstructor) {
+ this.isSpecializedConstructor = isSpecializedConstructor;
+ }
+
+ /**
+ * Check if something is a specialized constructor
+ * @return true if specialized constructor
+ */
+ public boolean isSpecializedConstructor() {
+ return isSpecializedConstructor;
+ }
+
+ /**
+ * Check if this is an optimistic builtin function
+ * @return true if optimistic builtin
+ */
+ public boolean isOptimistic() {
+ return isOptimistic;
+ }
+
+ /**
+ * Tag something as optimitic builtin or not
+ * @param isOptimistic boolean, true if builtin constructor
+ */
+ public void setIsOptimistic(final boolean isOptimistic) {
+ this.isOptimistic = isOptimistic;
+ }
+
+ /**
+ * Get the SpecializedFunction guard for specializations, i.e. optimistic
+ * builtins
+ * @return specialization, null if none
+ */
+ public Type getLinkLogicClass() {
+ return linkLogicClass;
+ }
+
+ /**
+ * Set thre SpecializedFunction link logic class for specializations, i.e. optimistic
+ * builtins
+ * @param linkLogicClass link logic class
+ */
+
+ public void setLinkLogicClass(final Type linkLogicClass) {
+ this.linkLogicClass = linkLogicClass;
+ }
+
+ /**
* @return the attributes
*/
public int getAttributes() {
@@ -304,19 +356,6 @@
}
}
break;
- case SPECIALIZED_CONSTRUCTOR: {
- final Type returnType = Type.getReturnType(javaDesc);
- if (!isJSObjectType(returnType)) {
- error("return value of a @SpecializedConstructor method should be a valid JS type, found " + returnType);
- }
- final Type[] argTypes = Type.getArgumentTypes(javaDesc);
- for (int i = 0; i < argTypes.length; i++) {
- if (!isValidJSType(argTypes[i])) {
- error(i + "'th argument of a @SpecializedConstructor method is not valid JS type, found " + argTypes[i]);
- }
- }
- }
- break;
case FUNCTION: {
final Type returnType = Type.getReturnType(javaDesc);
if (!(isValidJSType(returnType) || Type.VOID_TYPE == returnType)) {
@@ -351,7 +390,7 @@
break;
case SPECIALIZED_FUNCTION: {
final Type returnType = Type.getReturnType(javaDesc);
- if (!(isValidJSType(returnType) || Type.VOID_TYPE == returnType)) {
+ if (!(isValidJSType(returnType) || (isSpecializedConstructor() && Type.VOID_TYPE == returnType))) {
error("return value of a @SpecializedFunction method should be a valid JS type, found " + returnType);
}
final Type[] argTypes = Type.getArgumentTypes(javaDesc);
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/MethodGenerator.java Thu Sep 25 15:53:47 2014 +0200
@@ -55,6 +55,7 @@
import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
+import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_1;
import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
@@ -75,13 +76,16 @@
import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE;
import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH;
import static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE;
-import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE;
-
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_INIT2;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_INIT3;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_TYPE;
+import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_SPECIALIZATION;
import java.util.List;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Type;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
/**
* Base class for all method generating classes.
@@ -94,6 +98,8 @@
private final Type returnType;
private final Type[] argumentTypes;
+ static final Type EMPTY_LINK_LOGIC_TYPE = Type.getType(LinkLogic.getEmptyLinkLogicClass());
+
MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) {
super(Main.ASM_VERSION, mv);
this.access = access;
@@ -379,6 +385,11 @@
super.visitFieldInsn(GETFIELD, owner, field, desc);
}
+ private static boolean linkLogicIsEmpty(final Type type) {
+ assert EMPTY_LINK_LOGIC_TYPE != null; //type is ok for null if we are a @SpecializedFunction without any attribs
+ return EMPTY_LINK_LOGIC_TYPE.equals(type);
+ }
+
void memberInfoArray(final String className, final List<MemberInfo> mis) {
if (mis.isEmpty()) {
pushNull();
@@ -387,12 +398,22 @@
int pos = 0;
push(mis.size());
- newObjectArray(METHODHANDLE_TYPE);
+ newObjectArray(SPECIALIZATION_TYPE);
for (final MemberInfo mi : mis) {
dup();
push(pos++);
+ visitTypeInsn(NEW, SPECIALIZATION_TYPE);
+ dup();
visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc()));
- arrayStore(TYPE_METHODHANDLE);
+ final Type linkLogicClass = mi.getLinkLogicClass();
+ final boolean linkLogic = !linkLogicIsEmpty(linkLogicClass);
+ final String ctor = linkLogic ? SPECIALIZATION_INIT3 : SPECIALIZATION_INIT2;
+ if (linkLogic) {
+ visitLdcInsn(linkLogicClass);
+ }
+ visitInsn(mi.isOptimistic() ? ICONST_1 : ICONST_0);
+ visitMethodInsn(INVOKESPECIAL, SPECIALIZATION_TYPE, INIT, ctor, false);
+ arrayStore(TYPE_SPECIALIZATION);
}
}
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfo.java Thu Sep 25 15:53:47 2014 +0200
@@ -37,8 +37,8 @@
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Setter;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
@@ -56,8 +56,8 @@
static final String SETTER_ANNO_DESC = Type.getDescriptor(Setter.class);
static final String PROPERTY_ANNO_DESC = Type.getDescriptor(Property.class);
static final String WHERE_ENUM_DESC = Type.getDescriptor(Where.class);
+ static final String LINK_LOGIC_DESC = Type.getDescriptor(LinkLogic.class);
static final String SPECIALIZED_FUNCTION = Type.getDescriptor(SpecializedFunction.class);
- static final String SPECIALIZED_CONSTRUCTOR = Type.getDescriptor(SpecializedConstructor.class);
static final Map<String, Kind> annotations = new HashMap<>();
@@ -69,7 +69,6 @@
annotations.put(SETTER_ANNO_DESC, Kind.SETTER);
annotations.put(PROPERTY_ANNO_DESC, Kind.PROPERTY);
annotations.put(SPECIALIZED_FUNCTION, Kind.SPECIALIZED_FUNCTION);
- annotations.put(SPECIALIZED_CONSTRUCTOR, Kind.SPECIALIZED_CONSTRUCTOR);
}
// name of the script class
@@ -119,11 +118,12 @@
List<MemberInfo> getSpecializedConstructors() {
final List<MemberInfo> res = new LinkedList<>();
for (final MemberInfo memInfo : members) {
- if (memInfo.getKind() == Kind.SPECIALIZED_CONSTRUCTOR) {
+ if (memInfo.isSpecializedConstructor()) {
+ assert memInfo.getKind() == Kind.SPECIALIZED_FUNCTION;
res.add(memInfo);
}
}
- return res;
+ return Collections.unmodifiableList(res);
}
int getPrototypeMemberCount() {
@@ -175,7 +175,7 @@
res.add(memInfo);
}
}
- return res;
+ return Collections.unmodifiableList(res);
}
MemberInfo findSetter(final MemberInfo getter) {
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInfoCollector.java Thu Sep 25 15:53:47 2014 +0200
@@ -27,7 +27,6 @@
import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.SCRIPT_CLASS_ANNO_DESC;
import static jdk.nashorn.internal.tools.nasgen.ScriptClassInfo.WHERE_ENUM_DESC;
-
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
@@ -41,6 +40,7 @@
import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
+import jdk.internal.org.objectweb.asm.Type;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
@@ -194,6 +194,7 @@
final MemberInfo memInfo = new MemberInfo();
+ //annokind == e.g. GETTER or SPECIALIZED_FUNCTION
memInfo.setKind(annoKind);
memInfo.setJavaName(methodName);
memInfo.setJavaDesc(methodDesc);
@@ -208,12 +209,18 @@
private Integer attributes;
private Integer arity;
private Where where;
+ private boolean isSpecializedConstructor;
+ private boolean isOptimistic;
+ private Type linkLogicClass = MethodGenerator.EMPTY_LINK_LOGIC_TYPE;
@Override
public void visit(final String annotationName, final Object annotationValue) {
switch (annotationName) {
case "name":
this.name = (String)annotationValue;
+ if (name.isEmpty()) {
+ name = null;
+ }
break;
case "attributes":
this.attributes = (Integer)annotationValue;
@@ -221,6 +228,17 @@
case "arity":
this.arity = (Integer)annotationValue;
break;
+ case "isConstructor":
+ assert annoKind == Kind.SPECIALIZED_FUNCTION;
+ this.isSpecializedConstructor = (Boolean)annotationValue;
+ break;
+ case "isOptimistic":
+ assert annoKind == Kind.SPECIALIZED_FUNCTION;
+ this.isOptimistic = (Boolean)annotationValue;
+ break;
+ case "linkLogic":
+ this.linkLogicClass = (Type)annotationValue;
+ break;
default:
break;
}
@@ -230,12 +248,19 @@
@Override
public void visitEnum(final String enumName, final String desc, final String enumValue) {
- if ("where".equals(enumName) && WHERE_ENUM_DESC.equals(desc)) {
- this.where = Where.valueOf(enumValue);
+ switch (enumName) {
+ case "where":
+ if (WHERE_ENUM_DESC.equals(desc)) {
+ this.where = Where.valueOf(enumValue);
+ }
+ break;
+ default:
+ break;
}
super.visitEnum(enumName, desc, enumValue);
}
+ @SuppressWarnings("fallthrough")
@Override
public void visitEnd() {
super.visitEnd();
@@ -256,7 +281,6 @@
case SETTER:
where = Where.INSTANCE;
break;
- case SPECIALIZED_CONSTRUCTOR:
case CONSTRUCTOR:
where = Where.CONSTRUCTOR;
break;
@@ -264,12 +288,18 @@
where = Where.PROTOTYPE;
break;
case SPECIALIZED_FUNCTION:
- //TODO is this correct
+ if (isSpecializedConstructor) {
+ where = Where.CONSTRUCTOR;
+ }
+ //fallthru
default:
break;
}
}
memInfo.setWhere(where);
+ memInfo.setLinkLogicClass(linkLogicClass);
+ memInfo.setIsSpecializedConstructor(isSpecializedConstructor);
+ memInfo.setIsOptimistic(isOptimistic);
}
};
}
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/ScriptClassInstrumentor.java Thu Sep 25 15:53:47 2014 +0200
@@ -38,7 +38,6 @@
import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_DESC;
import static jdk.nashorn.internal.tools.nasgen.StringConstants.SCRIPTOBJECT_TYPE;
-
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -50,7 +49,6 @@
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor;
-import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.tools.nasgen.MemberInfo.Kind;
--- a/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen/StringConstants.java Thu Sep 25 15:53:47 2014 +0200
@@ -37,6 +37,7 @@
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.Specialization;
/**
* String constants used for code generation/instrumentation.
@@ -44,20 +45,26 @@
@SuppressWarnings("javadoc")
public interface StringConstants {
// standard jdk types, methods
- static final Type TYPE_METHODHANDLE = Type.getType(MethodHandle.class);
- static final Type TYPE_METHODHANDLE_ARRAY = Type.getType(MethodHandle[].class);
- static final Type TYPE_OBJECT = Type.getType(Object.class);
- static final Type TYPE_STRING = Type.getType(String.class);
- static final Type TYPE_COLLECTION = Type.getType(Collection.class);
- static final Type TYPE_COLLECTIONS = Type.getType(Collections.class);
- static final Type TYPE_ARRAYLIST = Type.getType(ArrayList.class);
- static final Type TYPE_LIST = Type.getType(List.class);
+ static final Type TYPE_METHODHANDLE = Type.getType(MethodHandle.class);
+ static final Type TYPE_METHODHANDLE_ARRAY = Type.getType(MethodHandle[].class);
+ static final Type TYPE_SPECIALIZATION = Type.getType(Specialization.class);
+ static final Type TYPE_SPECIALIZATION_ARRAY = Type.getType(Specialization[].class);
+ static final Type TYPE_OBJECT = Type.getType(Object.class);
+ static final Type TYPE_STRING = Type.getType(String.class);
+ static final Type TYPE_CLASS = Type.getType(Class.class);
+ static final Type TYPE_COLLECTION = Type.getType(Collection.class);
+ static final Type TYPE_COLLECTIONS = Type.getType(Collections.class);
+ static final Type TYPE_ARRAYLIST = Type.getType(ArrayList.class);
+ static final Type TYPE_LIST = Type.getType(List.class);
static final String CLINIT = "<clinit>";
static final String INIT = "<init>";
static final String DEFAULT_INIT_DESC = Type.getMethodDescriptor(Type.VOID_TYPE);
static final String METHODHANDLE_TYPE = TYPE_METHODHANDLE.getInternalName();
+ static final String SPECIALIZATION_TYPE = TYPE_SPECIALIZATION.getInternalName();
+ static final String SPECIALIZATION_INIT2 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_METHODHANDLE, Type.getType(boolean.class));
+ static final String SPECIALIZATION_INIT3 = Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_METHODHANDLE, TYPE_CLASS, Type.getType(boolean.class));
static final String OBJECT_TYPE = TYPE_OBJECT.getInternalName();
static final String OBJECT_DESC = TYPE_OBJECT.getDescriptor();
static final String STRING_TYPE = TYPE_STRING.getInternalName();
@@ -122,11 +129,11 @@
static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_DESC =
Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE);
static final String SCRIPTFUNCTIONIMPL_MAKEFUNCTION_SPECS_DESC =
- Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY);
+ Type.getMethodDescriptor(TYPE_SCRIPTFUNCTION, TYPE_STRING, TYPE_METHODHANDLE, TYPE_SPECIALIZATION_ARRAY);
static final String SCRIPTFUNCTIONIMPL_INIT_DESC3 =
- Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_METHODHANDLE_ARRAY);
+ Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_SPECIALIZATION_ARRAY);
static final String SCRIPTFUNCTIONIMPL_INIT_DESC4 =
- Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_METHODHANDLE_ARRAY);
+ Type.getMethodDescriptor(Type.VOID_TYPE, TYPE_STRING, TYPE_METHODHANDLE, TYPE_PROPERTYMAP, TYPE_SPECIALIZATION_ARRAY);
// ScriptObject
static final String SCRIPTOBJECT_TYPE = TYPE_SCRIPTOBJECT.getInternalName();
--- a/nashorn/samples/BufferArray.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/samples/BufferArray.java Thu Sep 25 15:53:47 2014 +0200
@@ -52,41 +52,49 @@
// underlying nio buffer
private final DoubleBuffer buf;
- public BufferArray(int size) {
+ /**
+ * Constructor
+ * @param size initial size
+ */
+ public BufferArray(final int size) {
buf = DoubleBuffer.allocate(size);
}
- public BufferArray(DoubleBuffer buf) {
+ /**
+ * Constructur
+ * @param buf {@link DoubleBuffer} to link to
+ */
+ public BufferArray(final DoubleBuffer buf) {
this.buf = buf;
}
// called to check if indexed property exists
@Override
- public boolean hasSlot(int index) {
+ public boolean hasSlot(final int index) {
return index > 0 && index < buf.capacity();
}
// get the value from that index
@Override
- public Object getSlot(int index) {
+ public Object getSlot(final int index) {
return buf.get(index);
}
// set the value at that index
@Override
- public void setSlot(int index, Object value) {
+ public void setSlot(final int index, final Object value) {
buf.put(index, ((Number)value).doubleValue());
}
// do you have a property of that given name?
@Override
- public boolean hasMember(String name) {
+ public boolean hasMember(final String name) {
return "length".equals(name) || "buf".equals(name);
}
// get the value of that named property
@Override
- public Object getMember(String name) {
+ public Object getMember(final String name) {
switch (name) {
case "length":
return buf.capacity();
@@ -94,7 +102,7 @@
// return a 'function' value for this property
return new AbstractJSObject() {
@Override
- public Object call(Object thiz, Object... args) {
+ public Object call(final Object thiz, final Object... args) {
return BufferArray.this.buf;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ApplySpecialization.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ApplySpecialization.java Thu Sep 25 15:53:47 2014 +0200
@@ -136,6 +136,7 @@
}
};
+ final Set<Expression> argumentsFound = new HashSet<>();
final Deque<Set<Expression>> stack = new ArrayDeque<>();
//ensure that arguments is only passed as arg to apply
try {
@@ -145,7 +146,11 @@
}
private boolean isArguments(final Expression expr) {
- return expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName());
+ if (expr instanceof IdentNode && ARGUMENTS.equals(((IdentNode)expr).getName())) {
+ argumentsFound.add(expr);
+ return true;
+ }
+ return false;
}
private boolean isParam(final String name) {
@@ -159,7 +164,7 @@
@Override
public Node leaveIdentNode(final IdentNode identNode) {
- if (isParam(identNode.getName()) || ARGUMENTS.equals(identNode.getName()) && !isCurrentArg(identNode)) {
+ if (isParam(identNode.getName()) || isArguments(identNode) && !isCurrentArg(identNode)) {
throw uoe; //avoid filling in stack trace
}
return identNode;
@@ -186,7 +191,9 @@
}
});
} catch (final UnsupportedOperationException e) {
- log.fine("'arguments' escapes, is not used in standard call dispatch, or is reassigned in '" + functionNode.getName() + "'. Aborting");
+ if (!argumentsFound.isEmpty()) {
+ log.fine("'arguments' is used but escapes, or is reassigned in '" + functionNode.getName() + "'. Aborting");
+ }
return true; //bad
}
@@ -267,9 +274,9 @@
return false;
}
- if (!Global.instance().isSpecialNameValid("apply")) {
+ if (!Global.isBuiltinFunctionPrototypeApply()) {
log.fine("Apply transform disabled: apply/call overridden");
- assert !Global.instance().isSpecialNameValid("call") : "call and apply should have the same SwitchPoint";
+ assert !Global.isBuiltinFunctionPrototypeCall() : "call and apply should have the same SwitchPoint";
return false;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ClassEmitter.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/ClassEmitter.java Thu Sep 25 15:53:47 2014 +0200
@@ -51,15 +51,14 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.methodDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.typeDescriptor;
import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup;
-
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
-
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
@@ -160,8 +159,12 @@
this.methodNames = new HashSet<>();
}
+ /**
+ * Return the method names encountered
+ * @return method names
+ */
public Set<String> getMethodNames() {
- return methodNames;
+ return Collections.unmodifiableSet(methodNames);
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompileUnit.java Thu Sep 25 15:53:47 2014 +0200
@@ -60,6 +60,10 @@
emittedUnitCount++;
}
+ /**
+ * Get the amount of emitted compile units so far in the system
+ * @return emitted compile unit count
+ */
public static int getEmittedUnitCount() {
return emittedUnitCount;
}
@@ -72,6 +76,10 @@
return isUsed;
}
+ /**
+ * Check if a compile unit has code, not counting inits and clinits
+ * @return true of if there is "real code" in the compile unit
+ */
public boolean hasCode() {
return (classEmitter.getMethodCount() - classEmitter.getInitCount() - classEmitter.getClinitCount()) > 0;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/MethodEmitter.java Thu Sep 25 15:53:47 2014 +0200
@@ -71,7 +71,6 @@
import static jdk.nashorn.internal.codegen.ObjectClassGenerator.PRIMITIVE_FIELD_TYPE;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_OPTIMISTIC;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_PROGRAM_POINT_SHIFT;
-
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.util.Collection;
@@ -99,13 +98,13 @@
import jdk.nashorn.internal.ir.RuntimeNode;
import jdk.nashorn.internal.ir.Symbol;
import jdk.nashorn.internal.ir.TryNode;
-import jdk.nashorn.internal.objects.Global;
import jdk.nashorn.internal.runtime.ArgumentSetter;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.RewriteException;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.logging.DebugLogger;
@@ -180,9 +179,6 @@
/** Bootstrap for array populators */
private static final Handle POPULATE_ARRAY_BOOTSTRAP = new Handle(H_INVOKESTATIC, RewriteException.BOOTSTRAP.className(), RewriteException.BOOTSTRAP.name(), RewriteException.BOOTSTRAP.descriptor());
- /** Bootstrap for global name invalidation */
- private static final Handle INVALIDATE_NAME_BOOTSTRAP = new Handle(H_INVOKESTATIC, Global.BOOTSTRAP.className(), Global.BOOTSTRAP.name(), Global.BOOTSTRAP.descriptor());
-
/**
* Constructor - internal use from ClassEmitter only
* @see ClassEmitter#method
@@ -2131,10 +2127,13 @@
}
MethodEmitter invalidateSpecialName(final String name) {
- //this is a nop if the global hasn't registered this as a special name - we can just ignore it
- if (Global.instance().isSpecialName(name)) {
- debug("dynamic_invalidate_name", "name=", name);
- method.visitInvokeDynamicInsn(name, "()V", INVALIDATE_NAME_BOOTSTRAP);
+ switch (name) {
+ case "apply":
+ case "call":
+ debug("invalidate_name", "name=", name);
+ load("Function");
+ invoke(ScriptRuntime.INVALIDATE_RESERVED_BUILTIN_NAME);
+ break;
}
return this;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java Thu Sep 25 15:53:47 2014 +0200
@@ -429,7 +429,6 @@
}
private static void doCleanup() throws IOException {
- final long start = System.nanoTime();
final Path[] files = getAllRegularFilesInLastModifiedOrder();
final int nFiles = files.length;
final int filesToDelete = Math.max(0, nFiles - MAX_FILES);
@@ -445,7 +444,6 @@
}
files[i] = null; // gc eligible
};
- final long duration = System.nanoTime() - start;
}
private static Path[] getAllRegularFilesInLastModifiedOrder() throws IOException {
@@ -497,7 +495,7 @@
private static long getTime(final Path path) {
try {
return Files.getLastModifiedTime(path).toMillis();
- } catch (IOException e) {
+ } catch (final IOException e) {
// All files for which we can't retrieve the last modified date will be considered oldest.
return -1L;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Thu Sep 25 15:53:47 2014 +0200
@@ -238,17 +238,21 @@
* Note that even IS_STRICT is one such flag but that requires special handling.
*/
- // parser, lower debugging this function
+ /** parser, print parse tree */
public static final int IS_PRINT_PARSE = 1 << 18;
+ /** parser, print lower parse tree */
public static final int IS_PRINT_LOWER_PARSE = 1 << 19;
+ /** parser, print AST */
public static final int IS_PRINT_AST = 1 << 20;
+ /** parser, print lower AST */
public static final int IS_PRINT_LOWER_AST = 1 << 21;
+ /** parser, print symbols */
public static final int IS_PRINT_SYMBOLS = 1 << 22;
+ // callsite tracing, profiling within this function
/** profile callsites in this function? */
public static final int IS_PROFILE = 1 << 23;
- // callsite tracing, profiling within this function
/** trace callsite enterexit in this function? */
public static final int IS_TRACE_ENTEREXIT = 1 << 24;
@@ -337,7 +341,7 @@
private FunctionNode(
final FunctionNode functionNode,
final long lastToken,
- Object endParserState,
+ final Object endParserState,
final int flags,
final String name,
final Type returnType,
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Thu Sep 25 15:53:47 2014 +0200
@@ -237,6 +237,10 @@
return value;
}
+ private static Expression[] valueToArray(final List<Expression> value) {
+ return value.toArray(new Expression[value.size()]);
+ }
+
/**
* Create a new null literal
*
@@ -981,10 +985,9 @@
* @return the new literal node
*/
public static LiteralNode<Expression[]> newInstance(final long token, final int finish, final List<Expression> value) {
- return new ArrayLiteralNode(token, finish, value.toArray(new Expression[value.size()]));
+ return new ArrayLiteralNode(token, finish, valueToArray(value));
}
-
/**
* Create a new array literal based on a parent node (source, token, finish)
*
@@ -994,7 +997,7 @@
* @return the new literal node
*/
public static LiteralNode<?> newInstance(final Node parent, final List<Expression> value) {
- return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), value.toArray(new Expression[value.size()]));
+ return new ArrayLiteralNode(parent.getToken(), parent.getFinish(), valueToArray(value));
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Symbol.java Thu Sep 25 15:53:47 2014 +0200
@@ -448,14 +448,25 @@
return (flags & IS_FUNCTION_SELF) != 0;
}
+ /**
+ * Is this a block scoped symbol
+ * @return true if block scoped
+ */
public boolean isBlockScoped() {
return isLet() || isConst();
}
+ /**
+ * Has this symbol been declared
+ * @return true if declared
+ */
public boolean hasBeenDeclared() {
return (flags & HAS_BEEN_DECLARED) != 0;
}
+ /**
+ * Mark this symbol as declared
+ */
public void setHasBeenDeclared() {
if (!hasBeenDeclared()) {
flags |= HAS_BEEN_DECLARED;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/MethodHandleFactory.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/MethodHandleFactory.java Thu Sep 25 15:53:47 2014 +0200
@@ -116,6 +116,10 @@
private static final String VOID_TAG = "[VOID]";
+ private static void err(final String str) {
+ Context.getContext().getErr().println(str);
+ }
+
/**
* Tracer that is applied before a value is returned from the traced function. It will output the return
* value and its class
@@ -124,13 +128,16 @@
* @return return value unmodified
*/
static Object traceReturn(final DebugLogger logger, final Object value) {
- if (logger.isEnabled()) {
- final String str = " return" +
- (VOID_TAG.equals(value) ?
- ";" :
- " " + stripName(value) + "; // [type=" + (value == null ? "null]" : stripName(value.getClass()) + ']'));
+ final String str = " return" +
+ (VOID_TAG.equals(value) ?
+ ";" :
+ " " + stripName(value) + "; // [type=" + (value == null ? "null]" : stripName(value.getClass()) + ']'));
+ if (logger == null) {
+ err(str);
+ } else if (logger.isEnabled()) {
logger.log(TRACE_LEVEL, str);
}
+
return value;
}
@@ -169,8 +176,11 @@
}
}
- assert logger != null;
- logger.log(TRACE_LEVEL, sb);
+ if (logger == null) {
+ err(sb.toString());
+ } else {
+ logger.log(TRACE_LEVEL, sb);
+ }
stacktrace(logger);
}
@@ -181,7 +191,12 @@
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final PrintStream ps = new PrintStream(baos);
new Throwable().printStackTrace(ps);
- logger.log(TRACE_LEVEL, baos.toString());
+ final String st = baos.toString();
+ if (logger == null) {
+ err(st);
+ } else {
+ logger.log(TRACE_LEVEL, st);
+ }
}
private static String argString(final Object arg) {
@@ -201,7 +216,7 @@
if (arg instanceof ScriptObject) {
return arg.toString() +
" (map=" + Debug.id(((ScriptObject)arg).getMap()) +
- ")";
+ ')';
}
return arg.toString();
@@ -209,6 +224,18 @@
/**
* Add a debug printout to a method handle, tracing parameters and return values
+ * Output will be unconditional to stderr
+ *
+ * @param mh method handle to trace
+ * @param tag start of trace message
+ * @return traced method handle
+ */
+ public static MethodHandle addDebugPrintout(final MethodHandle mh, final Object tag) {
+ return addDebugPrintout(null, Level.OFF, mh, 0, true, tag);
+ }
+
+ /**
+ * Add a debug printout to a method handle, tracing parameters and return values
*
* @param logger a specific logger to which to write the output
* @param level level over which to print
@@ -222,6 +249,20 @@
/**
* Add a debug printout to a method handle, tracing parameters and return values
+ * Output will be unconditional to stderr
+ *
+ * @param mh method handle to trace
+ * @param paramStart first param to print/trace
+ * @param printReturnValue should we print/trace return value if available?
+ * @param tag start of trace message
+ * @return traced method handle
+ */
+ public static MethodHandle addDebugPrintout(final MethodHandle mh, final int paramStart, final boolean printReturnValue, final Object tag) {
+ return addDebugPrintout(null, Level.OFF, mh, paramStart, printReturnValue, tag);
+ }
+
+ /**
+ * Add a debug printout to a method handle, tracing parameters and return values
*
* @param logger a specific logger to which to write the output
* @param level level over which to print
@@ -240,7 +281,6 @@
return mh;
}
- assert logger != null;
assert TRACE != null;
MethodHandle trace = MethodHandles.insertArguments(TRACE, 0, logger, tag, paramStart);
@@ -428,6 +468,12 @@
}
@Override
+ public MethodHandle identity(final Class<?> type) {
+ final MethodHandle mh = MethodHandles.identity(type);
+ return debug(mh, "identity", type);
+ }
+
+ @Override
public MethodHandle asCollector(final MethodHandle handle, final Class<?> arrayType, final int arrayLength) {
final MethodHandle mh = handle.asCollector(arrayType, arrayLength);
return debug(mh, "asCollector", handle, arrayType, arrayLength);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/MethodHandleFunctionality.java Thu Sep 25 15:53:47 2014 +0200
@@ -173,6 +173,15 @@
public MethodHandle constant(Class<?> type, Object value);
/**
+ * Wrapper for {@link java.lang.invoke.MethodHandles#identity(Class)}
+ *
+ * @param type type of value
+ *
+ * @return method handle that returns identity argument
+ */
+ public MethodHandle identity(Class<?> type);
+
+ /**
* Wrapper for {@link java.lang.invoke.MethodHandle#asType(MethodType)}
*
* @param handle method handle for type conversion
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayBufferView.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ArrayBufferView.java Thu Sep 25 15:53:47 2014 +0200
@@ -31,6 +31,7 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java Thu Sep 25 15:53:47 2014 +0200
@@ -25,23 +25,19 @@
package jdk.nashorn.internal.objects;
-import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
import java.io.IOException;
import java.io.PrintWriter;
-import java.lang.invoke.CallSite;
-import java.lang.invoke.ConstantCallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import java.lang.reflect.Field;
+import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
@@ -52,8 +48,6 @@
import jdk.internal.dynalink.linker.LinkRequest;
import jdk.nashorn.api.scripting.ClassFilter;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
-import jdk.nashorn.internal.codegen.ApplySpecialization;
-import jdk.nashorn.internal.codegen.CompilerConstants.Call;
import jdk.nashorn.internal.lookup.Lookup;
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Property;
@@ -72,6 +66,7 @@
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.ScriptingFunctions;
+import jdk.nashorn.internal.runtime.Specialization;
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
@@ -107,10 +102,6 @@
* it's when you start adding property checks for said builtins you have
* problems with guard speed.
*/
- public final Map<String, SwitchPoint> optimisticFunctionMap;
-
- /** Name invalidator for things like call/apply */
- public static final Call BOOTSTRAP = staticCall(MethodHandles.lookup(), Global.class, "invalidateNameBootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class);
/** Nashorn extension: arguments array */
@Property(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
@@ -428,9 +419,6 @@
private static final MethodHandle LOADWITHNEWGLOBAL = findOwnMH_S("loadWithNewGlobal", Object.class, Object.class, Object[].class);
private static final MethodHandle EXIT = findOwnMH_S("exit", Object.class, Object.class, Object.class);
- /** Invalidate a reserved name, such as "apply" or "call" if assigned */
- public MethodHandle INVALIDATE_RESERVED_NAME = MH.bindTo(findOwnMH_V("invalidateReservedName", void.class, String.class), this);
-
// initialized by nasgen
private static PropertyMap $nasgenmap$;
@@ -482,7 +470,6 @@
super(checkAndGetMap(context));
this.context = context;
this.setIsScope();
- this.optimisticFunctionMap = new HashMap<>();
//we can only share one instance of Global constants between globals, or we consume way too much
//memory - this is good enough for most programs
while (gcsInstance.get() == null) {
@@ -1244,6 +1231,40 @@
return instance.function == instance.getBuiltinFunction();
}
+ /**
+ * Get the switchpoint used to check property changes for Function.prototype.apply
+ * @return the switchpoint guarding apply (same as guarding call, and everything else in function)
+ */
+ public static SwitchPoint getBuiltinFunctionApplySwitchPoint() {
+ return ScriptFunction.getPrototype(Global.instance().getBuiltinFunction()).getProperty("apply").getBuiltinSwitchPoint();
+ }
+
+ private static boolean isBuiltinFunctionProperty(final String name) {
+ final Global instance = Global.instance();
+ final ScriptFunction builtinFunction = instance.getBuiltinFunction();
+ if (builtinFunction == null) {
+ return false; //conservative for compile-only mode
+ }
+ final boolean isBuiltinFunction = instance.function == builtinFunction;
+ return isBuiltinFunction && ScriptFunction.getPrototype(builtinFunction).getProperty(name).isBuiltin();
+ }
+
+ /**
+ * Check if the Function.prototype.apply has not been replaced
+ * @return true if Function.prototype.apply has been replaced
+ */
+ public static boolean isBuiltinFunctionPrototypeApply() {
+ return isBuiltinFunctionProperty("apply");
+ }
+
+ /**
+ * Check if the Function.prototype.apply has not been replaced
+ * @return true if Function.prototype.call has been replaced
+ */
+ public static boolean isBuiltinFunctionPrototypeCall() {
+ return isBuiltinFunctionProperty("call");
+ }
+
private ScriptFunction getBuiltinJSAdapter() {
return builtinJSAdapter;
}
@@ -1688,6 +1709,12 @@
splitState = state;
}
+ private <T extends ScriptObject> T initConstructorAndSwitchPoint(final String name, final Class<T> clazz) {
+ final T func = initConstructor(name, clazz);
+ tagBuiltinProperties(name, func);
+ return func;
+ }
+
private void init(final ScriptEngine engine) {
assert Context.getGlobal() == this : "this global is not set as current";
@@ -1702,8 +1729,19 @@
// initialize global function properties
this.eval = this.builtinEval = ScriptFunctionImpl.makeFunction("eval", EVAL);
- this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT,
- new MethodHandle[] { GlobalFunctions.PARSEINT_OI, GlobalFunctions.PARSEINT_O });
+ this.parseInt = ScriptFunctionImpl.makeFunction("parseInt", GlobalFunctions.PARSEINT,
+ new Specialization[] {
+ new Specialization(GlobalFunctions.PARSEINT_Z),
+ new Specialization(GlobalFunctions.PARSEINT_I),
+ new Specialization(GlobalFunctions.PARSEINT_J),
+ new Specialization(GlobalFunctions.PARSEINT_OI),
+ new Specialization(GlobalFunctions.PARSEINT_O) });
+ this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
+ this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN,
+ new Specialization[] {
+ new Specialization(GlobalFunctions.IS_NAN_I),
+ new Specialization(GlobalFunctions.IS_NAN_J),
+ new Specialization(GlobalFunctions.IS_NAN_D) });
this.parseFloat = ScriptFunctionImpl.makeFunction("parseFloat", GlobalFunctions.PARSEFLOAT);
this.isNaN = ScriptFunctionImpl.makeFunction("isNaN", GlobalFunctions.IS_NAN);
this.isFinite = ScriptFunctionImpl.makeFunction("isFinite", GlobalFunctions.IS_FINITE);
@@ -1720,15 +1758,15 @@
this.quit = ScriptFunctionImpl.makeFunction("quit", EXIT);
// built-in constructors
- this.builtinArray = initConstructor("Array", ScriptFunction.class);
- this.builtinBoolean = initConstructor("Boolean", ScriptFunction.class);
- this.builtinDate = initConstructor("Date", ScriptFunction.class);
- this.builtinJSON = initConstructor("JSON", ScriptObject.class);
- this.builtinJSAdapter = initConstructor("JSAdapter", ScriptFunction.class);
- this.builtinMath = initConstructor("Math", ScriptObject.class);
- this.builtinNumber = initConstructor("Number", ScriptFunction.class);
- this.builtinRegExp = initConstructor("RegExp", ScriptFunction.class);
- this.builtinString = initConstructor("String", ScriptFunction.class);
+ this.builtinArray = initConstructorAndSwitchPoint("Array", ScriptFunction.class);
+ this.builtinBoolean = initConstructorAndSwitchPoint("Boolean", ScriptFunction.class);
+ this.builtinDate = initConstructorAndSwitchPoint("Date", ScriptFunction.class);
+ this.builtinJSON = initConstructorAndSwitchPoint("JSON", ScriptObject.class);
+ this.builtinJSAdapter = initConstructorAndSwitchPoint("JSAdapter", ScriptFunction.class);
+ this.builtinMath = initConstructorAndSwitchPoint("Math", ScriptObject.class);
+ this.builtinNumber = initConstructorAndSwitchPoint("Number", ScriptFunction.class);
+ this.builtinRegExp = initConstructorAndSwitchPoint("RegExp", ScriptFunction.class);
+ this.builtinString = initConstructorAndSwitchPoint("String", ScriptFunction.class);
// initialize String.prototype.length to 0
// add String.prototype.length
@@ -1830,6 +1868,8 @@
// Error.prototype.message = "";
errorProto.set(NativeError.MESSAGE, "", 0);
+ tagBuiltinProperties("Error", builtinError);
+
this.builtinEvalError = initErrorSubtype("EvalError", errorProto);
this.builtinRangeError = initErrorSubtype("RangeError", errorProto);
this.builtinReferenceError = initErrorSubtype("ReferenceError", errorProto);
@@ -1844,6 +1884,7 @@
prototype.set(NativeError.NAME, name, 0);
prototype.set(NativeError.MESSAGE, "", 0);
prototype.setInitialProto(errorProto);
+ tagBuiltinProperties(name, cons);
return cons;
}
@@ -1910,17 +1951,18 @@
}
private void initTypedArray() {
- this.builtinArrayBuffer = initConstructor("ArrayBuffer", ScriptFunction.class);
- this.builtinDataView = initConstructor("DataView", ScriptFunction.class);
- this.builtinInt8Array = initConstructor("Int8Array", ScriptFunction.class);
- this.builtinUint8Array = initConstructor("Uint8Array", ScriptFunction.class);
- this.builtinUint8ClampedArray = initConstructor("Uint8ClampedArray", ScriptFunction.class);
- this.builtinInt16Array = initConstructor("Int16Array", ScriptFunction.class);
- this.builtinUint16Array = initConstructor("Uint16Array", ScriptFunction.class);
- this.builtinInt32Array = initConstructor("Int32Array", ScriptFunction.class);
- this.builtinUint32Array = initConstructor("Uint32Array", ScriptFunction.class);
- this.builtinFloat32Array = initConstructor("Float32Array", ScriptFunction.class);
- this.builtinFloat64Array = initConstructor("Float64Array", ScriptFunction.class);
+ this.builtinArrayBuffer = initConstructorAndSwitchPoint("ArrayBuffer", ScriptFunction.class);
+ this.builtinDataView = initConstructorAndSwitchPoint("DataView", ScriptFunction.class);
+ this.builtinInt8Array = initConstructorAndSwitchPoint("Int8Array", ScriptFunction.class);
+ this.builtinUint8Array = initConstructorAndSwitchPoint("Uint8Array", ScriptFunction.class);
+ this.builtinUint8ClampedArray = initConstructorAndSwitchPoint("Uint8ClampedArray", ScriptFunction.class);
+ this.builtinInt16Array = initConstructorAndSwitchPoint("Int16Array", ScriptFunction.class);
+ this.builtinUint16Array = initConstructorAndSwitchPoint("Uint16Array", ScriptFunction.class);
+ this.builtinInt32Array = initConstructorAndSwitchPoint("Int32Array", ScriptFunction.class);
+ this.builtinUint32Array = initConstructorAndSwitchPoint("Uint32Array", ScriptFunction.class);
+ this.builtinFloat32Array = initConstructorAndSwitchPoint("Float32Array", ScriptFunction.class);
+ this.builtinFloat64Array = initConstructorAndSwitchPoint("Float64Array", ScriptFunction.class);
+
}
private void copyBuiltins() {
@@ -1993,10 +2035,6 @@
return UNDEFINED;
}
- /**
- * These classes are generated by nasgen tool and so we have to use
- * reflection to load and create new instance of these classes.
- */
private <T extends ScriptObject> T initConstructor(final String name, final Class<T> clazz) {
try {
// Assuming class name pattern for built-in JS constructors.
@@ -2021,12 +2059,52 @@
}
res.setIsBuiltin();
+
return res;
} catch (final ClassNotFoundException | InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
+ private List<jdk.nashorn.internal.runtime.Property> extractBuiltinProperties(final String name, final ScriptObject func) {
+ final List<jdk.nashorn.internal.runtime.Property> list = new ArrayList<>();
+
+ list.addAll(Arrays.asList(func.getMap().getProperties()));
+
+ if (func instanceof ScriptFunction) {
+ final ScriptObject proto = ScriptFunction.getPrototype((ScriptFunction)func);
+ if (proto != null) {
+ list.addAll(Arrays.asList(proto.getMap().getProperties()));
+ }
+ }
+
+ final jdk.nashorn.internal.runtime.Property prop = getProperty(name);
+ if (prop != null) {
+ list.add(prop);
+ }
+
+ return list;
+ }
+
+ /**
+ * Given a builtin object, traverse its properties recursively and associate them with a name that
+ * will be a key to their invalidation switchpoint.
+ * @param name name for key
+ * @param func builtin script object
+ */
+ private void tagBuiltinProperties(final String name, final ScriptObject func) {
+ SwitchPoint sp = context.getBuiltinSwitchPoint(name);
+ if (sp == null) {
+ sp = context.newBuiltinSwitchPoint(name);
+ }
+
+ //get all builtin properties in this builtin object and register switchpoints keyed on the propery name,
+ //one overwrite destroys all for now, e.g. Function.prototype.apply = 17; also destroys Function.prototype.call etc
+ for (final jdk.nashorn.internal.runtime.Property prop : extractBuiltinProperties(name, func)) {
+ prop.setBuiltinSwitchPoint(sp);
+ }
+ }
+
// Function and Object constructors are inter-dependent. Also,
// Function.prototype
// functions are not properly initialized. We fix the references here.
@@ -2035,7 +2113,8 @@
// to play with object references carefully!!
private void initFunctionAndObject() {
// First-n-foremost is Function
- this.builtinFunction = initConstructor("Function", ScriptFunction.class);
+
+ this.builtinFunction = initConstructor("Function", ScriptFunction.class);
// create global anonymous function
final ScriptFunction anon = ScriptFunctionImpl.newAnonymousFunction();
@@ -2101,13 +2180,6 @@
}
}
- //make sure apply and call have the same invalidation switchpoint
- final SwitchPoint sp = new SwitchPoint();
- optimisticFunctionMap.put("apply", sp);
- optimisticFunctionMap.put("call", sp);
- getFunctionPrototype().getProperty("apply").setChangeCallback(sp);
- getFunctionPrototype().getProperty("call").setChangeCallback(sp);
-
properties = getObjectPrototype().getMap().getProperties();
for (final jdk.nashorn.internal.runtime.Property property : properties) {
@@ -2125,10 +2197,10 @@
}
}
}
- }
- private static MethodHandle findOwnMH_V(final String name, final Class<?> rtype, final Class<?>... types) {
- return MH.findVirtual(MethodHandles.lookup(), Global.class, name, MH.type(rtype, types));
+ tagBuiltinProperties("Object", builtinObject);
+ tagBuiltinProperties("Function", builtinFunction);
+ tagBuiltinProperties("Function", anon);
}
private static MethodHandle findOwnMH_S(final String name, final Class<?> rtype, final Class<?>... types) {
@@ -2147,62 +2219,4 @@
protected boolean isGlobal() {
return true;
}
-
- /**
- * Check if there is a switchpoint for a reserved name. If there
- * is, it must be invalidated upon properties with this name
- * @param name property name
- * @return switchpoint for invalidating this property, or null if not registered
- */
- public SwitchPoint getChangeCallback(final String name) {
- return optimisticFunctionMap.get(name);
- }
-
- /**
- * Is this a special name, that might be subject to invalidation
- * on write, such as "apply" or "call"
- * @param name name to check
- * @return true if special name
- */
- public boolean isSpecialName(final String name) {
- return getChangeCallback(name) != null;
- }
-
- /**
- * Check if a reserved property name is invalidated
- * @param name property name
- * @return true if someone has written to it since Global was instantiated
- */
- public boolean isSpecialNameValid(final String name) {
- final SwitchPoint sp = getChangeCallback(name);
- return sp != null && !sp.hasBeenInvalidated();
- }
-
- /**
- * 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->call specialization
- * @param name property name
- */
- public void invalidateReservedName(final String name) {
- final SwitchPoint sp = getChangeCallback(name);
- if (sp != null) {
- getContext().getLogger(ApplySpecialization.class).info("Overwrote special name '" + name +"' - invalidating switchpoint");
- SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
- }
- }
-
- /**
- * Bootstrapper for invalidating a builtin name
- * @param lookup lookup
- * @param name name to invalidate
- * @param type methodhandle type
- * @return callsite for invalidator
- */
- public static CallSite invalidateNameBootstrap(final MethodHandles.Lookup lookup, final String name, final MethodType type) {
- final MethodHandle target = MH.insertArguments(Global.instance().INVALIDATE_RESERVED_NAME, 0, name);
- return new ConstantCallSite(target);
- }
-
-
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Thu Sep 25 15:53:47 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -33,8 +33,8 @@
import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator;
import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator;
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
-
import java.lang.invoke.MethodHandle;
+import java.lang.invoke.SwitchPoint;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -52,12 +52,13 @@
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
import jdk.nashorn.internal.objects.annotations.Setter;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.Debug;
import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.OptimisticBuiltins;
import jdk.nashorn.internal.runtime.PropertyDescriptor;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
@@ -67,17 +68,20 @@
import jdk.nashorn.internal.runtime.arrays.ArrayData;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
+import jdk.nashorn.internal.runtime.arrays.ContinuousArrayData;
+import jdk.nashorn.internal.runtime.arrays.IntElements;
+import jdk.nashorn.internal.runtime.arrays.IntOrLongElements;
import jdk.nashorn.internal.runtime.arrays.IteratorAction;
+import jdk.nashorn.internal.runtime.arrays.NumericElements;
import jdk.nashorn.internal.runtime.linker.Bootstrap;
import jdk.nashorn.internal.runtime.linker.InvokeByName;
-import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
/**
* Runtime representation of a JavaScript array. NativeArray only holds numeric
* keyed values. All other values are stored in spill.
*/
@ScriptClass("Array")
-public final class NativeArray extends ScriptObject {
+public final class NativeArray extends ScriptObject implements OptimisticBuiltins {
private static final Object JOIN = new Object();
private static final Object EVERY_CALLBACK_INVOKER = new Object();
private static final Object SOME_CALLBACK_INVOKER = new Object();
@@ -88,6 +92,16 @@
private static final Object CALL_CMP = new Object();
private static final Object TO_LOCALE_STRING = new Object();
+ private SwitchPoint lengthMadeNotWritableSwitchPoint;
+ private PushLinkLogic pushLinkLogic;
+ private PopLinkLogic popLinkLogic;
+
+ /**
+ * Index for the modification SwitchPoint that triggers when length
+ * becomes not writable
+ */
+ private static final int LENGTH_NOT_WRITABLE_SWITCHPOINT = 0;
+
/*
* Constructors.
*/
@@ -420,6 +434,28 @@
return getArray().asObjectArray();
}
+ @Override
+ public void setIsLengthNotWritable() {
+ super.setIsLengthNotWritable();
+ /*
+ * Switchpoints are created lazily. If we link any push or pop site,
+ * we need to create the "length made not writable" switchpoint, if it
+ * doesn't exist.
+ *
+ * If the switchpoint already exists, we will find it here, and invalidate
+ * it, invalidating all previous callsites that use it.
+ *
+ * If the switchpoint doesn't exist, no push/pop has been linked so far,
+ * because that would create it too. We invalidate it immediately and the
+ * check link logic for all future callsites will fail immediately at link
+ * time
+ */
+ if (lengthMadeNotWritableSwitchPoint == null) {
+ lengthMadeNotWritableSwitchPoint = new SwitchPoint();
+ }
+ SwitchPoint.invalidateAll(new SwitchPoint[] { lengthMadeNotWritableSwitchPoint });
+ }
+
/**
* ECMA 15.4.3.2 Array.isArray ( arg )
*
@@ -638,7 +674,7 @@
* @param self self reference
* @return the new NativeArray
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeArray construct(final boolean newObj, final Object self) {
return new NativeArray(0);
}
@@ -653,7 +689,7 @@
* @param element first element
* @return the new NativeArray
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static Object construct(final boolean newObj, final Object self, final boolean element) {
return new NativeArray(new Object[] { element });
}
@@ -668,7 +704,7 @@
* @param length array length
* @return the new NativeArray
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeArray construct(final boolean newObj, final Object self, final int length) {
if (length >= 0) {
return new NativeArray(length);
@@ -687,7 +723,7 @@
* @param length array length
* @return the new NativeArray
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeArray construct(final boolean newObj, final Object self, final long length) {
if (length >= 0L && length <= JSType.MAX_UINT) {
return new NativeArray(length);
@@ -706,7 +742,7 @@
* @param length array length
* @return the new NativeArray
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeArray construct(final boolean newObj, final Object self, final double length) {
final long uint32length = JSType.toUint32(length);
@@ -721,7 +757,7 @@
* ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] )
*
* @param self self reference
- * @param args arguments to concat
+ * @param args arguments
* @return resulting NativeArray
*/
@Function(attributes = Attribute.NOT_ENUMERABLE, arity = 1)
@@ -793,6 +829,68 @@
}
/**
+ * Specialization of pop for ContinuousArrayData
+ * The link guard checks that the array is continuous AND not empty.
+ * The runtime guard checks that the guard is continuous (CCE otherwise)
+ *
+ * Primitive specialization, {@link LinkLogic}
+ *
+ * @param self self reference
+ * @return element popped
+ * @throws ClassCastException if array is empty, facilitating Undefined return value
+ */
+ @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
+ public static int popInt(final Object self) {
+ //must be non empty IntArrayData
+ return getContinuousNonEmptyArrayDataCCE(self, IntElements.class).fastPopInt();
+ }
+
+ /**
+ * Specialization of pop for ContinuousArrayData
+ *
+ * Primitive specialization, {@link LinkLogic}
+ *
+ * @param self self reference
+ * @return element popped
+ * @throws ClassCastException if array is empty, facilitating Undefined return value
+ */
+ @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
+ public static long popLong(final Object self) {
+ //must be non empty Int or LongArrayData
+ return getContinuousNonEmptyArrayDataCCE(self, IntOrLongElements.class).fastPopLong();
+ }
+
+ /**
+ * Specialization of pop for ContinuousArrayData
+ *
+ * Primitive specialization, {@link LinkLogic}
+ *
+ * @param self self reference
+ * @return element popped
+ * @throws ClassCastException if array is empty, facilitating Undefined return value
+ */
+ @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
+ public static double popDouble(final Object self) {
+ //must be non empty int long or double array data
+ return getContinuousNonEmptyArrayDataCCE(self, NumericElements.class).fastPopDouble();
+ }
+
+ /**
+ * Specialization of pop for ContinuousArrayData
+ *
+ * Primitive specialization, {@link LinkLogic}
+ *
+ * @param self self reference
+ * @return element popped
+ * @throws ClassCastException if array is empty, facilitating Undefined return value
+ */
+ @SpecializedFunction(name="pop", linkLogic=PopLinkLogic.class)
+ public static Object popObject(final Object self) {
+ //can be any data, because the numeric ones will throw cce and force relink
+ return getContinuousArrayDataCCE(self, null).fastPopObject();
+ }
+
+ /**
* ECMA 15.4.4.6 Array.prototype.pop ()
*
* @param self self reference
@@ -829,6 +927,62 @@
/**
* ECMA 15.4.4.7 Array.prototype.push (args...)
*
+ * Primitive specialization, {@link LinkLogic}
+ *
+ * @param self self reference
+ * @param arg a primitive to push
+ * @return array length after push
+ */
+ @SpecializedFunction(linkLogic=PushLinkLogic.class)
+ public static long push(final Object self, final int arg) {
+ return getContinuousArrayDataCCE(self, Integer.class).fastPush(arg);
+ }
+
+ /**
+ * ECMA 15.4.4.7 Array.prototype.push (args...)
+ *
+ * Primitive specialization, {@link LinkLogic}
+ *
+ * @param self self reference
+ * @param arg a primitive to push
+ * @return array length after push
+ */
+ @SpecializedFunction(linkLogic=PushLinkLogic.class)
+ public static long push(final Object self, final long arg) {
+ return getContinuousArrayDataCCE(self, Long.class).fastPush(arg);
+ }
+
+ /**
+ * ECMA 15.4.4.7 Array.prototype.push (args...)
+ *
+ * Primitive specialization, {@link LinkLogic}
+ *
+ * @param self self reference
+ * @param arg a primitive to push
+ * @return array length after push
+ */
+ @SpecializedFunction(linkLogic=PushLinkLogic.class)
+ public static long push(final Object self, final double arg) {
+ return getContinuousArrayDataCCE(self, Double.class).fastPush(arg);
+ }
+
+ /**
+ * ECMA 15.4.4.7 Array.prototype.push (args...)
+ *
+ * Primitive specialization, {@link LinkLogic}
+ *
+ * @param self self reference
+ * @param arg a primitive to push
+ * @return array length after push
+ */
+ @SpecializedFunction(name="push", linkLogic=PushLinkLogic.class)
+ public static long pushObject(final Object self, final Object arg) {
+ return getContinuousArrayDataCCE(self, Object.class).fastPush(arg);
+ }
+
+ /**
+ * ECMA 15.4.4.7 Array.prototype.push (args...)
+ *
* @param self self reference
* @param args arguments to push
* @return array length after pushes
@@ -857,61 +1011,6 @@
}
/**
- * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single int argument
- *
- * @param self self reference
- * @param arg argument to push
- * @return array after pushes
- */
-/* @SpecializedFunction
- public static long push(final Object self, final int arg) {
- try {
- final ScriptObject sobj = (ScriptObject)self;
- final ArrayData arrayData = sobj.getArray();
- final long length = arrayData.length();
-
- if (bulkable(sobj) && length + 1 <= JSType.MAX_UINT) {
- sobj.setArray(arrayData.ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
- return length + 1;
- }
-
- long len = JSType.toUint32(sobj.getLength());
- sobj.set(len++, arg, true);
- sobj.set("length", len, true);
- return len;
- } catch (final ClassCastException | NullPointerException e) {
- throw typeError("not.an.object", ScriptRuntime.safeToString(self));
- }
- }
-*/
- /**
- * ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single number argument
- *
- * @param self self reference
- * @param arg argument to push
- * @return array after pushes
- */
- /* @SpecializedFunction
- public static long push(final Object self, final double arg) {
- try {
- final ScriptObject sobj = (ScriptObject)self; final ArrayData arrayData = sobj.getArray();
- final long length = arrayData.length();
-
- if (bulkable(sobj) && length + 1 <= JSType.MAX_UINT) {
- sobj.setArray(arrayData.ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
- return length + 1;
- }
-
- long len = JSType.toUint32(sobj.getLength());
- sobj.set(len++, arg, true);
- sobj.set("length", len, true);
- return len;
- } catch (final ClassCastException | NullPointerException e) {
- throw typeError("not.an.object", ScriptRuntime.safeToString(self));
- }
- }
-*/
- /**
* ECMA 15.4.4.7 Array.prototype.push (args...) specialized for single object argument
*
* @param self self reference
@@ -925,7 +1024,7 @@
final ArrayData arrayData = sobj.getArray();
final long length = arrayData.length();
if (bulkable(sobj) && length < JSType.MAX_UINT) {
- sobj.setArray(arrayData.push(true, arg)); //ensure(length).set(ArrayIndex.getArrayIndex(length), arg, true));
+ sobj.setArray(arrayData.push(true, arg));
return length + 1;
}
@@ -1584,6 +1683,192 @@
@Override
public String toString() {
- return "NativeArray@" + Debug.id(this) + '@' + getArray().getClass().getSimpleName();
+ return "NativeArray@" + Debug.id(this) + " [" + getArray().getClass().getSimpleName() + ']';
+ }
+
+ @Override
+ public SpecializedFunction.LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz) {
+ if (clazz == PushLinkLogic.class) {
+ return pushLinkLogic == null ? new PushLinkLogic(this) : pushLinkLogic;
+ } else if (clazz == PopLinkLogic.class) {
+ return popLinkLogic == null ? new PopLinkLogic(this) : pushLinkLogic;
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasPerInstanceAssumptions() {
+ return true; //length switchpoint
+ }
+
+ /**
+ * This is an abstract super class that contains common functionality for all
+ * specialized optimistic builtins in NativeArray. For example, it handles the
+ * modification switchpoint which is touched when length is written.
+ */
+ private static abstract class ArrayLinkLogic extends SpecializedFunction.LinkLogic {
+ private final NativeArray array;
+
+ protected ArrayLinkLogic(final NativeArray array) {
+ this.array = array;
+ }
+
+ private SwitchPoint getSwitchPoint() {
+ return array.lengthMadeNotWritableSwitchPoint;
+ }
+
+ private SwitchPoint newSwitchPoint() {
+ assert array.lengthMadeNotWritableSwitchPoint == null;
+ final SwitchPoint sp = new SwitchPoint();
+ array.lengthMadeNotWritableSwitchPoint = sp;
+ return sp;
+ }
+
+ protected static ContinuousArrayData getContinuousArrayData(final Object self) {
+ try {
+ //cast to NativeArray, to avoid cases like x = {0:0, 1:1}, x.length = 2, where we can't use the array push/pop
+ return (ContinuousArrayData)((NativeArray)self).getArray();
+ } catch (final Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Push and pop callsites can throw ClassCastException as a mechanism to have them
+ * relinked - this enabled fast checks of the kind of ((IntArrayData)arrayData).push(x)
+ * for an IntArrayData only push - if this fails, a CCE will be thrown and we will relink
+ */
+ @Override
+ public Class<? extends Throwable> getRelinkException() {
+ return ClassCastException.class;
+ }
+
+ @Override
+ public boolean hasModificationSwitchPoints() {
+ return getSwitchPoint() != null;
+ }
+
+ @Override
+ public boolean hasModificationSwitchPoint(final int index) {
+ assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
+ return hasModificationSwitchPoints();
+ }
+
+ @Override
+ public SwitchPoint getOrCreateModificationSwitchPoint(final int index) {
+ assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
+ SwitchPoint sp = getSwitchPoint();
+ if (sp == null) {
+ sp = newSwitchPoint();
+ }
+ return sp;
+ }
+
+ @Override
+ public SwitchPoint[] getOrCreateModificationSwitchPoints() {
+ return new SwitchPoint[] { getOrCreateModificationSwitchPoint(LENGTH_NOT_WRITABLE_SWITCHPOINT) };
+ }
+
+ @Override
+ public void invalidateModificationSwitchPoint(final int index) {
+ assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
+ invalidateModificationSwitchPoints();
+ }
+
+ @Override
+ public void invalidateModificationSwitchPoints() {
+ final SwitchPoint sp = getSwitchPoint();
+ assert sp != null : "trying to invalidate non-existant modified SwitchPoint";
+ if (!sp.hasBeenInvalidated()) {
+ SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
+ }
+ }
+
+ @Override
+ public boolean hasInvalidatedModificationSwitchPoint(final int index) {
+ assert index == LENGTH_NOT_WRITABLE_SWITCHPOINT;
+ return hasInvalidatedModificationSwitchPoints();
+ }
+
+ @Override
+ public boolean hasInvalidatedModificationSwitchPoints() {
+ final SwitchPoint sp = getSwitchPoint();
+ return sp != null && !sp.hasBeenInvalidated();
+ }
+ }
+
+ /**
+ * This is linker logic for optimistic pushes
+ */
+ private static final class PushLinkLogic extends ArrayLinkLogic {
+ private PushLinkLogic(final NativeArray array) {
+ super(array);
+ }
+
+ @Override
+ public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+ return getContinuousArrayData(self) != null;
+ }
+ }
+
+ /**
+ * This is linker logic for optimistic pops
+ */
+ private static final class PopLinkLogic extends ArrayLinkLogic {
+ private PopLinkLogic(final NativeArray array) {
+ super(array);
+ }
+
+ /**
+ * We need to check if we are dealing with a continuous non empty array data here,
+ * as pop with a primitive return value returns undefined for arrays with length 0
+ */
+ @Override
+ public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+ final ContinuousArrayData data = getContinuousNonEmptyArrayData(self);
+ if (data != null) {
+ final Class<?> elementType = data.getElementType();
+ final Class<?> returnType = desc.getMethodType().returnType();
+ final boolean typeFits = JSType.getAccessorTypeIndex(returnType) >= JSType.getAccessorTypeIndex(elementType);
+ return typeFits;
+ }
+ return false;
+ }
+
+ private ContinuousArrayData getContinuousNonEmptyArrayData(final Object self) {
+ final ContinuousArrayData data = getContinuousArrayData(self);
+ if (data != null) {
+ return data.length() == 0 ? null : data;
+ }
+ return null;
+ }
+ }
+
+ //runtime calls for push and pops. they could be used as guards, but they also perform the runtime logic,
+ //so rather than synthesizing them into a guard method handle that would also perform the push on the
+ //retrieved receiver, we use this as runtime logic
+
+ //TODO - fold these into the Link logics, but I'll do that as a later step, as I want to do a checkin
+ //where everything works first
+
+ private static final <T> ContinuousArrayData getContinuousNonEmptyArrayDataCCE(final Object self, final Class<T> clazz) {
+ try {
+ @SuppressWarnings("unchecked")
+ final ContinuousArrayData data = (ContinuousArrayData)(T)((NativeArray)self).getArray();
+ if (data.length() != 0L) {
+ return data; //if length is 0 we cannot pop and have to relink, because then we'd have to return an undefined, which is a wider type than e.g. int
+ }
+ } catch (final NullPointerException e) {
+ //fallthru
+ }
+ throw new ClassCastException();
+ }
+
+ private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class<?> elementType) {
+ try {
+ return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType"
+ } catch (final NullPointerException e) {
+ throw new ClassCastException();
+ }
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDataView.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDataView.java Thu Sep 25 15:53:47 2014 +0200
@@ -27,7 +27,6 @@
import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import jdk.nashorn.internal.objects.annotations.Attribute;
@@ -35,7 +34,6 @@
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
@@ -156,7 +154,7 @@
* @param offset offset in bytes from the start of the ArrayBuffer
* @return newly constructed DataView object
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset) {
if (!(arrBuf instanceof NativeArrayBuffer)) {
throw typeError("not.an.arraybuffer.in.dataview");
@@ -174,7 +172,7 @@
* @param length is the number of bytes from the offset that this DataView will reference
* @return newly constructed DataView object
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeDataView constructor(final boolean newObj, final Object self, final Object arrBuf, final int offset, final int length) {
if (!(arrBuf instanceof NativeArrayBuffer)) {
throw typeError("not.an.arraybuffer.in.dataview");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDate.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeDate.java Thu Sep 25 15:53:47 2014 +0200
@@ -30,7 +30,6 @@
import static java.lang.Double.isNaN;
import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
-
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.Callable;
@@ -38,7 +37,7 @@
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.parser.DateParser;
import jdk.nashorn.internal.runtime.ConsString;
@@ -155,7 +154,7 @@
* @param self self references
* @return Date representing now
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static Object construct(final boolean isNew, final Object self) {
final NativeDate result = new NativeDate();
return isNew ? result : toStringImpl(result, FORMAT_DATE_TIME);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java Thu Sep 25 15:53:47 2014 +0200
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@@ -85,6 +84,11 @@
}
@Override
+ public Class<?> getElementType() {
+ return double.class;
+ }
+
+ @Override
protected MethodHandle getGetElem() {
return GET_ELEM;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java Thu Sep 25 15:53:47 2014 +0200
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@@ -94,6 +93,11 @@
return SET_ELEM;
}
+ @Override
+ public Class<?> getElementType() {
+ return double.class;
+ }
+
private double getElem(final int index) {
try {
return nb.get(index);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java Thu Sep 25 15:53:47 2014 +0200
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@@ -95,6 +94,11 @@
return SET_ELEM;
}
+ @Override
+ public Class<?> getElementType() {
+ return int.class;
+ }
+
private int getElem(final int index) {
try {
return nb.get(index);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java Thu Sep 25 15:53:47 2014 +0200
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@@ -113,6 +112,11 @@
}
@Override
+ public Class<?> getElementType() {
+ return int.class;
+ }
+
+ @Override
public int getInt(final int index) {
return getElem(index);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt8Array.java Thu Sep 25 15:53:47 2014 +0200
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@@ -93,6 +92,11 @@
return SET_ELEM;
}
+ @Override
+ public Class<?> getElementType() {
+ return int.class;
+ }
+
private int getElem(final int index) {
try {
return nb.get(index);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java Thu Sep 25 15:53:47 2014 +0200
@@ -48,7 +48,6 @@
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
-import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
import jdk.nashorn.internal.scripts.JO;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExp.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExp.java Thu Sep 25 15:53:47 2014 +0200
@@ -33,13 +33,14 @@
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
+
import jdk.nashorn.internal.objects.annotations.Attribute;
import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.Property;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.BitVector;
import jdk.nashorn.internal.runtime.JSType;
@@ -143,7 +144,7 @@
* @param self self reference
* @return new NativeRegExp
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeRegExp constructor(final boolean isNew, final Object self) {
return new NativeRegExp("", "");
}
@@ -158,7 +159,7 @@
* @param pattern pattern
* @return new NativeRegExp
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern) {
return newRegExp(pattern, UNDEFINED);
}
@@ -174,7 +175,7 @@
* @param flags flags
* @return new NativeRegExp
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static NativeRegExp constructor(final boolean isNew, final Object self, final Object pattern, final Object flags) {
return newRegExp(pattern, flags);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeString.java Thu Sep 25 15:53:47 2014 +0200
@@ -29,7 +29,6 @@
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -49,11 +48,12 @@
import jdk.nashorn.internal.objects.annotations.Function;
import jdk.nashorn.internal.objects.annotations.Getter;
import jdk.nashorn.internal.objects.annotations.ScriptClass;
-import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
+import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
import jdk.nashorn.internal.objects.annotations.Where;
import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.JSType;
+import jdk.nashorn.internal.runtime.OptimisticBuiltins;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
@@ -67,7 +67,7 @@
* ECMA 15.5 String Objects.
*/
@ScriptClass("String")
-public final class NativeString extends ScriptObject {
+public final class NativeString extends ScriptObject implements OptimisticBuiltins {
private final CharSequence value;
@@ -568,6 +568,14 @@
return pos < 0 || pos >= str.length() ? "" : String.valueOf(str.charAt(pos));
}
+ private static int getValidChar(final Object self, final int pos) {
+ try {
+ return ((CharSequence)self).charAt(pos);
+ } catch (final IndexOutOfBoundsException e) {
+ throw new ClassCastException();
+ }
+ }
+
/**
* ECMA 15.5.4.5 String.prototype.charCodeAt (pos)
* @param self self reference
@@ -576,7 +584,9 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static double charCodeAt(final Object self, final Object pos) {
- return charCodeAtImpl(checkObjectToString(self), JSType.toInteger(pos));
+ final String str = checkObjectToString(self);
+ final int idx = JSType.toInteger(pos);
+ return idx < 0 || idx >= str.length() ? Double.NaN : str.charAt(idx);
}
/**
@@ -585,9 +595,20 @@
* @param pos position in string
* @return number representing charcode at position
*/
- @SpecializedFunction
- public static double charCodeAt(final Object self, final double pos) {
- return charCodeAt(self, (int) pos);
+ @SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
+ public static int charCodeAt(final Object self, final double pos) {
+ return charCodeAt(self, (int)pos); //toInt pos is ok
+ }
+
+ /**
+ * ECMA 15.5.4.5 String.prototype.charCodeAt (pos) - specialized version for long position
+ * @param self self reference
+ * @param pos position in string
+ * @return number representing charcode at position
+ */
+ @SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
+ public static int charCodeAt(final Object self, final long pos) {
+ return charCodeAt(self, (int)pos);
}
/**
@@ -596,13 +617,10 @@
* @param pos position in string
* @return number representing charcode at position
*/
- @SpecializedFunction
- public static double charCodeAt(final Object self, final int pos) {
- return charCodeAtImpl(checkObjectToString(self), pos);
- }
- private static double charCodeAtImpl(final String str, final int pos) {
- return pos < 0 || pos >= str.length() ? Double.NaN : str.charAt(pos);
+ @SpecializedFunction(linkLogic=CharCodeAtLinkLogic.class)
+ public static int charCodeAt(final Object self, final int pos) {
+ return getValidChar(self, pos);
}
/**
@@ -1097,7 +1115,6 @@
*/
@Function(attributes = Attribute.NOT_ENUMERABLE)
public static String trim(final Object self) {
-
final String str = checkObjectToString(self);
int start = 0;
int end = str.length() - 1;
@@ -1181,7 +1198,7 @@
*
* @return new NativeString ("")
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static Object constructor(final boolean newObj, final Object self) {
return newObj ? newObj("") : "";
}
@@ -1197,7 +1214,7 @@
*
* @return new NativeString (arg)
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static Object constructor(final boolean newObj, final Object self, final Object arg) {
final CharSequence str = JSType.toCharSequence(arg);
return newObj ? newObj(str) : str.toString();
@@ -1214,8 +1231,42 @@
*
* @return new NativeString containing the string representation of the arg
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static Object constructor(final boolean newObj, final Object self, final int arg) {
+ final String str = Integer.toString(arg);
+ return newObj ? newObj(str) : str;
+ }
+
+ /**
+ * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
+ *
+ * Constructor
+ *
+ * @param newObj is this constructor invoked with the new operator
+ * @param self self reference
+ * @param arg the arg
+ *
+ * @return new NativeString containing the string representation of the arg
+ */
+ @SpecializedFunction(isConstructor=true)
+ public static Object constructor(final boolean newObj, final Object self, final long arg) {
+ final String str = Long.toString(arg);
+ return newObj ? newObj(str) : str;
+ }
+
+ /**
+ * ECMA 15.5.2.1 new String ( [ value ] ) - special version with exactly one {@code int} arg
+ *
+ * Constructor
+ *
+ * @param newObj is this constructor invoked with the new operator
+ * @param self self reference
+ * @param arg the arg
+ *
+ * @return new NativeString containing the string representation of the arg
+ */
+ @SpecializedFunction(isConstructor=true)
+ public static Object constructor(final boolean newObj, final Object self, final double arg) {
final String str = JSType.toString(arg);
return newObj ? newObj(str) : str;
}
@@ -1231,9 +1282,9 @@
*
* @return new NativeString containing the string representation of the arg
*/
- @SpecializedConstructor
+ @SpecializedFunction(isConstructor=true)
public static Object constructor(final boolean newObj, final Object self, final boolean arg) {
- final String str = JSType.toString(arg);
+ final String str = Boolean.toString(arg);
return newObj ? newObj(str) : str;
}
@@ -1281,7 +1332,7 @@
} else if (self != null && self == Global.instance().getStringPrototype()) {
return "";
} else {
- throw typeError( "not.a.string", ScriptRuntime.safeToString(self));
+ throw typeError("not.a.string", ScriptRuntime.safeToString(self));
}
}
@@ -1310,4 +1361,50 @@
return MH.findStatic(MethodHandles.lookup(), NativeString.class, name, type);
}
+ @Override
+ public LinkLogic getLinkLogic(final Class<? extends LinkLogic> clazz) {
+ if (clazz == CharCodeAtLinkLogic.class) {
+ return CharCodeAtLinkLogic.INSTANCE;
+ }
+ return null;
+ }
+
+ @Override
+ public boolean hasPerInstanceAssumptions() {
+ return false;
+ }
+
+ /**
+ * This is linker logic charCodeAt - when we specialize further methods in NativeString
+ * It may be expanded. It's link check makes sure that we are dealing with a char
+ * sequence and that we are in range
+ */
+ private static final class CharCodeAtLinkLogic extends SpecializedFunction.LinkLogic {
+
+ private static final CharCodeAtLinkLogic INSTANCE = new CharCodeAtLinkLogic();
+
+ @Override
+ public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+ try {
+ //check that it's a char sequence or throw cce
+ final CharSequence cs = (CharSequence)self;
+ //check that the index, representable as an int, is inside the array
+ final int intIndex = JSType.toInteger(request.getArguments()[1]);
+ return intIndex >= 0 && intIndex < cs.length(); //can link
+ } catch (final ClassCastException | IndexOutOfBoundsException e) {
+ //fallthru
+ }
+ return false;
+ }
+
+ /**
+ * charCodeAt callsites can throw ClassCastException as a mechanism to have them
+ * relinked - this enabled fast checks of the kind of ((IntArrayData)arrayData).push(x)
+ * for an IntArrayData only push - if this fails, a CCE will be thrown and we will relink
+ */
+ @Override
+ public Class<? extends Throwable> getRelinkException() {
+ return ClassCastException.class;
+ }
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java Thu Sep 25 15:53:47 2014 +0200
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@@ -119,6 +118,11 @@
}
@Override
+ public Class<?> getElementType() {
+ return int.class;
+ }
+
+ @Override
public int getInt(final int index) {
return getElem(index);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java Thu Sep 25 15:53:47 2014 +0200
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@@ -128,6 +127,11 @@
}
@Override
+ public Class<?> getElementType() {
+ return int.class;
+ }
+
+ @Override
public int getInt(final int index) {
return (int)getLong(index);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java Thu Sep 25 15:53:47 2014 +0200
@@ -26,7 +26,6 @@
package jdk.nashorn.internal.objects;
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@@ -119,6 +118,11 @@
}
@Override
+ public Class<?> getElementType() {
+ return int.class;
+ }
+
+ @Override
public int getInt(final int index) {
return getElem(index);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8ClampedArray.java Thu Sep 25 15:53:47 2014 +0200
@@ -28,7 +28,6 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
import static jdk.nashorn.internal.lookup.Lookup.MH;
-
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.ByteBuffer;
@@ -98,6 +97,11 @@
return SET_ELEM;
}
+ @Override
+ public Class<?> getElementType() {
+ return int.class;
+ }
+
private int getElem(final int index) {
try {
return nb.get(index) & 0xff;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ScriptFunctionImpl.java Thu Sep 25 15:53:47 2014 +0200
@@ -30,6 +30,7 @@
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
+
import jdk.nashorn.internal.runtime.AccessorProperty;
import jdk.nashorn.internal.runtime.GlobalFunctions;
import jdk.nashorn.internal.runtime.Property;
@@ -38,6 +39,7 @@
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptFunctionData;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.Specialization;
/**
* Concrete implementation of ScriptFunction. This sets correct map for the
@@ -58,7 +60,7 @@
// Marker object for lazily initialized prototype object
private static final Object LAZY_PROTOTYPE = new Object();
- private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs, final Global global) {
+ private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final Specialization[] specs, final Global global) {
super(name, invokeHandle, map$, null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
init(global);
}
@@ -71,11 +73,11 @@
* @param invokeHandle handle for invocation
* @param specs specialized versions of this method, if available, null otherwise
*/
- ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final MethodHandle[] specs) {
+ ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final Specialization[] specs) {
this(name, invokeHandle, specs, Global.instance());
}
- private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs, final Global global) {
+ private ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs, final Global global) {
super(name, invokeHandle, map.addAll(map$), null, specs, ScriptFunctionData.IS_BUILTIN_CONSTRUCTOR);
init(global);
}
@@ -89,11 +91,11 @@
* @param map initial property map
* @param specs specialized versions of this method, if available, null otherwise
*/
- ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final MethodHandle[] specs) {
+ ScriptFunctionImpl(final String name, final MethodHandle invokeHandle, final PropertyMap map, final Specialization[] specs) {
this(name, invokeHandle, map, specs, Global.instance());
}
- private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags, final Global global) {
+ private ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final Specialization[] specs, final int flags, final Global global) {
super(name, methodHandle, getMap(isStrict(flags)), scope, specs, flags);
init(global);
}
@@ -107,7 +109,7 @@
* @param specs specialized versions of this method, if available, null otherwise
* @param flags {@link ScriptFunctionData} flags
*/
- ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final MethodHandle[] specs, final int flags) {
+ ScriptFunctionImpl(final String name, final MethodHandle methodHandle, final ScriptObject scope, final Specialization[] specs, final int flags) {
this(name, methodHandle, scope, specs, flags, Global.instance());
}
@@ -184,7 +186,7 @@
return new AnonymousFunction();
}
- private static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs, final int flags) {
+ private static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final Specialization[] specs, final int flags) {
final ScriptFunctionImpl func = new ScriptFunctionImpl(name, methodHandle, null, specs, flags);
func.setPrototype(UNDEFINED);
// Non-constructor built-in functions do not have "prototype" property
@@ -201,7 +203,7 @@
* @param specs specialized versions of function if available, null otherwise
* @return new ScriptFunction
*/
- static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final MethodHandle[] specs) {
+ static ScriptFunction makeFunction(final String name, final MethodHandle methodHandle, final Specialization[] specs) {
return makeFunction(name, methodHandle, specs, ScriptFunctionData.IS_BUILTIN);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/SpecializedConstructor.java Tue Sep 23 15:58:44 2014 +0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.nashorn.internal.objects.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * The SpecializedConstructor annotation is used to flag more type specific constructors than the standard one in
- * Native objects. For example {@link jdk.nashorn.internal.objects.NativeArray#construct} takes an arbitrary number of
- * Object elements as an array. Call this constructor, including the varargs collector that allocates the array
- * upon each invocation, is much more expensive than calling a specialized constructor that takes one arguments
- * of, e.g. int type from the call site, such as
- * {@link jdk.nashorn.internal.objects.NativeArray#construct(boolean, Object, int)}.
- * {@link jdk.nashorn.internal.runtime.ScriptFunction} will try to look up the most specific function when
- * linking the callsite.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface SpecializedConstructor {
- //empty
-}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/annotations/SpecializedFunction.java Thu Sep 25 15:53:47 2014 +0200
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -29,18 +29,315 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.SwitchPoint;
+import jdk.internal.dynalink.CallSiteDescriptor;
+import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.nashorn.internal.runtime.ScriptFunction;
/**
- * The SpecializedFunction annotation is used to flag more type specific functions than the standard one in
- * Native objects. For example {@link jdk.nashorn.internal.objects.NativeMath#max} takes an arbitrary number of
- * Object elements as an array. Call this function, including the varargs collector that allocates the array
- * upon each invocation, is much more expensive than calling a specialized function that takes two arguments
- * of, e.g. int type from the call site, such as {@link jdk.nashorn.internal.objects.NativeMath#max(Object, int, int)}.
- * {@link jdk.nashorn.internal.runtime.ScriptFunction} will try to look up the most specific function when
- * linking the callsite.
+ * The SpecializedFunction annotation is used to flag more type specific
+ * functions than the standard one in the native objects
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SpecializedFunction {
- //empty
+
+ /**
+ * Functionality for testing if we are allowed to link a specialized
+ * function the first time we encounter it. Then the guard will handle the
+ * rest of the invocations
+ *
+ * This is the same for all callsites in Nashorn, the first time callsite is
+ * linked, we have to manually check that the linkage is OK. Even if we add
+ * a guard and it fails upon the first try, this is not good enough.
+ * (Symmetrical to how it works everywhere else in the Nashorn runtime).
+ *
+ * Here we abstract out a few of the most common link guard checks.
+ */
+ public static abstract class LinkLogic {
+ /**
+ * Empty link logic instance - this is the default
+ * "no special linking or runtime guard behavior"
+ */
+ public static final LinkLogic EMPTY_INSTANCE = new Empty();
+
+ private static final SwitchPoint[] INVALIDATED_SWITCHPOINTS = new SwitchPoint[0];
+
+ private SwitchPoint[] modificationSwitchPoints; //cache
+
+ /** Empty link logic class - allow all linking, no guards */
+ private static final class Empty extends LinkLogic {
+ @Override
+ public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+ return true;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return true;
+ }
+ };
+
+ /**
+ * Get the class representing the empty link logic
+ * @return class representing empty link logic
+ */
+ public static Class<? extends LinkLogic> getEmptyLinkLogicClass() {
+ return Empty.class;
+ }
+
+ /**
+ * Should this callsite relink when an exception is thrown
+ *
+ * @return the relink exception, or null if none
+ */
+ public Class<? extends Throwable> getRelinkException() {
+ return null;
+ }
+
+ /**
+ * Is this link logic class empty - i.e. no special linking logic
+ * supplied
+ *
+ * @param clazz class to check
+ *
+ * @return true if this link logic is empty
+ */
+ public static boolean isEmpty(final Class<? extends LinkLogic> clazz) {
+ return clazz == Empty.class;
+ }
+
+ /**
+ * Is this link logic instance empty - i.e. no special linking logic
+ * supplied
+ *
+ * @return true if this link logic instance is empty
+ */
+ public boolean isEmpty() {
+ return false;
+ }
+
+ /**
+ * Given a callsite, can we link this method based on the receiver and
+ * parameters?
+ *
+ * @param self receiver
+ * @param desc callsite descriptor
+ * @param request link request
+ *
+ * @return true if we can link this callsite at this time
+ */
+ public abstract boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request);
+
+ /**
+ * Given a callsite, do we require an extra guard for specialization to
+ * go through?
+ *
+ * @param self receiver
+ *
+ * @return true if a guard is to be woven into the callsite
+ */
+ public boolean needsGuard(final Object self) {
+ return true;
+ }
+
+ /**
+ * Given a callsite, and optional arguments, do we need an extra guard
+ * for specialization to go through - this guard can be a function of
+ * the arguments too
+ *
+ * @param self receiver
+ * @param args arguments
+ *
+ * @return true if a guard is to be woven into the callsite
+ */
+ public boolean needsGuard(final Object self, final Object... args) {
+ return true;
+ }
+
+ /**
+ * Given a callsite, and optional arguments, return any extra guard we
+ * might need for specialization as a method handle.
+ *
+ * @return methodhandle for guard, or null if no guard is needed
+ */
+ public MethodHandle getGuard() {
+ return null;
+ }
+
+ /**
+ * Return the modification SwitchPoint of a particular index from this OptimisticBuiltins
+ * If none exists, one is created and that one is return.
+ *
+ * The implementor must map indexes to specific SwitchPoints for specific events and keep
+ * track of what they mean, for example NativeArray.LENGTH_NOT_WRITABLE_SWITCHPOINT
+ * might be a useful index mapping
+ *
+ * @param index index for SwitchPoint to get or create
+ * @return modification SwitchPoint of particular index for the receiver
+ */
+ public SwitchPoint getOrCreateModificationSwitchPoint(final int index) {
+ return null;
+ }
+
+ /**
+ * Return the modification SwitchPoint from this OptimisticBuiltins. If none
+ * exists, one is created and that one is return.
+ *
+ * @return modification SwitchPoint for the receiver
+ */
+ public SwitchPoint[] getOrCreateModificationSwitchPoints() {
+ return null;
+ }
+
+ /**
+ * Hook to invalidate a modification SwitchPoint by index.
+ *
+ * @param index index for SwitchPoint to invalidate
+ */
+ public void invalidateModificationSwitchPoint(final int index) {
+ //empty
+ }
+
+ /**
+ * Hook to invalidate all modification SwitchPoints for a receiver
+ */
+ public void invalidateModificationSwitchPoints() {
+ //empty
+ }
+
+ /**
+ * Check whether the receiver has an invalidated modification SwitchPoint.
+ *
+ * @param index index for the modification SwitchPoint
+ * @return true if the particular SwitchPoint at the index is invalidated
+ */
+ public boolean hasInvalidatedModificationSwitchPoint(final int index) {
+ return false;
+ }
+
+ /**
+ * Check whether at least one of the modification SwitchPoints has been
+ * invalidated
+ * @return true if one of the SwitchPoints has been invalidated
+ */
+ public boolean hasInvalidatedModificationSwitchPoints() {
+ return false;
+ }
+
+ /**
+ * Check whether this OptimisticBuiltins has a SwitchPoints of particular
+ * index.
+ *
+ * As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of,
+ * e.g. in the constructor of every subclass.
+ *
+ * @param index index for the modification SwitchPoint
+ * @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not
+ */
+ public boolean hasModificationSwitchPoint(final int index) {
+ return false;
+ }
+
+ /**
+ * Check whether this OptimisticBuiltins has SwitchPoints.
+ *
+ * As creation overhead for a SwitchPoint is non-zero, we have to create them lazily instead of,
+ * e.g. in the constructor of every subclass.
+ *
+ * @return true if a modification SwitchPoint exists, no matter if it has been invalidated or not
+ */
+ public boolean hasModificationSwitchPoints() {
+ return false;
+ }
+
+ /**
+ * Check, given a link request and a receiver, if this specialization
+ * fits This is used by the linker in {@link ScriptFunction} to figure
+ * out if an optimistic builtin can be linked when first discovered
+ *
+ * @param self receiver
+ * @param desc callsite descriptor
+ * @param request link request
+
+ * @return true if we can link, false otherwise - that means we have to
+ * pick a non specialized target
+ */
+ public boolean checkLinkable(final Object self, final CallSiteDescriptor desc, final LinkRequest request) {
+ // no matter what the modification switchpoints are, if any of them are invalidated,
+ // we can't link. Side effect is that if it's the first time we see this callsite,
+ // we have to create the SwitchPoint(s) so future modification switchpoint invalidations
+ // relink it
+ final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(self);
+ if (sps == INVALIDATED_SWITCHPOINTS) {
+ // nope, can't do the fast link as this assumption
+ // has been invalidated already, e.g. length of an
+ // array set to not writable
+ return false;
+ }
+ modificationSwitchPoints = sps; //cache
+
+ // check the link guard, if it says we can link, go ahead
+ return canLink(self, desc, request);
+ }
+
+ private SwitchPoint[] getOrCreateModificationSwitchPoints(final Object self) {
+ final SwitchPoint[] sps = getOrCreateModificationSwitchPoints(); //ask for all my switchpoints
+ if (sps != null) { //switchpoint exists, but some may be invalidated
+ for (final SwitchPoint sp : sps) {
+ if (sp.hasBeenInvalidated()) {
+ return INVALIDATED_SWITCHPOINTS;
+ }
+ }
+ }
+ return sps;
+ }
+
+ /**
+ * Get the cached modification switchpoints. Only possible to do after a link
+ * check call has been performed, one that has answered "true", or you will get the
+ * wrong information.
+ *
+ * Should be used only from {@link ScriptFunction#findCallMethod}
+ *
+ * @return cached modification switchpoints for this callsite, null if none
+ */
+ public SwitchPoint[] getModificationSwitchPoints() {
+ return modificationSwitchPoints == null ? null : modificationSwitchPoints.clone();
+ }
+ }
+
+ /**
+ * name override for return value polymorphism, for example we can't have
+ * pop(V)I and pop(V)D in the same Java class, so they need to be named,
+ * e.g. popInt(V)I and popDouble(V)D for disambiguation, however, their
+ * names still need to resolve to "pop" to JavaScript so we can still
+ * specialize on return values and so that the linker can find them
+ *
+ * @return name, "" means no override, use the Java function name, e.g.
+ * "push"
+ */
+ String name() default "";
+
+ /**
+ * Return the guard for this specialized function. The default is no guard.
+ *
+ * @return guard
+ */
+ Class<?> linkLogic() default LinkLogic.Empty.class;
+
+ /**
+ * Is this a specialized constructor?
+ */
+ boolean isConstructor() default false;
+
+ /**
+ * Can this function throw UnwarrantedOptimismExceptions? This works just
+ * like the normal functions, but we need the function to be
+ * immutable/non-state modifying, as we can't generate continuations for
+ * native code. Luckily a lot of the methods we want to specialize have this
+ * property
+ */
+ boolean isOptimistic() default false;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java Thu Sep 25 15:53:47 2014 +0200
@@ -36,7 +36,6 @@
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 @@
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 @@
* @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 @@
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 @@
}
@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 @@
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 @@
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 @@
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 @@
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 @@
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 ";
}
});
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java Thu Sep 25 15:53:47 2014 +0200
@@ -81,13 +81,17 @@
/**
* 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
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeStore.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeStore.java Thu Sep 25 15:53:47 2014 +0200
@@ -118,6 +118,8 @@
* @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 @@
/**
* 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,
@@ -216,6 +220,7 @@
* 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
*/
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java Thu Sep 25 15:53:47 2014 +0200
@@ -33,12 +33,13 @@
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.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 @@
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,20 +79,40 @@
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, 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, final Specialization specialization) {
+ this(invoker, constructor, 0, null, specialization, DebugLogger.DISABLED_LOGGER);
}
- static CompiledFunction createBuiltInConstructor(final MethodHandle invoker) {
- return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)));
- }
-
- CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
- this(invoker, constructor, 0, null, DebugLogger.DISABLED_LOGGER);
- }
-
- CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final int flags, final MethodType callSiteType, final DebugLogger log) {
- this.invoker = invoker;
+ 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");
+ } else {
+ this.invoker = invoker;
+ }
this.constructor = constructor;
this.flags = flags;
this.callSiteType = callSiteType;
@@ -97,7 +121,7 @@
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 +129,45 @@
}
}
+ 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 +178,19 @@
@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 +352,12 @@
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 +479,17 @@
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) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java Thu Sep 25 15:53:47 2014 +0200
@@ -40,6 +40,7 @@
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;
@@ -63,7 +64,9 @@
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.logging.Level;
+
import javax.script.ScriptEngine;
+
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
import jdk.nashorn.api.scripting.ClassFilter;
@@ -127,6 +130,16 @@
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;
@@ -1371,4 +1384,34 @@
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 {
+
+ }
+
+ /**
+ * 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);
+ }
+
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FinalScriptFunctionData.java Thu Sep 25 15:53:47 2014 +0200
@@ -60,13 +60,13 @@
* @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 @@
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) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/FindProperty.java Thu Sep 25 15:53:47 2014 +0200
@@ -79,6 +79,8 @@
*
* @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 @@
*
* @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
*/
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalConstants.java Thu Sep 25 15:53:47 2014 +0200
@@ -358,8 +358,12 @@
* @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");
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalFunctions.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalFunctions.java Thu Sep 25 15:53:47 2014 +0200
@@ -42,12 +42,30 @@
/** 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);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/OptimisticBuiltins.java Thu Sep 25 15:53:47 2014 +0200
@@ -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();
+
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Property.java Thu Sep 25 15:53:47 2014 +0200
@@ -28,7 +28,6 @@
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 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 @@
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 @@
* @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 @@
* 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();
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java Thu Sep 25 15:53:47 2014 +0200
@@ -950,7 +950,7 @@
@Override
public void remove() {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("remove");
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java Thu Sep 25 15:53:47 2014 +0200
@@ -26,11 +26,11 @@
package jdk.nashorn.internal.runtime;
import static jdk.nashorn.internal.lookup.Lookup.MH;
-
import java.io.IOException;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -454,7 +454,7 @@
// 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;
@@ -597,6 +597,8 @@
* 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 +660,8 @@
@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 +725,10 @@
return functionNodeId;
}
+ /**
+ * Get the source for the script
+ * @return source
+ */
public Source getSource() {
return source;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java Thu Sep 25 15:53:47 2014 +0200
@@ -181,9 +181,6 @@
/** 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 @@
_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");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java Thu Sep 25 15:53:47 2014 +0200
@@ -30,26 +30,29 @@
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 @@
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 @@
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 @@
}
/**
+ * 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 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 @@
}
} //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 @@
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 @@
//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 @@
}
}
- 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 @@
// 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 @@
// 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 @@
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()
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java Thu Sep 25 15:53:47 2014 +0200
@@ -28,13 +28,13 @@
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 @@
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 @@
* @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 @@
* 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 @@
}
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 @@
abstract boolean isRecompilable();
CompiledFunction getGeneric(final ScriptObject runtimeScope) {
- return getBest(getGenericType(), runtimeScope);
+ return getBest(getGenericType(), runtimeScope, CompiledFunction.NO_FUNCTIONS);
}
/**
@@ -420,7 +424,7 @@
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);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java Thu Sep 25 15:53:47 2014 +0200
@@ -47,7 +47,6 @@
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 @@
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>
@@ -1514,6 +1526,23 @@
}
/**
+ * 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
*/
@@ -1916,17 +1945,6 @@
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 @@
*/
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 @@
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) {
@@ -2166,7 +2183,7 @@
}
}
- 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 @@
@Override
public void remove() {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("remove");
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptRuntime.java Thu Sep 25 15:53:47 2014 +0200
@@ -32,9 +32,9 @@
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 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 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 @@
@Override
public void remove() {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("remove");
}
}
@@ -328,7 +334,7 @@
@Override
public void remove() {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("remove");
}
};
}
@@ -998,4 +1004,19 @@
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->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 });
+ }
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java Thu Sep 25 15:53:47 2014 +0200
@@ -28,7 +28,6 @@
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 @@
* 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 @@
}
}
- private SetMethod createSetMethod() {
+ private SetMethod createSetMethod(final SwitchPoint builtinSwitchPoint) {
if (find != null) {
return createExistingPropertySetter();
}
@@ -130,7 +129,7 @@
return createGlobalPropertySetter();
}
- return createNewPropertySetter();
+ return createNewPropertySetter(builtinSwitchPoint);
}
private void checkStrictCreateNewVariable() {
@@ -185,8 +184,8 @@
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 @@
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 @@
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) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Specialization.java Thu Sep 25 15:53:47 2014 +0200
@@ -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;
+ }
+
+}
+
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/StoredScript.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/StoredScript.java Thu Sep 25 15:53:47 2014 +0200
@@ -55,8 +55,10 @@
/**
* 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 @@
this.initializers = initializers;
}
+ /**
+ * Get the compilation id for this StoredScript
+ * @return compilation id
+ */
public int getCompilationId() {
return compilationId;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/UserAccessorProperty.java Thu Sep 25 15:53:47 2014 +0200
@@ -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;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java Thu Sep 25 15:53:47 2014 +0200
@@ -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 @@
/**
* 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 @@
* @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
@@ -655,7 +654,7 @@
* @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 @@
}
}
+ /**
+ * 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
*
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java Thu Sep 25 15:53:47 2014 +0200
@@ -201,7 +201,7 @@
}
@Override
- protected ArrayData convert(final Class<?> type) {
+ public ArrayData convert(final Class<?> type) {
underlying = underlying.convert(type);
setLength(underlying.length());
return this;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ContinuousArrayData.java Thu Sep 25 15:53:47 2014 +0200
@@ -30,7 +30,6 @@
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;
@@ -116,6 +115,12 @@
}
/**
+ * 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 @@
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 @@
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
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntArrayData.java Thu Sep 25 15:53:47 2014 +0200
@@ -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 @@
* 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 @@
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)) {
@@ -100,11 +109,6 @@
}
@Override
- public Object[] asObjectArray() {
- return toObjectArray(array, (int) length());
- }
-
- @Override
public Object asArrayOfType(final Class<?> componentType) {
if (componentType == int.class) {
return array.length == length() ? array.clone() : Arrays.copyOf(array, (int) length());
@@ -112,7 +116,7 @@
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 @@
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 @@
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 @@
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();
}
}
@@ -355,4 +371,41 @@
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();
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntElements.java Thu Sep 25 15:53:47 2014 +0200
@@ -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
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntOrLongElements.java Thu Sep 25 15:53:47 2014 +0200
@@ -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
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/LongArrayData.java Thu Sep 25 15:53:47 2014 +0200
@@ -27,7 +27,6 @@
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 @@
* 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,6 +56,11 @@
}
@Override
+ public Class<?> getElementType() {
+ return long.class;
+ }
+
+ @Override
public ArrayData copy() {
return new LongArrayData(array.clone(), (int)length());
}
@@ -324,4 +328,41 @@
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;
+ //return array[(int)--length];
+ }
+
+ @Override
+ public double fastPopDouble() {
+ return fastPopLong();
+ }
+
+ @Override
+ public Object fastPopObject() {
+ return fastPopLong();
+ }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java Thu Sep 25 15:53:47 2014 +0200
@@ -28,7 +28,6 @@
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 @@
* 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,6 +55,11 @@
}
@Override
+ public Class<?> getElementType() {
+ return double.class;
+ }
+
+ @Override
public ArrayData copy() {
return new NumberArrayData(array.clone(), (int) length());
}
@@ -298,4 +302,41 @@
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();
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumericElements.java Thu Sep 25 15:53:47 2014 +0200
@@ -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
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java Thu Sep 25 15:53:47 2014 +0200
@@ -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,8 +56,13 @@
}
@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
@@ -232,6 +236,42 @@
}
@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) {
return ScriptRuntime.UNDEFINED;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/SparseArrayData.java Thu Sep 25 15:53:47 2014 +0200
@@ -329,7 +329,7 @@
}
@Override
- protected ArrayData convert(final Class<?> type) {
+ public ArrayData convert(final Class<?> type) {
underlying = underlying.convert(type);
return this;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/TypedArrayData.java Thu Sep 25 15:53:47 2014 +0200
@@ -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;
@@ -134,7 +133,7 @@
}
@Override
- protected ArrayData convert(final Class<?> type) {
+ public ArrayData convert(final Class<?> type) {
throw new UnsupportedOperationException();
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Thu Sep 25 15:53:47 2014 +0200
@@ -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 @@
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 @@
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;
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/examples/charcodeat-benchmark.js Thu Sep 25 15:53:47 2014 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Simple benchmark to measure charCodeAt specialized method performance
+ */
+
+var str = "sghjkdsfkjghsdfjkfkjdfkjdfjkdfjkfdjkfdkfldjfhdfpkjdhafgksdjfgldfgjldfkjgdlfjgldkfjgkldfj";
+var RESULT1 = 9187;
+var RESULT2 = 1496;
+
+function f() {
+ var len = str.length;
+ var c = 0;
+ for (var i = 0; i < len; i++) {
+ c += str.charCodeAt(i);
+ }
+ return c;
+}
+
+function bench(res) {
+ var d = new Date;
+ var sum = 0;
+ for (var i = 0; i < 1e6; i++) {
+ sum |= f();
+ }
+ if (sum == res) {
+ print("Verified OK");
+ } else {
+ print("Verification failed " + sum + " should be " + res);
+ }
+ print((new Date - d) + " ms");
+}
+
+bench(RESULT1);
+
+print("Replacing charCodeAt... ");
+
+String.prototype.charCodeAt = function() { return 17; }
+
+bench(RESULT2);
+
+print("Done");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/examples/push-pop-benchmark.js Thu Sep 25 15:53:47 2014 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Simple benchmark to measure push/pop specialized method performance
+ */
+
+var a = [];
+
+var RESULT = 15;
+
+function bench() {
+ var sum = 0;
+ for (var i=0;i<10;i++) {
+ a.push(i);
+ }
+ for (var i=0;i<10;i++) {
+ sum |= a.pop();
+ }
+ return sum;
+}
+
+function runbench() {
+ var sum = 0;
+ for (var iters = 0; iters<1e8; iters++) {
+ sum |= bench();
+ }
+ return sum;
+}
+
+var d = new Date;
+var res = runbench();
+print((new Date - d) + " ms");
+print();
+if (res != RESULT) {
+ print("ERROR: Wrong result - should be " + RESULT);
+} else {
+ print("Verified OK - result is correct");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/apply_to_call/apply_to_call5.js Thu Sep 25 15:53:47 2014 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * apply_to_call5.js - do one apply to call specialization, then override, apply and make sure it reverts (i.e. stops
+ * calling call)
+ *
+ * @test
+ * @run
+ */
+
+print("start");
+
+var x = {
+ a : 0,
+ b : 0,
+ c : 0,
+ initialize : function(x,y,z) {
+ this.a = x;
+ this.b = y;
+ this.c = z;
+ }
+};
+
+function test() {
+ x.initialize.apply(x, arguments);
+}
+
+test(4711,23,17);
+print(x.a);
+print(x.b);
+print(x.c);
+
+print("Overwriting apply now");
+x.initialize.apply = function() { print("New function for apply - not a property"); }
+
+test(4712);
+print(x.a);
+
+
+var x2 = {
+ a : 0,
+ b : 0,
+ c : 0,
+ initialize : function(x,y,z) {
+ this.a = x;
+ this.b = y;
+ this.c = z;
+ }
+};
+
+function test2() {
+ x2.initialize.apply(x2, arguments);
+}
+
+test2(4711,23,17);
+print(x2.a);
+print(x2.b);
+print(x2.c);
+
+print("Overwriting apply now");
+x2.initialize['apply'] = function() { print("New function for apply - not a property"); }
+
+test(4712);
+print(x2.a);
+
+var x3 = {
+ a : 0,
+ b : 0,
+ c : 0,
+ initialize : function(x,y,z) {
+ this.a = x;
+ this.b = y;
+ this.c = z;
+ }
+};
+
+function test3() {
+ x3.initialize.apply(x3, arguments);
+}
+
+test3(4711,23,17);
+print(x3.a);
+print(x3.b);
+print(x3.c);
+
+print("Overwriting apply now");
+eval("x3.initialize['apply'] = function() { print('New function for apply - not a property'); }");
+
+test(4712);
+print(x3.a);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/apply_to_call/apply_to_call5.js.EXPECTED Thu Sep 25 15:53:47 2014 +0200
@@ -0,0 +1,19 @@
+start
+4711
+23
+17
+Overwriting apply now
+New function for apply - not a property
+4711
+4711
+23
+17
+Overwriting apply now
+New function for apply - not a property
+4711
+4711
+23
+17
+Overwriting apply now
+New function for apply - not a property
+4711
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/fastpushpop.js Thu Sep 25 15:53:47 2014 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * fastpushpop.js: make sure guards work for fast push implementation
+ * and normal one
+ *
+ * @test
+ * @run
+ */
+
+var a = [1,2,3];
+a.push(4);
+a.push(5);
+a.push(6);
+print(a);
+
+var a2 = Object.defineProperty(a,"length", { writable: false });
+try {
+ a2.push(7);
+} catch (e) {
+ print("first: " + (e instanceof TypeError));
+}
+
+print(a2);
+
+var b = [1,2,3,,,,4711.17,"dingo!"];
+b.push(4);
+b.push(5);
+b.push(6);
+print(b);
+
+var b2 = Object.defineProperty(b,"length", { writable: false });
+try {
+ b2.push(7);
+} catch (e) {
+ print("second: " + (e instanceof TypeError));
+}
+
+print(b2);
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/fastpushpop.js.EXPECTED Thu Sep 25 15:53:47 2014 +0200
@@ -0,0 +1,6 @@
+1,2,3,4,5,6
+first: true
+1,2,3,4,5,6,7
+1,2,3,,,,4711.17,dingo!,4,5,6
+second: true
+1,2,3,,,,4711.17,dingo!,4,5,6,7
--- a/nashorn/test/script/basic/run-octane.js Tue Sep 23 15:58:44 2014 +0400
+++ b/nashorn/test/script/basic/run-octane.js Thu Sep 25 15:53:47 2014 +0200
@@ -54,7 +54,7 @@
}
}
- print_verbose(arg, "loading '" + arg.name + "' [" + f + "]...");
+ print_verbose(arg, "loading '" + arg.name + "' [" + f + "]... " + file_name);
load(file_name);
}
@@ -139,7 +139,7 @@
mean_score /= iters;
} catch (e) {
print_always(arg, "*** Aborted and setting score to zero. Reason: " + e);
- if (e instanceof java.lang.Throwable) {
+ if (is_this_nashorn() && e instanceof java.lang.Throwable) {
e.printStackTrace();
}
mean_score = min_score = max_score = 0;
@@ -148,7 +148,7 @@
var res = mean_score.toFixed(0);
if (verbose) {
- res += " ops/minute (" + min_score.toFixed(0) + "-" + max_score.toFixed(0) + "), warmup=" + scores[0].toFixed(0);
+ res += " ops/minute (" + min_score.toFixed(0) + "-" + max_score.toFixed(0) + "), warmup=" + scores[0].toFixed(0);
}
print_always(arg, res);
}