8025435: Optimistic builtins support, implemented initial optimistic versions of push, pop, and charCodeAt
Reviewed-by: attila, hannesw, sundar
This commit is contained in:
parent
643e8d87e6
commit
da0b4cb7df
nashorn
buildtools/nasgen/src/jdk/nashorn/internal/tools/nasgen
ClassGenerator.javaMemberInfo.javaMethodGenerator.javaScriptClassInfo.javaScriptClassInfoCollector.javaScriptClassInstrumentor.javaStringConstants.java
samples
src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal
codegen
ApplySpecialization.javaClassEmitter.javaCompileUnit.javaMethodEmitter.javaOptimisticTypesPersistence.java
ir
lookup
objects
ArrayBufferView.javaGlobal.javaNativeArray.javaNativeDataView.javaNativeDate.javaNativeFloat32Array.javaNativeFloat64Array.javaNativeInt16Array.javaNativeInt32Array.javaNativeInt8Array.javaNativeJSAdapter.javaNativeRegExp.javaNativeString.javaNativeUint16Array.javaNativeUint32Array.javaNativeUint8Array.javaNativeUint8ClampedArray.javaScriptFunctionImpl.java
annotations
runtime
AccessorProperty.javaCodeInstaller.javaCodeStore.javaCompiledFunction.javaContext.javaFinalScriptFunctionData.javaFindProperty.javaGlobalConstants.javaGlobalFunctions.javaOptimisticBuiltins.javaProperty.javaPropertyMap.javaRecompilableScriptFunctionData.javaScriptEnvironment.javaScriptFunction.javaScriptFunctionData.javaScriptObject.javaScriptRuntime.javaSetMethodCreator.javaSpecialization.javaStoredScript.javaUserAccessorProperty.java
arrays
ArrayData.javaArrayFilter.javaContinuousArrayData.javaIntArrayData.javaIntElements.javaIntOrLongElements.javaLongArrayData.javaNumberArrayData.javaNumericElements.javaObjectArrayData.javaSparseArrayData.javaTypedArrayData.java
linker
test
@ -292,7 +292,6 @@ public class ClassGenerator {
|
||||
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) {
|
||||
|
@ -28,7 +28,6 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.OBJECT_ARRAY_DES
|
||||
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 @@ public final class MemberInfo implements Cloneable {
|
||||
* 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 @@ public final class MemberInfo implements Cloneable {
|
||||
|
||||
private Where where;
|
||||
|
||||
private Type linkLogicClass;
|
||||
|
||||
private boolean isSpecializedConstructor;
|
||||
|
||||
private boolean isOptimistic;
|
||||
|
||||
/**
|
||||
* @return the kind
|
||||
*/
|
||||
@ -135,6 +136,57 @@ public final class MemberInfo implements Cloneable {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@ -304,19 +356,6 @@ public final class MemberInfo implements Cloneable {
|
||||
}
|
||||
}
|
||||
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 @@ public final class MemberInfo implements Cloneable {
|
||||
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);
|
||||
|
@ -55,6 +55,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
|
||||
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.SALOAD;
|
||||
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 @@ public class MethodGenerator extends MethodVisitor {
|
||||
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 @@ public class MethodGenerator extends MethodVisitor {
|
||||
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 @@ public class MethodGenerator extends MethodVisitor {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,8 @@ 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.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 @@ public final class ScriptClassInfo {
|
||||
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 @@ public final class ScriptClassInfo {
|
||||
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 @@ public final class ScriptClassInfo {
|
||||
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 @@ public final class ScriptClassInfo {
|
||||
res.add(memInfo);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return Collections.unmodifiableList(res);
|
||||
}
|
||||
|
||||
MemberInfo findSetter(final MemberInfo getter) {
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.tools.nasgen;
|
||||
|
||||
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.ClassVisitor;
|
||||
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 @@ public class ScriptClassInfoCollector extends ClassVisitor {
|
||||
|
||||
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 @@ public class ScriptClassInfoCollector extends ClassVisitor {
|
||||
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 @@ public class ScriptClassInfoCollector extends ClassVisitor {
|
||||
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 @@ public class ScriptClassInfoCollector extends ClassVisitor {
|
||||
|
||||
@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 @@ public class ScriptClassInfoCollector extends ClassVisitor {
|
||||
case SETTER:
|
||||
where = Where.INSTANCE;
|
||||
break;
|
||||
case SPECIALIZED_CONSTRUCTOR:
|
||||
case CONSTRUCTOR:
|
||||
where = Where.CONSTRUCTOR;
|
||||
break;
|
||||
@ -264,12 +288,18 @@ public class ScriptClassInfoCollector extends ClassVisitor {
|
||||
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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ import static jdk.nashorn.internal.tools.nasgen.StringConstants.DEFAULT_INIT_DES
|
||||
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.ClassVisitor;
|
||||
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;
|
||||
|
@ -37,6 +37,7 @@ import jdk.nashorn.internal.runtime.AccessorProperty;
|
||||
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 @@ import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
@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 @@ public interface StringConstants {
|
||||
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();
|
||||
|
@ -52,41 +52,49 @@ public class BufferArray extends AbstractJSObject {
|
||||
// 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 @@ public class BufferArray extends AbstractJSObject {
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -136,6 +136,7 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
|
||||
}
|
||||
};
|
||||
|
||||
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 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
|
||||
}
|
||||
|
||||
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 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
|
||||
|
||||
@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 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
|
||||
}
|
||||
});
|
||||
} 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 @@ public final class ApplySpecialization extends NodeVisitor<LexicalContext> imple
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -51,15 +51,14 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.className;
|
||||
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 @@ public class ClassEmitter implements Emitter {
|
||||
this.methodNames = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the method names encountered
|
||||
* @return method names
|
||||
*/
|
||||
public Set<String> getMethodNames() {
|
||||
return methodNames;
|
||||
return Collections.unmodifiableSet(methodNames);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,6 +60,10 @@ public final class CompileUnit implements Comparable<CompileUnit> {
|
||||
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 @@ public final class CompileUnit implements Comparable<CompileUnit> {
|
||||
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;
|
||||
}
|
||||
|
@ -71,7 +71,6 @@ import static jdk.nashorn.internal.codegen.CompilerConstants.virtualCallNoLookup
|
||||
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.LocalVariableConversion;
|
||||
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 @@ public class MethodEmitter implements Emitter {
|
||||
/** 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 @@ public class MethodEmitter implements Emitter {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -429,7 +429,6 @@ public final class OptimisticTypesPersistence {
|
||||
}
|
||||
|
||||
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 @@ public final class OptimisticTypesPersistence {
|
||||
}
|
||||
files[i] = null; // gc eligible
|
||||
};
|
||||
final long duration = System.nanoTime() - start;
|
||||
}
|
||||
|
||||
private static Path[] getAllRegularFilesInLastModifiedOrder() throws IOException {
|
||||
@ -497,7 +495,7 @@ public final class OptimisticTypesPersistence {
|
||||
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;
|
||||
}
|
||||
|
@ -238,17 +238,21 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
* 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 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
private FunctionNode(
|
||||
final FunctionNode functionNode,
|
||||
final long lastToken,
|
||||
Object endParserState,
|
||||
final Object endParserState,
|
||||
final int flags,
|
||||
final String name,
|
||||
final Type returnType,
|
||||
|
@ -237,6 +237,10 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
|
||||
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 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
|
||||
* @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 @@ public abstract class LiteralNode<T> extends Expression implements PropertyKey {
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -448,14 +448,25 @@ public final class Symbol implements Comparable<Symbol> {
|
||||
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;
|
||||
|
66
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/MethodHandleFactory.java
66
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/lookup/MethodHandleFactory.java
@ -116,6 +116,10 @@ public final class MethodHandleFactory {
|
||||
|
||||
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 @@ public final class MethodHandleFactory {
|
||||
* @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 @@ public final class MethodHandleFactory {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public final class MethodHandleFactory {
|
||||
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,12 +216,24 @@ public final class MethodHandleFactory {
|
||||
if (arg instanceof ScriptObject) {
|
||||
return arg.toString() +
|
||||
" (map=" + Debug.id(((ScriptObject)arg).getMap()) +
|
||||
")";
|
||||
')';
|
||||
}
|
||||
|
||||
return arg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@ -221,6 +248,20 @@ public final class MethodHandleFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -240,7 +281,6 @@ public final class MethodHandleFactory {
|
||||
return mh;
|
||||
}
|
||||
|
||||
assert logger != null;
|
||||
assert TRACE != null;
|
||||
|
||||
MethodHandle trace = MethodHandles.insertArguments(TRACE, 0, logger, tag, paramStart);
|
||||
@ -427,6 +467,12 @@ public final class MethodHandleFactory {
|
||||
return debug(mh, "constant", type, value);
|
||||
}
|
||||
|
||||
@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);
|
||||
|
@ -172,6 +172,15 @@ public interface MethodHandleFunctionality {
|
||||
*/
|
||||
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)}
|
||||
*
|
||||
|
@ -31,6 +31,7 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_
|
||||
|
||||
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;
|
||||
|
@ -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.GuardedInvocation;
|
||||
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.ScriptFunction;
|
||||
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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
* 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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
// 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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
// 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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
prototype.set(NativeError.NAME, name, 0);
|
||||
prototype.set(NativeError.MESSAGE, "", 0);
|
||||
prototype.setInitialProto(errorProto);
|
||||
tagBuiltinProperties(name, cons);
|
||||
return cons;
|
||||
}
|
||||
|
||||
@ -1910,17 +1951,18 @@ public final class Global extends ScriptObject implements Scope {
|
||||
}
|
||||
|
||||
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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
}
|
||||
|
||||
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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
// 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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
}
|
||||
}
|
||||
|
||||
//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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public final class Global extends ScriptObject implements Scope {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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.ArrayIndex.isValidArrayIndex;
|
||||
import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.arrayLikeIterator;
|
||||
import static jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator.reverseArrayLikeIterator;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor.CALLSITE_STRICT;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.SwitchPoint;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -52,12 +52,13 @@ 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.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.Undefined;
|
||||
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 @@ public final class NativeArray extends ScriptObject {
|
||||
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 @@ public final class NativeArray extends ScriptObject {
|
||||
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 @@ public final class NativeArray extends ScriptObject {
|
||||
* @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 @@ public final class NativeArray extends ScriptObject {
|
||||
* @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 @@ public final class NativeArray extends ScriptObject {
|
||||
* @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 @@ public final class NativeArray extends ScriptObject {
|
||||
* @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 @@ public final class NativeArray extends ScriptObject {
|
||||
* @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 @@ public final class NativeArray extends ScriptObject {
|
||||
* 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)
|
||||
@ -792,6 +828,68 @@ public final class NativeArray extends ScriptObject {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ()
|
||||
*
|
||||
@ -826,6 +924,62 @@ public final class NativeArray extends ScriptObject {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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...)
|
||||
*
|
||||
@ -856,61 +1010,6 @@ public final class NativeArray extends ScriptObject {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@ -925,7 +1024,7 @@ public final class NativeArray extends ScriptObject {
|
||||
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 @@ public final class NativeArray extends ScriptObject {
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.objects;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.rangeError;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import jdk.nashorn.internal.objects.annotations.Attribute;
|
||||
@ -35,7 +34,6 @@ import jdk.nashorn.internal.objects.annotations.Constructor;
|
||||
import jdk.nashorn.internal.objects.annotations.Function;
|
||||
import jdk.nashorn.internal.objects.annotations.Property;
|
||||
import jdk.nashorn.internal.objects.annotations.ScriptClass;
|
||||
import jdk.nashorn.internal.objects.annotations.SpecializedConstructor;
|
||||
import jdk.nashorn.internal.objects.annotations.SpecializedFunction;
|
||||
import jdk.nashorn.internal.runtime.JSType;
|
||||
import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
@ -156,7 +154,7 @@ public class NativeDataView extends ScriptObject {
|
||||
* @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 @@ public class NativeDataView extends ScriptObject {
|
||||
* @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");
|
||||
|
@ -30,7 +30,6 @@ import static java.lang.Double.isInfinite;
|
||||
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.Attribute;
|
||||
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 @@ public final class NativeDate extends ScriptObject {
|
||||
* @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);
|
||||
|
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat32Array.java
@ -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;
|
||||
@ -84,6 +83,11 @@ public final class NativeFloat32Array extends ArrayBufferView {
|
||||
super(((FloatBuffer)nb.position(start).limit(end)).slice(), end - start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return double.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MethodHandle getGetElem() {
|
||||
return GET_ELEM;
|
||||
|
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeFloat64Array.java
@ -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 @@ public final class NativeFloat64Array extends ArrayBufferView {
|
||||
return SET_ELEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return double.class;
|
||||
}
|
||||
|
||||
private double getElem(final int index) {
|
||||
try {
|
||||
return nb.get(index);
|
||||
|
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt16Array.java
@ -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 @@ public final class NativeInt16Array extends ArrayBufferView {
|
||||
return SET_ELEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return int.class;
|
||||
}
|
||||
|
||||
private int getElem(final int index) {
|
||||
try {
|
||||
return nb.get(index);
|
||||
|
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeInt32Array.java
@ -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;
|
||||
@ -112,6 +111,11 @@ public final class NativeInt32Array extends ArrayBufferView {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return int.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(final int index) {
|
||||
return getElem(index);
|
||||
|
@ -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 @@ public final class NativeInt8Array extends ArrayBufferView {
|
||||
return SET_ELEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return int.class;
|
||||
}
|
||||
|
||||
private int getElem(final int index) {
|
||||
try {
|
||||
return nb.get(index);
|
||||
|
@ -48,7 +48,6 @@ import jdk.nashorn.internal.runtime.PropertyMap;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
|
||||
import jdk.nashorn.internal.runtime.arrays.ArrayLikeIterator;
|
||||
import jdk.nashorn.internal.scripts.JO;
|
||||
|
||||
|
@ -33,13 +33,14 @@ import java.util.ArrayList;
|
||||
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 @@ public final class NativeRegExp extends ScriptObject {
|
||||
* @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 @@ public final class NativeRegExp extends ScriptObject {
|
||||
* @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 @@ public final class NativeRegExp extends ScriptObject {
|
||||
* @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);
|
||||
}
|
||||
|
@ -29,7 +29,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
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.Constructor;
|
||||
import jdk.nashorn.internal.objects.annotations.Function;
|
||||
import jdk.nashorn.internal.objects.annotations.Getter;
|
||||
import jdk.nashorn.internal.objects.annotations.ScriptClass;
|
||||
import jdk.nashorn.internal.objects.annotations.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 @@ import jdk.nashorn.internal.runtime.linker.PrimitiveLookup;
|
||||
* 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 @@ public final class NativeString extends ScriptObject {
|
||||
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 @@ public final class NativeString extends ScriptObject {
|
||||
*/
|
||||
@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 @@ public final class NativeString extends ScriptObject {
|
||||
* @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 @@ public final class NativeString extends ScriptObject {
|
||||
* @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 @@ public final class NativeString extends ScriptObject {
|
||||
*/
|
||||
@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 @@ public final class NativeString extends ScriptObject {
|
||||
*
|
||||
* @return new NativeString ("")
|
||||
*/
|
||||
@SpecializedConstructor
|
||||
@SpecializedFunction(isConstructor=true)
|
||||
public static Object constructor(final boolean newObj, final Object self) {
|
||||
return newObj ? newObj("") : "";
|
||||
}
|
||||
@ -1197,7 +1214,7 @@ public final class NativeString extends ScriptObject {
|
||||
*
|
||||
* @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 @@ public final class NativeString extends ScriptObject {
|
||||
*
|
||||
* @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 @@ public final class NativeString extends ScriptObject {
|
||||
*
|
||||
* @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 @@ public final class NativeString extends ScriptObject {
|
||||
} 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 @@ public final class NativeString extends ScriptObject {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint16Array.java
@ -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;
|
||||
@ -118,6 +117,11 @@ public final class NativeUint16Array extends ArrayBufferView {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return int.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(final int index) {
|
||||
return getElem(index);
|
||||
|
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint32Array.java
@ -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;
|
||||
@ -127,6 +126,11 @@ public final class NativeUint32Array extends ArrayBufferView {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return int.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(final int index) {
|
||||
return (int)getLong(index);
|
||||
|
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java
6
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeUint8Array.java
@ -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;
|
||||
@ -118,6 +117,11 @@ public final class NativeUint8Array extends ArrayBufferView {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return int.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(final int index) {
|
||||
return getElem(index);
|
||||
|
@ -28,7 +28,6 @@ package jdk.nashorn.internal.objects;
|
||||
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 @@ public final class NativeUint8ClampedArray extends ArrayBufferView {
|
||||
return SET_ELEM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return int.class;
|
||||
}
|
||||
|
||||
private int getElem(final int index) {
|
||||
try {
|
||||
return nb.get(index) & 0xff;
|
||||
|
18
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
18
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/ScriptFunctionImpl.java
@ -30,6 +30,7 @@ import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
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.RecompilableScriptFunctionData;
|
||||
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 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
// 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 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
* @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 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
* @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 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
* @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 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
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 @@ public class ScriptFunctionImpl extends ScriptFunction {
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
@ -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.ElementType;
|
||||
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;
|
||||
}
|
||||
|
50
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java
50
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AccessorProperty.java
@ -36,7 +36,6 @@ import static jdk.nashorn.internal.lookup.MethodHandleFactory.stripName;
|
||||
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
|
||||
import static jdk.nashorn.internal.runtime.JSType.getNumberOfAccessorTypes;
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
@ -57,9 +56,7 @@ public class AccessorProperty extends Property {
|
||||
private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
||||
|
||||
private static final MethodHandle REPLACE_MAP = findOwnMH_S("replaceMap", Object.class, Object.class, PropertyMap.class);
|
||||
private static final MethodHandle INVALIDATE_SP = findOwnMH_S("invalidateSwitchPoint", Object.class, Object.class, SwitchPoint.class);
|
||||
|
||||
private static final SwitchPoint NO_CHANGE_CALLBACK = new SwitchPoint();
|
||||
private static final MethodHandle INVALIDATE_SP = findOwnMH_S("invalidateSwitchPoint", Object.class, AccessorProperty.class, Object.class);
|
||||
|
||||
private static final int NOOF_TYPES = getNumberOfAccessorTypes();
|
||||
private static final long serialVersionUID = 3371720170182154920L;
|
||||
@ -221,7 +218,7 @@ public class AccessorProperty extends Property {
|
||||
* @param setter the property setter or null if non writable, non configurable
|
||||
*/
|
||||
private AccessorProperty(final String key, final int flags, final int slot, final MethodHandle getter, final MethodHandle setter) {
|
||||
super(key, flags | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
|
||||
super(key, flags | IS_BUILTIN | (getter.type().returnType().isPrimitive() ? IS_NASGEN_PRIMITIVE : 0), slot);
|
||||
assert !isSpill();
|
||||
|
||||
// we don't need to prep the setters these will never be invalidated as this is a nasgen
|
||||
@ -602,7 +599,6 @@ public class AccessorProperty extends Property {
|
||||
|
||||
private Property getWiderProperty(final Class<?> type) {
|
||||
return copy(type); //invalidate cache of new property
|
||||
|
||||
}
|
||||
|
||||
private PropertyMap getWiderMap(final PropertyMap oldMap, final Property newProperty) {
|
||||
@ -627,8 +623,10 @@ public class AccessorProperty extends Property {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object invalidateSwitchPoint(final Object obj, final SwitchPoint sp) {
|
||||
SwitchPoint.invalidateAll(new SwitchPoint[] { sp });
|
||||
private static Object invalidateSwitchPoint(final AccessorProperty property, final Object obj) {
|
||||
if (!property.builtinSwitchPoint.hasBeenInvalidated()) {
|
||||
SwitchPoint.invalidateAll(new SwitchPoint[] { property.builtinSwitchPoint });
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@ -668,12 +666,8 @@ public class AccessorProperty extends Property {
|
||||
mh = generateSetter(!forType.isPrimitive() ? Object.class : forType, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a special global name that requires switchpoint invalidation
|
||||
*/
|
||||
final SwitchPoint ccb = getChangeCallback();
|
||||
if (ccb != null && ccb != NO_CHANGE_CALLBACK) {
|
||||
mh = MH.filterArguments(mh, 0, MH.insertArguments(debugInvalidate(getKey(), ccb), 1, changeCallback));
|
||||
if (isBuiltin()) {
|
||||
mh = MH.filterArguments(mh, 0, debugInvalidate(MH.insertArguments(INVALIDATE_SP, 0, this), getKey()));
|
||||
}
|
||||
|
||||
assert mh.type().returnType() == void.class : mh.type();
|
||||
@ -681,25 +675,6 @@ public class AccessorProperty extends Property {
|
||||
return mh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the change callback for this property
|
||||
* @return switchpoint that is invalidated when property changes
|
||||
*/
|
||||
protected SwitchPoint getChangeCallback() {
|
||||
if (changeCallback == null) {
|
||||
try {
|
||||
changeCallback = Global.instance().getChangeCallback(getKey());
|
||||
} catch (final NullPointerException e) {
|
||||
assert !"apply".equals(getKey()) && !"call".equals(getKey());
|
||||
//empty
|
||||
}
|
||||
if (changeCallback == null) {
|
||||
changeCallback = NO_CHANGE_CALLBACK;
|
||||
}
|
||||
}
|
||||
return changeCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean canChangeType() {
|
||||
if (OBJECT_FIELDS_ONLY) {
|
||||
@ -724,7 +699,6 @@ public class AccessorProperty extends Property {
|
||||
return currentType;
|
||||
}
|
||||
|
||||
|
||||
private MethodHandle debug(final MethodHandle mh, final Class<?> forType, final Class<?> type, final String tag) {
|
||||
if (!Context.DEBUG || !Global.hasInstance()) {
|
||||
return mh;
|
||||
@ -780,9 +754,9 @@ public class AccessorProperty extends Property {
|
||||
return mh;
|
||||
}
|
||||
|
||||
private static MethodHandle debugInvalidate(final String key, final SwitchPoint sp) {
|
||||
private static MethodHandle debugInvalidate(final MethodHandle invalidator, final String key) {
|
||||
if (!Context.DEBUG || !Global.hasInstance()) {
|
||||
return INVALIDATE_SP;
|
||||
return invalidator;
|
||||
}
|
||||
|
||||
final Context context = Context.getContextTrusted();
|
||||
@ -790,11 +764,11 @@ public class AccessorProperty extends Property {
|
||||
|
||||
return context.addLoggingToHandle(
|
||||
ObjectClassGenerator.class,
|
||||
INVALIDATE_SP,
|
||||
invalidator,
|
||||
new Supplier<String>() {
|
||||
@Override
|
||||
public String get() {
|
||||
return "Field change callback for " + key + " triggered: " + sp;
|
||||
return "Field change callback for " + key + " triggered ";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -81,13 +81,17 @@ public interface CodeInstaller<T> {
|
||||
|
||||
/**
|
||||
* Store a compiled script for later reuse
|
||||
*
|
||||
* @param cacheKey key to use in cache
|
||||
* @param source the script source
|
||||
* @param mainClassName the main class name
|
||||
* @param classBytes map of class names to class bytes
|
||||
* @param initializers compilation id -> FunctionInitializer map
|
||||
* @param constants constants array
|
||||
* @param compilationId compilation id
|
||||
*/
|
||||
public void storeScript(String cacheKey, Source source, String mainClassName, Map<String, byte[]> classBytes,
|
||||
Map<Integer, FunctionInitializer> initializers, Object[] constants, int compilationId);
|
||||
public void storeScript(final String cacheKey, final Source source, final String mainClassName, final Map<String, byte[]> classBytes,
|
||||
final Map<Integer, FunctionInitializer> initializers, final Object[] constants, final int compilationId);
|
||||
|
||||
/**
|
||||
* Load a previously compiled script
|
||||
|
@ -118,6 +118,8 @@ public abstract class CodeStore implements Loggable {
|
||||
* @param initializers the function initializers
|
||||
* @param constants the constants array
|
||||
* @param compilationId the compilation id
|
||||
*
|
||||
* @return stored script
|
||||
*/
|
||||
public StoredScript store(final String functionKey,
|
||||
final Source source,
|
||||
@ -153,11 +155,13 @@ public abstract class CodeStore implements Loggable {
|
||||
/**
|
||||
* Returns a new StoredScript instance.
|
||||
*
|
||||
* @param source the source
|
||||
* @param mainClassName the main class name
|
||||
* @param classBytes a map of class bytes
|
||||
* @param initializers function initializers
|
||||
* @param constants the constants array
|
||||
* @param compilationId the compilation id
|
||||
*
|
||||
* @return The compiled script
|
||||
*/
|
||||
public StoredScript storedScriptFor(final Source source, final String mainClassName,
|
||||
@ -216,6 +220,7 @@ public abstract class CodeStore implements Loggable {
|
||||
* Constructor
|
||||
*
|
||||
* @param path directory to store code in
|
||||
* @param readOnly is this a read only code store
|
||||
* @param minSize minimum file size for caching scripts
|
||||
* @throws IOException
|
||||
*/
|
||||
|
109
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java
109
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java
@ -33,12 +33,13 @@ import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.MutableCallSite;
|
||||
import java.lang.invoke.SwitchPoint;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.nashorn.internal.codegen.Compiler;
|
||||
import jdk.nashorn.internal.codegen.Compiler.CompilationPhases;
|
||||
@ -46,6 +47,7 @@ import jdk.nashorn.internal.codegen.TypeMap;
|
||||
import jdk.nashorn.internal.codegen.types.ArrayType;
|
||||
import jdk.nashorn.internal.codegen.types.Type;
|
||||
import jdk.nashorn.internal.ir.FunctionNode;
|
||||
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
|
||||
import jdk.nashorn.internal.runtime.events.RecompilationEvent;
|
||||
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||
import jdk.nashorn.internal.runtime.logging.DebugLogger;
|
||||
@ -63,6 +65,8 @@ final class CompiledFunction {
|
||||
|
||||
private final DebugLogger log;
|
||||
|
||||
static final Collection<CompiledFunction> NO_FUNCTIONS = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* The method type may be more specific than the invoker, if. e.g.
|
||||
* the invoker is guarded, and a guard with a generic object only
|
||||
@ -75,20 +79,40 @@ final class CompiledFunction {
|
||||
private final int flags; // from FunctionNode
|
||||
private final MethodType callSiteType;
|
||||
|
||||
private final Specialization specialization;
|
||||
|
||||
CompiledFunction(final MethodHandle invoker) {
|
||||
this(invoker, null);
|
||||
this(invoker, null, null);
|
||||
}
|
||||
|
||||
static CompiledFunction createBuiltInConstructor(final MethodHandle invoker) {
|
||||
return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)));
|
||||
static CompiledFunction createBuiltInConstructor(final MethodHandle invoker, final Specialization specialization) {
|
||||
return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)), specialization);
|
||||
}
|
||||
|
||||
CompiledFunction(final MethodHandle invoker, final MethodHandle constructor) {
|
||||
this(invoker, constructor, 0, null, DebugLogger.DISABLED_LOGGER);
|
||||
CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final Specialization specialization) {
|
||||
this(invoker, constructor, 0, null, specialization, DebugLogger.DISABLED_LOGGER);
|
||||
}
|
||||
|
||||
CompiledFunction(final MethodHandle invoker, final MethodHandle constructor, final int flags, final MethodType callSiteType, final DebugLogger log) {
|
||||
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 @@ final class CompiledFunction {
|
||||
|
||||
CompiledFunction(final MethodHandle invoker, final RecompilableScriptFunctionData functionData,
|
||||
final Map<Integer, Type> invalidatedProgramPoints, final MethodType callSiteType, final int flags) {
|
||||
this(invoker, null, flags, callSiteType, functionData.getLogger());
|
||||
this(invoker, null, flags, callSiteType, null, functionData.getLogger());
|
||||
if ((flags & FunctionNode.IS_DEOPTIMIZABLE) != 0) {
|
||||
optimismInfo = new OptimismInfo(functionData, invalidatedProgramPoints);
|
||||
} else {
|
||||
@ -105,10 +129,45 @@ final class CompiledFunction {
|
||||
}
|
||||
}
|
||||
|
||||
static CompiledFunction createBuiltInConstructor(final MethodHandle invoker) {
|
||||
return new CompiledFunction(MH.insertArguments(invoker, 0, false), createConstructorFromInvoker(MH.insertArguments(invoker, 0, true)), null);
|
||||
}
|
||||
|
||||
boolean isSpecialization() {
|
||||
return specialization != null;
|
||||
}
|
||||
|
||||
boolean hasLinkLogic() {
|
||||
return getLinkLogicClass() != null;
|
||||
}
|
||||
|
||||
Class<? extends LinkLogic> getLinkLogicClass() {
|
||||
if (isSpecialization()) {
|
||||
final Class<? extends LinkLogic> linkLogicClass = specialization.getLinkLogicClass();
|
||||
assert !LinkLogic.isEmpty(linkLogicClass) : "empty link logic classes should have been removed by nasgen";
|
||||
return linkLogicClass;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optimistic specialization is one that can throw UnwarrantedOptimismException.
|
||||
* This is allowed for native methods, as long as they are functional, i.e. don't change
|
||||
* any state between entering and throwing the UOE. Then we can re-execute a wider version
|
||||
* of the method in the continuation. Rest-of method generation for optimistic builtins is
|
||||
* of course not possible, but this approach works and fits into the same relinking
|
||||
* framework
|
||||
*
|
||||
* @return true if optimistic builtin
|
||||
*/
|
||||
boolean isOptimistic() {
|
||||
return isSpecialization() ? specialization.isOptimistic() : false;
|
||||
}
|
||||
|
||||
boolean isApplyToCall() {
|
||||
return (flags & FunctionNode.HAS_APPLY_TO_CALL_SPECIALIZATION) != 0;
|
||||
}
|
||||
@ -119,7 +178,19 @@ final class CompiledFunction {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[invokerType=" + invoker.type() + " ctor=" + constructor + " weight=" + weight() + " isApplyToCall=" + isApplyToCall() + "]";
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
final Class<? extends LinkLogic> linkLogicClass = getLinkLogicClass();
|
||||
|
||||
sb.append("[invokerType=").
|
||||
append(invoker.type()).
|
||||
append(" ctor=").
|
||||
append(constructor).
|
||||
append(" weight=").
|
||||
append(weight()).
|
||||
append(" linkLogic=").
|
||||
append(linkLogicClass != null ? linkLogicClass.getSimpleName() : "none");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
boolean needsCallee() {
|
||||
@ -281,10 +352,12 @@ final class CompiledFunction {
|
||||
if (other == null) {
|
||||
return true;
|
||||
}
|
||||
return betterThanFinal(type(), other.type(), callSiteMethodType);
|
||||
return betterThanFinal(this, other, callSiteMethodType);
|
||||
}
|
||||
|
||||
static boolean betterThanFinal(final MethodType thisMethodType, final MethodType otherMethodType, final MethodType callSiteMethodType) {
|
||||
private static boolean betterThanFinal(final CompiledFunction cf, final CompiledFunction other, final MethodType callSiteMethodType) {
|
||||
final MethodType thisMethodType = cf.type();
|
||||
final MethodType otherMethodType = other.type();
|
||||
final int thisParamCount = getParamCount(thisMethodType);
|
||||
final int otherParamCount = getParamCount(otherMethodType);
|
||||
final int callSiteRawParamCount = getParamCount(callSiteMethodType);
|
||||
@ -406,7 +479,17 @@ final class CompiledFunction {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new AssertionError(thisMethodType + " identically applicable to " + otherMethodType + " for " + callSiteMethodType); // Signatures are identical
|
||||
//if they are equal, pick the specialized one first
|
||||
if (cf.isSpecialization() != other.isSpecialization()) {
|
||||
return cf.isSpecialization(); //always pick the specialized version if we can
|
||||
}
|
||||
|
||||
if (cf.isSpecialization() && other.isSpecialization()) {
|
||||
return cf.getLinkLogicClass() != null; //pick link logic specialization above generic specializations
|
||||
}
|
||||
|
||||
// Signatures are identical
|
||||
throw new AssertionError(thisMethodType + " identically applicable to " + otherMethodType + " for " + callSiteMethodType);
|
||||
}
|
||||
|
||||
private static Type[] toTypeWithoutCallee(final MethodType type, final int thisIndex) {
|
||||
|
@ -40,6 +40,7 @@ import java.io.PrintWriter;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.SwitchPoint;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.reflect.Field;
|
||||
@ -63,7 +64,9 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
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 @@ public final class Context {
|
||||
private static MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
|
||||
private static MethodType CREATE_PROGRAM_FUNCTION_TYPE = MethodType.methodType(ScriptFunction.class, ScriptObject.class);
|
||||
|
||||
/**
|
||||
* Keeps track of which builtin prototypes and properties have been relinked
|
||||
* Currently we are conservative and associate the name of a builtin class with all
|
||||
* its properties, so it's enough to invalidate a property to break all assumptions
|
||||
* about a prototype. This can be changed to a more fine grained approach, but no one
|
||||
* ever needs this, given the very rare occurance of swapping out only parts of
|
||||
* a builtin v.s. the entire builtin object
|
||||
*/
|
||||
private final Map<String, SwitchPoint> builtinSwitchPoints = new HashMap<>();
|
||||
|
||||
/* Force DebuggerSupport to be loaded. */
|
||||
static {
|
||||
DebuggerSupport.FORCELOAD = true;
|
||||
@ -1371,4 +1384,34 @@ public final class Context {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a special kind of switchpoint used to guard builtin
|
||||
* properties and prototypes. In the future it might contain
|
||||
* logic to e.g. multiple switchpoint classes.
|
||||
*/
|
||||
public static final class BuiltinSwitchPoint extends SwitchPoint {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -60,13 +60,13 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
|
||||
* @param specs specializations
|
||||
* @param flags {@link ScriptFunctionData} flags
|
||||
*/
|
||||
FinalScriptFunctionData(final String name, final MethodHandle mh, final MethodHandle[] specs, final int flags) {
|
||||
FinalScriptFunctionData(final String name, final MethodHandle mh, final Specialization[] specs, final int flags) {
|
||||
super(name, methodHandleArity(mh), flags);
|
||||
|
||||
addInvoker(mh);
|
||||
if (specs != null) {
|
||||
for (final MethodHandle spec : specs) {
|
||||
addInvoker(spec);
|
||||
for (final Specialization spec : specs) {
|
||||
addInvoker(spec.getMethodHandle(), spec);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -114,16 +114,25 @@ final class FinalScriptFunctionData extends ScriptFunctionData {
|
||||
return MethodType.genericMethodType(max + 1);
|
||||
}
|
||||
|
||||
private void addInvoker(final MethodHandle mh) {
|
||||
private CompiledFunction addInvoker(final MethodHandle mh, final Specialization specialization) {
|
||||
assert !needsCallee(mh);
|
||||
|
||||
final CompiledFunction invoker;
|
||||
if (isConstructor(mh)) {
|
||||
// only nasgen constructors: (boolean, self, args) are subject to binding a boolean newObj. isConstructor
|
||||
// is too conservative a check. However, isConstructor(mh) always implies isConstructor param
|
||||
assert isConstructor();
|
||||
code.add(CompiledFunction.createBuiltInConstructor(mh));
|
||||
invoker = CompiledFunction.createBuiltInConstructor(mh);
|
||||
} else {
|
||||
code.add(new CompiledFunction(mh));
|
||||
invoker = new CompiledFunction(mh, null, specialization);
|
||||
}
|
||||
code.add(invoker);
|
||||
|
||||
return invoker;
|
||||
}
|
||||
|
||||
private CompiledFunction addInvoker(final MethodHandle mh) {
|
||||
return addInvoker(mh, null);
|
||||
}
|
||||
|
||||
private static int methodHandleArity(final MethodHandle mh) {
|
||||
|
@ -79,6 +79,8 @@ public final class FindProperty {
|
||||
*
|
||||
* @param type type of getter, e.g. int.class if we want a function with {@code get()I} signature
|
||||
* @param programPoint program point, or INVALID_PROGRAM_POINT if pessimistic
|
||||
* @param request link request
|
||||
*
|
||||
* @return method handle for the getter
|
||||
*/
|
||||
public MethodHandle getGetter(final Class<?> type, final int programPoint, final LinkRequest request) {
|
||||
@ -102,6 +104,7 @@ public final class FindProperty {
|
||||
*
|
||||
* @param type type of setter, e.g. int.class if we want a function with {@code set(I)V} signature
|
||||
* @param strict are we in strict mode
|
||||
* @param request link request
|
||||
*
|
||||
* @return method handle for the getter
|
||||
*/
|
||||
|
@ -358,8 +358,12 @@ public final class GlobalConstants implements Loggable {
|
||||
* @param c constant value
|
||||
* @return method handle (with dummy receiver) that returns this constant
|
||||
*/
|
||||
public static MethodHandle staticConstantGetter(final Object c) {
|
||||
return MH.dropArguments(JSType.unboxConstant(c), 0, Object.class);
|
||||
}
|
||||
|
||||
private MethodHandle constantGetter(final Object c) {
|
||||
final MethodHandle mh = MH.dropArguments(JSType.unboxConstant(c), 0, Object.class);
|
||||
final MethodHandle mh = staticConstantGetter(c);
|
||||
if (log.isEnabled()) {
|
||||
return MethodHandleFactory.addDebugPrintout(log, Level.FINEST, mh, "getting as constant");
|
||||
}
|
||||
|
18
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalFunctions.java
18
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/GlobalFunctions.java
@ -42,12 +42,30 @@ public final class GlobalFunctions {
|
||||
/** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
|
||||
public static final MethodHandle PARSEINT_OI = findOwnMH("parseInt", double.class, Object.class, Object.class, int.class);
|
||||
|
||||
/** ParseInt - NaN for booleans (thru string conversion to number conversion) */
|
||||
public static final MethodHandle PARSEINT_Z = MH.dropArguments(MH.dropArguments(MH.constant(double.class, Double.NaN), 0, boolean.class), 0, Object.class);
|
||||
|
||||
/** ParseInt - identity for ints */
|
||||
public static final MethodHandle PARSEINT_I = MH.dropArguments(MH.identity(int.class), 0, Object.class);
|
||||
|
||||
/** ParseInt - identity for longs */
|
||||
public static final MethodHandle PARSEINT_J = MH.dropArguments(MH.identity(long.class), 0, Object.class);
|
||||
|
||||
/** Methodhandle (specialized) to implementation of ECMA 15.1.2.2, parseInt */
|
||||
public static final MethodHandle PARSEINT_O = findOwnMH("parseInt", double.class, Object.class, Object.class);
|
||||
|
||||
/** Methodhandle to implementation of ECMA 15.1.2.3, parseFloat */
|
||||
public static final MethodHandle PARSEFLOAT = findOwnMH("parseFloat", double.class, Object.class, Object.class);
|
||||
|
||||
/** isNan for integers - always false */
|
||||
public static final MethodHandle IS_NAN_I = MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class);
|
||||
|
||||
/** isNan for longs - always false */
|
||||
public static final MethodHandle IS_NAN_J = MH.dropArguments(MH.constant(boolean.class, false), 0, Object.class);
|
||||
|
||||
/** IsNan for doubles - use Double.isNaN */
|
||||
public static final MethodHandle IS_NAN_D = MH.dropArguments(MH.findStatic(MethodHandles.lookup(), Double.class, "isNaN", MH.type(boolean.class, double.class)), 0, Object.class);
|
||||
|
||||
/** Methodhandle to implementation of ECMA 15.1.2.4, isNaN */
|
||||
public static final MethodHandle IS_NAN = findOwnMH("isNaN", boolean.class, Object.class, Object.class);
|
||||
|
||||
|
65
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/OptimisticBuiltins.java
Normal file
65
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/OptimisticBuiltins.java
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. 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();
|
||||
|
||||
}
|
@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime;
|
||||
import static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE;
|
||||
import static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE;
|
||||
import static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.SwitchPoint;
|
||||
@ -84,6 +83,9 @@ public abstract class Property implements Serializable {
|
||||
*/
|
||||
public static final int IS_NASGEN_PRIMITIVE = 1 << 6;
|
||||
|
||||
/** Is this a builtin property, e.g. Function.prototype.apply */
|
||||
public static final int IS_BUILTIN = 1 << 7;
|
||||
|
||||
/** Is this property bound to a receiver? This means get/set operations will be delegated to
|
||||
* a statically defined object instead of the object passed as callsite parameter. */
|
||||
public static final int IS_BOUND = 1 << 7;
|
||||
@ -101,7 +103,7 @@ public abstract class Property implements Serializable {
|
||||
private final int slot;
|
||||
|
||||
/** SwitchPoint that is invalidated when property is changed, optional */
|
||||
protected transient SwitchPoint changeCallback;
|
||||
protected transient SwitchPoint builtinSwitchPoint;
|
||||
|
||||
private static final long serialVersionUID = 2099814273074501176L;
|
||||
|
||||
@ -125,10 +127,10 @@ public abstract class Property implements Serializable {
|
||||
* @param property source property
|
||||
*/
|
||||
Property(final Property property, final int flags) {
|
||||
this.key = property.key;
|
||||
this.slot = property.slot;
|
||||
this.changeCallback = property.changeCallback;
|
||||
this.flags = flags;
|
||||
this.key = property.key;
|
||||
this.slot = property.slot;
|
||||
this.builtinSwitchPoint = property.builtinSwitchPoint;
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,8 +184,26 @@ public abstract class Property implements Serializable {
|
||||
* changed
|
||||
* @param sp SwitchPoint to use for change callback
|
||||
*/
|
||||
public final void setChangeCallback(final SwitchPoint sp) {
|
||||
this.changeCallback = sp;
|
||||
public final void setBuiltinSwitchPoint(final SwitchPoint sp) {
|
||||
this.builtinSwitchPoint = sp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builtin properties have an invalidation switchpoint that is
|
||||
* invalidated when they are set, this is a getter for it
|
||||
* @return builtin switchpoint, or null if none
|
||||
*/
|
||||
public final SwitchPoint getBuiltinSwitchPoint() {
|
||||
return builtinSwitchPoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this is a builtin property, this means that it has
|
||||
* a builtin switchpoint that hasn't been invalidated by a setter
|
||||
* @return true if builtin, untouched (unset) property
|
||||
*/
|
||||
public boolean isBuiltin() {
|
||||
return builtinSwitchPoint != null && !builtinSwitchPoint.hasBeenInvalidated();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -950,7 +950,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException("remove");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
|
||||
// CompilationEnvironment#declareLocalSymbol()).
|
||||
|
||||
if (log.isEnabled()) {
|
||||
log.info("Type specialization of '", functionName, "' signature: ", actualCallSiteType);
|
||||
log.info("Parameter type specialization of '", functionName, "' signature: ", actualCallSiteType);
|
||||
}
|
||||
|
||||
final boolean persistentCache = usePersistentCodeCache() && persist;
|
||||
@ -597,6 +597,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
|
||||
* 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 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
|
||||
|
||||
|
||||
@Override
|
||||
synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) {
|
||||
CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope);
|
||||
synchronized CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
|
||||
CompiledFunction existingBest = super.getBest(callSiteType, runtimeScope, forbidden);
|
||||
if (existingBest == null) {
|
||||
existingBest = addCode(compileTypeSpecialization(callSiteType, runtimeScope, true), callSiteType);
|
||||
}
|
||||
@ -723,6 +725,10 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
|
||||
return functionNodeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source for the script
|
||||
* @return source
|
||||
*/
|
||||
public Source getSource() {
|
||||
return source;
|
||||
}
|
||||
|
4
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java
4
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptEnvironment.java
@ -181,9 +181,6 @@ public final class ScriptEnvironment {
|
||||
/** print symbols and their contents for the script */
|
||||
public final boolean _print_symbols;
|
||||
|
||||
/** range analysis for known types */
|
||||
public final boolean _range_analysis;
|
||||
|
||||
/** is this environment in scripting mode? */
|
||||
public final boolean _scripting;
|
||||
|
||||
@ -255,7 +252,6 @@ public final class ScriptEnvironment {
|
||||
_print_parse = options.getBoolean("print.parse");
|
||||
_print_lower_parse = options.getBoolean("print.lower.parse");
|
||||
_print_symbols = options.getBoolean("print.symbols");
|
||||
_range_analysis = options.getBoolean("range.analysis");
|
||||
_scripting = options.getBoolean("scripting");
|
||||
_strict = options.getBoolean("strict");
|
||||
_version = options.getBoolean("version");
|
||||
|
119
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java
119
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java
@ -30,26 +30,29 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.SwitchPoint;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
import jdk.internal.dynalink.support.Guards;
|
||||
import jdk.nashorn.internal.codegen.ApplySpecialization;
|
||||
import jdk.nashorn.internal.codegen.Compiler;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
import jdk.nashorn.internal.objects.Global;
|
||||
import jdk.nashorn.internal.objects.NativeFunction;
|
||||
import jdk.nashorn.internal.runtime.ScriptFunctionData;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic;
|
||||
import jdk.nashorn.internal.runtime.linker.Bootstrap;
|
||||
import jdk.nashorn.internal.runtime.linker.NashornCallSiteDescriptor;
|
||||
import jdk.nashorn.internal.runtime.logging.DebugLogger;
|
||||
|
||||
/**
|
||||
* Runtime representation of a JavaScript function.
|
||||
@ -114,7 +117,7 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
final MethodHandle methodHandle,
|
||||
final PropertyMap map,
|
||||
final ScriptObject scope,
|
||||
final MethodHandle[] specs,
|
||||
final Specialization[] specs,
|
||||
final int flags) {
|
||||
|
||||
this(new FinalScriptFunctionData(name, methodHandle, specs, flags), map, scope);
|
||||
@ -468,13 +471,12 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
protected GuardedInvocation findNewMethod(final CallSiteDescriptor desc, final LinkRequest request) {
|
||||
final MethodType type = desc.getMethodType();
|
||||
assert desc.getMethodType().returnType() == Object.class && !NashornCallSiteDescriptor.isOptimistic(desc);
|
||||
final CompiledFunction cf = data.getBestConstructor(type, scope);
|
||||
final CompiledFunction cf = data.getBestConstructor(type, scope, CompiledFunction.NO_FUNCTIONS);
|
||||
final GuardedInvocation bestCtorInv = cf.createConstructorInvocation();
|
||||
//TODO - ClassCastException
|
||||
return new GuardedInvocation(pairArguments(bestCtorInv.getInvocation(), type), getFunctionGuard(this, cf.getFlags()), bestCtorInv.getSwitchPoints(), null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Object wrapFilter(final Object obj) {
|
||||
if (obj instanceof ScriptObject || !ScriptFunctionData.isPrimitiveThis(obj)) {
|
||||
return obj;
|
||||
@ -489,6 +491,35 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
return Context.getGlobal();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
}
|
||||
} //else just fall through and link as ordinary function or unstable apply
|
||||
|
||||
final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT;
|
||||
final CompiledFunction cf = data.getBestInvoker(type, scope);
|
||||
int programPoint = INVALID_PROGRAM_POINT;
|
||||
if (NashornCallSiteDescriptor.isOptimistic(desc)) {
|
||||
programPoint = NashornCallSiteDescriptor.getProgramPoint(desc);
|
||||
}
|
||||
|
||||
CompiledFunction cf = data.getBestInvoker(type, scope, CompiledFunction.NO_FUNCTIONS);
|
||||
final Object self = request.getArguments()[1];
|
||||
final Collection<CompiledFunction> forbidden = new HashSet<>();
|
||||
|
||||
//check for special fast versions of the compiled function
|
||||
final List<SwitchPoint> sps = new ArrayList<>();
|
||||
Class<? extends Throwable> exceptionGuard = null;
|
||||
|
||||
while (cf.isSpecialization()) {
|
||||
final Class<? extends LinkLogic> linkLogicClass = cf.getLinkLogicClass();
|
||||
//if linklogic is null, we can always link with the standard mechanism, it's still a specialization
|
||||
final LinkLogic linkLogic = getLinkLogic(self, linkLogicClass);
|
||||
|
||||
if (linkLogic != null && linkLogic.checkLinkable(self, desc, request)) {
|
||||
final DebugLogger log = Context.getContextTrusted().getLogger(Compiler.class);
|
||||
|
||||
if (log.isEnabled()) {
|
||||
log.info("Linking optimistic builtin function: '", name, "' args=", Arrays.toString(request.getArguments()), " desc=", desc);
|
||||
}
|
||||
|
||||
final SwitchPoint[] msps = linkLogic.getModificationSwitchPoints();
|
||||
if (msps != null) {
|
||||
for (final SwitchPoint sp : msps) {
|
||||
if (sp != null) {
|
||||
assert !sp.hasBeenInvalidated();
|
||||
sps.add(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exceptionGuard = linkLogic.getRelinkException();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//could not link this specialization because link check failed
|
||||
forbidden.add(cf);
|
||||
final CompiledFunction oldCf = cf;
|
||||
cf = data.getBestInvoker(type, scope, forbidden);
|
||||
assert oldCf != cf;
|
||||
}
|
||||
|
||||
final GuardedInvocation bestInvoker = cf.createFunctionInvocation(type.returnType(), programPoint);
|
||||
final MethodHandle callHandle = bestInvoker.getInvocation();
|
||||
|
||||
@ -588,7 +664,20 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
|
||||
boundHandle = pairArguments(boundHandle, type);
|
||||
|
||||
return new GuardedInvocation(boundHandle, guard == null ? getFunctionGuard(this, cf.getFlags()) : guard, bestInvoker.getSwitchPoints(), null);
|
||||
if (bestInvoker.getSwitchPoints() != null) {
|
||||
sps.addAll(Arrays.asList(bestInvoker.getSwitchPoints()));
|
||||
}
|
||||
final SwitchPoint[] spsArray = sps.isEmpty() ? null : sps.toArray(new SwitchPoint[sps.size()]);
|
||||
|
||||
return new GuardedInvocation(
|
||||
boundHandle,
|
||||
guard == null ?
|
||||
getFunctionGuard(
|
||||
this,
|
||||
cf.getFlags()) :
|
||||
guard,
|
||||
spsArray,
|
||||
exceptionGuard);
|
||||
}
|
||||
|
||||
private GuardedInvocation createApplyOrCallCall(final boolean isApply, final CallSiteDescriptor desc, final LinkRequest request, final Object[] args) {
|
||||
@ -610,7 +699,7 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
|
||||
//box call back to apply
|
||||
CallSiteDescriptor appliedDesc = desc;
|
||||
final SwitchPoint applyToCallSwitchPoint = Global.instance().getChangeCallback("apply");
|
||||
final SwitchPoint applyToCallSwitchPoint = Global.getBuiltinFunctionApplySwitchPoint();
|
||||
//enough to change the proto switchPoint here
|
||||
|
||||
final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
|
||||
@ -656,7 +745,7 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
}
|
||||
}
|
||||
|
||||
appliedDesc = appliedDesc.changeMethodType(appliedType);
|
||||
appliedDesc = appliedDesc.changeMethodType(appliedType); //no extra args
|
||||
|
||||
// Create the same arguments for the delegate linking request that would be passed in an actual apply'd invocation
|
||||
final Object[] appliedArgs = new Object[isApply ? 3 : appliedType.parameterCount()];
|
||||
@ -681,6 +770,7 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
|
||||
// Ask the linker machinery for an invocation of the target function
|
||||
final LinkRequest appliedRequest = request.replaceArguments(appliedDesc, appliedArgs);
|
||||
|
||||
GuardedInvocation appliedInvocation;
|
||||
try {
|
||||
appliedInvocation = Bootstrap.getLinkerServices().getGuardedInvocation(appliedRequest);
|
||||
@ -742,7 +832,7 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
// We need to account for the dropped (apply|call) function argument.
|
||||
guard = MH.dropArguments(guard, 0, descType.parameterType(0));
|
||||
// Take the "isApplyFunction" guard, and bind it to this function.
|
||||
MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this);
|
||||
MethodHandle applyFnGuard = MH.insertArguments(IS_APPLY_FUNCTION, 2, this); //TODO replace this with switchpoint
|
||||
// Adapt the guard to receive all the arguments that the original guard does.
|
||||
applyFnGuard = MH.dropArguments(applyFnGuard, 2, guardType.parameterArray());
|
||||
// Fold the original function guard into our apply guard.
|
||||
@ -894,6 +984,7 @@ public abstract class ScriptFunction extends ScriptObject {
|
||||
return self instanceof ScriptFunction && ((ScriptFunction)self).data == data && arg instanceof ScriptObject;
|
||||
}
|
||||
|
||||
//TODO this can probably be removed given that we have builtin switchpoints in the context
|
||||
@SuppressWarnings("unused")
|
||||
private static boolean isApplyFunction(final boolean appliedFnCondition, final Object self, final Object expectedSelf) {
|
||||
// NOTE: we're using self == expectedSelf as we're only using this with built-in functions apply() and call()
|
||||
|
26
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java
26
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java
@ -28,13 +28,13 @@ package jdk.nashorn.internal.runtime;
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import jdk.nashorn.internal.runtime.linker.LinkerCallSite;
|
||||
@ -136,7 +136,7 @@ public abstract class ScriptFunctionData implements Serializable {
|
||||
final MethodHandle boundInvoker = bindInvokeHandle(originalInv.createComposableInvoker(), fn, self, args);
|
||||
|
||||
if (isConstructor()) {
|
||||
return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.createComposableConstructor(), fn, args));
|
||||
return new CompiledFunction(boundInvoker, bindConstructHandle(originalInv.createComposableConstructor(), fn, args), null);
|
||||
}
|
||||
|
||||
return new CompiledFunction(boundInvoker);
|
||||
@ -224,18 +224,22 @@ public abstract class ScriptFunctionData implements Serializable {
|
||||
* @param callSiteType callsite type
|
||||
* @return compiled function object representing the best invoker.
|
||||
*/
|
||||
final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope) {
|
||||
final CompiledFunction cf = getBest(callSiteType, runtimeScope);
|
||||
final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope) {
|
||||
return getBestInvoker(callSiteType, runtimeScope, CompiledFunction.NO_FUNCTIONS);
|
||||
}
|
||||
|
||||
final CompiledFunction getBestInvoker(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
|
||||
final CompiledFunction cf = getBest(callSiteType, runtimeScope, forbidden);
|
||||
assert cf != null;
|
||||
return cf;
|
||||
}
|
||||
|
||||
final CompiledFunction getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope) {
|
||||
final CompiledFunction getBestConstructor(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
|
||||
if (!isConstructor()) {
|
||||
throw typeError("not.a.constructor", toSource());
|
||||
}
|
||||
// Constructor call sites don't have a "this", but getBest is meant to operate on "callee, this, ..." style
|
||||
final CompiledFunction cf = getBest(callSiteType.insertParameterTypes(1, Object.class), runtimeScope);
|
||||
final CompiledFunction cf = getBest(callSiteType.insertParameterTypes(1, Object.class), runtimeScope, forbidden);
|
||||
return cf;
|
||||
}
|
||||
|
||||
@ -350,7 +354,7 @@ public abstract class ScriptFunctionData implements Serializable {
|
||||
* scope is not known, but that might cause compilation of code that will need more deoptimization passes.
|
||||
* @return the best function for the specified call site type.
|
||||
*/
|
||||
CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope) {
|
||||
CompiledFunction getBest(final MethodType callSiteType, final ScriptObject runtimeScope, final Collection<CompiledFunction> forbidden) {
|
||||
assert callSiteType.parameterCount() >= 2 : callSiteType; // Must have at least (callee, this)
|
||||
assert callSiteType.parameterType(0).isAssignableFrom(ScriptFunction.class) : callSiteType; // Callee must be assignable from script function
|
||||
|
||||
@ -363,8 +367,8 @@ public abstract class ScriptFunctionData implements Serializable {
|
||||
}
|
||||
|
||||
CompiledFunction best = null;
|
||||
for(final CompiledFunction candidate: code) {
|
||||
if(candidate.betterThanFinal(best, callSiteType)) {
|
||||
for (final CompiledFunction candidate: code) {
|
||||
if (!forbidden.contains(candidate) && candidate.betterThanFinal(best, callSiteType)) {
|
||||
best = candidate;
|
||||
}
|
||||
}
|
||||
@ -376,7 +380,7 @@ public abstract class ScriptFunctionData implements Serializable {
|
||||
abstract boolean isRecompilable();
|
||||
|
||||
CompiledFunction getGeneric(final ScriptObject runtimeScope) {
|
||||
return getBest(getGenericType(), runtimeScope);
|
||||
return getBest(getGenericType(), runtimeScope, CompiledFunction.NO_FUNCTIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,7 +424,7 @@ public abstract class ScriptFunctionData implements Serializable {
|
||||
|
||||
final List<CompiledFunction> boundList = new LinkedList<>();
|
||||
final ScriptObject runtimeScope = fn.getScope();
|
||||
final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(runtimeScope), getGenericConstructor(runtimeScope));
|
||||
final CompiledFunction bindTarget = new CompiledFunction(getGenericInvoker(runtimeScope), getGenericConstructor(runtimeScope), null);
|
||||
boundList.add(bind(bindTarget, fn, self, allArgs));
|
||||
|
||||
return new FinalScriptFunctionData(name, Math.max(0, getArity() - length), boundList, boundFlags);
|
||||
|
@ -47,7 +47,6 @@ import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
|
||||
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.getArrayIndex;
|
||||
import static jdk.nashorn.internal.runtime.arrays.ArrayIndex.isValidArrayIndex;
|
||||
import static jdk.nashorn.internal.runtime.linker.NashornGuards.explicitInstanceOfCheck;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
@ -820,6 +819,19 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
return false;
|
||||
}
|
||||
|
||||
private SwitchPoint findBuiltinSwitchPoint(final String key) {
|
||||
for (ScriptObject myProto = getProto(); myProto != null; myProto = myProto.getProto()) {
|
||||
final Property prop = myProto.getMap().findProperty(key);
|
||||
if (prop != null) {
|
||||
final SwitchPoint sp = prop.getBuiltinSwitchPoint();
|
||||
if (sp != null && !sp.hasBeenInvalidated()) {
|
||||
return sp;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new property to the object.
|
||||
* <p>
|
||||
@ -1513,6 +1525,23 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
flags |= IS_LENGTH_NOT_WRITABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
return MH.filterArguments(methodHandle, 0, filter.asType(filter.type().changeReturnType(methodHandle.type().parameterType(0))));
|
||||
}
|
||||
|
||||
//this will only return true if apply is still builtin
|
||||
private static SwitchPoint checkReservedName(final CallSiteDescriptor desc, final LinkRequest request) {
|
||||
final boolean isApplyToCall = NashornCallSiteDescriptor.isApplyToCall(desc);
|
||||
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
|
||||
if ("apply".equals(name) && isApplyToCall && Global.instance().isSpecialNameValid(name)) {
|
||||
assert Global.instance().getChangeCallback("apply") == Global.instance().getChangeCallback("call");
|
||||
return Global.instance().getChangeCallback("apply");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the appropriate GET method for an invoke dynamic call.
|
||||
*
|
||||
@ -1938,14 +1956,13 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
*/
|
||||
protected GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
|
||||
final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request);
|
||||
final String name;
|
||||
final SwitchPoint reservedNameSwitchPoint;
|
||||
|
||||
reservedNameSwitchPoint = checkReservedName(desc, request);
|
||||
if (reservedNameSwitchPoint != null) {
|
||||
name = "call"; //turn apply into call, it is the builtin apply and has been modified to explode args
|
||||
} else {
|
||||
name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
|
||||
String name;
|
||||
name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
|
||||
if (NashornCallSiteDescriptor.isApplyToCall(desc)) {
|
||||
if (Global.isBuiltinFunctionPrototypeApply()) {
|
||||
name = "call";
|
||||
}
|
||||
}
|
||||
|
||||
if (request.isCallSiteUnstable() || hasWithScope()) {
|
||||
@ -2006,7 +2023,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
assert OBJECT_FIELDS_ONLY || guard != null : "we always need a map guard here";
|
||||
|
||||
final GuardedInvocation inv = new GuardedInvocation(mh, guard, protoSwitchPoint, exception);
|
||||
return inv.addSwitchPoint(reservedNameSwitchPoint);
|
||||
return inv.addSwitchPoint(findBuiltinSwitchPoint(name));
|
||||
}
|
||||
|
||||
private static GuardedInvocation findMegaMorphicGetMethod(final CallSiteDescriptor desc, final String name, final boolean isMethod) {
|
||||
@ -2166,7 +2183,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
}
|
||||
}
|
||||
|
||||
final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation();
|
||||
final GuardedInvocation inv = new SetMethodCreator(this, find, desc, request).createGuardedInvocation(findBuiltinSwitchPoint(name));
|
||||
|
||||
final GuardedInvocation cinv = Global.getConstants().findSetMethod(find, this, inv, desc, request);
|
||||
if (cinv != null) {
|
||||
@ -2429,7 +2446,7 @@ public abstract class ScriptObject implements PropertyAccess {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException("remove");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,9 @@ import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.syntaxError;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
|
||||
import static jdk.nashorn.internal.runtime.JSType.isRepresentableAsInt;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.SwitchPoint;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
@ -46,6 +46,7 @@ import java.util.Objects;
|
||||
import jdk.internal.dynalink.beans.StaticClass;
|
||||
import jdk.nashorn.api.scripting.JSObject;
|
||||
import jdk.nashorn.api.scripting.ScriptObjectMirror;
|
||||
import jdk.nashorn.internal.codegen.ApplySpecialization;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants;
|
||||
import jdk.nashorn.internal.codegen.CompilerConstants.Call;
|
||||
import jdk.nashorn.internal.ir.debug.JSONWriter;
|
||||
@ -112,6 +113,11 @@ public final class ScriptRuntime {
|
||||
*/
|
||||
public static final Call THROW_REFERENCE_ERROR = staticCall(MethodHandles.lookup(), ScriptRuntime.class, "throwReferenceError", void.class, String.class);
|
||||
|
||||
/**
|
||||
* Used to invalidate builtin names, e.g "Function" mapping to all properties in Function.prototype and Function.prototype itself.
|
||||
*/
|
||||
public static final Call INVALIDATE_RESERVED_BUILTIN_NAME = staticCallNoLookup(ScriptRuntime.class, "invalidateReservedBuiltinName", void.class, String.class);
|
||||
|
||||
/**
|
||||
* Converts a switch tag value to a simple integer. deflt value if it can't.
|
||||
*
|
||||
@ -290,7 +296,7 @@ public final class ScriptRuntime {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException("remove");
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,7 +334,7 @@ public final class ScriptRuntime {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException("remove");
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -998,4 +1004,19 @@ public final class ScriptRuntime {
|
||||
return nx < ny;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag a reserved name as invalidated - used when someone writes
|
||||
* to a property with this name - overly conservative, but link time
|
||||
* is too late to apply e.g. apply->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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
25
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
25
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime;
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.ECMAErrors.referenceError;
|
||||
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.SwitchPoint;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
@ -81,8 +80,8 @@ final class SetMethodCreator {
|
||||
* Creates the actual guarded invocation that represents the dynamic setter method for the property.
|
||||
* @return the actual guarded invocation that represents the dynamic setter method for the property.
|
||||
*/
|
||||
GuardedInvocation createGuardedInvocation() {
|
||||
return createSetMethod().createGuardedInvocation();
|
||||
GuardedInvocation createGuardedInvocation(final SwitchPoint builtinSwitchPoint) {
|
||||
return createSetMethod(builtinSwitchPoint).createGuardedInvocation();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -119,7 +118,7 @@ final class SetMethodCreator {
|
||||
}
|
||||
}
|
||||
|
||||
private SetMethod createSetMethod() {
|
||||
private SetMethod createSetMethod(final SwitchPoint builtinSwitchPoint) {
|
||||
if (find != null) {
|
||||
return createExistingPropertySetter();
|
||||
}
|
||||
@ -130,7 +129,7 @@ final class SetMethodCreator {
|
||||
return createGlobalPropertySetter();
|
||||
}
|
||||
|
||||
return createNewPropertySetter();
|
||||
return createNewPropertySetter(builtinSwitchPoint);
|
||||
}
|
||||
|
||||
private void checkStrictCreateNewVariable() {
|
||||
@ -185,8 +184,8 @@ final class SetMethodCreator {
|
||||
return new SetMethod(MH.filterArguments(global.addSpill(type, getName()), 0, ScriptObject.GLOBALFILTER), null);
|
||||
}
|
||||
|
||||
private SetMethod createNewPropertySetter() {
|
||||
final SetMethod sm = map.getFreeFieldSlot() > -1 ? createNewFieldSetter() : createNewSpillPropertySetter();
|
||||
private SetMethod createNewPropertySetter(final SwitchPoint builtinSwitchPoint) {
|
||||
final SetMethod sm = map.getFreeFieldSlot() > -1 ? createNewFieldSetter(builtinSwitchPoint) : createNewSpillPropertySetter(builtinSwitchPoint);
|
||||
final PropertyListeners listeners = map.getListeners();
|
||||
if (listeners != null) {
|
||||
listeners.propertyAdded(sm.property);
|
||||
@ -194,7 +193,9 @@ final class SetMethodCreator {
|
||||
return sm;
|
||||
}
|
||||
|
||||
private SetMethod createNewSetter(final Property property) {
|
||||
private SetMethod createNewSetter(final Property property, final SwitchPoint builtinSwitchPoint) {
|
||||
property.setBuiltinSwitchPoint(builtinSwitchPoint);
|
||||
|
||||
final PropertyMap oldMap = getMap();
|
||||
final PropertyMap newMap = getNewMap(property);
|
||||
final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc);
|
||||
@ -230,12 +231,12 @@ final class SetMethodCreator {
|
||||
return new SetMethod(MH.asType(MH.guardWithTest(extCheck, casGuard, nop), fastSetter.type()), property);
|
||||
}
|
||||
|
||||
private SetMethod createNewFieldSetter() {
|
||||
return createNewSetter(new AccessorProperty(getName(), 0, sobj.getClass(), getMap().getFreeFieldSlot(), type));
|
||||
private SetMethod createNewFieldSetter(final SwitchPoint builtinSwitchPoint) {
|
||||
return createNewSetter(new AccessorProperty(getName(), 0, sobj.getClass(), getMap().getFreeFieldSlot(), type), builtinSwitchPoint);
|
||||
}
|
||||
|
||||
private SetMethod createNewSpillPropertySetter() {
|
||||
return createNewSetter(new SpillProperty(getName(), 0, getMap().getFreeSpillSlot(), type));
|
||||
private SetMethod createNewSpillPropertySetter(final SwitchPoint builtinSwitchPoint) {
|
||||
return createNewSetter(new SpillProperty(getName(), 0, getMap().getFreeSpillSlot(), type), builtinSwitchPoint);
|
||||
}
|
||||
|
||||
private PropertyMap getNewMap(final Property property) {
|
||||
|
114
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Specialization.java
Normal file
114
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Specialization.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -55,8 +55,10 @@ public final class StoredScript implements Serializable {
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param compilationId compilation id
|
||||
* @param mainClassName main class name
|
||||
* @param classBytes map of class names to class bytes
|
||||
* @param initializers initializer map, id -> FunctionInitializer
|
||||
* @param constants constants array
|
||||
*/
|
||||
public StoredScript(final int compilationId, final String mainClassName, final Map<String, byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers, final Object[] constants) {
|
||||
@ -67,6 +69,10 @@ public final class StoredScript implements Serializable {
|
||||
this.initializers = initializers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the compilation id for this StoredScript
|
||||
* @return compilation id
|
||||
*/
|
||||
public int getCompilationId() {
|
||||
return compilationId;
|
||||
}
|
||||
|
@ -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;
|
||||
|
19
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java
19
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java
@ -26,7 +26,6 @@
|
||||
package jdk.nashorn.internal.runtime.arrays;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.staticCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.ByteBuffer;
|
||||
@ -58,7 +57,7 @@ public abstract class ArrayData {
|
||||
/**
|
||||
* Length of the array data. Not necessarily length of the wrapped array.
|
||||
*/
|
||||
private long length;
|
||||
protected long length;
|
||||
|
||||
/**
|
||||
* Method handle to throw an {@link UnwarrantedOptimismException} when getting an element
|
||||
@ -520,7 +519,7 @@ public abstract class ArrayData {
|
||||
* @param type new element type
|
||||
* @return new array data
|
||||
*/
|
||||
protected abstract ArrayData convert(Class<?> type);
|
||||
public abstract ArrayData convert(Class<?> type);
|
||||
|
||||
/**
|
||||
* Push an array of items to the end of the array
|
||||
@ -655,7 +654,7 @@ public abstract class ArrayData {
|
||||
* @param size current size
|
||||
* @return next size to allocate for internal array
|
||||
*/
|
||||
protected static int nextSize(final int size) {
|
||||
public static int nextSize(final int size) {
|
||||
return alignUp(size + 1) * 2;
|
||||
}
|
||||
|
||||
@ -681,6 +680,18 @@ public abstract class ArrayData {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a fast call if one exists
|
||||
*
|
||||
* @param clazz array data class
|
||||
* @param desc callsite descriptor
|
||||
* @param request link request
|
||||
* @return fast property getter if one is found
|
||||
*/
|
||||
public GuardedInvocation findFastCallMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a fast property getter if one exists
|
||||
*
|
||||
|
2
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
2
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayFilter.java
@ -201,7 +201,7 @@ abstract class ArrayFilter extends ArrayData {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ArrayData convert(final Class<?> type) {
|
||||
public ArrayData convert(final Class<?> type) {
|
||||
underlying = underlying.convert(type);
|
||||
setLength(underlying.length());
|
||||
return this;
|
||||
|
@ -30,7 +30,6 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.JSType.getAccessorTypeIndex;
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
|
||||
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.isValid;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
@ -115,6 +114,12 @@ public abstract class ContinuousArrayData extends ArrayData {
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -175,11 +180,6 @@ public abstract class ContinuousArrayData extends ArrayData {
|
||||
return MH.asType(setHas, setHas.type().changeParameterType(2, elementType).changeParameterType(0, clazz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuardedInvocation findFastGetMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request, final String operator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Fast access guard - it is impractical for JIT performance reasons to use only CCE asType as guard :-(, also we need
|
||||
the null case explicitly, which is the one that CCE doesn't handle */
|
||||
protected static final MethodHandle FAST_ACCESS_GUARD =
|
||||
@ -269,4 +269,72 @@ public abstract class ContinuousArrayData extends ArrayData {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization - fast push implementation
|
||||
* @param arg argument
|
||||
* @return new array length
|
||||
*/
|
||||
public long fastPush(final int arg) {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization - fast push implementation
|
||||
* @param arg argument
|
||||
* @return new array length
|
||||
*/
|
||||
public long fastPush(final long arg) {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization - fast push implementation
|
||||
* @param arg argument
|
||||
* @return new array length
|
||||
*/
|
||||
public long fastPush(final double arg) {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization - fast push implementation
|
||||
* @param arg argument
|
||||
* @return new array length
|
||||
*/
|
||||
public long fastPush(final Object arg) {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization - fast pop implementation
|
||||
* @return element value
|
||||
*/
|
||||
public int fastPopInt() {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization - fast pop implementation
|
||||
* @return element value
|
||||
*/
|
||||
public long fastPopLong() {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization - fast pop implementation
|
||||
* @return element value
|
||||
*/
|
||||
public double fastPopDouble() {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialization - fast pop implementation
|
||||
* @return element value
|
||||
*/
|
||||
public Object fastPopObject() {
|
||||
throw new ClassCastException(String.valueOf(getClass())); //type is wrong, relink
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@
|
||||
package jdk.nashorn.internal.runtime.arrays;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
@ -38,7 +37,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
* Implementation of {@link ArrayData} as soon as an int has been
|
||||
* written to the array. This is the default data for new arrays
|
||||
*/
|
||||
final class IntArrayData extends ContinuousArrayData {
|
||||
final class IntArrayData extends ContinuousArrayData implements IntElements {
|
||||
/**
|
||||
* The wrapped array
|
||||
*/
|
||||
@ -64,9 +63,19 @@ final class IntArrayData extends ContinuousArrayData {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return int.class;
|
||||
}
|
||||
|
||||
private static final MethodHandle HAS_GET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "getElem", int.class, int.class).methodHandle();
|
||||
private static final MethodHandle SET_ELEM = specialCall(MethodHandles.lookup(), IntArrayData.class, "setElem", void.class, int.class, int.class).methodHandle();
|
||||
|
||||
@Override
|
||||
public Object[] asObjectArray() {
|
||||
return toObjectArray();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private int getElem(final int index) {
|
||||
if (has(index)) {
|
||||
@ -99,11 +108,6 @@ final class IntArrayData extends ContinuousArrayData {
|
||||
return new IntArrayData(array.clone(), (int) length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] asObjectArray() {
|
||||
return toObjectArray(array, (int) length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object asArrayOfType(final Class<?> componentType) {
|
||||
if (componentType == int.class) {
|
||||
@ -112,7 +116,7 @@ final class IntArrayData extends ContinuousArrayData {
|
||||
return super.asArrayOfType(componentType);
|
||||
}
|
||||
|
||||
private static Object[] toObjectArray(final int[] array, final int length) {
|
||||
private Object[] toObjectArray() {
|
||||
assert length <= array.length : "length exceeds internal array size";
|
||||
final Object[] oarray = new Object[array.length];
|
||||
|
||||
@ -123,7 +127,7 @@ final class IntArrayData extends ContinuousArrayData {
|
||||
return oarray;
|
||||
}
|
||||
|
||||
private static double[] toDoubleArray(final int[] array, final int length) {
|
||||
private double[] toDoubleArray() {
|
||||
assert length <= array.length : "length exceeds internal array size";
|
||||
final double[] darray = new double[array.length];
|
||||
|
||||
@ -134,7 +138,7 @@ final class IntArrayData extends ContinuousArrayData {
|
||||
return darray;
|
||||
}
|
||||
|
||||
private static long[] toLongArray(final int[] array, final int length) {
|
||||
private long[] toLongArray() {
|
||||
assert length <= array.length : "length exceeds internal array size";
|
||||
final long[] larray = new long[array.length];
|
||||
|
||||
@ -145,18 +149,30 @@ final class IntArrayData extends ContinuousArrayData {
|
||||
return larray;
|
||||
}
|
||||
|
||||
private LongArrayData convertToLong() {
|
||||
return new LongArrayData(toLongArray(), (int)length);
|
||||
}
|
||||
|
||||
private NumberArrayData convertToDouble() {
|
||||
return new NumberArrayData(toDoubleArray(), (int)length);
|
||||
}
|
||||
|
||||
private ObjectArrayData convertToObject() {
|
||||
return new ObjectArrayData(toObjectArray(), (int)length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayData convert(final Class<?> type) {
|
||||
if (type == Integer.class) {
|
||||
return this;
|
||||
}
|
||||
final int length = (int) length();
|
||||
if (type == Long.class) {
|
||||
return new LongArrayData(IntArrayData.toLongArray(array, length), length);
|
||||
return convertToLong();
|
||||
} else if (type == Double.class) {
|
||||
return new NumberArrayData(IntArrayData.toDoubleArray(array, length), length);
|
||||
return convertToDouble();
|
||||
} else {
|
||||
return new ObjectArrayData(IntArrayData.toObjectArray(array, length), length);
|
||||
assert type == null || (!Number.class.isAssignableFrom(type) && !type.isPrimitive());
|
||||
return convertToObject();
|
||||
}
|
||||
}
|
||||
|
||||
@ -355,4 +371,41 @@ final class IntArrayData extends ContinuousArrayData {
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final int arg) {
|
||||
final int len = (int)length;
|
||||
if (len == array.length) {
|
||||
array = Arrays.copyOf(array, nextSize(len));
|
||||
}
|
||||
array[len] = arg;
|
||||
return ++length;
|
||||
}
|
||||
|
||||
//length must not be zero
|
||||
@Override
|
||||
public int fastPopInt() {
|
||||
if (length == 0) {
|
||||
throw new ClassCastException(); //relink
|
||||
}
|
||||
final int newLength = (int)--length;
|
||||
final int elem = array[newLength];
|
||||
array[newLength] = 0;
|
||||
return elem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPopLong() {
|
||||
return fastPopInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double fastPopDouble() {
|
||||
return fastPopInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fastPopObject() {
|
||||
return fastPopInt();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
@ -22,26 +22,13 @@
|
||||
* 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;
|
||||
package jdk.nashorn.internal.runtime.arrays;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface SpecializedConstructor {
|
||||
public interface IntElements extends IntOrLongElements {
|
||||
//empty
|
||||
}
|
34
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntOrLongElements.java
Normal file
34
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/IntOrLongElements.java
Normal file
@ -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
|
||||
}
|
@ -27,7 +27,6 @@ package jdk.nashorn.internal.runtime.arrays;
|
||||
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
@ -39,7 +38,7 @@ import jdk.nashorn.internal.runtime.ScriptRuntime;
|
||||
* Implementation of {@link ArrayData} as soon as a long has been
|
||||
* written to the array
|
||||
*/
|
||||
final class LongArrayData extends ContinuousArrayData {
|
||||
final class LongArrayData extends ContinuousArrayData implements IntOrLongElements {
|
||||
/**
|
||||
* The wrapped array
|
||||
*/
|
||||
@ -56,6 +55,11 @@ final class LongArrayData extends ContinuousArrayData {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return long.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayData copy() {
|
||||
return new LongArrayData(array.clone(), (int)length());
|
||||
@ -324,4 +328,41 @@ final class LongArrayData extends ContinuousArrayData {
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final int arg) {
|
||||
return fastPush((long)arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final long arg) {
|
||||
final int len = (int)length;
|
||||
if (len == array.length) {
|
||||
array = Arrays.copyOf(array, nextSize(len));
|
||||
}
|
||||
array[len] = arg;
|
||||
return ++length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPopLong() {
|
||||
if (length == 0) {
|
||||
throw new ClassCastException();
|
||||
}
|
||||
final int newLength = (int)--length;
|
||||
final long elem = array[newLength];
|
||||
array[newLength] = 0;
|
||||
return elem;
|
||||
//return array[(int)--length];
|
||||
}
|
||||
|
||||
@Override
|
||||
public double fastPopDouble() {
|
||||
return fastPopLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fastPopObject() {
|
||||
return fastPopLong();
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ package jdk.nashorn.internal.runtime.arrays;
|
||||
import static jdk.nashorn.internal.codegen.CompilerConstants.specialCall;
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.Arrays;
|
||||
@ -38,7 +37,7 @@ import jdk.nashorn.internal.codegen.types.Type;
|
||||
* Implementation of {@link ArrayData} as soon as a double has been
|
||||
* written to the array
|
||||
*/
|
||||
final class NumberArrayData extends ContinuousArrayData {
|
||||
final class NumberArrayData extends ContinuousArrayData implements NumericElements {
|
||||
/**
|
||||
* The wrapped array
|
||||
*/
|
||||
@ -55,6 +54,11 @@ final class NumberArrayData extends ContinuousArrayData {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getElementType() {
|
||||
return double.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayData copy() {
|
||||
return new NumberArrayData(array.clone(), (int) length());
|
||||
@ -298,4 +302,41 @@ final class NumberArrayData extends ContinuousArrayData {
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final int arg) {
|
||||
return fastPush((double)arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final long arg) {
|
||||
return fastPush((double)arg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long fastPush(final double arg) {
|
||||
final int len = (int)length;
|
||||
if (len == array.length) {
|
||||
//note that fastpush never creates spares arrays, there is nothing to gain by that - it will just use even more memory
|
||||
array = Arrays.copyOf(array, nextSize(len));
|
||||
}
|
||||
array[len] = arg;
|
||||
return ++length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double fastPopDouble() {
|
||||
if (length == 0) {
|
||||
throw new ClassCastException();
|
||||
}
|
||||
final int newLength = (int)--length;
|
||||
final double elem = array[newLength];
|
||||
array[newLength] = 0;
|
||||
return elem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fastPopObject() {
|
||||
return fastPopDouble();
|
||||
}
|
||||
}
|
||||
|
35
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumericElements.java
Normal file
35
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/NumericElements.java
Normal file
@ -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
|
||||
}
|
@ -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;
|
||||
@ -56,9 +55,14 @@ final class ObjectArrayData extends ContinuousArrayData {
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
@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
|
||||
@ -231,6 +235,42 @@ final class ObjectArrayData extends ContinuousArrayData {
|
||||
return new DeletedRangeArrayFilter(this, fromIndex, toIndex);
|
||||
}
|
||||
|
||||
@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) {
|
||||
|
@ -329,7 +329,7 @@ class SparseArrayData extends ArrayData {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ArrayData convert(final Class<?> type) {
|
||||
public ArrayData convert(final Class<?> type) {
|
||||
underlying = underlying.convert(type);
|
||||
return this;
|
||||
}
|
||||
|
@ -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 @@ public abstract class TypedArrayData<T extends Buffer> extends ContinuousArrayDa
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ArrayData convert(final Class<?> type) {
|
||||
public ArrayData convert(final Class<?> type) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -26,14 +26,16 @@
|
||||
package jdk.nashorn.internal.runtime.linker;
|
||||
|
||||
import static jdk.nashorn.internal.lookup.Lookup.MH;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.SwitchPoint;
|
||||
import jdk.internal.dynalink.CallSiteDescriptor;
|
||||
import jdk.internal.dynalink.linker.GuardedInvocation;
|
||||
import jdk.internal.dynalink.linker.LinkRequest;
|
||||
import jdk.internal.dynalink.support.Guards;
|
||||
import jdk.nashorn.internal.runtime.Context;
|
||||
import jdk.nashorn.internal.runtime.FindProperty;
|
||||
import jdk.nashorn.internal.runtime.GlobalConstants;
|
||||
import jdk.nashorn.internal.runtime.ScriptObject;
|
||||
import jdk.nashorn.internal.runtime.UserAccessorProperty;
|
||||
|
||||
@ -86,27 +88,41 @@ public final class PrimitiveLookup {
|
||||
final MethodHandle protoFilter) {
|
||||
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
|
||||
|
||||
if(desc.getNameTokenCount() > 2) {
|
||||
//checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem)
|
||||
//if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be.
|
||||
//so in that case we can skip creation of primitive wrapper and start our search with the prototype.
|
||||
if (desc.getNameTokenCount() > 2) {
|
||||
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
|
||||
final FindProperty find = wrappedReceiver.findProperty(name, true);
|
||||
if(find == null) {
|
||||
|
||||
if (find == null) {
|
||||
// Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
|
||||
return null;
|
||||
} else if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
|
||||
}
|
||||
|
||||
final SwitchPoint sp = find.getProperty().getBuiltinSwitchPoint(); //can use this instead of proto filter
|
||||
if (sp instanceof Context.BuiltinSwitchPoint && !sp.hasBeenInvalidated()) {
|
||||
return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
|
||||
}
|
||||
|
||||
if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
|
||||
// If property is found in the prototype object bind the method handle directly to
|
||||
// the proto filter instead of going through wrapper instantiation below.
|
||||
final ScriptObject proto = wrappedReceiver.getProto();
|
||||
final GuardedInvocation link = proto.lookup(desc, request);
|
||||
|
||||
if (link != null) {
|
||||
final MethodHandle invocation = link.getInvocation();
|
||||
final MethodHandle invocation = link.getInvocation(); //this contains the builtin switchpoint
|
||||
|
||||
final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
|
||||
final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
|
||||
final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
|
||||
|
||||
return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final GuardedInvocation link = wrappedReceiver.lookup(desc, request);
|
||||
if (link != null) {
|
||||
MethodHandle method = link.getInvocation();
|
||||
@ -116,8 +132,10 @@ public final class PrimitiveLookup {
|
||||
assert receiverType.isAssignableFrom(wrapType.returnType());
|
||||
method = MH.filterArguments(method, 0, MH.asType(wrapFilter, wrapType.changeReturnType(receiverType)));
|
||||
}
|
||||
|
||||
return new GuardedInvocation(method, guard, link.getSwitchPoints(), null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
63
nashorn/test/examples/charcodeat-benchmark.js
Normal file
63
nashorn/test/examples/charcodeat-benchmark.js
Normal file
@ -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");
|
59
nashorn/test/examples/push-pop-benchmark.js
Normal file
59
nashorn/test/examples/push-pop-benchmark.js
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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");
|
||||
}
|
111
nashorn/test/script/basic/apply_to_call/apply_to_call5.js
Normal file
111
nashorn/test/script/basic/apply_to_call/apply_to_call5.js
Normal file
@ -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);
|
@ -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
|
61
nashorn/test/script/basic/fastpushpop.js
Normal file
61
nashorn/test/script/basic/fastpushpop.js
Normal file
@ -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);
|
||||
|
6
nashorn/test/script/basic/fastpushpop.js.EXPECTED
Normal file
6
nashorn/test/script/basic/fastpushpop.js.EXPECTED
Normal file
@ -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
|
@ -54,7 +54,7 @@ function load_bench(arg) {
|
||||
}
|
||||
}
|
||||
|
||||
print_verbose(arg, "loading '" + arg.name + "' [" + f + "]...");
|
||||
print_verbose(arg, "loading '" + arg.name + "' [" + f + "]... " + file_name);
|
||||
load(file_name);
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ function run_one_benchmark(arg, iters) {
|
||||
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 @@ function run_one_benchmark(arg, iters) {
|
||||
|
||||
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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user